diff --git a/.gitignore b/.gitignore index cc9c0c0..08f010b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules/ npm-debug.log* node_trace.*.log .env +flags diff --git a/index.html b/index.html index 172459e..5619624 100644 --- a/index.html +++ b/index.html @@ -70,6 +70,7 @@ background: var(--surface); box-shadow: var(--shadow); backdrop-filter: blur(18px); + overflow: hidden; } .hero { @@ -171,7 +172,7 @@ .server-card { display: grid; - grid-template-columns: 3.5rem 1fr auto; + grid-template-columns: 3.5rem minmax(0, 1fr) auto; gap: 0.9rem; align-items: center; width: 100%; @@ -213,7 +214,15 @@ } .server-name { + display: block; font-weight: 800; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .server-info { + min-width: 0; } .server-meta, @@ -222,9 +231,18 @@ font-size: 0.82rem; } + .server-meta { + display: block; + margin-top: 0.15rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .ping { min-width: 4.5rem; text-align: right; + white-space: nowrap; } .pill { @@ -241,24 +259,82 @@ .controls-grid { display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-columns: minmax(0, 1fr); gap: 0.8rem; } - .checkbox-row { + .toggle-row { display: flex; align-items: center; - gap: 0.55rem; + justify-content: space-between; + gap: 0.85rem; min-height: 100%; border: 1px solid var(--border); border-radius: 1rem; padding: 0.75rem 0.9rem; color: var(--muted); background: var(--surface-strong); + cursor: pointer; + overflow: hidden; } - .checkbox-row input { - accent-color: var(--accent); + .toggle-row input { + position: absolute; + opacity: 0; + pointer-events: none; + } + + .toggle-text { + display: grid; + gap: 0.15rem; + min-width: 0; + } + + .toggle-title { + color: var(--text); + font-weight: 800; + } + + .toggle-description { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 0.82rem; + } + + .toggle-track { + position: relative; + flex: 0 0 auto; + width: 3.25rem; + height: 1.8rem; + border: 1px solid var(--border); + border-radius: 999px; + background: color-mix(in srgb, var(--muted) 22%, transparent); + transition: + background 0.2s, + border-color 0.2s; + } + + .toggle-track::after { + content: ""; + position: absolute; + top: 0.22rem; + left: 0.22rem; + width: 1.22rem; + height: 1.22rem; + border-radius: 50%; + background: var(--surface-strong); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.22); + transition: transform 0.2s; + } + + .toggle-row input:checked + .toggle-track { + border-color: var(--accent); + background: var(--accent); + } + + .toggle-row input:checked + .toggle-track::after { + transform: translateX(1.45rem); } .start-row { @@ -372,6 +448,7 @@ margin-top: 0.55rem; color: var(--muted); font-size: 0.9rem; + overflow-wrap: anywhere; } .graph-container { @@ -412,9 +489,8 @@

Измерение скорости сети

- Выберите сервер, проверьте задержку до каждого узла и запустите - download/upload тест. Настройки темы и акцентного цвета сохраняются - в браузере. + Выберите ближайший сервер, проверьте задержку и запустите тест + скорости. Тема и акцентный цвет сохраняются в этом браузере.

@@ -448,19 +524,25 @@ @@ -660,7 +742,7 @@ button.innerHTML = ` ${flagContent} - + ${escapeHtml(server.name)} ${escapeHtml(server.country)} · ${escapeHtml(server.address)} @@ -671,7 +753,7 @@ }); elements.serverStatus.textContent = servers.length - ? "Выберите сервер для теста скорости." + ? "Нажмите на карточку сервера, чтобы выбрать цель теста." : "В конфиге нет серверов."; } @@ -697,8 +779,8 @@ function updateSelectedServerText() { const server = getSelectedServer(); elements.targetServerText.textContent = server - ? `Цель: ${server.name}, ${server.country} (${server.address})` - : "Сервер не выбран"; + ? `Тест будет запущен через ${server.name} (${server.country}).` + : "Выберите сервер для теста."; } async function refreshAllPings() { @@ -1074,8 +1156,8 @@ elements.startBtn.disabled = true; resetMetrics(); - const minutes = parseFloat(elements.durationInput.value) || 0.5; - const singleDurationMs = Math.max(5000, minutes * 60 * 1000); + const seconds = parseFloat(elements.durationInput.value) || 30; + const singleDurationMs = Math.max(5000, seconds * 1000); const simultaneous = elements.simultaneousCheckbox.checked; totalTestDurationMs = simultaneous ? singleDurationMs : singleDurationMs * 2; globalTestStartTime = performance.now(); diff --git a/server.js b/server.js index a728466..f5786cd 100644 --- a/server.js +++ b/server.js @@ -16,7 +16,8 @@ const CHUNK_SIZE = 64 * 1024; const INDEX_PATH = path.join(__dirname, "index.html"); const SERVERS_CONFIG_PATH = path.join(__dirname, "servers.json"); const FLAGS_DIR = path.join(__dirname, "flags"); -const FLAG_API_URL = "https://flagcdn.com"; +// const FLAG_API_URL = "https://flagcdn.com"; +const FLAG_API_URL = "https://flagicons.lipis.dev/flags/4x3"; const serversConfig = loadServersConfig(); diff --git a/servers.json b/servers.json index f923b3e..0ecbfd2 100644 --- a/servers.json +++ b/servers.json @@ -7,6 +7,13 @@ "address": "http://localhost:3000", "country": "Локальный сервер", "countryCode": "un" + }, + { + "id": "vpn1", + "name": "VPN сервер в Нидерландах", + "address": "http://vpn1.bratskih.tech:3000", + "country": "Нидерланды", + "countryCode": "nl" } ] }