Minor UI fixes

This commit is contained in:
ayurishchev committed 2026-08-26 22:19:42 +03:00
1 parent 6410273cf8
commit 7a93594e69
34 files changed
+254 -117

No files matched your search

+1 -1
View File
@@ -1,4 +1,4 @@
118e09f98944ac59593af603c04a1d5f0e7cafb6549b5a562300bc31d9c769da control-api
48c9b99fa88be751d9badfba8b7d80f894e326a743a90e85478f1d2251ce4ab6 validator-agent
8877cf7c6d2bdd58faf70865be602b3db5f18508f4607c8942bc8899ce0fb1e6 prober
4c7cf560b4a7b87f8de0fcc5a4fe6200c45eadf5ae04b022d67c8a8e196f39cc admin-dashboard
83fc0bcf22277ef9fbcd79761999f7b474fd717677d21c75a688b31684a22b15 admin-dashboard
Binary file not shown.
+50 -24
View File
@@ -6,10 +6,11 @@
Palette: cool signal-blue accent on a blue-grey neutral ground (was a
warm teal/green), semantic status colors kept independent of the
accent. Radius: a sharp 2/3/4/6px scale (was 6/10/16px + pill) — status
badges are square tags, not pills. Typography: --font-display
(IBM Plex Mono, already vendored) carries headings/nav/labels/table
heads — an operations-console register — while --font-ui (Manrope)
stays on body copy and form microcopy for readability at length.
badges are square tags, not pills. Typography: --font-display and
--font-mono are both JetBrains Mono — one unified operations-console
monospace register for headings/nav/labels/table heads *and* raw data
(addresses, counters) alike — while --font-ui (IBM Plex Sans) stays on
body copy and form microcopy for readability at length.
Both a light and a dark palette are defined. The bare :root (no
data-theme attribute) follows the OS/browser color-scheme; the sidebar
toggle (see layout.html) stamps documentElement with
@@ -48,14 +49,13 @@
--shadow-sm: 0 1px 2px rgba(12, 18, 30, .06), 0 1px 1px rgba(12, 18, 30, .05);
--shadow-md: 0 10px 28px rgba(12, 18, 30, .16);
--font-ui: "Manrope", -apple-system, "Segoe UI", sans-serif;
--font-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
/* Same physical face as --font-mono today (only Plex Mono is vendored)
but a distinct token: it marks the "console chrome" role (headings,
nav, labels, table heads) versus --font-mono's "raw data" role
(addresses, counters), so the two can diverge later without a
find-and-replace. */
--font-display: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
--font-ui: "IBM Plex Sans", -apple-system, "Segoe UI", sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
/* Same value as --font-mono: kept as a distinct token because it marks
a different semantic role (console chrome — headings, nav, labels,
table heads — versus --font-mono's "raw data" role), so the two can
diverge later without a find-and-replace. */
--font-display: "JetBrains Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
color-scheme: light;
}
@@ -136,18 +136,31 @@ body {
-webkit-font-smoothing: antialiased;
}
a { color: inherit; }
::selection { background: var(--accent-soft); color: var(--text); }
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
/* faint technical grid texture on the page ground, behind .shell */
.bg-grid {
position: fixed; inset: 0; z-index: 0; pointer-events: none;
background-image:
linear-gradient(var(--border-soft) 1px, transparent 1px),
linear-gradient(90deg, var(--border-soft) 1px, transparent 1px);
background-size: 48px 48px;
opacity: .35;
-webkit-mask-image: linear-gradient(to bottom, black, transparent 640px);
mask-image: linear-gradient(to bottom, black, transparent 640px);
}
h1, h2, h3 { text-wrap: balance; }
h1 {
font-family: var(--font-display);
font-size: 19px; font-weight: 500; letter-spacing: -.005em;
font-size: 19px; font-weight: 700; letter-spacing: -.005em;
margin: 0 0 4px;
}
h2.section-title {
font-family: var(--font-display);
font-size: 12px;
font-weight: 500;
font-weight: 700;
text-transform: uppercase;
letter-spacing: .07em;
color: var(--text-muted);
@@ -157,7 +170,7 @@ section:first-of-type h2.section-title,
main > h2.section-title:first-child { margin-top: 0; }
/* ---------- shell layout ---------- */
.shell { display: grid; grid-template-columns: 224px 1fr; min-height: 100vh; }
.shell { position: relative; z-index: 1; display: grid; grid-template-columns: 224px 1fr; min-height: 100vh; }
.sidebar {
background: var(--surface);
border-right: 1px solid var(--border);
@@ -179,7 +192,7 @@ main > h2.section-title:first-child { margin-top: 0; }
.brand-mark svg { width: 15px; height: 15px; }
.brand-name {
font-family: var(--font-display);
font-weight: 500; font-size: 13px; letter-spacing: -.005em; line-height: 1.2;
font-weight: 700; font-size: 13px; letter-spacing: -.005em; line-height: 1.2;
}
.brand-name small { display: block; font-weight: 400; font-size: 10.5px; color: var(--text-faint); letter-spacing: .02em; }
@@ -192,7 +205,7 @@ nav.nav-groups { display: flex; flex-direction: column; gap: 1px; }
text-decoration: none;
color: var(--text-muted);
font-family: var(--font-display);
font-weight: 500;
font-weight: 600;
font-size: 12.5px;
transition: background .12s ease, color .12s ease, border-color .12s ease;
}
@@ -219,7 +232,10 @@ nav.nav-groups { display: flex; flex-direction: column; gap: 1px; }
background: var(--success);
box-shadow: 0 0 0 3px var(--success-soft);
flex-shrink: 0;
animation: pulse 2.2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .pulse-dot { animation: none; } }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
.theme-toggle {
display: grid; place-items: center;
@@ -264,16 +280,18 @@ nav.nav-groups { display: flex; flex-direction: column; gap: 1px; }
.stat-card { background: var(--surface); padding: 12px 14px; }
.stat-card .value {
font-family: var(--font-mono);
font-size: 22px; font-weight: 500;
font-size: 22px; font-weight: 700;
display: block;
font-variant-numeric: tabular-nums;
}
.stat-card .label {
font-family: var(--font-display);
font-size: 10.5px; color: var(--text-muted); font-weight: 500;
font-size: 10.5px; color: var(--text-muted); font-weight: 600;
text-transform: uppercase; letter-spacing: .06em;
}
.stat-card.accented .value { color: var(--accent); }
.stat-card.warn .value { color: var(--warning); }
.stat-card.bad .value { color: var(--danger); }
/* ---------- panels ---------- */
.panel {
@@ -285,13 +303,20 @@ nav.nav-groups { display: flex; flex-direction: column; gap: 1px; }
}
.panel + .panel { margin-top: 14px; }
.panel-body { padding: 16px 18px; }
.panel-head {
display: flex; align-items: center; justify-content: space-between;
padding: 10px 16px;
border-bottom: 1px solid var(--border-soft);
background: var(--surface-alt);
}
.panel-head h2 { font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--text-muted); }
/* ---------- forms ---------- */
.field-row { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; }
.field { display: flex; flex-direction: column; gap: 5px; flex: 1 1 220px; }
.field label {
font-family: var(--font-display);
font-size: 10.5px; font-weight: 500;
font-size: 10.5px; font-weight: 700;
text-transform: uppercase; letter-spacing: .05em;
color: var(--text-muted);
}
@@ -318,7 +343,7 @@ input:focus, textarea:focus, select:focus {
.btn {
display: inline-flex; align-items: center; gap: 6px;
font-family: var(--font-display);
font-weight: 500;
font-weight: 700;
font-size: 12.5px;
padding: 8px 13px;
border-radius: var(--radius-xs);
@@ -348,7 +373,7 @@ thead th {
text-transform: uppercase;
letter-spacing: .06em;
color: var(--text-faint);
font-weight: 500;
font-weight: 700;
padding: 9px 18px;
border-bottom: 1px solid var(--border);
background: var(--surface-alt);
@@ -368,7 +393,7 @@ td.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; colo
border-radius: var(--radius-xs);
font-family: var(--font-display);
font-size: 10.5px;
font-weight: 500;
font-weight: 700;
text-transform: uppercase;
letter-spacing: .02em;
white-space: nowrap;
@@ -401,6 +426,7 @@ td.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; colo
.muted { color: var(--text-faint); font-size: 12px; }
code.inline { font-family: var(--font-mono); background: var(--surface-alt); border: 1px solid var(--border-soft); padding: 1px 6px; border-radius: var(--radius-xs); font-size: 12px; }
.section-note { padding: 14px 16px 4px; font-size: 12.5px; color: var(--text-muted); }
.inline-form { display: flex; gap: 6px; align-items: center; }
.inline-form input, .inline-form textarea { margin: 0; }
@@ -432,7 +458,7 @@ code.inline { font-family: var(--font-mono); background: var(--surface-alt); bor
background: var(--surface);
position: sticky; top: 0; z-index: 30;
}
.topbar-mobile strong { font-family: var(--font-display); font-weight: 500; font-size: 13px; }
.topbar-mobile strong { font-family: var(--font-display); font-size: 13px; }
label.burger {
width: 32px; height: 32px; border-radius: var(--radius-xs);
border: 1px solid var(--border);
+17 -13
View File
@@ -9,20 +9,24 @@ commit, if a newer version is actually needed.
|---|---|---|---|
| `htmx.min.js` | https://unpkg.com/htmx.org@2.0.10/dist/htmx.min.js | 2.0.10 | 2026-08-23 |
| `alpine.min.js` | https://unpkg.com/alpinejs@3.16.2/dist/cdn.min.js | 3.16.2 | 2026-08-23 |
| `fonts.css` + `fonts/*.woff2` | Google Fonts CSS2 API (`family=Manrope:wght@500;600;700;800\|family=IBM+Plex+Mono:wght@400;500`) | Manrope v20, IBM Plex Mono v20 | 2026-08-23 |
| `fonts.css` + `fonts/*.woff2` | Google Fonts CSS2 API (`family=JetBrains+Mono:wght@400;500;600;700;800\|family=IBM+Plex+Sans:wght@400;500;600;700`) | JetBrains Mono v24, IBM Plex Sans v23 | 2026-08-26 |
## Fonts
The dashboard's design system (`../dashboard.css`) uses **Manrope**
(UI chrome/headings — a variable font, so one file per subset covers all
four vendored weights) and **IBM Plex Mono** (tabular data: IP addresses,
timestamps, ports — one file per weight per subset). Only the `latin`,
`latin-ext`, `cyrillic`, and `cyrillic-ext` subsets are vendored (the UI
is Russian/English only) — `greek` and `vietnamese` from the upstream CSS
were dropped. `fonts.css` was hand-rewritten from the fetched Google Fonts
CSS to point at the local `fonts/*.woff2` files instead of
`fonts.gstatic.com`, keeping the original `unicode-range` subsetting so
browsers still only fetch the subset(s) actually used.
The dashboard's design system (`../dashboard.css`) uses **JetBrains
Mono** (all headings/nav/labels/table chrome *and* tabular data — IP
addresses, timestamps, ports, counters — a single monospace register
throughout) and **IBM Plex Sans** (body copy, form microcopy). Both are
variable fonts, so one file per subset covers every vendored weight.
Only the `latin`, `latin-ext`, `cyrillic`, and `cyrillic-ext` subsets are
vendored (the UI is Russian/English only) — `greek` and `vietnamese` from
the upstream CSS were dropped. `fonts.css` was hand-rewritten from the
fetched Google Fonts CSS to point at the local `fonts/*.woff2` files
instead of `fonts.gstatic.com`, keeping the original `unicode-range`
subsetting so browsers still only fetch the subset(s) actually used.
Replaces the previously vendored Manrope + IBM Plex Mono (removed
2026-08-26 — superseded, no longer referenced by `dashboard.css`).
No CSS framework is vendored: the design system in `dashboard.css` is
hand-written (sidebar shell, panels, tables, pills, forms, buttons,
@@ -37,5 +41,5 @@ doesn't use any component that requires JS beyond htmx/Alpine themselves
(the mobile sidebar toggle is a pure-CSS checkbox trick, not JS;
confirmations use the browser's native dialog via htmx's `hx-confirm`).
Licenses: htmx (BSD 2-Clause), Alpine.js (MIT), Manrope (OFL-1.1), IBM Plex
Mono (OFL-1.1) — all permit vendoring/redistribution unmodified.
Licenses: htmx (BSD 2-Clause), Alpine.js (MIT), JetBrains Mono (OFL-1.1),
IBM Plex Sans (OFL-1.1) — all permit vendoring/redistribution unmodified.
+171 -75
View File
@@ -1,192 +1,288 @@
@font-face {
font-family: 'IBM Plex Mono';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("fonts/ibm-plex-mono-cyrillic-ext.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-cyrillic-ext.woff2") format("woff2");
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'IBM Plex Mono';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("fonts/ibm-plex-mono-cyrillic.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-cyrillic.woff2") format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'IBM Plex Mono';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("fonts/ibm-plex-mono-latin-ext.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'IBM Plex Mono';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("fonts/ibm-plex-mono-latin.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'IBM Plex Mono';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("fonts/ibm-plex-mono-cyrillic-ext-2.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-cyrillic-ext.woff2") format("woff2");
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'IBM Plex Mono';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("fonts/ibm-plex-mono-cyrillic-2.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-cyrillic.woff2") format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'IBM Plex Mono';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("fonts/ibm-plex-mono-latin-ext-2.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'IBM Plex Mono';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("fonts/ibm-plex-mono-latin-2.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Manrope';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("fonts/manrope-cyrillic-ext.woff2") format("woff2");
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'Manrope';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("fonts/manrope-cyrillic.woff2") format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Manrope';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("fonts/manrope-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Manrope';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("fonts/manrope-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Manrope';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("fonts/manrope-cyrillic-ext.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-cyrillic-ext.woff2") format("woff2");
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'Manrope';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("fonts/manrope-cyrillic.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-cyrillic.woff2") format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Manrope';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("fonts/manrope-latin-ext.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Manrope';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("fonts/manrope-latin.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Manrope';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("fonts/manrope-cyrillic-ext.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-cyrillic-ext.woff2") format("woff2");
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'Manrope';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("fonts/manrope-cyrillic.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-cyrillic.woff2") format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Manrope';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("fonts/manrope-latin-ext.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Manrope';
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("fonts/manrope-latin.woff2") format("woff2");
src: url("fonts/ibm-plex-sans-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Manrope';
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 800;
font-weight: 400;
font-display: swap;
src: url("fonts/manrope-cyrillic-ext.woff2") format("woff2");
src: url("fonts/jetbrains-mono-cyrillic-ext.woff2") format("woff2");
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'Manrope';
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 800;
font-weight: 400;
font-display: swap;
src: url("fonts/manrope-cyrillic.woff2") format("woff2");
src: url("fonts/jetbrains-mono-cyrillic.woff2") format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Manrope';
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 800;
font-weight: 400;
font-display: swap;
src: url("fonts/manrope-latin-ext.woff2") format("woff2");
src: url("fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Manrope';
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("fonts/jetbrains-mono-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("fonts/jetbrains-mono-cyrillic-ext.woff2") format("woff2");
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("fonts/jetbrains-mono-cyrillic.woff2") format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("fonts/jetbrains-mono-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("fonts/jetbrains-mono-cyrillic-ext.woff2") format("woff2");
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("fonts/jetbrains-mono-cyrillic.woff2") format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("fonts/jetbrains-mono-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("fonts/jetbrains-mono-cyrillic-ext.woff2") format("woff2");
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("fonts/jetbrains-mono-cyrillic.woff2") format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("fonts/jetbrains-mono-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 800;
font-display: swap;
src: url("fonts/manrope-latin.woff2") format("woff2");
src: url("fonts/jetbrains-mono-cyrillic-ext.woff2") format("woff2");
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 800;
font-display: swap;
src: url("fonts/jetbrains-mono-cyrillic.woff2") format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 800;
font-display: swap;
src: url("fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 800;
font-display: swap;
src: url("fonts/jetbrains-mono-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,6 +3,7 @@
<html lang="ru">
<head>{{template "html_head" .}}</head>
<body>
<div class="bg-grid"></div>
<input type="checkbox" id="nav-toggle" class="nav-toggle">
<div class="shell">
{{template "sidebar_nav" .}}
@@ -27,6 +28,7 @@
<p class="muted">Сначала создайте хотя бы одну <a href="/targets">группу целей</a>.</p>
{{else}}
<div class="panel">
<div class="panel-head"><h2>Новый тип проверки</h2></div>
<div class="panel-body">
<form hx-post="/check-types" hx-target="#checktypes-table-wrap" hx-swap="innerHTML" hx-on::after-request="this.reset()">
<div class="field-row">
@@ -3,6 +3,7 @@
<html lang="ru">
<head>{{template "html_head" .}}</head>
<body>
<div class="bg-grid"></div>
<input type="checkbox" id="nav-toggle" class="nav-toggle">
<div class="shell">
{{template "sidebar_nav" .}}
+1
View File
@@ -3,6 +3,7 @@
<html lang="ru">
<head>{{template "html_head" .}}</head>
<body>
<div class="bg-grid"></div>
<input type="checkbox" id="nav-toggle" class="nav-toggle">
<div class="shell">
{{template "sidebar_nav" .}}
@@ -3,6 +3,7 @@
<html lang="ru">
<head>{{template "html_head" .}}</head>
<body>
<div class="bg-grid"></div>
<input type="checkbox" id="nav-toggle" class="nav-toggle">
<div class="shell">
{{template "sidebar_nav" .}}
@@ -3,7 +3,7 @@
<div class="stat-card accented"><span class="value">{{.Status.TotalIPs}}</span><span class="label">всего IP</span></div>
<div class="stat-card"><span class="value">{{.Status.TotalValidators}}</span><span class="label">валидаторов</span></div>
{{range $state, $count := .Status.IPsByState}}
<div class="stat-card"><span class="value">{{$count}}</span><span class="label">{{$state}}</span></div>
<div class="stat-card{{if eq $state "failed"}} bad{{else if eq $state "checking"}} accented{{end}}"><span class="value">{{$count}}</span><span class="label">{{$state}}</span></div>
{{end}}
</div>
@@ -3,6 +3,7 @@
<html lang="ru">
<head>{{template "html_head" .}}</head>
<body>
<div class="bg-grid"></div>
<input type="checkbox" id="nav-toggle" class="nav-toggle">
<div class="shell">
{{template "sidebar_nav" .}}
+4 -3
View File
@@ -3,6 +3,7 @@
<html lang="ru">
<head>{{template "html_head" .}}</head>
<body>
<div class="bg-grid"></div>
<input type="checkbox" id="nav-toggle" class="nav-toggle">
<div class="shell">
{{template "sidebar_nav" .}}
@@ -20,11 +21,9 @@
{{define "sites_content"}}
<div class="topbar"><h1>Площадки</h1></div>
<p class="muted" style="margin-bottom:16px">Внешние площадки (проберы), проверяющие адреса «снаружи». Число площадок
не ограничено — добавляйте столько слотов, сколько нужно. «Статус» показывает, подключён ли прямо сейчас
процесс prober на этой площадке (по heartbeat, аналогично валидаторам).</p>
<div class="panel">
<div class="panel-head"><h2>Добавить площадку</h2></div>
<div class="panel-body">
<form hx-post="/sites" hx-target="#sites-table-wrap" hx-swap="innerHTML" hx-on::after-request="this.reset()">
<div class="field-row">
@@ -77,5 +76,7 @@
</table>
{{if not .Items}}<p class="muted" style="padding:16px">Площадок пока нет — добавьте первую формой выше.</p>{{end}}
</div>
<div class="section-note">Число площадок не ограничено — форма выше добавляет следующий слот. «Статус» отражает
<code class="inline">POST /probers/register</code> и heartbeat, аналогично валидаторам.</div>
</div>
{{end}}
@@ -3,6 +3,7 @@
<html lang="ru">
<head>{{template "html_head" .}}</head>
<body>
<div class="bg-grid"></div>
<input type="checkbox" id="nav-toggle" class="nav-toggle">
<div class="shell">
{{template "sidebar_nav" .}}
@@ -23,6 +24,7 @@
<p class="muted" style="margin-bottom:16px">Группа целей — именованный список URL/адресов, на который затем ссылаются типы проверок.</p>
<div class="panel">
<div class="panel-head"><h2>Новая группа целей</h2></div>
<div class="panel-body">
<form hx-post="/targets" hx-target="#targets-table-wrap" hx-swap="innerHTML" hx-on::after-request="this.reset()">
<div class="field-row">
@@ -3,6 +3,7 @@
<html lang="ru">
<head>{{template "html_head" .}}</head>
<body>
<div class="bg-grid"></div>
<input type="checkbox" id="nav-toggle" class="nav-toggle">
<div class="shell">
{{template "sidebar_nav" .}}
@@ -22,6 +23,7 @@
<div class="topbar"><h1>Валидаторы</h1></div>
<div class="panel">
<div class="panel-head"><h2>Новый валидатор</h2></div>
<div class="panel-body">
<form hx-post="/validators" hx-target="#validators-table-wrap" hx-swap="innerHTML" hx-on::after-request="this.reset()">
<div class="field-row">