Admin: group ⓘ, group toggles in the title row, status readouts, Theme section
configGroups[name].help now renders as an ⓘ beside the group title (.group-info / .group-info-btn / .group-info-pop): a real labelled button — click pins a popover with the text, hover and focus peek at it, Escape or a click elsewhere closes it, and inside a collapsed group's <summary> it never folds the group. The paragraph above the fields is gone; per-field help stays one small line under its control. configGroups[name].toggle names a switch/boolean field of the group: it moves into the title row, right-aligned (.field-group-toggle), as the group's on/off. While off the body dims to 0.45 (.field-group.is-off) but every field stays editable; the field is not repeated in the body, is saved exactly as before and still drives showWhen. Works with collapsed (the switch never folds the row) and columns. A toggle naming a non-boolean field is ignored. The module card's status line is a .module-status readout: 1px --border, a background a shade lighter than the card, monospace, small radius and padding, with ok / connecting / error as the text (and border) colour. New Theme section near the top: five swatches (.theme-swatch with a miniature bg/panel/accent preview), the current one marked, click POSTs /api/admin/theme and applies at once, errors show on a status line; other admin pages' changes arrive live over /api/events, and the login card already wears the server's theme. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
f79e8abd92
commit
4dde529162
+175
-4
@@ -94,6 +94,35 @@ body { overflow: auto; }
|
||||
}
|
||||
.module-health.error { color: var(--danger); }
|
||||
|
||||
/* a module card's own status line ("polling timers on 10.3.11.20:1025",
|
||||
"no ProPresenter host configured"): a readout, so it sits in a bordered
|
||||
monospace box a shade lighter than the card; ok / connecting / error
|
||||
show as the text (and border) colour, the box itself never changes */
|
||||
.module-status {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
margin-top: 8px;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
background: color-mix(in srgb, var(--text) 5%, var(--panel));
|
||||
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
||||
font-size: 11.5px;
|
||||
line-height: 1.45;
|
||||
color: var(--muted);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.module-status:empty { display: none; }
|
||||
.module-status.ok { color: var(--text); }
|
||||
.module-status.connecting {
|
||||
color: var(--warn);
|
||||
border-color: color-mix(in srgb, var(--warn) 40%, var(--border));
|
||||
}
|
||||
.module-status.error {
|
||||
color: var(--danger);
|
||||
border-color: color-mix(in srgb, var(--danger) 40%, var(--border));
|
||||
}
|
||||
|
||||
.module-mount-error {
|
||||
margin-top: 8px;
|
||||
padding: 8px 10px;
|
||||
@@ -121,6 +150,10 @@ body { overflow: auto; }
|
||||
border-radius: 9px;
|
||||
}
|
||||
.field-group-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
position: relative; /* the ⓘ popover hangs off this row */
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
@@ -128,8 +161,82 @@ body { overflow: auto; }
|
||||
color: var(--muted);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.field-group-name { min-width: 0; }
|
||||
.field-group .field:last-child { margin-bottom: 0; }
|
||||
|
||||
/* group help (configGroups[name].help): an ⓘ beside the title. Hover or
|
||||
focus peeks at the text; a click pins it open until the next click. */
|
||||
.group-info { display: inline-flex; align-items: center; }
|
||||
.group-info-btn {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
padding: 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--muted);
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
font: italic 700 10px/1 ui-serif, Georgia, "Times New Roman", serif;
|
||||
text-transform: none;
|
||||
letter-spacing: 0;
|
||||
cursor: help;
|
||||
}
|
||||
.group-info-btn:hover,
|
||||
.group-info.is-open .group-info-btn { color: var(--text); border-color: var(--text); }
|
||||
.group-info-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
|
||||
.group-info-pop {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: calc(100% + 6px);
|
||||
z-index: 5;
|
||||
max-width: min(440px, 100%);
|
||||
padding: 8px 10px;
|
||||
background: color-mix(in srgb, var(--text) 6%, var(--panel));
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
white-space: normal;
|
||||
cursor: auto;
|
||||
}
|
||||
/* keeps the popover open while the pointer crosses the gap down to it */
|
||||
.group-info-pop::before { content: ""; position: absolute; left: 0; right: 0; top: -8px; height: 8px; }
|
||||
.group-info:hover .group-info-pop,
|
||||
.group-info-btn:focus-visible + .group-info-pop,
|
||||
.group-info.is-open .group-info-pop { display: block; }
|
||||
|
||||
/* group toggle (configGroups[name].toggle): the named switch sits at the
|
||||
right of the title row as the group's on/off; the body dims while it is
|
||||
off but stays editable */
|
||||
.field-group-toggle {
|
||||
margin-left: auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex: none;
|
||||
}
|
||||
.field-group-toggle .field {
|
||||
margin: 0;
|
||||
max-width: none;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
color: var(--text);
|
||||
}
|
||||
.field-group-toggle .field.switch-field { flex-direction: row-reverse; gap: 8px; }
|
||||
.field-group-toggle .field.switch-field .switch-label { font-size: 12px; }
|
||||
.field-group-toggle .field.check { flex-direction: row-reverse; gap: 8px; }
|
||||
.field-group.is-off > .field-group-body { opacity: 0.45; transition: opacity 0.15s; }
|
||||
.field-group.has-toggle > .field-group-body { transition: opacity 0.15s; }
|
||||
|
||||
/* collapsible groups (manifest configGroups[name].collapsed) */
|
||||
details.field-group > summary.field-group-title {
|
||||
cursor: pointer;
|
||||
@@ -160,18 +267,16 @@ details.field-group > summary.field-group-title:hover { color: var(--text); }
|
||||
gap: 4px 16px;
|
||||
}
|
||||
.field-group-body.is-columns .field { margin-bottom: 4px; max-width: none; }
|
||||
.field-group-body.is-columns .field-group-help { grid-column: 1 / -1; }
|
||||
@media (max-width: 560px) { .field-group-body.is-columns { grid-template-columns: 1fr 1fr; } }
|
||||
|
||||
.field-group-help,
|
||||
/* one line of guidance under a control (field `help`) */
|
||||
.field-help {
|
||||
display: block;
|
||||
font-size: 11.5px;
|
||||
line-height: 1.45;
|
||||
color: var(--muted);
|
||||
margin-top: 2px;
|
||||
}
|
||||
.field-group-help { margin: -4px 0 8px; }
|
||||
.field-help { margin-top: 2px; }
|
||||
.field-help code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
||||
|
||||
/* showWhen: a hidden dependent field must actually collapse — `.field`'s
|
||||
@@ -312,3 +417,69 @@ a.btn { text-decoration: none; }
|
||||
.catalog-title { display: flex; align-items: center; gap: 8px; }
|
||||
.catalog-row .module-desc { margin: 4px 0 2px; }
|
||||
.catalog-row .module-health { margin-top: 2px; }
|
||||
|
||||
/* ── theme ──────────────────────────────────────────────────────────── */
|
||||
|
||||
/* one swatch per preset: a miniature dashboard (page, a tile on it, the
|
||||
accent as a status dot) and the name; the current one wears the accent */
|
||||
.theme-swatches {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(116px, 1fr));
|
||||
gap: 10px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.theme-swatch {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 7px;
|
||||
padding: 8px;
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
color: var(--text);
|
||||
font: inherit;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
.theme-swatch:hover { border-color: var(--muted); }
|
||||
.theme-swatch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
||||
.theme-swatch.is-current { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
|
||||
.theme-preview {
|
||||
position: relative;
|
||||
display: block;
|
||||
height: 46px;
|
||||
border-radius: 6px;
|
||||
background: var(--sw-bg);
|
||||
border: 1px solid color-mix(in srgb, var(--sw-panel) 60%, var(--sw-accent));
|
||||
overflow: hidden;
|
||||
}
|
||||
.theme-preview::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 8px; right: 8px; top: 10px; bottom: 8px;
|
||||
border-radius: 4px;
|
||||
background: var(--sw-panel);
|
||||
border: 1px solid color-mix(in srgb, var(--sw-panel) 75%, var(--sw-accent));
|
||||
}
|
||||
.theme-preview::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 14px; top: 16px;
|
||||
width: 8px; height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--sw-accent);
|
||||
box-shadow: 0 0 6px var(--sw-accent);
|
||||
}
|
||||
.theme-name { display: flex; align-items: center; gap: 6px; }
|
||||
.theme-swatch.is-current .theme-name::after {
|
||||
content: "current";
|
||||
margin-left: auto;
|
||||
font-size: 9.5px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent);
|
||||
}
|
||||
#theme-status { margin-top: 4px; }
|
||||
|
||||
Reference in New Issue
Block a user