feat: add click-to-copy IP address with localized tooltip

This commit is contained in:
NetworkCats
2026-03-07 03:56:05 +08:00
parent 30b65d5b25
commit 2ed0bf3b6d
18 changed files with 103 additions and 1 deletions
+3
View File
@@ -188,3 +188,6 @@ msgstr "فشل البحث في قاعدة البيانات"
msgid "Template render failed"
msgstr "فشل عرض القالب"
msgid "Copied"
msgstr "تم النسخ"
+3
View File
@@ -188,3 +188,6 @@ msgstr "Datenbankabfrage fehlgeschlagen"
msgid "Template render failed"
msgstr "Vorlagen-Rendering fehlgeschlagen"
msgid "Copied"
msgstr "Kopiert"
+3
View File
@@ -188,3 +188,6 @@ msgstr "Database lookup failed"
msgid "Template render failed"
msgstr "Template render failed"
msgid "Copied"
msgstr "Copied"
+3
View File
@@ -188,3 +188,6 @@ msgstr "La consulta a la base de datos fallo"
msgid "Template render failed"
msgstr "La renderizacion de la plantilla fallo"
msgid "Copied"
msgstr "Copiado"
+3
View File
@@ -188,3 +188,6 @@ msgstr "Echec de la recherche dans la base de donnees"
msgid "Template render failed"
msgstr "Echec du rendu du modele"
msgid "Copied"
msgstr "Copie"
+3
View File
@@ -188,3 +188,6 @@ msgstr "Pencarian basis data gagal"
msgid "Template render failed"
msgstr "Render template gagal"
msgid "Copied"
msgstr "Disalin"
+3
View File
@@ -188,3 +188,6 @@ msgstr "Ricerca nel database fallita"
msgid "Template render failed"
msgstr "Rendering del template fallito"
msgid "Copied"
msgstr "Copiato"
+3
View File
@@ -188,3 +188,6 @@ msgstr "データベース検索に失敗しました"
msgid "Template render failed"
msgstr "テンプレートのレンダリングに失敗しました"
msgid "Copied"
msgstr "コピーしました"
+3
View File
@@ -188,3 +188,6 @@ msgstr "데이터베이스 조회 실패"
msgid "Template render failed"
msgstr "템플릿 렌더링 실패"
msgid "Copied"
msgstr "복사됨"
+3
View File
@@ -188,3 +188,6 @@ msgstr "Database-opzoeking mislukt"
msgid "Template render failed"
msgstr "Sjabloonweergave mislukt"
msgid "Copied"
msgstr "Gekopieerd"
+3
View File
@@ -188,3 +188,6 @@ msgstr "Falha na consulta ao banco de dados"
msgid "Template render failed"
msgstr "Falha na renderização do template"
msgid "Copied"
msgstr "Copiado"
+3
View File
@@ -188,3 +188,6 @@ msgstr "Ошибка поиска в базе данных"
msgid "Template render failed"
msgstr "Ошибка рендеринга шаблона"
msgid "Copied"
msgstr "Скопировано"
+3
View File
@@ -188,3 +188,6 @@ msgstr "数据库查询失败"
msgid "Template render failed"
msgstr "模板渲染失败"
msgid "Copied"
msgstr "已复制"
+3
View File
@@ -188,3 +188,6 @@ msgstr "資料庫查詢失敗"
msgid "Template render failed"
msgstr "範本渲染失敗"
msgid "Copied"
msgstr "已複製"
+4
View File
@@ -100,6 +100,7 @@ struct IndexTemplate {
t_footer_source: &'static str,
t_footer_db: &'static str,
t_footer_attribution: &'static str,
t_copied: &'static str,
t_table_aria: &'static str,
t_faq_aria: &'static str,
t_nav_aria: &'static str,
@@ -332,6 +333,7 @@ fn build_translations(locale: Locale) -> Translations {
t_footer_attribution: i18n::translate(locale, "IP data provided by:"),
t_error: i18n::translate(locale, "Error"),
t_go_home: i18n::translate(locale, "Go to Home"),
t_copied: i18n::translate(locale, "Copied"),
t_table_aria: i18n::translate(locale, "IP address information"),
t_faq_aria: i18n::translate(locale, "Frequently Asked Questions"),
t_nav_aria: i18n::translate(locale, "Project links"),
@@ -391,6 +393,7 @@ struct Translations {
t_footer_attribution: &'static str,
t_error: &'static str,
t_go_home: &'static str,
t_copied: &'static str,
t_table_aria: &'static str,
t_faq_aria: &'static str,
t_nav_aria: &'static str,
@@ -636,6 +639,7 @@ pub async fn root(
t_footer_source: t.t_footer_source,
t_footer_db: t.t_footer_db,
t_footer_attribution: t.t_footer_attribution,
t_copied: t.t_copied,
t_table_aria: t.t_table_aria,
t_faq_aria: t.t_faq_aria,
t_nav_aria: t.t_nav_aria,
+30
View File
@@ -136,3 +136,33 @@
if(!error.hidden)showError(validate(input.value));
});
})();
(function(){
"use strict";
var wrap=document.querySelector(".ip-copy-wrap");
if(!wrap)return;
var h1=wrap.querySelector(".ip-display");
var tooltip=wrap.querySelector(".ip-copied-tooltip");
if(!h1||!tooltip||!navigator.clipboard)return;
var timer=0;
wrap.style.cursor="pointer";
wrap.setAttribute("role","button");
wrap.setAttribute("tabindex","0");
function copyIp(){
var ip=h1.textContent.trim();
navigator.clipboard.writeText(ip).then(function(){
tooltip.hidden=false;
clearTimeout(timer);
timer=setTimeout(function(){tooltip.hidden=true;},1500);
});
}
wrap.addEventListener("click",copyIp);
wrap.addEventListener("keydown",function(e){
if(e.key==="Enter"||e.key===" "){
e.preventDefault();
copyIp();
}
});
})();
+23
View File
@@ -136,6 +136,13 @@ main {
}
}
.ip-copy-wrap {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
}
.ip-display {
text-align: center;
font-size: clamp(28px, 6vw, 42px);
@@ -146,6 +153,22 @@ main {
word-break: break-all;
}
.ip-copied-tooltip {
font-size: 13px;
font-weight: 500;
color: #FFF;
background: var(--color-label);
padding: 4px 12px;
border-radius: 6px;
pointer-events: none;
animation: ip-tooltip-fade 1.5s ease-out;
}
@keyframes ip-tooltip-fade {
0%, 70% { opacity: 1; }
100% { opacity: 0; }
}
.info-table {
inline-size: 100%;
border-collapse: collapse;
+4 -1
View File
@@ -145,7 +145,10 @@
{% include "_search_form.html" %}
<div itemscope itemtype="https://schema.org/WebPage">
<h1 class="ip-display" itemprop="name">{{ ip }}</h1>
<div class="ip-copy-wrap" data-copied="{{ t_copied }}">
<h1 class="ip-display" itemprop="name">{{ ip }}</h1>
<span class="ip-copied-tooltip" aria-live="polite" hidden>{{ t_copied }}</span>
</div>
<table class="info-table" aria-label="{{ t_table_aria }}">
<tbody>