feat(ui): documents open in an almost-fullscreen modal instead of a new page — same-page overlay on chat + Sources, /document.html kept as the no-JS/direct-link fallback
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
# Phase 26 — Document Modal Viewer
|
||||
|
||||
**Source:** `TODO.md L4 — "New documents should open in an almost-fullscreen modal, not in a new page"`
|
||||
**Story:** `.agent/user_stories/document-modal.md`
|
||||
**Context:** Phase 10 added the separate `/document.html` viewer page; phase 19 added the shared header bar that now lives on every page. The document content is served by the stateless `GET /api/documents/content` endpoint (PLAN §4).
|
||||
|
||||
## Objective
|
||||
Stop opening cited documents in a new page/tab. Clicking a source chip or a Sources-table path link now opens the document in an **almost-fullscreen modal overlay** on the current page, fed by the same `/api/documents/content` endpoint. The existing `/document.html` page stays as the no-JS / direct-link fallback and its behaviour is unchanged.
|
||||
|
||||
## Dependencies
|
||||
- `10_story_document_viewer` (complete) — the `/document.html` page, the `document.js` renderer, the `renderMarkdown` escape-first renderer in `markdown.js`, and the `#doc-content` / `.doc-md` / `.doc-raw` markup this phase reuses inside the modal.
|
||||
- `19_shared_header` (complete) — the shared header bar the modal sits under; the modal must not disturb the header.
|
||||
- `08_story_dark_tech_theme` (complete) — the Phase-08 tokens and the ≥4.5:1 contrast / `prefers-reduced-motion` contract the modal must honour.
|
||||
|
||||
## Tasks
|
||||
1. `01_modal_css_and_html.md` — the modal CSS (overlay, backdrop, close button, scrollable content area) + inject the modal skeleton into `index.html`
|
||||
2. `02_app_js_modal_intercept.md` — intercept document links in `app.js` + `sources.js`, fetch content via `/api/documents/content`, render inside the modal
|
||||
3. `03_document_js_modal_mode.md` — adapt `document.js` to optionally render in modal mode (reuse the same API call) for the direct-link fallback path
|
||||
4. `04_e2e_regression_suite.md` — update `test_document_viewer.py` to verify modal behaviour; the story gate, run in isolation
|
||||
|
||||
## Testing & Quality
|
||||
- Unit/integration: none required for the modal itself (frontend-only); the `/api/documents/content` endpoint is unchanged (no `app/` change → no coverage delta).
|
||||
- Coverage: frontend-only; the >90% `app/` gate is unaffected.
|
||||
- E2E: `tests/e2e/test_document_viewer.py` rewritten for the modal contract (task 4), green **in isolation** (prereq `podman compose up -d db`).
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] Clicking a source chip (chat) or a Sources-table path link opens the document in an almost-fullscreen modal on the **same page** (no new tab, no navigation).
|
||||
- [ ] The modal renders the same content the `/document.html` page renders: md/markdown via the shared renderer (`.doc-md`), other formats in `<pre class="doc-raw">`, source/format/path/indexed/chunks meta.
|
||||
- [ ] The modal has a visible close control, closes on Escape, closes on backdrop click, and keeps the dark theme + a11y frame (skip-link, focus trap, `:focus-visible`, aria-label).
|
||||
- [ ] The existing `/document.html` page still works unchanged (direct link, back button, XSS-safe rendering, not-found state).
|
||||
- [ ] No CDN tags on any touched page; every asset reference is same-origin or `data:`.
|
||||
- [ ] `uv run pytest` green; `uv run pytest --cov=app --cov-report=term-missing` TOTAL ≥ pre-change number (gate >90%).
|
||||
- [ ] `uv run pytest tests/e2e/test_document_viewer.py -v --no-cov` green in isolation.
|
||||
- [ ] `uv run ruff check . && uv run pyright` clean.
|
||||
- [ ] UI Structure Check (AGENTS.md rule 5): modal content uses the standard centered column width for md; backdrop behind content; no 360px overflow.
|
||||
- [ ] `.agent/user_stories/document-modal.md` exists.
|
||||
- [ ] One `--no-gpg-sign` commit staging only this phase's files; `.agent/phases/todo/26_document_modal_viewer/` moved to `.agent/phases/complete/`.
|
||||
|
||||
## Locked decisions
|
||||
- **No backend change** — the modal reuses `GET /api/documents/content` unchanged (A10 untouched: the API stays stateless).
|
||||
- **A11 untouched** — vanilla HTML/CSS/JS, no CDN, zero new packages, no new assets, system font stack; the modal is pure CSS + JS.
|
||||
- **No anchor revised** — this is a UI-behaviour change (PLAN §7.5 gains `#doc-modal`, `#doc-modal-backdrop`, `#doc-modal-close`, `#doc-modal-content`); the `/document.html` page and its story are unchanged.
|
||||
- **A16 honoured** — one story E2E suite (rewritten) + adapted regressions.
|
||||
- **A17 honoured** — one atomic `--no-gpg-sign` commit.
|
||||
Reference in New Issue
Block a user