- ⇅ button on each group header: sorts units alpha (labelPlural + symbol tiebreak) via order API
- ⚙ Settings moved to admin-header alongside Log out
- Unit type gets sortPosition?: number (1-based, optional)
- Converter sort: partitions pinned/floating, inserts pins at requested slots
Pins > length append at end; gaps fill naturally with floating items
- Admin unit form: Force position number input
- AppConfig gains yoloVisibility: 'auto' | 'never' (default: auto)
- Group gains alwaysShowLabel?: boolean
- YOLO toggle only renders when showYoloToggle is true (auto + >1 group)
- Group divider shows when >1 group OR alwaysShowLabel is set
- New /admin/api/config GET+PUT endpoint for yolo settings
- Admin: alwaysShowLabel checkbox in group form
- Admin: ⚙ Settings panel with YOLO label, description, and visibility controls
When a {id:description} reference forms a cycle, the back-reference
now expands to 'Label (symbol)' rather than being stripped.
So pound ↔ dickload renders as 'See dickload (dl)' and 'See pound (lb)'.
Two bugs:
1. Sentinel used double-underscore delimiters (__DESC:id__) — fragile regex
[^_]+ would break on IDs containing underscores, and Pass-1 output
containing sentinels would leak through Pass 2 unstripped.
2. After Pass 2 substitution, sentinels inside substituted text (from
Pass-1 output of the referenced id) were never cleaned up.
Fix: switch to null-byte delimiters (\x00DESC:id\x00) which cannot appear
in user text, and add a second .replace(SENTINEL_RE, '') pass to strip any
sentinels that survive after substitution (self-refs, nested cycles).
- Replace native title-based tooltip with custom positioned div
Native title only renders on mousemove; custom div fires on mouseenter
after 500ms delay as intended
- Tooltip styled dark with fade-in; Dan Mode gets yellow-on-black with magenta glow
- Units with descriptions show a small superscript ⓘ on the result label
Pass 1 resolves all field tokens ({id}, {id:label}, {id:plural}, {id:symbol})
and replaces {id:description} tokens with sentinels.
Pass 2 replaces sentinels with Pass 1 output for the referenced id — one level
deep, so mutual references expand once then stop cleanly.
ConverterCard now uses resolveAllDescriptions() for efficiency (one map
build per reactive update instead of per-unit).
- Unit and Group get hidden?: boolean — filtered server-side before render
- Hidden group also suppresses all its units from the converter
- New resolveDescription() utility in src/lib/description.ts
supports {id}, {id:label}, {id:plural}, {id:symbol} placeholders
- ConverterCard pre-resolves descriptions and passes result to ConversionResult
- ConversionResult accepts description prop instead of reading unit.description
- Admin forms: Hidden checkbox added for both units and groups
- drag-handle color overridden to --pico-primary-inverse on selected/drag-over rows
(white in light/dark themes, black on Dan Mode yellow)
- Extract KEBAB_RE, SESSION_COOKIE, SESSION_MAX_AGE_MS, COOKIE_MAX_AGE,
authRequest(), and sessionResponse() to auth.ts — eliminating 4 copies
of the auth() wrapper and 3 copies of KEBAB_RE across admin API routes
- Remove timing side-channel: drop a.length !== b.length early-return
before timingSafeEqual in verifySession (SHA-256 HMAC always 64 chars)
- Fix YOLO localStorage write-before-read race using initialization guard
- Fix admin layout /api/ bypass to return {} instead of {authenticated:true}
- Extract extractError() helper in admin page — removes 4 inline patterns
- Parallel Promise.all in admin loadData() — halves round-trip latency
- Parallel Promise.all in moveCheckedUnits() + surface per-request errors
- Hoist Big(inputValue) above .map() in converter — one alloc per recompute
- O(n) single-pass orderedResults using Map instead of O(n*groups) filters
- Fix expandedGroups.add() mutation — use Set assignment for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements full admin interface for managing units and groups.
Migrates converter from static imports to server-side data loading.
- Switch adapter-static → adapter-node
- Add bcryptjs session auth with HMAC-signed cookies
- Add data/units.json and data/config.json data layer
- Add atomic file writes via temp-file rename
- Add public GET /api/units endpoint
- Add auth-gated admin CRUD API for units and groups
- Add two-panel admin UI with group tree and edit forms
- Add YOLO mode toggle for cross-group conversions
- Add visual group dividers in converter results grid
- Update ResultItem type for nullable convertedValue and isYolo flag
- Group deletion supports reassign/orphan with toBase recalculation
Rollback point: 067fd44
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>