The project landing page at /<project> had its own hand-rolled
header with <svg class="logo"> — not the canonical app-header__logo
class, and not loading shared/logo.js. So the logo on that page was
purely decorative while every other tool's logo (in the same beta
build) was wrapped by shared/logo.js into a clickable link to
/<project>. Inconsistent and surprising — clicking the logo from
mdedit/archive/etc. takes you to project landing, but clicking the
logo on project landing did nothing.
Inline the wrap directly in the template (the page is server-
rendered, so it can't lean on shared/logo.js the way bundled tools
do):
<a class="app-header__logo-link" href="/" title="ZDDC home">
<svg class="app-header__logo" ...>...</svg>
</a>
href="/" because "next up" from the project landing is the
deployment root (the project picker / landing tool).
Also rename .logo → .app-header__logo for visual consistency, and
add the matching hover/focus styles inline. The test asserts both
the wrapping anchor and the canonical class name.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GET /<project> (no trailing slash) used to 301 to /<project>/ which
served the browse listing. Now it serves a small server-rendered
landing page with:
- Four lifecycle-stage cards (archive/working/staging/reviewing)
linking to the no-slash form of each canonical folder, so each
card opens its default tool (archive view, mdedit sandboxed to
working/, transmittal at staging/, mdedit at reviewing/).
- A "Browse all files" link to the slash form for the generic
file tree.
- A "Master Deliverables List" section with step-by-step
instructions for editing any party's MDL plus direct links to
the MDL of each party already present under archive/ (sorted,
case-preserved). Falls back to a friendly "no parties yet"
message when the archive is fresh.
Trailing-slash form (/<project>/) is unchanged — still 200 +
embedded browse.html. The slash-vs-no-slash convention now extends
all the way up the URL tree:
/ → landing tool (project picker)
/<project> → project landing (this commit)
/<project>/ → browse
/<project>/working → mdedit
/<project>/working/ → browse
... etc.
Implementation:
- new internal/handler/projecthandler.go — IsProjectRootURL
predicate + ServeProjectLanding rendering an inlined html/template.
Page styles are inline; tokens mirror shared/base.css and
auto-flip on prefers-color-scheme: dark.
- dispatcher in cmd/zddc-server/main.go: at the IsDir branch's
no-slash fork, intercept depth-1 single-segment URLs before
the historical 301. Other depths still 301 unchanged.
Tests:
- internal/handler/projecthandler_test.go (4 cases): predicate
coverage; landing page renders project name + four stage cards;
on-disk parties surface as MDL links with case preserved; fresh
project falls back to the no-parties-yet copy.
- cmd/zddc-server/main_test.go TestDispatchSlashRouting: the
"project root no-slash → 301" case becomes "→ landing (200)".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>