Commit graph

11 commits

Author SHA1 Message Date
ef849ab3fa feat(shared): replace floating elevation toggle with a header profile menu
Drop the bottom-right floating "Admin mode" switch in favour of a proper
account menu in the header's upper-right (every tool's .header-right).

New shared/profile-menu.{js,css}: a circular avatar button (email initial)
opening a dropdown with the signed-in email, an "Admin mode" item (only for
can_elevate principals — drives elevation.setOn/setOff, drops on leave),
Profile (/.profile), and Access tokens (/.tokens). The panel is portaled to
<body> + position:fixed so it overlays content reliably regardless of the
app's stacking contexts; the button shows a red ring while elevated.

No logout: authentication is the upstream proxy's concern (oauth2-proxy /
Authelia) — ZDDC owns no session, so the menu doesn't render sign-out.

elevation.js keeps the state machine (cookie, armed banner/frame, ephemeral
pagehide-clear, zddc:elevationchange, ?admin= URL) but no longer renders any
control — the profile menu is the UI. elevation.css drops the floating-
toggle styles (keeps banner + frame). All 7 templates drop the dead
elevation-toggle placeholder; all 7 build.sh bundle profile-menu.{js,css}.

Validated in a containerized browser: menu items, links, elevation arming +
armed ring, dropdown overlays content, no floating toggle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 19:43:43 -05:00
050902fa9e chore: elevation slot in every tool + docs + helper file splits + smell cleanup
Polish pass after the big refactor in 2d114fc.

== Header elevation slot propagated ==

shared/elevation.{js,css} surface a header checkbox for admins.
30-minute sudo-style cookie window (Max-Age=1800, SameSite=Lax).
Only renders when /.profile/access reports can_elevate=true; quiet
for non-admins. Slot added to all 7 tool templates and concat'd
into all 7 build.sh files; admin in any tool now sees the toggle.

Three text-rename ride-alongs in archive/classifier/transmittal
templates: "Add Local Directory" → "Use Local Directory" (the same
rename that landed in browse earlier in this branch).

== Docs ==

- CLAUDE.md gets an "Admin elevation is sudo-style" paragraph in
  the "Things that bite if you forget" section.
- AGENTS.md gets a dedicated "Admin elevation (sudo-style)" section
  alongside "Bearer tokens" — same depth as the existing auth docs.

== Helper file splits ==

The retired form editor's shared helpers got bundled into a single
zddc_admin.go in the cleanup; that name is now misleading. Split by
concern:

- admin_helpers.go: hasAnyAdminScope (the only admin-specific helper)
- paths.go: resolvePath, urlPathOf, chainDirs (URL ↔ filesystem path
  math — used by several profile / zddc-file handlers)
- profile_assets.go (renamed from zddc_admin_assets.go): custom CSS
  pipeline. URL renamed from /.profile/zddc/assets/ → /.profile/assets/
  since /.profile/zddc/ no longer hosts an editor.
- treeEntry moves to profilehandler.go (alongside AccessView, its
  only consumer).
- writeError moves to profileprojects.go (its only consumer).

== Smell cleanup ==

- zddc.HasAnyAdminGrant(fsRoot, email) — new elevation-independent
  primitive that walks the cascade and reports whether email is named
  in any admin: list anywhere. Replaces the synthetic-elevated probe
  hack in enumerateAccess (`Principal{Email, Elevated: true}` was
  "lying" to the elevation gate to ask what it would say). The handler's
  hasAnyAdminScope collapses to a 4-line wrapper that gates on
  p.Elevated and delegates.
- Access-log middleware records `elevated` per request, so forensics
  can distinguish "admin acting as user" from "admin exercising power."
- browse/js/app.js's ?file= deep link walks multi-segment paths. Each
  intermediate segment is matched + expanded; the leaf gets
  selected/previewed. Auto-shows hidden when any segment starts with
  . or _. Silently no-ops on unresolved segments.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 12:15:41 -05:00
