Unify the Viewer Header for Markdown and HTML Pages
Problem
The viewer currently renders two intentionally different shell headers:
- Markdown pages use a centered document header constrained to
52rem, with a large1.75remtitle above the version and theme controls. - HTML pages use a compact, fixed, full-width
3remtoolbar with a1remellipsized title, version and theme controls, and an Open fullscreen action.
This split came from the full-screen HTML viewer design, which preserved Markdown as a traditional readable document. The result is that navigation and viewer-owned controls look like two different products even though both page formats belong to the same viewer.
This is a shell inconsistency, not a Markdown rendering or theme bug.
Desired Outcome
Use one compact top toolbar for both Markdown and HTML pages while preserving their different content behavior:
- Markdown remains a centered, normally scrolling readable document.
- HTML remains a full-viewport, sandboxed iframe.
- HTML alone retains the Open fullscreen action.
- Version selection, theme selection, title styling, focus states, and responsive behavior look consistent across formats.
Implementation Plan
1. Create a shared toolbar partial
Add app/templates/viewer/_toolbar.html containing:
- Page title.
- Shared version-menu partial.
- Shared theme-menu partial.
- Optional fullscreen action when a fullscreen URL is present.
Keep the toolbar server-rendered and script-free. Continue using semantic <header>, <h1>, and <nav> elements.
2. Adopt the shared toolbar in both viewer templates
Update app/templates/viewer/html_host.html to render the shared partial without changing its iframe structure.
Update app/templates/viewer/markdown.html to:
- Add a Markdown-specific body class such as
viewer-markdown-host. - Replace the large
.viewer-headerand.viewer-titleblock with the shared toolbar. - Keep the existing
.viewer-main,.viewer-content, and.markdown-bodystructure. - Omit the fullscreen URL so Markdown does not display Open fullscreen.
This also reduces the prominent duplicate-heading effect when the page title and the first Markdown # heading contain similar text.
3. Refactor viewer CSS around shared chrome
In app/static/viewer.css:
- Make toolbar height, typography, border, spacing, title ellipsis, action alignment, dropdown placement, hover styles, and focus styles common to both formats.
- Keep the toolbar visually identical across formats.
- Let the Markdown toolbar be sticky and remain in normal document flow.
- Preserve fixed positioning and viewport-height calculations for the HTML host.
- Retain the Markdown content width of
52rem, content card, padding, typography, and normal scrolling. - Remove obsolete
.viewer-header,.viewer-header-controls, and.viewer-titlerules after the templates stop using them.
4. Handle responsive layouts explicitly
Verify the shared toolbar at narrow widths:
- The title shrinks first and uses single-line ellipsis.
- Version, theme, and fullscreen controls remain usable.
- Dropdown panels remain within the viewport and open from the appropriate edge.
- No controls wrap over or overlap the content.
- Keyboard focus rings remain visible.
If necessary, shorten or selectively hide nonessential action labels at the smallest breakpoint without introducing JavaScript.
5. Update automated tests
Update tests/test_viewer_smoke.py:
- Replace the assertion that Markdown must not contain
.viewer-toolbar. - Verify Markdown renders the shared toolbar and retains the content card.
- Verify Markdown does not render the fullscreen action.
Update tests/test_viewer_security.py:
- Preserve all HTML iframe, sandbox, immutable raw URL, and safe new-tab assertions.
- Verify the HTML host continues to provide the fullscreen action.
Update tests/test_viewer_css.py and theme tests:
- Verify shared toolbar styling and body-specific positioning.
- Cover long-title ellipsis and bounded menus.
- Verify System, Light, and Dark selections work from both formats.
- Confirm no iframe or raw HTML palette behavior changes.
Run the complete pytest suite.
6. Update documentation
Update README.md, docs/architecture.md, and MEMORY.md to explain:
- Markdown and HTML share viewer-owned toolbar chrome.
- Their content layouts remain intentionally different.
- Published HTML still controls its own palette inside the sandbox.
- The previous decision that Markdown would not adopt the toolbar has been superseded.
Add a note to docs/full-screen-html-viewer-plan.md or link to a new decision entry so the historical document no longer appears to describe current intended behavior.
Security and Compatibility Constraints
The change must not alter:
- REST or MCP schemas.
- Public or versioned viewer URLs.
- Markdown sanitization.
- HTML iframe sandboxing.
- CSP or security headers.
- Immutable version pinning.
- Theme-cookie behavior.
- Raw HTML fidelity.
Acceptance Criteria
- Markdown and HTML pages display the same compact top toolbar.
- Title, version, and theme controls use identical typography and alignment.
- Markdown remains centered, readable, and normally scrollable.
- HTML remains a borderless full-viewport sandboxed iframe.
- Open fullscreen appears only for HTML pages.
- Long titles and controls remain usable on mobile widths.
- Light, Dark, and System themes render correctly.
- All existing security guarantees and the complete automated test suite pass.