**Phase 92 final verification pass — all green.** This pass re-verified the completed tasks (all 5 task files already in `complete/`) against every completion criterion; no defects found, nothing to fix. - Verified: 9th identity var `grid_line` end-to-end (migration `0015` at head, model/`theming.py`/schemas/API, 422 + built-in→NULL tests present); `styles.css` zero hardcoded literals outside `:root` + derived `--brand-*` vars; 9th picker in theme form; wordmark themed; `theme.js` save/reset/re-show/mount live-sync; dedicated E2E suite + phase-91 suite updated. - `uv run pytest --cov=app --cov-report=term-missing` → **1845 passed, exit 0, TOTAL 99%** (>90%) - `uv run ruff check .` → clean; `uv run pyright` → 0 errors, 0 warnings - `uv run pytest tests/e2e/test_theme_save_and_coverage.py -v --no-cov` → **3 passed** (save-live, reset-live, whole-site) - `uv run pytest tests/e2e/test_admin_theme_tab.py -v --no-cov` → **5 passed** - Criteria: (1) Save/Reset repaint open page, no nav, SPA-nav survives, pre-paint intact ✅; (2) both `rg` gates green (only `:root` + documented `#fff` Stop label; zero SVG hex attrs), grid/selection/hovers/wash/wordmark E2E-proven ✅; (3) no-op contract live-checked: row-less `/` = no tag + exact A1 CSP, grid-only row = 9-var tag in `COLOR_FIELDS` order + sha256 CSP, with-row ≡ row-less bytes ✅; (4) full suite/coverage/lint/both E2E ✅; (5) commit left to the harness per instructions. - Deviations (previously made, probe-verified, kept): live repaint uses CSSOM `<html>` overrides because Chromium blocks `<style>` textContent mutations under the locked sha256-only CSP (tag text still mirrors the next load; `<html>` style exact-saved after Save, empty after Reset); wordmark themed via 3 `.brand-mark` CSS rules instead of inline styles (task 03's inline attrs were CSP-blocked — fixed during task 04). - Next pending phase: none — `todo/` contains only `92_theme_save_and_coverage`.
135 lines
6.3 KiB
HTML
135 lines
6.3 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
<meta name="description" content="Edit a saved chat answer before it is committed to the docs repository (admin-only).">
|
|
<title>Edit doc · Brain of Reese</title>
|
|
<link rel="icon" type="image/svg+xml" href="/assets/favicon.svg">
|
|
<link rel="stylesheet" href="/assets/styles.css">
|
|
</head>
|
|
<body>
|
|
<a class="skip-link" href="#main">Skip to content</a>
|
|
|
|
<!-- Phase 59 task 06: the SLIM header — this is a flow page (the
|
|
login.html / shared.html minimal-flow-page lineage), not one of
|
|
the app's pages: no nav, no auth pair, no hamburger. Brand +
|
|
the "← Back to chat" link are the whole chrome. -->
|
|
<header class="app-header">
|
|
<div class="container header-inner">
|
|
<span class="brand">
|
|
<svg class="brand-mark" aria-hidden="true" viewBox="0 0 64 64"><path d="M32 4 55 18v28L32 60 9 46V18Z" stroke-width="4" stroke-linejoin="round"/><circle cx="32" cy="32" r="6.5"/><path d="M32 25.5V16M32 48v-9.5M25.5 32H16M48 32h-9.5" stroke-width="3" stroke-linecap="round"/></svg>
|
|
<span class="brand-text">Brain of <strong>Reese</strong></span>
|
|
</span>
|
|
<a class="doc-edit-back" href="/">
|
|
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5"/><path d="m12 19-7-7 7-7"/></svg>
|
|
<span>Back to chat</span>
|
|
</a>
|
|
</div>
|
|
</header>
|
|
|
|
<main id="main" class="app-main" tabindex="-1">
|
|
<div class="container doc-edit-shell">
|
|
<!-- The 46rem base column (a FORM column — it hard-codes 46rem,
|
|
it does not ride --chat-column, so phase 58's wide-desktop
|
|
doubling never stretches the form). -->
|
|
<div class="page-head">
|
|
<h1>Edit doc</h1>
|
|
<p class="page-sub">
|
|
Review the saved answer, adjust anything, then push it to the
|
|
docs branch — the commit lands in the configured docs repo;
|
|
you open the PR yourself.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Phase 59 task 06: the admin gate — the EXACT #sources-gate
|
|
pattern (phase 16) and the same .sources-gate visual
|
|
language (phases 35/50). The page is static; the API is the
|
|
authority — the draft endpoints are admin-only regardless,
|
|
so a non-admin visitor gets the gate and NO draft data
|
|
(doc-edit.js makes no /api/doc-drafts call before whoami
|
|
says admin). -->
|
|
<section class="sources-gate" id="doc-edit-gate" aria-labelledby="doc-edit-gate-title" hidden>
|
|
<div class="sources-gate-glyph" aria-hidden="true">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="10" width="16" height="10" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/><circle cx="12" cy="14.5" r="1.4" fill="currentColor" stroke="none"/><path d="M12 16v2"/></svg>
|
|
</div>
|
|
<h2 id="doc-edit-gate-title">Sign in to edit docs</h2>
|
|
<p class="sources-gate-sub">
|
|
Saving a chat answer as documentation is admin-only. Chat —
|
|
and any document an answer cites — stays open to everyone.
|
|
</p>
|
|
<a class="sources-gate-link" href="/login.html?next=/doc-edit.html">Sign in</a>
|
|
</section>
|
|
|
|
<!-- SHIPS hidden (anonymous-safe; the gate is what anonymous
|
|
visitors see). doc-edit.js reveals it once the cached whoami
|
|
says admin, then loads the draft from ?draft=<token> (the
|
|
uuid4 token task 05's button navigated with). -->
|
|
<div id="doc-edit-content" hidden>
|
|
<form id="doc-edit-form">
|
|
<label for="draft-title">Title</label>
|
|
<input
|
|
id="draft-title"
|
|
name="title"
|
|
type="text"
|
|
autocomplete="off"
|
|
required
|
|
>
|
|
|
|
<label for="draft-path">In-repo path</label>
|
|
<input
|
|
id="draft-path"
|
|
name="path"
|
|
type="text"
|
|
autocomplete="off"
|
|
required
|
|
>
|
|
|
|
<label for="draft-body">Body — markdown</label>
|
|
<textarea id="draft-body" name="body" required></textarea>
|
|
|
|
<div class="doc-edit-actions">
|
|
<button type="submit" id="push-doc-btn">Push to docs branch</button>
|
|
<a class="doc-edit-back" href="/">
|
|
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5"/><path d="m12 19-7-7 7-7"/></svg>
|
|
<span>Back to chat</span>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- §7.4 never-stale: the polite live region carries the
|
|
push lifecycle — "Pushing…" while the request is out,
|
|
then `Pushed to <branch> — commit <sha7>.` on success.
|
|
doc-edit.js owns the text (textContent only). -->
|
|
<p class="doc-edit-status" id="push-status" role="status" aria-live="polite"></p>
|
|
|
|
<!-- The error banner (role=alert), hidden until a load or
|
|
push failure: the server's detail (git's stderr,
|
|
trimmed to its first meaningful lines) lands here and
|
|
the fields are preserved — the fix is an edit, not a
|
|
re-type. -->
|
|
<div class="doc-edit-error" id="push-error" role="alert" hidden></div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<footer class="app-footer">
|
|
<div class="container footer-inner">
|
|
<span class="footer-text">Powered by self-hosted models</span>
|
|
</div>
|
|
</footer>
|
|
|
|
<!-- Phase 39: the brand layer — classic script, first on the page:
|
|
window.BOR_BRAND at parse time, refreshed from /api/config.
|
|
Phase 59 task 06: the page module loads the shared header module
|
|
through its own relative `import "./header.js"` — a hoisted
|
|
import evaluated before this body runs (single-evaluation
|
|
design: no direct header.js <script> tag; esbuild inlines it
|
|
into the page bundle in the image build). On this slim flow
|
|
page the import is the cached whoami (fetchIsAdmin) the admin
|
|
gate runs on. -->
|
|
<script src="assets/brand.js"></script>
|
|
<script type="module" src="/assets/doc-edit.js"></script>
|
|
</body>
|
|
</html>
|