Files
brain-of-reese/.agents/phases/complete/60_sticky_navbar/00_phase.md
T
ducoterra dbf2af26c6 refactor(agents): migrate .agent/ planning tree to .agents/
Standardize on the .agents/ directory (shared with project skills):
phases/, user_stories/, reports/, screenshots/, validate.sh, and
phase-sessions/ + pipeline.log all move to .agents/ (git mv preserves
history; runtime artifacts move alongside).

Updates every reference in AGENTS.md, README.md, .gitignore, app
docstrings, and test story headers. Historical KB content in data/
and the runtime pipeline.log transcript are left untouched.
2026-09-05 10:57:07 -04:00

4.4 KiB
Raw Blame History

Phase 60 — Sticky Navbar (stays stuck to the top while scrolling)

Source: TODO.md L3 — "The navbar disappears when you scroll down, should stay stuck to the top of the screen" Story: n/a (TODO-derived — owner roadmap confirmation 2026-08-31, A1–A3) Context: The navbar already HAS the sticky CSS: .app-header (frontend/assets/styles.css ~L194 — position: sticky; top: 0; z-index: 20) and the document viewer's two-row .doc-header (~L2201 — also position: sticky; top: 0), both direct children of <body> on every page. The bug: html, body { height: 100% } (~L40) pins the body box to exactly one viewport, and a sticky element's travel range is constrained to its containing block — so after ~1 viewport of scrolling the header un-pins and scrolls away with the body. Verified with headless Chromium during the TODO audit (2026-08-31): with the current rule the header's rect top is −1264px after a 2000px scroll; with height dropped from body (keeping min-height: 100dvh) it is top = 0, and on a short page the footer still lands at the viewport bottom (800/800 at 1280×800). The document must stay the scroll container (phase 52 no-inner-scroller contract, ~L387) — this fix adds no scroller, it only lets the body grow to its content. .agents/ is untracked (owner commit 281f355) — phase commits stage frontend/ tests/ only.

Objective

The navbar — and the document-viewer header — stays stuck to the top of the screen on every page at every scroll position, while the short-page layout (flex stretch, pinned composer, footer) stays exactly as it is today.

Dependencies

  • 59_response_to_docs_push (todo, preceding — no functional dependency; ordering by number)

Tasks

  1. 01_sticky_header_css.md — drop height: 100% from body (keep it on html), refresh the stale phase-12 comment, unit CSS pins in tests/unit/test_sticky_header.py.
  2. 02_e2e_sticky_navbar.md — tests/e2e/test_sticky_navbar.py (rect-top == 0 proofs on Sources + viewer at the bottom of long pages; short-page stretch/composer regressions), regression suites, atomic commit.

Testing & Quality

  • Unit CSS pins (house style, tests/unit/test_save_chat_ui.py pattern): html keeps height: 100%; the body rule carries NO height: (negative pin) and keeps min-height: 100dvh; .app-header and .doc-header keep position: sticky; top: 0.
  • E2E (mandatory, A3): tests/e2e/test_sticky_navbar.py, run in isolation.
  • Coverage: >90% on app/ (validate.sh gate — pure-CSS phase, gate still runs).

Completion Criteria

  • Sources page (KB long enough to scroll), 1280×800: after window.scrollTo(0, 999999) the .app-header rect top == 0 (±1px) and the header is visible.
  • Document viewer on a long doc: after full scroll, .doc-header rect top == 0 (±1px).
  • Short page (empty chat, 1280×800): body height == 800, .app-footer bottom == 800, .composer bottom ≈ 800 (±2px) — the phase-52 pin holds.
  • uv run pytest green; coverage TOTAL >90%.
  • uv run pytest tests/e2e/test_sticky_navbar.py -v --no-cov green in isolation (DB up).
  • Regression E2E suites green in isolation: test_pinned_composer.py, test_document_viewer.py, test_responsive_polish.py, test_smoke.py, test_no_reply_autoscroll.py, test_mobile_hamburger_nav.py.
  • uv run ruff check . && uv run pyright clean.
  • One --no-gpg-sign commit; phase dir moved to .agents/phases/complete/ (.agents/ stays untracked — owner instruction, commit 281f355).

Locked decisions

  • Owner-locked (2026-08-31, roadmap confirmation, A1–A3):
    1. A1 (root cause): the sticky travel range is capped by body { height: 100% } (styles.css L40) — the body box is pinned to one viewport and sticky elements (.app-header, .doc-header) can only travel within it.
    2. A2 (fix): CSS-only — drop height: 100% from body (keep it on html); the body's existing min-height: 100dvh keeps driving the short-page stretch. No JS changes, no new scroller (the document stays the scroll container).
    3. A3 (E2E): long-scroll surfaces = the seeded Sources table + the document viewer, with KB seeding via import_sources (the test_document_viewer.py pattern — fixtures + generated docs). No real LLM involved.

Commit

git add frontend/ tests/ && git commit --no-gpg-sign -m "fix(web): keep the navbar stuck to the top — drop the body height cap on the sticky range"