смена галочки на тоггл и работа с текстом, замена апи

This commit is contained in:
Илья Братских 2026-06-24 08:55:07 +03:00 committed by KBAHTNET
parent 26bdf14af5
commit e4d289b9a3
4 changed files with 116 additions and 25 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ node_modules/
npm-debug.log* npm-debug.log*
node_trace.*.log node_trace.*.log
.env .env
flags

View File

@ -70,6 +70,7 @@
background: var(--surface); background: var(--surface);
box-shadow: var(--shadow); box-shadow: var(--shadow);
backdrop-filter: blur(18px); backdrop-filter: blur(18px);
overflow: hidden;
} }
.hero { .hero {
@ -171,7 +172,7 @@
.server-card { .server-card {
display: grid; display: grid;
grid-template-columns: 3.5rem 1fr auto; grid-template-columns: 3.5rem minmax(0, 1fr) auto;
gap: 0.9rem; gap: 0.9rem;
align-items: center; align-items: center;
width: 100%; width: 100%;
@ -213,7 +214,15 @@
} }
.server-name { .server-name {
display: block;
font-weight: 800; font-weight: 800;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.server-info {
min-width: 0;
} }
.server-meta, .server-meta,
@ -222,9 +231,18 @@
font-size: 0.82rem; font-size: 0.82rem;
} }
.server-meta {
display: block;
margin-top: 0.15rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ping { .ping {
min-width: 4.5rem; min-width: 4.5rem;
text-align: right; text-align: right;
white-space: nowrap;
} }
.pill { .pill {
@ -241,24 +259,82 @@
.controls-grid { .controls-grid {
display: grid; display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-columns: minmax(0, 1fr);
gap: 0.8rem; gap: 0.8rem;
} }
.checkbox-row { .toggle-row {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.55rem; justify-content: space-between;
gap: 0.85rem;
min-height: 100%; min-height: 100%;
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: 1rem; border-radius: 1rem;
padding: 0.75rem 0.9rem; padding: 0.75rem 0.9rem;
color: var(--muted); color: var(--muted);
background: var(--surface-strong); background: var(--surface-strong);
cursor: pointer;
overflow: hidden;
} }
.checkbox-row input { .toggle-row input {
accent-color: var(--accent); 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 { .start-row {
@ -372,6 +448,7 @@
margin-top: 0.55rem; margin-top: 0.55rem;
color: var(--muted); color: var(--muted);
font-size: 0.9rem; font-size: 0.9rem;
overflow-wrap: anywhere;
} }
.graph-container { .graph-container {
@ -412,9 +489,8 @@
<div> <div>
<h1>Измерение скорости сети</h1> <h1>Измерение скорости сети</h1>
<p class="lead"> <p class="lead">
Выберите сервер, проверьте задержку до каждого узла и запустите Выберите ближайший сервер, проверьте задержку и запустите тест
download/upload тест. Настройки темы и акцентного цвета сохраняются скорости. Тема и акцентный цвет сохраняются в этом браузере.
в браузере.
</p> </p>
</div> </div>
@ -448,19 +524,25 @@
<aside class="panel" aria-label="Параметры теста"> <aside class="panel" aria-label="Параметры теста">
<div class="controls-grid"> <div class="controls-grid">
<label class="field"> <label class="field">
Длительность этапа, минут Длительность этапа, секунд
<input <input
type="number" type="number"
id="durationInput" id="durationInput"
value="0.5" value="30"
min="0.1" min="5"
max="10" max="600"
step="0.1" step="5"
/> />
</label> </label>
<label class="checkbox-row"> <label class="toggle-row">
<input type="checkbox" id="simultaneousCheckbox" checked /> <span class="toggle-text">
Одновременный тест <span class="toggle-title">Параллельный тест</span>
<span class="toggle-description">
Скачивание и отдача одновременно
</span>
</span>
<input type="checkbox" id="simultaneousCheckbox" />
<span class="toggle-track" aria-hidden="true"></span>
</label> </label>
</div> </div>
<div class="start-row"> <div class="start-row">
@ -469,7 +551,7 @@
</button> </button>
<div class="timer" id="timerDisplay">--:--</div> <div class="timer" id="timerDisplay">--:--</div>
</div> </div>
<p class="status" id="targetServerText">Сервер не выбран</p> <p class="status" id="targetServerText">Выберите сервер для теста</p>
</aside> </aside>
</div> </div>
@ -660,7 +742,7 @@
button.innerHTML = ` button.innerHTML = `
<span class="flag">${flagContent}</span> <span class="flag">${flagContent}</span>
<span> <span class="server-info">
<span class="server-name">${escapeHtml(server.name)}</span> <span class="server-name">${escapeHtml(server.name)}</span>
<span class="server-meta">${escapeHtml(server.country)} · ${escapeHtml(server.address)}</span> <span class="server-meta">${escapeHtml(server.country)} · ${escapeHtml(server.address)}</span>
</span> </span>
@ -671,7 +753,7 @@
}); });
elements.serverStatus.textContent = servers.length elements.serverStatus.textContent = servers.length
? "Выберите сервер для теста скорости." ? "Нажмите на карточку сервера, чтобы выбрать цель теста."
: "В конфиге нет серверов."; : "В конфиге нет серверов.";
} }
@ -697,8 +779,8 @@
function updateSelectedServerText() { function updateSelectedServerText() {
const server = getSelectedServer(); const server = getSelectedServer();
elements.targetServerText.textContent = server elements.targetServerText.textContent = server
? `Цель: ${server.name}, ${server.country} (${server.address})` ? `Тест будет запущен через ${server.name} (${server.country}).`
: "Сервер не выбран"; : "Выберите сервер для теста.";
} }
async function refreshAllPings() { async function refreshAllPings() {
@ -1074,8 +1156,8 @@
elements.startBtn.disabled = true; elements.startBtn.disabled = true;
resetMetrics(); resetMetrics();
const minutes = parseFloat(elements.durationInput.value) || 0.5; const seconds = parseFloat(elements.durationInput.value) || 30;
const singleDurationMs = Math.max(5000, minutes * 60 * 1000); const singleDurationMs = Math.max(5000, seconds * 1000);
const simultaneous = elements.simultaneousCheckbox.checked; const simultaneous = elements.simultaneousCheckbox.checked;
totalTestDurationMs = simultaneous ? singleDurationMs : singleDurationMs * 2; totalTestDurationMs = simultaneous ? singleDurationMs : singleDurationMs * 2;
globalTestStartTime = performance.now(); globalTestStartTime = performance.now();

View File

@ -16,7 +16,8 @@ const CHUNK_SIZE = 64 * 1024;
const INDEX_PATH = path.join(__dirname, "index.html"); const INDEX_PATH = path.join(__dirname, "index.html");
const SERVERS_CONFIG_PATH = path.join(__dirname, "servers.json"); const SERVERS_CONFIG_PATH = path.join(__dirname, "servers.json");
const FLAGS_DIR = path.join(__dirname, "flags"); 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(); const serversConfig = loadServersConfig();

View File

@ -7,6 +7,13 @@
"address": "http://localhost:3000", "address": "http://localhost:3000",
"country": "Локальный сервер", "country": "Локальный сервер",
"countryCode": "un" "countryCode": "un"
},
{
"id": "vpn1",
"name": "VPN сервер в Нидерландах",
"address": "http://vpn1.bratskih.tech:3000",
"country": "Нидерланды",
"countryCode": "nl"
} }
] ]
} }