ui: /settings/notifications list + edit form (3 kinds)

Add settings.html (shell + sub-tab nav + conditional list/edit body),
notifications.html and notification_edit.html (glob stubs), and the
supporting CSS tokens (.ch-row, .ch-icon, .toggle, .kind-grid,
.kind-card, .radio-pip, .test-pill) to input.css. Rebuild styles.css.
Add ui_parse_test.go to catch template regressions at test time.

The kind picker is JS-driven (no full page reload); the enabled toggle
mirrors the existing visual toggle pattern; the test-notification button
uses HTMX and renders the JSON response as a coloured pill client-side.
This commit is contained in:
2026-05-04 20:25:06 +01:00
parent d373d19647
commit 371fe734f3
6 changed files with 686 additions and 1 deletions
+99
View File
@@ -451,4 +451,103 @@
radial-gradient(ellipse at top, color-mix(in oklch, var(--accent), transparent 95%), transparent 60%),
var(--panel);
}
/* ---------- notification channel rows (/settings/notifications) ---------- */
.ch-row {
display: grid; align-items: center;
grid-template-columns: 28px 200px 1fr 100px 130px 140px;
column-gap: 16px;
padding: 14px 18px; font-size: 13px;
border-bottom: 1px solid var(--line-soft);
transition: background 100ms ease;
}
.ch-row:last-child { border-bottom: 0; }
.ch-row.head {
cursor: default; font-size: 11px; color: var(--ink-fade);
text-transform: uppercase; letter-spacing: 0.08em;
padding-top: 10px; padding-bottom: 10px;
}
.ch-row.head:hover { background: transparent; }
/* Whole-row click → edit page (mirrors .host-row.clickable). */
.ch-row.clickable { position: relative; cursor: pointer; }
.ch-row.clickable .row-link {
position: absolute; inset: 0; z-index: 0;
text-indent: -9999px; overflow: hidden;
}
.ch-row.clickable:hover { background: var(--panel-hi); }
.ch-row.clickable > * { position: relative; z-index: 1; pointer-events: none; }
.ch-row.clickable > .row-link { pointer-events: auto; }
.ch-row.clickable > .row-action { pointer-events: auto; }
/* Channel kind icons */
.ch-icon {
width: 24px; height: 24px;
border-radius: 5px;
display: inline-flex; align-items: center; justify-content: center;
font-family: 'JetBrains Mono', monospace; font-size: 10px; font-weight: 600;
background: var(--panel-hi); color: var(--ink-mute);
border: 1px solid var(--line);
}
.ch-icon.webhook { color: var(--accent); border-color: color-mix(in oklch, var(--accent), transparent 60%); }
.ch-icon.ntfy { color: var(--warn); border-color: color-mix(in oklch, var(--warn), transparent 60%); }
.ch-icon.smtp { color: var(--ok); border-color: color-mix(in oklch, var(--ok), transparent 60%); }
/* ---------- toggle (enabled/disabled switch) ---------- */
.toggle {
display: inline-block; width: 30px; height: 16px; border-radius: 9999px;
background: var(--line); position: relative; cursor: pointer;
transition: background 120ms ease; flex-shrink: 0;
}
.toggle::after {
content: ""; position: absolute; left: 2px; top: 2px;
width: 12px; height: 12px; border-radius: 9999px;
background: var(--ink-mid);
transition: all 120ms ease;
}
.toggle.on { background: color-mix(in oklch, var(--accent), transparent 50%); }
.toggle.on::after { left: 16px; background: var(--accent); }
/* ---------- kind-picker radio cards (channel edit form) ---------- */
.kind-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 14px; }
.kind-card {
border: 1px solid var(--line-soft); background: var(--bg);
border-radius: 7px; padding: 16px;
cursor: pointer;
transition: border-color 120ms ease, background 120ms ease;
}
.kind-card:hover { border-color: var(--ink-mute); }
.kind-card.selected {
border-color: color-mix(in oklch, var(--accent), transparent 50%);
background: color-mix(in oklch, var(--accent), transparent 95%);
}
/* Radio pip inside kind cards */
.radio-pip {
width: 14px; height: 14px;
border-radius: 9999px;
border: 1px solid var(--line);
display: inline-flex; align-items: center; justify-content: center;
flex-shrink: 0;
}
.radio-pip.on { border-color: var(--accent); }
.radio-pip.on::after {
content: ""; width: 6px; height: 6px; border-radius: 9999px;
background: var(--accent);
}
/* ---------- test-result pills (notification test button) ---------- */
.test-pill {
display: inline-block;
padding: 5px 10px; border-radius: 5px; font-size: 12.5px;
}
.test-pill-ok {
border: 1px solid color-mix(in oklch, var(--ok), transparent 60%);
background: color-mix(in oklch, var(--ok), transparent 92%);
color: var(--ok);
}
.test-pill-fail {
border: 1px solid color-mix(in oklch, var(--bad), transparent 60%);
background: color-mix(in oklch, var(--bad), transparent 92%);
color: var(--bad);
}
}