• v0.9.0 33a1f4b375

    v0.9.0 Stable

    rimskij released this 2026-08-30 21:03:40 +02:00 | 3 commits to dev since this release

    The admin is rebuilt: shared UI primitives, the brand palette and type, an
    editorial index in place of the data grid, and song editing at its own URL. The
    release also repairs an admin that had been unable to write anything for nine
    months, and closes the path traversal that repair would otherwise have made
    reachable.

    Added

    • Song editing has its own URL/admin/songs/<slug> renders the edit form and a files section, so an edit can be reloaded, shared and reached with the browser Back button. A row's Files link deep-links to #files, which keeps uploading one click from the list now that the file dialog is gone
    • Shared UI primitivesModal, Button (variants plus a pending state), Field/TextareaField (label, error and description wiring) and a SongForm extracted from the add and edit dialogs. Each admin surface previously carried its own copy
    • The design language is enforced by testsadmin-palette fails the build on any off-palette Tailwind hue, on a colour class with no dark: sibling, and on classes that cannot work in both themes; token-contrast recomputes WCAG ratios from the real hexes in globals.css. Two acceptance criteria that a reviewer used to have to remember to grep

    Changed

    • The admin wears the brand palette and type — Anton uppercase chrome, warm near-monochrome, and red reserved for hover, focus, active state and destructive actions. The Logout button is no longer red
    • The songs table is an index list — hairline-divided rows mirroring the public index, with the title as the link to its edit page. A list of songs with per-row actions, not a data grid: nothing sorted or compared across columns, and dropping the table dropped the horizontal scroll wrapper five columns needed
    • The dashboard reads top-down — header, then messages, then SONGS with a live count and the Add/Import pair, then the rows, then SETTINGS. The All Songs heading previously sat immediately above the Settings card with the songs list forty lines below it, so a screen-reader user landing on that heading reached a suggestions toggle and a theme picker
    • Featured state is written out — each row reads Featured or Not featured with a contrast step, rather than a single static word whose only state signal was a red checkbox fill. Colour is now redundant reinforcement, not the sole channel
    • The edit and file dialogs are retired — both opened over the list; the page behind them is reachable by link
    • Heading rules are visible in light themePageHeading and SectionHeading drew border-neutral-200, which is the light page ground, so their underline rendered at 1.000:1. Identical, not faint

    Fixed

    • Every admin write route returned 500withValidation consumed the request body to validate it, and each handler then read it again; a Fetch Request body is a one-shot stream, so the second read threw and the error surfaced as an internal error. Adding, importing, editing, deleting and featuring a song were all broken, in dev since 2025-11-12. The middleware now validates a clone. Its own JSDoc example had been demonstrating the double read, which is how the pattern reached every route
    • The file input was unreachable by keyboard — the upload control used display: none, which removes an element from the tab order, so there was no keyboard path to choosing a file at all (WCAG 2.1.1, level A)
    • The song row hover band was flush against its text — the band's edges landed on the glyphs, reading as a tight box rather than a row. It now reaches the page gutter while the text keeps its column

    Security

    • Path traversal in three admin routesslug went into a filesystem path under content/ guarded only by an existence check. delete-song would recursively delete any directory given ../x, delete-file would unlink any file through either slug or filename, and edit-song would overwrite any pre-existing lyrics.md. Post-authentication, and unreachable while the routes were failing, but live the moment they worked. Containment now lives in one place, resolveWithin
    • The write routes had no authorization of their own — they trusted the middleware alone, while three sibling routes each carried an explicit check. All four now match
    • 500 responses leaked absolute server paths — the raw error message was returned to the client, and Node filesystem errors embed paths. Unknown errors now return a constant
    Downloads
  • v0.8.0 fa80869f5d

    v0.8.0 Stable

    rimskij released this 2026-08-25 20:37:02 +02:00 | 29 commits to dev since this release

    Added

    • Version number in the footer — the running release is shown after the copyright line (· V0.8.0), inlined at build time from package.json, so it is possible to tell at a glance which build production is serving

    Changed

    • Brand assets page is a flat 3×3 grid — the Facebook background image and the three section headings (Logo, Paleta barw, Social media) are gone, leaving nine tiles that fill a three-column grid exactly. The grouped asset model existed only to drive per-section column spans, so it flattened to a plain list. A visually hidden heading keeps the route reachable for screen readers navigating by heading list
    • Logo tiles are tighter and the images are clickable — the tile background and padding are gone (every asset already carries its own ground, so the second layer put a white square inside a beige one), the grid and section spacing are pulled in, and clicking a thumbnail opens the full-size PNG in a new tab. The PNG/PDF links still download. The one genuinely transparent asset keeps a light ground, and its caption now says so
    • En dashes in Polish copy — user-visible strings now use the spaced półpauza (–) instead of the em dash (—), which is the correct Polish convention: logo captions, the search no-results message, the reading-settings hint and the header's home link. Song lyrics are untouched — their dashes are the lyricist's

    Fixed

    • Duplicate main landmark on the home and logo pages — the locale layout already wraps every route in <main id="main-content">, and both pages nested a second <main> inside it. Two landmarks on one page break landmark navigation and blunt the skip link, which targets the outer one
    Downloads
  • v0.7.0 f13f78debe

    v0.7.0 Stable

    rimskij released this 2026-08-25 19:06:36 +02:00 | 36 commits to dev since this release

    Added

    • Logo page/logo (linked from the header next to Pieśni) presents the choir's brand assets as thumbnails grouped into Logo, Paleta barw and Social media, each with a PNG download and, where one exists, the print-quality PDF. The files previously lived only in docs/LOGO/, which is not served, so there was no way to get the logo for a poster or a Facebook event

    Fixed

    • Admin login was impossibleADMIN_PASSWORD_HASH is read from .env, where Next.js expands $ as a variable reference; a bcrypt hash starts $2b$12$, so the app received a truncated 47-character fragment and rejected every password as a mismatch. Broken since the 2026-06-04 security hardening introduced the hashed password. verifyPassword now validates the hash shape and reports the misconfiguration by name instead of blaming the password
    • PDF files under public/ returned 404 — the locale middleware redirected any unprefixed path, and its static-asset skip-list covered images and fonts but not .pdf, so every PDF resolved to 301 → /en/…pdf → 404. The skip rule now lives in one tested place rather than inline in the middleware
    • Download links were indistinguishable to screen readers — every logo tile's links were named just "PNG" and "PDF", so browsing by links list gave twenty identically-named entries (WCAG 2.4.4). Each now carries its asset caption

    Changed

    • Slop gate is now enforced — a calibrated slopgate.config.json makes /commit, /push and /ship block on an over-budget diff and scores introduced duplication, which was previously never measured in this repo
    Downloads
  • v0.5.3 810c1ae376

    rimskij released this 2026-07-18 16:05:11 +02:00 | 54 commits to dev since this release

    Added

    • Header files menu on the song page — a compact Pliki dropdown beside the reading settings surfaces the song's sheets/audio/video from the top of the page, so a rehearsing musician reaches them without scrolling past the lyrics; the lyric surface stays the hero (dropdown, not an expanded list)

    Changed

    • The bottom resources section is replaced by the header files menu (renders nothing when a song has no files)
    Downloads
  • v0.5.2 de98124772

    rimskij released this 2026-07-18 15:33:31 +02:00 | 56 commits to dev since this release

    Changed

    • Constructivist parity on the song page — the reading page now shares the home's editorial language: a hero title led by the red-tick accent (still natural-case Geist), NUTY / AUDIO as Anton headers with red ticks matching POLECANE, and the footer restyled in the uppercase-tracked editorial voice
    • Tighter reading measure (max-w-2xl) so short lyric lines read as a composed column instead of swimming in empty space
    Downloads
  • v0.5.1 4fd871cb66

    rimskij released this 2026-07-18 15:18:37 +02:00 | 58 commits to dev since this release

    Fixed

    • Footer shade — the footer sat on neutral-50 (a lighter, cooler near-white) instead of the warm paper ground; it now matches the header's ground tokens (neutral-200 / neutral-950) with a matching hairline, so chrome sits on the body ground top and bottom
    Downloads
  • v0.5.0 503cf48017

    rimskij released this 2026-07-18 15:05:37 +02:00 | 60 commits to dev since this release

    Defiant editorial direction (from an /impeccable:critique, 26 → 31/40):
    constructivist weight returns to the chrome while the reading surface
    stays calm — bold in the chrome, restrained in the content.

    Added

    • Constructivist chromeAnton section headers (POLECANE / SZUKAJ PIEŚNI) with a sparse red-tick accent, and an Anton wordmark beside the logo (desktop; mark-only on mobile); song titles stay natural-case Geist for pl/de diacritics
    • Search-first find cluster — search leads the home page, with the language filter and list bound beneath it (DOM order = focus order, WCAG 2.4.3)

    Changed

    • Reading controls de-orphaned into the song-page title header instead of floating in an empty row
    • Quieter chorus marker — the recurring refrain is now a red left rule + italic (no red fill/box), so pages with several choruses no longer read as a red band
    • Weightier, touch-friendly index rows — larger titles, py-5 targets, and a persistent (non-hover) arrow that slides on hover
    • Design direction recorded.impeccable.md now documents the "defiant chrome" pivot so it isn't reverted

    Fixed

    • 44px touch targets on the theme toggle and language selector (adaptive min-h on touch, compact on desktop); the resource download arrow is now persistently visible
    • No "Unknown" filler — a missing/placeholder credit drops out of featured rows via the canonical songMetaParts grammar, matching the index
    • Long-metadata overflow — long authors truncate (max-w + ellipsis) instead of breaking the row
    • prefers-reduced-motion now honored globally for every CSS transition, not just the opt-in motion-safe ones
    Downloads
  • v0.4.0 2c6ca34450

    v0.4.0 Stable

    rimskij released this 2026-07-12 18:47:54 +02:00 | 65 commits to main since this release

    Reading-surface typesetting and an editorial resources section, on the
    minimal-index direction (#304 lineage).

    Added

    • Editorial resources section on the song page — NUTY / AUDIO / WIDEO file groups as index rows (no tabs, counters, or rainbow icons); nothing renders when a song has no files
    • Labeled, separated credits — the song header now credits lyricist and composer distinctly, with localized language names, via a new song-meta.ts SSOT (songMetaLine / songMetaParts)

    Changed

    • Stanza rhythm on the reading page — verses now read as verses; a .lyrics-content p gap restores stanza spacing that Tailwind preflight had zeroed
    • Chorus markers activated — the brand-red chorus rule now fires on the recurring refrains in warszawianka, di szwue, czerwony sztandar, and Międzynarodówka; Bella ciao and Barāye split from single blocks into stanzas
    • Localized chrome — typography controls, search suggestion labels, the skip link, and error fallbacks now flow through the i18n catalog (new typography catalog)

    Fixed

    • Junk-proof index metadatan/a / unknown / malformed years dropped from index rows via the songMetaParts grammar; language names localized (Jidysz, not yi)
    • Search input — long queries no longer slide under the magnifier icon (pl-4 pr-12)
    • Metadata · separators legible in light mode; featured author hint restored on mobile
    • Content: warszawianka year 187 → 1879; removed a stray source-URL line from the-day-the-nazi-died

    Removed

    • Unreachable legacy /songs route chain (SheetMusicList, Breadcrumb), the @headlessui/react dependency, the suggestions API matchedOn field, and ~40 dead catalog keys
    Downloads
  • v0.3.1 e1a82ab6bb

    rimskij released this 2026-07-11 15:08:15 +02:00 | 73 commits to dev since this release

    Fixed

    • Language filter names now localize with the active UI language (Polski / Polnisch / Polish) instead of always showing English — the home filter read a static English map instead of the existing per-locale i18n catalog
    Downloads
  • v0.3.0 5c8130ae47

    rimskij released this 2026-07-06 20:56:36 +02:00 | 75 commits to dev since this release

    Brand identity & design overhaul (#304) — public surfaces moved to a minimal
    editorial index, near-monochrome warm palette with red as a single sparse accent.

    Added

    • Brand palette as live @theme tokens — red #BF2E2E, warm ink #232321, paper #EAE5E4, maroon #1B0E0D — plus a warm neutral ramp (replaces the hueless default)
    • Logo mark (LogoMark) in the site header, replacing the text-only masthead
    • Editorial index homepage & search results — natural-case Geist titles, muted author · year · language metadata, hairline dividers, hover arrows, no cards

    Changed

    • Reading surface branded — comfortable ~1.5 default leading, brand-red chorus marker + differentiated verse/chorus/bridge sections
    • Reading page harmonized to the editorial index — natural-case Geist title, no card, muted metadata line
    • One red+charcoal search-match system — matched text highlighted in place via <mark> (weight + tint + aria-label), no amber/blue/purple/green rainbow
    • Header sits on the body ground (no white bar); theme/language controls ghosted
    • Onboarding cue + empty-state "clear filters" recovery; clearer copy (named languages, deduped loading)

    Accessibility

    • WCAG 2.1 AA across public pages — every red-on-ground pairing verified ≥4.5:1, 44px touch targets, meaning never conveyed by colour alone
    • AA-safe muted text — retuned neutral-600 (2.41:1 → 5.05:1 on paper)
    Downloads