- Remove build-local.sh and old build-push.sh (crictl/scp/buildah workflow)
- New build-push.sh: docker build + push to registry.nerdrage.cloud/dickloads
- deployment.yaml: update image to registry.nerdrage.cloud/dickloads:latest, imagePullPolicy Always
- hooks.server.ts: replace empty stub with multi-origin CSRF guard
- Always allows humorunits.com and dickloads.com (+ www variants)
- ALLOWED_ORIGINS env var for additional origins (staging, preview)
- Dev: localhost:3000/4173/5173 auto-allowed when NODE_ENV != production
or ALLOWED_ORIGINS is unset — no config needed for local dev
- svelte.config.js: disable built-in single-origin CSRF check (we own it now)
trustProxy: true so X-Forwarded-Proto/IP are correct behind nginx-ingress
- login route: derive secure-cookie flag from X-Forwarded-Proto header so
session cookies are marked Secure even when Node sees plain HTTP from ingress
- deployment.yaml: add NODE_ENV=production and explicit ALLOWED_ORIGINS
- ⇅ 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
- Unit ID rename: updates group.baseUnitId refs + {old-id:*} in all descriptions
- Group ID rename: updates unit.group refs + {old-id:*} in all descriptions
- Admin form ID fields unlocked; hint text updated
- renameIdInDescription() shared helper in both PUT handlers
- start.sh: builds and launches Node production server on 192.168.0.94:4078
- Multi-domain CSRF: not needed — SvelteKit natively passes when Origin matches Host
- hooks.server.ts: minimal stub with explanation
- svelte.config.js: reverted csrf experiment (not supported in this version)
Concurrent calls from rapid reloads or rapid saves could pile up,
each writing state on completion and potentially re-triggering more loads.
Guards ensure only one load is in flight at a time; extra calls are dropped.
- 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).
- selectUnit/selectGroup now async; call autoSaveCurrentForm before switching
- Enter in any form field (except textarea) triggers save
- Escape restores form to snapshot (discards unsaved changes)
- discardUnitForm/discardGroupForm helpers for snapshot restore
- 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)