Add the app shell: sidebar, header, and routing

The view and the focused date live in the URL. That makes the back button
work and a week shareable, and gives "which week am I looking at" exactly
one answer -- v1 kept the selected date in localStorage *and* in the
database with no defined source of truth between them.

Date arithmetic is a pure module with its own tests, run natively rather
than in a browser. v1 did this inline in a 1,431-line week view where the
only way to check it was to build, deploy and look. Thirteen tests,
including that a month covers whole weeks and needs six rows when the
month does -- v1 shipped "Fix print preview to display all 6 rows for
6-week months" -- and that stepping a month from the 31st lands on the
last day of a shorter one instead of skipping February.

The sidebar shows each calendar in its own colour, read from the CalDAV
server rather than hashed from its path, and hiding one narrows the
time-range query rather than filtering in the browser.

Two things the browser loop found. chrono::Local traps on wasm without the
wasmbind feature, which surfaces as a bare "unreachable" with no message
in a release build. And toggling a calendar's visibility silently
reordered the sidebar, because the insert wrote position 0 -- position is
nullable now, for the same reason colour is: "never arranged" is a
different statement from "first".

e2e/dev.sh brings the whole stack up seeded with a week of events. It
exists partly to record that trunk serve owns dist/: running trunk build
against it concurrently rewrites the files without rewriting the integrity
hashes in the served index.html, and the browser then blocks its own
scripts, which looks like a blank page and is nothing of the sort.
This commit is contained in:
2026-08-26 20:48:56 -04:00
parent 6eee422421
commit ba90a30e41
21 changed files with 1817 additions and 126 deletions
+1
View File
@@ -67,6 +67,7 @@ leptos_router = "0.8"
gloo-net = { version = "0.6", features = ["json"] }
wasm-bindgen = "0.2"
web-sys = "0.3"
js-sys = "0.3"
console_error_panic_hook = "0.1"
# CLI