Add albums: group photos by free-text tags

An album is a tag. Photos carry lowercase free-text tags in their .toml
sidecar (`tags = [...]`), parallel to the existing day grouping — no
database, all derived at build time.

- albums.go: parseTags (lowercase/trim/dedupe, slug via sanitiseSlug),
  groupByTag mirroring groupByDay, and rendering for album pages, the
  index, and the JSON API. Slug collisions between distinct names are
  suffixed and logged.
- Routes: /album/<slug>/ (paginated square grid per tag), /albums/ (index
  with counts), /tags.json (machine-readable tag list, served statically
  like feed.xml).
- POST /upload gains a `tags` field written into the sidecar; the web
  upload form gains a tags input.
- Tags shown on each photo page linking to their album; an Albums link in
  the timeline/grid header.
This commit is contained in:
puttaalu committed 2026-10-08 16:14:09 +02:00
1 parent f33bdd55b1
commit a42abfab48
11 files changed
+469 -6

No files matched your search

+54
View File
@@ -422,3 +422,57 @@ body {
.dlayout { flex-direction: column; }
.dsidebar { width: 100%; border-left: none; border-top: 1px solid var(--line); }
}
/* ── Tags / albums ─────────────────────────────────────────── */
.dtags {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin: 10px 0 14px;
}
.tag,
.album-chip {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 10px;
background: var(--bg0);
border: 1px solid var(--bg2);
color: var(--fg3);
font-family: monospace;
font-size: 12px;
text-decoration: none;
border-radius: 2px;
transition: color 0.15s, border-color 0.15s;
}
.tag:hover,
.album-chip:hover {
color: var(--aqua);
border-color: var(--fg4);
}
.album-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 16px;
}
.album-chip {
font-size: 14px;
padding: 7px 14px;
}
.album-chip-count {
color: var(--fg4);
font-size: 11px;
}
.album-empty {
color: var(--fg4);
font-family: var(--serif);
margin-top: 16px;
}