Apply the theme: tokens, Oswald, song cards, toasts
The theme handoff encoded as CSS custom properties rather than a Tailwind config, since there is no Tailwind here. Palette, spacing, radii, shadows and motion follow it as written; docs/theme.md lists what differs and why. - Oswald vendored as a 21KB variable woff2, latin subset, no CDN. Its phantom weight 900 resolved to 700 — loading a weight you don't have is what made the brand render differently per platform - color-scheme: dark makes the native audio element fit the palette, which was the handoff's complaint about it - Songs are text cards rather than artwork tiles, because there is no artwork. The unreviewed state keeps its red-brown border and gains a badge, so it is never carried by colour alone - Nav is the three-column grid; the mobile menu is <details>, no JS - Flash messages became bottom-right toasts Favicon carried over from the Nuxt project.
This commit is contained in:
@@ -162,6 +162,13 @@ says so.
|
||||
40. **`main` is release code, `dev` is development.** Work lands on `dev` and reaches `main` by merge
|
||||
at release, so `main` is always a list of things that shipped. Nightly builds, if any, come off
|
||||
`dev`.
|
||||
42. **The theme handoff is implemented as CSS custom properties, not a Tailwind config.** Its
|
||||
palette, spacing, shadows, motion and component shapes are followed as written; the parts that
|
||||
assumed Tailwind, Pico or cover artwork are adapted rather than dropped, and each adaptation is
|
||||
listed in [theme.md](./theme.md). Oswald's phantom weight 900 resolved to 700 — loading a weight
|
||||
you do not have is what made the brand render differently per platform. The custom audio player
|
||||
stays deferred: `color-scheme: dark` makes the native control fit the palette, which was the
|
||||
actual complaint.
|
||||
41. **No password minimum; rate limit logins instead.** A length policy protects against guessing,
|
||||
and guessing is better answered directly: 10 failures per email in 15 minutes, then a 15-minute
|
||||
lockout, cleared by a correct password. The floor was rejected because typing an 8-character
|
||||
|
||||
@@ -130,6 +130,27 @@ Also here: pruning the count-based leaderboards once the queue has drained and t
|
||||
|
||||
---
|
||||
|
||||
## Review form as a mixer channel
|
||||
|
||||
Idea for the UI polish pass, not now: put the score slider and the review textarea **on one row**,
|
||||
with the slider **vertical** like a channel fader on a mixing desk. The score stops being a form
|
||||
field and becomes the instrument the app is actually about, and the two things you do at once —
|
||||
decide a number, write why — stop being stacked a screenful apart.
|
||||
|
||||
Notes for whoever builds it:
|
||||
|
||||
- A vertical `<input type="range">` is native now: `writing-mode: vertical-lr; direction: rtl` gives
|
||||
bottom-to-top travel with no JS and no custom widget, so keyboard support and the value stay free.
|
||||
- Keep the live `<output>` — on a fader it wants to sit at the top of the track, reading like a
|
||||
channel's gain display.
|
||||
- The row needs a mobile answer: below ~640px, either keep the fader and shrink the textarea beside
|
||||
it, or fall back to the current stacked layout. A short vertical fader is worse than a horizontal
|
||||
one, so measure before choosing.
|
||||
- Tick marks along the track (1 / 25 / 50 / 75 / 100) replace today's `.scorescale` row, and are
|
||||
what make it read as equipment rather than decoration.
|
||||
|
||||
---
|
||||
|
||||
## Filters on the browse list
|
||||
|
||||
`/songs` is newest-first with no filters. Once there are a couple of hundred songs, "which ones
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# Theme
|
||||
|
||||
Dark-only. Rock/metal club poster, not SaaS dashboard: near-black surfaces, warm bronze/amber
|
||||
accents, condensed uppercase display type, one-tone-lighter surfaces instead of borders everywhere.
|
||||
Restrained motion — 150 ms, one easing curve, no bounce. **There is no light theme and none is
|
||||
wanted.**
|
||||
|
||||
The tokens themselves live in [`static/style.css`](../static/style.css) as CSS custom properties, and
|
||||
that file is the source of truth. This page records the decisions behind them and the places the
|
||||
implementation deliberately differs from the theme handoff it came from.
|
||||
|
||||
## Rules
|
||||
|
||||
- **Nothing outside `:root` invents a value.** No colour, spacing step, radius or duration appears in
|
||||
a rule unless it is declared as a token first. Six spacing steps (4–32 px), one radius (4 px, plus
|
||||
6 px for toasts and a pill), one duration, one curve.
|
||||
- **Headings step downward in brightness with level** — h1 lightest gold, h3 the primary bronze.
|
||||
- **Status colours are desaturated on purpose.** A pure red error would break the palette.
|
||||
- **`color-scheme: dark`** is set on `:root`, which is what keeps the native `<audio>` element,
|
||||
checkboxes, range inputs and scrollbars from rendering as white slabs.
|
||||
- **One focus treatment, everywhere:** a soft gold ring via `box-shadow` on `:focus-visible` only.
|
||||
Not optional — keyboard navigation is the only way through some admin tables.
|
||||
- **`prefers-reduced-motion`** drops the card lift and the panel slide, and keeps the fades.
|
||||
|
||||
## Type
|
||||
|
||||
Body is a system stack; no webfont for body text. Display is **Oswald**, vendored as a variable
|
||||
`.woff2` (latin subset, 21 KB) in `static/fonts/` — no CDN, matching the no-npm rule for HTMX.
|
||||
|
||||
The handoff asked for weight 900 in five places while loading only 400/600/700, so browsers were
|
||||
synthesising a fake bold that differed per platform. **Resolved as 700 being the top weight.** The
|
||||
variable font covers 400–700 and nothing asks for more.
|
||||
|
||||
## The unreviewed state
|
||||
|
||||
A song the viewer has not reviewed gets a red-brown border — it is the single most important state
|
||||
in the app, since it is how you see what still needs a review. It is **never carried by colour
|
||||
alone**: the card also shows an `arvostelematta` badge.
|
||||
|
||||
## Deviations from the handoff
|
||||
|
||||
| Handoff said | Here | Why |
|
||||
|---|---|---|
|
||||
| Tailwind theme config, utility classes | CSS custom properties, semantic classes | Decisions 4 and 8 — no Tailwind, no bundler, no npm |
|
||||
| Song cards are 16:9 tiles with cover artwork and a gradient scrim | Text cards, same borders, badges, hover glow and score badge | Songs have no artwork. There is no upload for one and nothing to derive it from |
|
||||
| Fixed bottom audio player bar | Player inline on the song page | Nothing plays across navigation, so a persistent bar would be an empty bar on every other page |
|
||||
| A styleguide page rendering every variant | Not built | The real pages cover every component; a second copy of them would drift |
|
||||
| Custom audio player skin | Native `<audio controls>` | Decision 14. It is keyboard-operable, screen-reader labelled and media-key aware for free, and replacing it later is one template partial — see [later.md](./later.md) |
|
||||
| Nav dropdown for the user block, hamburger with animated bars | User block is a plain row; mobile menu is `<details>` | No JS for either. The app has no dropdown-worthy menu yet: logout is one button |
|
||||
|
||||
Everything else — the palette, spacing, radii, shadows, motion, the 1450 px content width, the
|
||||
420 px auth column, badges, review cards, the admin section cards, bottom-right toasts — follows the
|
||||
handoff as written.
|
||||
Reference in New Issue
Block a user