Skip to content

feat: persistent Knowledge base masthead on every page - #25

Merged
oto-macenauer-absa merged 1 commit into
masterfrom
feature/persistent-masthead
Jul 29, 2026
Merged

feat: persistent Knowledge base masthead on every page#25
oto-macenauer-absa merged 1 commit into
masterfrom
feature/persistent-masthead

Conversation

@oto-macenauer-absa

Copy link
Copy Markdown
Collaborator

Closes #24.

Problem

The branded header — DOCS eyebrow, Knowledge base title, strapline — only
existed on the landing catalog. Opening a documentation app dropped it, leaving no
in-page way back to the catalog and no indication of which app was being viewed.

Render every page through the layout

Packaged sub-app pages previously bypassed Base.astro entirely: the catchall route
emitted the pre-built document verbatim, so chrome, fonts, marketplace CSS, theme
handling and the SPA router all had to be string-injected by transformSubAppHtml().
That forced a parallel implementation of everything the layout already did — which is
why Chrome.astro and chromeHtml() both existed and had to be kept in sync.

transformSubAppHtml() now rewrites URLs and splits the document into its parts
(head contents, body attributes, body contents, title); Base.astro re-hosts them.
The layout becomes the single owner of the document shell for landing, packaged and
iframe pages alike.

Superseded and removed: chromeHtml() and marketplaceRouterScript() — Astro's
<ClientRouter /> already handled navigation on these pages, so the bespoke
fetch-and-swap router was redundant.

Add the masthead

Masthead.astro renders the eyebrow, title and strapline plus a sub-navigation row:

  • Library → the catalog of all documentation sites
  • a dynamic second entry naming the app currently being viewed (absent on the catalog)

The entry matching the current location is inert text with aria-current="page" rather
than a link to itself.

Drop the chrome bar and dark mode

With the masthead carrying the navigation, the 56px fixed chrome bar was redundant —
gone, along with its app switcher and content offset. A fixed bar was also the piece
that escaped the shadow boundary when reframed pierced the DOM.

The marketplace is now light-only: no theme toggle, no persisted preference, no dark
palette. transformSubAppHtml() strips a sub-app's theme bootstrap and dark body
class unconditionally, so an embedding host's theme cannot bleed into the fragment.

Notes for the reviewer

  • Fixes a latent bug: Chrome.astro's theme button called toggleTheme(), which
    only the string-injected script defined — it was dead on every Astro-rendered page.
  • Iframe entries now flex-fill the viewport instead of hard-coding 100vh, which would
    have overflowed below the masthead.
  • The web-fragments #297 CSS-accumulation test was counting mid-swap: ClientRouter
    updates the URL on popstate before swapping the DOM, so neither waitForURL nor
    networkidle proved the swap had finished. It now waits for landing-only content.
    The guard itself is unchanged — verified the settled count does not grow.
  • The app contract required a dark variable set and a 56px sidebar offset; both are
    updated. HEADLESS_RULES.md also pointed at a non-existent src/input.css, now
    src/styles/marketplace.css.
  • This branch also carries the earlier unmerged feat: iframe-based app onboarding
    commit, which the masthead work builds on.

Testing

Both Playwright layers pass: 32 embedded (npm test) and 15 standalone
(playwright.config.ci.js). New coverage: masthead presence and crumb behaviour across
catalog / app-index / deep / iframe pages, absolute-path contract for masthead links,
single-document-shell integrity after the layout re-host, and a light-only assertion
(window.toggleTheme undefined, no mp-theme in localStorage, no .dark node).

🤖 Generated with Claude Code

https://claude.ai/code/session_015MkyFmv3JPCkTaFhPVUFtg

Closes #24.

The branded header only existed on the landing catalog. Opening a
documentation app dropped it, leaving no in-page way back to the catalog
and no indication of which app was being viewed.

Render every page through the layout
------------------------------------
Packaged sub-app pages previously bypassed Base.astro entirely: the
catchall route emitted the pre-built document verbatim, so chrome, fonts,
marketplace CSS, theme handling and the SPA router all had to be
string-injected by transformSubAppHtml(). That forced a parallel
implementation of everything the layout already did.

transformSubAppHtml() now rewrites URLs and splits the document into its
parts (head contents, body attributes, body contents, title), and
Base.astro re-hosts them. The layout becomes the single owner of the
document shell for landing, packaged and iframe pages alike.

Superseded and removed: chromeHtml() and marketplaceRouterScript() —
Astro's <ClientRouter /> already handled navigation on these pages, so
the bespoke fetch-and-swap router was redundant.

Add the masthead
----------------
Masthead.astro renders the DOCS eyebrow, title and strapline plus a
sub-navigation row: "Library" linking to the catalog, and a dynamic
second entry naming the app currently being viewed. The entry matching
the current location is inert text with aria-current="page" rather than
a link to itself.

Drop the chrome bar and dark mode
---------------------------------
With the masthead carrying the navigation, the 56px fixed chrome bar was
redundant, so it is gone along with its app switcher and content offset.
A fixed bar was also the piece that escaped the shadow boundary when
reframed pierced the DOM.

The marketplace is now light-only: no theme toggle, no persisted
preference, no dark palette. transformSubAppHtml() strips a sub-app's
theme bootstrap and `dark` body class unconditionally, so an embedding
host's theme cannot bleed into the fragment.

Notes
-----
- Fixes a latent bug: Chrome.astro's theme button called toggleTheme(),
  which only the string-injected script defined — it was dead on every
  Astro-rendered page.
- Iframe entries flex-fill the viewport instead of hard-coding 100vh,
  which would have overflowed below the masthead.
- The #297 CSS-accumulation test was counting mid-swap: ClientRouter
  updates the URL on popstate before swapping the DOM, so neither
  waitForURL nor networkidle proved the swap had finished. It now waits
  for landing-only content. The guard itself is unchanged.
- The app contract required a dark variable set and a 56px sidebar
  offset; both are updated. HEADLESS_RULES.md also pointed at a
  non-existent src/input.css, now src/styles/marketplace.css.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015MkyFmv3JPCkTaFhPVUFtg
@oto-macenauer-absa
oto-macenauer-absa merged commit 8469e48 into master Jul 29, 2026
4 of 5 checks passed
@oto-macenauer-absa
oto-macenauer-absa deleted the feature/persistent-masthead branch July 29, 2026 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Render every page through the Astro layout and add a persistent Knowledge base masthead

1 participant