d052e9fed3 Round of UX fixes: tool strip removed, MDL routing, browse markdown layout, reviewing depth-2
Four user-reported items:

1. landing: remove the standalone-tool strip from the site picker.
   Per user, it was awkward — links pointing at zddc.varasys.io
   releases from inside a deployment is a layering confusion. The
   nav.tool-strip block in landing/template.html and its CSS are
   gone.

2. zddc-server: route /Project/archive/<party>/mdl[/] to the tables
   app for the virtual-MDL case where the on-disk folder doesn't
   exist yet. Previously fell through to 404 because the dispatcher
   only routed virtual mdl/ via the IsDir branch — the IsNotExist
   branch was missing the equivalent check. Now both shapes (with
   and without trailing slash) hit RecognizeTableRequest's default-
   MDL fallback and ServeTable serves the embedded tables.html.

3. browse: re-layout the markdown editor to mirror mdedit's layout.
   Was: sidebar on right with TOC top + front-matter bottom.
   Now: sidebar on LEFT with YAML front matter top + Outline bottom,
        content on RIGHT with an informational header (file title +
        save controls + status + source) above the Toast UI editor.
   New horizontal resizer between the front-matter and outline
   sections inside the sidebar (drag the row boundary; arrow keys
   step by 24 px). Browse test selectors updated.

4. zddc-server reviewing aggregator: extend to depth ≥ 2 so the
   user can preview files inside virtual reviewing/<tracking>/
   received/ and staged/ folders. IsReviewingPath now returns a
   sidePath ("received[/rest]" or "staged[/rest]"); ServeReviewing's
   depth-2 branch proxies the underlying real folder's listing,
   emitting folder entries with virtual reviewing/ URLs (so
   navigation stays in the aggregator) and file entries with
   canonical archive/ or staging/ URLs (so byte fetches resolve
   directly). ACL is enforced against the real path; depth-1
   received/ + staged/ URLs are now virtual too (was canonical),
   so the user smoothly descends into the depth-2 listing.

