Apply the Nocturne fidelity pass to the web UI
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
# Veskslop UI — Nocturne fidelity pass
|
||||
|
||||
The shell (header, rail, call strip, composer, TTS box, console, right column)
|
||||
is faithful to the design. The drift is all in the layer added since: the Media
|
||||
archive and Bot tabs, plus a few spots in `style.css`.
|
||||
|
||||
**Part two** (icons, settings, menus, dialogs, toasts) starts further down.
|
||||
|
||||
## Install
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="nocturne.css" />
|
||||
<link rel="stylesheet" href="tokens-status.css" /> <!-- new, additive -->
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<link rel="stylesheet" href="media.css" /> <!-- replaces yours -->
|
||||
<link rel="stylesheet" href="style-overrides.css" /> <!-- new, load last -->
|
||||
<link rel="stylesheet" href="settings-popups.css" /> <!-- new, load last -->
|
||||
|
||||
<script src="icons.js"></script> <!-- replaces yours -->
|
||||
<script src="polish.js"></script> <!-- new, after icons.js -->
|
||||
```
|
||||
|
||||
`tokens-status.css`, `style-overrides.css`, `settings-popups.css` and `polish.js`
|
||||
are new files. `media.css` and `icons.js` are your files with the changes
|
||||
applied — diff them, don't assume.
|
||||
|
||||
---
|
||||
|
||||
## The root cause
|
||||
|
||||
Nocturne ships one accent and a neutral ramp. It has **no error / warning /
|
||||
success role and no categorical data scale.** So every feature that needed one
|
||||
invented its own: `#e5484d`, `#ffaa33`, `#44cc88`, `#ff5555`, `#ff8080`,
|
||||
`#c04040`, `#4f8cff`, `#8a6cff`, `#ff7a45`, `#2fbf71`, `#6b7280`, `#d29922`.
|
||||
Eighteen hexes, four different reds, none on the system's lightness scale.
|
||||
|
||||
`tokens-status.css` fills that hole properly — danger, warn, ok and a five-step
|
||||
data scale, generated in OKLCH on Nocturne's **own** shared lightness scale, so
|
||||
step 400 of danger carries the same visual weight as step 400 of accent. Chroma
|
||||
stays low; the accent is still the loudest thing on screen.
|
||||
|
||||
Everything else in this patch is downstream of having those tokens.
|
||||
|
||||
---
|
||||
|
||||
## What changed
|
||||
|
||||
### 1. Colour
|
||||
|
||||
- 18 hard-coded hexes replaced with tokens. Zero remain.
|
||||
- **Wrong-hue fallbacks removed.** `var(--color-accent-400, #4f8cff)` appeared
|
||||
six times. `#4f8cff` is blue; Nocturne's accent is blurple `#9184d9`. Any time
|
||||
that fallback fired — a load-order slip, a scoping mistake — the Media and Bot
|
||||
tabs turned a different colour than the rest of the app. Silent, and hard to
|
||||
spot because it only happens when something else is already broken.
|
||||
- The storage bar's five saturated hues become the low-chroma `--color-data-*`
|
||||
family. Nocturne's rule is that contrast comes from the tonal ramps, not from
|
||||
saturation; five alarm colours in a 10px bar broke it harder than anything
|
||||
else on screen.
|
||||
- `--color-mention: #d29922` was declared in a stray second `:root` block 400
|
||||
lines into `style.css`. It now lives with the other tokens as `--color-warn-400`.
|
||||
|
||||
### 2. Floods
|
||||
|
||||
Nocturne outlines; it does not fill.
|
||||
|
||||
- `.vk-toggle-half.vk-toggle-on` was a solid `accent-400` panel with `#fff`
|
||||
text — the one thing the guide names as a don't. Now tinted and outlined, the
|
||||
same treatment `.vk-scope-btn.active` already uses.
|
||||
- `.vk-media-badge` was `#e5484d` with white text at 9px. Now a `danger-800`
|
||||
tint with `danger-200` ink at 10px.
|
||||
- `.vk-bot-state-*` pills moved from alpha washes over saturated hues to deep
|
||||
ramp fills with full-opacity ink — an alpha wash over an unknown backdrop is
|
||||
how small text loses contrast without anyone noticing.
|
||||
|
||||
### 3. Weight
|
||||
|
||||
Nocturne heads cap at 500; hierarchy is size and space. Removed 11 instances of
|
||||
`font: 600` and `font-weight: 600` in `media.css`, plus `font-weight: 700` on
|
||||
the speaking state in `style.css`. That last one also **reflowed the row every
|
||||
time someone started or stopped talking** — the names jittered. Speaking now
|
||||
reads in `accent-200`, with the level meter beside it doing the loud work.
|
||||
|
||||
### 4. Edges and radii
|
||||
|
||||
`border: 1px solid` → the system's `inset 0 0 0 1px` edge, so elevation stays
|
||||
"hairline plus ambient darkness" rather than a drawn box. Literal `3px / 5px /
|
||||
6px / 7px` radii → `--radius-sm` / `--radius-md`. Six different corner radii
|
||||
were in play across the Bot tab.
|
||||
|
||||
### 5. Focus
|
||||
|
||||
`nocturne.css` sets a 2px accent `:focus-visible` ring, but every control built
|
||||
from a bare `<button>` that resets `background` and `border` loses it against
|
||||
its own surface. Explicitly restored on 18 controls: rail rows, guild marks,
|
||||
scope buttons, console tabs, chips, stars, mobile tabs, settings summaries,
|
||||
media links, tree heads, group titles. **This is the only keyboard path through
|
||||
the app** — worth checking by tabbing the whole thing once.
|
||||
|
||||
### 6. Contrast
|
||||
|
||||
- `.vk-media-done-note` was `color-mix(neutral-400 55%, transparent)` at 10px —
|
||||
roughly 2.4:1. Now `neutral-500`.
|
||||
- `.vk-bot-history-entry` and friends: 10px mono at `neutral-500` sits just
|
||||
under 4.5:1 on surface. Lifted one step to `neutral-400`.
|
||||
- **The offline state was the worst of it.** `opacity: .5` plus
|
||||
`saturate(.6)` on the entire body and console pushed every label under 3:1 —
|
||||
in the one state where you most need to read what is on screen and work out
|
||||
what died. Now the chrome dims behind a scrim and the type stays legible.
|
||||
Input is still blocked.
|
||||
|
||||
### 7. Status marks that were saying the wrong thing
|
||||
|
||||
- `.vk-dot.error` was `neutral-200` — a bright white dot, which reads as
|
||||
healthy. Now `danger-400`.
|
||||
- `.vk-toast.error` and `.vk-toast.ok` differed only by one hue step of the same
|
||||
near-white. Now genuinely different roles, plus a `warn` variant.
|
||||
- `.vk-presence.idle` and dnd both landed on `neutral-200`, so they were
|
||||
indistinguishable. idle drops a step; dnd keeps the bright dot and gains the
|
||||
bar that makes it readable without colour.
|
||||
|
||||
### 8. Rules
|
||||
|
||||
Nocturne's rules fade to transparent over 48px a side. The channel header does
|
||||
this; the settings panel's dozens of flat `inset 0 -1px 0` rules did not, which
|
||||
is most of why that panel reads as a different product bolted on. Now fading.
|
||||
|
||||
---
|
||||
|
||||
## Needs a small markup change
|
||||
|
||||
The storage bar is colour-only. `media.css` now carries
|
||||
`.vk-media-usage-legend` / `.vk-media-usage-key` — render one key per segment
|
||||
beside the bar:
|
||||
|
||||
```html
|
||||
<div class="vk-media-usage-legend">
|
||||
<span class="vk-media-usage-key image"><i></i>images 4.1 GiB</span>
|
||||
<span class="vk-media-usage-key gif"><i></i>gifs 0.8</span>
|
||||
<span class="vk-media-usage-key video"><i></i>video 11.2</span>
|
||||
<span class="vk-media-usage-key audio"><i></i>audio 0.3</span>
|
||||
<span class="vk-media-usage-key"><i></i>other 0.1</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
Add `.over` to `.vk-media-usage` past the warn threshold.
|
||||
|
||||
Also: `.vk-presence.dnd` now exists as a state. If `app.js` only emits
|
||||
`online` / `idle` / `offline`, dnd is still rendering as plain online.
|
||||
|
||||
---
|
||||
|
||||
## Not changed — worth a conversation
|
||||
|
||||
**The Media and Bot tabs are a second application inside the shell.** They
|
||||
don't use the rail, the right column or the console; they take over the whole
|
||||
body with their own toolbar, their own grid, their own modals at their own
|
||||
z-index tier. The patch makes them *look* like the rest of the app. It doesn't
|
||||
make them *behave* like it. Worth deciding whether Media is a scope alongside
|
||||
Guild/DM — which is what the segmented control currently implies — or a separate
|
||||
surface that should stop pretending to be one.
|
||||
|
||||
**Settings is carrying nine sections in one slide-over**, several of which
|
||||
(Flextalk voice profile, Bot audio, Speech) are deep enough to be their own
|
||||
screens. The `<details>` grouping is holding for now, but the voice profile
|
||||
panel already had to escape into its own draggable dialog, which is the usual
|
||||
sign.
|
||||
|
||||
**`.vk-media-play` is a text glyph** (font-size 44px) where the rest of the app
|
||||
uses Phosphor. Small, but it is the only place an icon doesn't match.
|
||||
|
||||
---
|
||||
|
||||
# Part two — icons, settings, menus, dialogs
|
||||
|
||||
## 9. Icons
|
||||
|
||||
`icons.js` is replaced. The old set was drawn on a 16-unit grid at a fixed 1.3
|
||||
stroke; the new one is Phosphor geometry on Phosphor's 256 grid.
|
||||
|
||||
- **Optical weight is now constant.** Stroke is computed per render size
|
||||
(`1.35 / size * 256`), so a 44px icon and an 11px icon carry the same line.
|
||||
Before, stroke scaled with the icon and large ones looked heavy.
|
||||
- **Round caps and joins throughout** — Phosphor regular's terminal, which the
|
||||
old mic, camera and gear each handled differently.
|
||||
- **The gear, mic, camera, refresh and warning were redrawn.** The gear was a
|
||||
circle with eight straight spokes; the mic was a rounded rect over an arc.
|
||||
They read as icons now rather than as diagrams.
|
||||
- **19 icons added**: headphones / headphonesSlash (the listening and deafened
|
||||
states, which had no mark of their own), screenshare, waveform, image, film,
|
||||
audio, folder, pause, stop, check, plus, minus, dots, funnel, sliders,
|
||||
download, copy, pencil, trash, pin, popout, info, error, ok, clock.
|
||||
- **Every old name still resolves** — aliases cover `microphone`, `deafen`,
|
||||
`video`, `close`, `settings`, `tts`, `magnify` — so nothing needs editing.
|
||||
- Unknown names now warn in the console instead of rendering an empty `<svg>`.
|
||||
That surfaced one already: `star` was used before it was defined, and worked
|
||||
only because a later line patched it in.
|
||||
- `VK.hydrateIcons(root)` fills any empty `[data-icon]`; it skips anything
|
||||
already rendered, so it won't fight `app.js`.
|
||||
|
||||
If you would rather ship the real Phosphor package, swap the file for
|
||||
`@phosphor-icons/web` and keep `VK.icon` as a wrapper — the names are Phosphor's
|
||||
own, so the mapping is one to one.
|
||||
|
||||
## 10. `polish.js` — what CSS can't reach
|
||||
|
||||
Three text glyphs are doing an icon's job. This is a small idempotent pass with
|
||||
a MutationObserver, so it also catches the Media and Bot tabs rebuilding:
|
||||
|
||||
- `<button id="scrape-x">X</button>` and its siblings → the `x` icon, plus
|
||||
`aria-label="Close"`. There were several, in the scrape and clean modals.
|
||||
- `.vk-media-play`'s ▶ character at 44px → the `play` icon.
|
||||
- `.vk-info`'s `title` → `data-tip`, so the styled tooltip below is the only one
|
||||
that fires, plus `aria-label` and `tabindex` so the help is reachable at all.
|
||||
|
||||
No markup edits. If you'd rather fold these into the source, the script says
|
||||
exactly what to change.
|
||||
|
||||
## 11. Settings, menus, dialogs, toasts
|
||||
|
||||
`settings-popups.css`. Presentation only, no behaviour or markup changes.
|
||||
|
||||
- **Scrim.** 55% flat wash → 72% of the page ground with a 3px blur. The page
|
||||
behind was legible enough that the eye kept reading it.
|
||||
- **Panel.** Square left edge → `--radius-lg` on the leading corners, the
|
||||
system's hairline, and a 200ms slide from the edge it is attached to.
|
||||
- **Head is sticky** and sits on a fading rule. Settings scrolls a long way;
|
||||
the title used to leave.
|
||||
- **Section rows.** The card was a flat fill with rows running together. Now the
|
||||
system edge, rows separated by rules that fade at both ends, values on
|
||||
tabular numerals so they align down the column.
|
||||
- **`.vk-info` was an unstyled letter `i`** with its help text trapped in a
|
||||
native tooltip — half a second of delay, no styling, invisible on touch. It is
|
||||
now a 14px ringed mark with a themed tooltip. Eleven help strings were sitting
|
||||
in `title` attributes where most people would never see them.
|
||||
- **Collapsible groups.** The summary was a bare uppercase line with nothing
|
||||
saying it was a control. It is a row now — hover tint, turning caret, and the
|
||||
body indented against a hairline so nesting is visible.
|
||||
- **Native controls.** Selects kept the platform arrow and a 1px border, numbers
|
||||
kept their spinners, ranges kept the platform track. All three now use the
|
||||
system's edge, accent thumb and focus ring. The select caret is a mask taking
|
||||
`--color-neutral-400`, not a hex baked into a data URI.
|
||||
- **Menus** get the hairline, a 120ms entrance and an accent bar on the active
|
||||
item instead of a tint with nothing anchoring it.
|
||||
- **Dialogs.** The voice-profile drawer was square-topped against the scrim and
|
||||
the media modals had unrelated radii. Both on `--radius-lg` and the system
|
||||
edge now; the profile drawer gains a grab handle, since its head was already
|
||||
the drag target but nothing said so.
|
||||
- **Toasts** get an icon slot coloured by role from `tokens-status.css`.
|
||||
- All of it respects `prefers-reduced-motion`.
|
||||
|
||||
## Worth doing next
|
||||
|
||||
`.vk-status-value:has(> .vk-select)` carries the select caret. If a select ever
|
||||
ships outside a status row, wrap it in `.vk-select-wrap` — the rule is there.
|
||||
Reference in New Issue
Block a user