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:
Esa Kataja
2026-07-31 22:16:29 +03:00
parent 91e136055c
commit f33f4fa4d6
16 changed files with 724 additions and 232 deletions
+18 -15
View File
@@ -2,21 +2,21 @@
<audio controls preload="none" src="/audio/{{.ID}}" class="player"></audio>
{{end}}
{{define "songrow"}}
<tr>
<td>
<a href="/songs/{{.ID}}">{{.Title}}</a>
<span class="muted">{{.Artist}}</span>
{{if .Own}}<span class="tag">oma</span>{{else if .Reviewed}}<span class="tag done">arvosteltu</span>{{end}}
</td>
<td class="nowrap">{{.GenreLabel}}</td>
<td class="nowrap">{{.Length}}</td>
<td class="nowrap">
{{if .Average}}<strong>{{score .Average}}</strong> <span class="muted">({{.ReviewCount}})</span>
{{else if .ReviewCount}}<span class="muted">{{.ReviewCount}} arvostelua</span>
{{else}}<span class="muted"></span>{{end}}
</td>
</tr>
{{define "songcard"}}
<a class="songcard{{if and (not .Own) (not .Reviewed)}} unreviewed{{end}}" href="/songs/{{.ID}}">
{{with .Average}}<span class="scorebadge">{{score .}}</span>{{end}}
<span class="title">{{.Title}}</span>
<span class="artist">{{.Artist}}</span>
<span class="meta">
<span class="badge genre">{{.GenreLabel}}</span>
<span>{{.Length}}</span>
<span>{{.Submitter}}</span>
{{if .Own}}<span class="badge admin">oma</span>
{{else if .Reviewed}}<span class="badge reviewed">arvosteltu</span>
{{else}}<span class="badge pending">arvostelematta</span>{{end}}
{{if .ReviewCount}}<span>{{.ReviewCount}} arvostelua</span>{{end}}
</span>
</a>
{{end}}
{{define "scorefield"}}
@@ -27,4 +27,7 @@
<output>{{.}}</output>
</span>
</label>
<span class="scorescale" aria-hidden="true">
<span>1</span><span>25</span><span>50</span><span>75</span><span>100</span>
</span>
{{end}}