Tests updated for the new IsReviewingPath signature and the depth-1
URL shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:30:34 -05:00
d5638e9697 feat(landing): MDL card with party dropdown on project view
The Master Deliverables List section was a long prose block ("To edit
the MDL: 1. open the archive, 2. click into a party folder, 3. click
mdl…") followed by a bullet list of party links — visually
inconsistent with the four stage cards above it.

Replaced by a fifth card in the .stages grid styled like the others:
heading + short description + an inline select + Open button. The
select populates from the same fetchParties() helper that backed the
old <ul.party-list>; selecting a party + clicking Open navigates to
/<project>/archive/<party>/mdl/.

Empty/error states:
  - No parties yet: select shows "(no party folders yet)"; hint copy
    expands to explain the URL-based fallback (zddc-server still
    auto-renders archive/<party>/mdl/ even when the folder is missing).
  - Network error: select shows "(could not enumerate parties)"; user
    can navigate via the URL bar.

Updated landing.spec.js — the old "lists existing parties as direct
MDL links" test now asserts on #mdlPartySelect contents + click-to-nav.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:25:14 -05:00
436e8ca066 feat(landing): standalone-tool strip on the site picker
Above the Groups / Projects cards, a horizontal strip of one link per
tool — each pointing at the latest stable single-file build on the
canonical release host (zddc.varasys.io/releases/<tool>_stable.html).
Useful for "try this tool" / offline use without first picking a
project.

Seven links (Archive, Transmittal, Classifier, Markdown, Browse, Form,
Tables). Landing itself is omitted from the strip — clicking landing
from landing is a no-op. Each card has the tool name in the display
serif and a short sans hint underneath. Wraps on narrow widths instead
of scrolling horizontally; sits inside pickerView so it auto-hides on
the per-project landing view.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:17:24 -05:00
315d039880 refactor(landing): project landing is now a single-file SPA, not server-rendered
The /<project> landing page was server-rendered via
internal/handler/projecthandler.go's html/template — an inconsistency
against the project's "every tool is a single-file HTML" convention.
Convert it to a mode of the existing landing/ tool: same bundle now
serves both / (project picker) and /<project> (project workspace).

Mechanics:

  - landing/template.html: pickerView (existing markup) + projectView
    (new: stage cards, browse-all, MDL section, party-list slot).
    Mode toggles by adding/removing .hidden on the two containers.
  - landing/js/landing.js: detectMode() reads location.pathname;
    renderProjectMode() populates stage hrefs from the project segment
    and fetches /<project>/archive/?json=1 for the party list. init()
    forks based on mode; picker init was extracted to initPicker().
    Existing public API + behaviour unchanged for picker mode.
  - landing/css/landing.css: appended ~115 lines for the project view
    (.stages grid, .stage-card hover, .party-list, MDL formatting).
  - cmd/zddc-server/main.go: dispatcher's IsProjectRootURL fork now
    calls appsSrv.Serve(w, r, "landing", chain, absPath) rather than
    the deleted ServeProjectLanding handler.
  - internal/handler/projecthandler.go: trimmed to just the
    IsProjectRootURL predicate (the dispatcher still needs it for
    routing). Template + render code (~220 lines) deleted.

Net effect: same UI as before — same logo wrapping (now via
shared/logo.js, no longer a hand-rolled inline anchor), same stage
cards, same MDL instructions with party links — but the page is now a
single-file SPA that themes like the rest, follows the same logo and
stage-strip conventions, and could in principle be downloaded and
served standalone.

Tests:
  - 3 new tests/landing.spec.js cases: detectMode exposure, project
    workspace renders at /<project> with correct stage hrefs + title,
    party listing populates from JSON fetch and filters dot-prefixed
    entries.
  - The dispatcher test for /Project no-slash still asserts 200 +
    no-redirect; the served body is now landing.html instead of the
    server-rendered template, but both pass the assertion.

LOC: roughly net-neutral. -220 in projecthandler.go, +115 in
landing.css, +130 in landing.js, +60 in template.html.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 07:57:30 -05:00
22c142e45a chore(headers): standardize across all 7 tools
Bring every tool's header in line with archive's pattern:

  [logo] [title] [version] [Add Local Directory] [⟳] ............... [◐] [?]
  ------------- header-left ---------------       ----- header-right -

Changes per tool:

* browse: rename "Select Directory" → "Add Local Directory"; add the
  red-non-stable wrap to the build label (was missing); add a help
  panel + bundle shared/help.js.

* classifier: rename selectDirectoryBtn → addDirectoryBtn,
  refreshBtn → refreshHeaderBtn for consistency. Update all JS
  callers and welcome-screen copy to the new label.

* mdedit: same id rename. Move the previously-in-pane refresh
  button into the header. Stop renaming the dir button to
  "Directory: <name>" once a folder is loaded — instead use the
  shared btn--subtle variant to de-emphasize while keeping the
  standard label.

* transmittal: convert non-standard <div class="app-header"> with
  spacer/icons containers to <header class="app-header"> with the
  canonical header-left/header-right pair. Move the publish split-
  button into header-left (Transmittal-specific primary action).
  Remove dead .app-header__spacer/__icons/header-icon-btn CSS now
  that nothing references those classes.

* landing, form: add help-btn + help-panel + bundle shared/help.js.
  Each panel is tool-specific (project picker docs for landing,
  schema-driven form docs for form).

Cross-cutting:

* shared/base.css: promote .btn--subtle from browse/css/tree.css
  so any tool with an online mode can de-emphasize Add Local
  Directory consistently.

Verified all 7 tools in headless Chromium: header structure correct,
build label red on non-stable cuts, help panel opens + closes via
button + Esc.
2026-05-04 07:49:17 -05:00
a6c3c9df5e chore(headers): standardize titles + refresh icon across tools
Cross-tool header inconsistencies cleaned up after the audit
prompted by the browse Phase 2 work:

  - landing/template.html: title was 'ZDDC Archive' (a holdover from
    when landing WAS the archive). The page is now the project
    picker — title shortened to plain 'ZDDC'. Browser tab title
    follows: 'ZDDC Archive — Projects' → 'ZDDC — Projects'. Title +
    build label wrapped in title-group div for layout consistency
    with archive/classifier/mdedit/browse.
  - form/template.html: title was bare; same title-group wrapping.
    The id='form-title' stays — its content is overwritten at
    runtime by form.js based on the form schema's name.
  - classifier/template.html: refresh button text 'Refresh' →
    '⟳' icon to match archive + browse. Same title attribute, just
    smaller visual weight.

Untouched (intentionally):
  - archive's button stays 'Add Local Directory' + addDirectoryBtn
    id — semantically different from the others (archive
    accumulates multiple directories; everyone else operates on
    one). The naming reflects that.
  - transmittal — different layout entirely (page-header with
    sender/receiver logo cells); not a candidate for app-header
    standardization.
2026-05-03 20:42:49 -05:00
d0929a2aa9 feat(landing): groups + click-to-open redesign
Replaces the caret-dropdown preset menu with two stacked cards:

  Groups (top)    — saved bundles of projects; click to open the archive
                    with that group's project set; per-row edit/delete
                    buttons.
  Projects        — filterable table; in default mode no checkboxes,
                    click any row to open just that project.

"+ New group" or a row's edit button enters select-mode: checkboxes
appear on each project row, an action bar shows above the projects card
with Save group / Open visible-checked / Cancel.

"Open visible-checked" intentionally excludes filter-hidden checked
projects so users can scope to a subset they're currently looking at.

Storage migrates from old zddc_landing_presets to zddc_landing_groups
(simpler shape: {name, projects: [...]}). One-shot migration runs on
first load.

Adds the new favicon SVG to the landing header alongside the title.
Drops the ?projects= URL state since selection is no longer the page's
primary state in click-to-open mode.

Updates Playwright suite: 9 new test cases covering click-to-open, group
crud, edit pre-population, "open selected visible" scoping, and legacy
preset migration. Adds a LandingApp._setNavigate test hook since
window.location.href cannot be reliably patched in modern engines.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 15:23:42 -05:00
c95f07966d feat(tools,build): in-flight HTML-tool reworks and build-infra updates
Bundles a stretch of in-progress work across the SPA tools so the
tree returns to a coherent shippable state ahead of cutting a new
zddc-server stable image:

- landing: substantial rework of the project picker (sortable/filterable
  table, presets refactor, ?projects= filter, ?v= channel propagation,
  loading/error states)
- archive: presets cleanup, source.js refactor, filtering/url-state
  alignment with the landing page
- mdedit: file-system module split, resizer, file-tree improvements,
  base/toc styling tweaks
- transmittal/classifier: small template touch-ups for shared chrome
- shared: build-lib.sh helpers, new favicon.svg
- bootstrap, build.sh: pick up the channel-aware install/track zip
  generation
- tests: new landing.spec.js, expanded archive/mdedit/build-label specs
- docs: CLAUDE.md picks up the zddc-server section and freshens the
  alpha-build exception note
- regenerated artifacts: install.zip, track-{alpha,beta,stable}.zip,
  *_alpha.html — these are produced by `sh build.sh` and per project
  convention are committed alongside the source changes

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 12:52:27 -05:00
ea385b5366 Initial commit
ZDDC — Zero Day Document Control. A file-naming convention plus five
single-file HTML tools (archive, transmittal, classifier, mdedit,
landing) and an optional Go HTTP server (zddc-server) with ACL and a
virtual archive index. Self-contained, offline-capable, dependency-free.

See README.md for an overview, AGENTS.md and ARCHITECTURE.md for the
build/release/architecture detail, bootstrap/README.md for the
two-level deployment install pattern, and zddc/README.md for the
HTTP server.
2026-04-27 11:05:47 -05:00