Skip to content

0.1.25 - #23

Merged
kristin-kronstain-brown merged 29 commits into
mainfrom
kkb-0.1.24
Aug 4, 2026
Merged

0.1.25#23
kristin-kronstain-brown merged 29 commits into
mainfrom
kkb-0.1.24

Conversation

@kristin-kronstain-brown

@kristin-kronstain-brown kristin-kronstain-brown commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

[v0.1.25] — 2026-08-03

Change — docTabs moves from a front-matter tab model to a content-directory (id) model (layouts/_partials/docs-tabs.html, layouts/partials/sidebar.html, hugo-*.toml, USAGE.md)

  • Why. The v0.1.21 docTabs prototype grouped pages by a front-matter tab: "<name>" key, re-derived the grouping by filtering the whole tree on every render, matched the active tab by URL string (which drifts between the OSS, enterprise, and local-dev URL shapes), and — because a tab was a virtual grouping, not a real container — linked each tab to its first item's page instead of a stable landing.
  • What changed. A tab is now a real content directory: config declares each tab with an id (a top-level directory under the version root) plus its name, the sidebar roots the left-nav tree inside that directory, the active tab resolves by page ancestry (.IsDescendant) so every URL shape agrees, and each tab links to its directory _index. The enable gate becomes "2+ present tab directories in this version"; below that the band is suppressed and the full tree renders as before. Two supporting fixes: a tab holding only its _index now emits a link to its own landing (an empty pre-rendered panel made the mobile chip a dead end), opt-in per call site so non-tab sidebars are untouched; and the band centers its tab row in the same utils/page-width container as the content column, so tabs align with the sidebar/content left edge at every page.width.
  • Consumer contract change (opt-in feature only). [[params.docTabs]] now requires an id per tab, and enabling docTabs means partitioning that version's content into one top-level directory per tab; the tab: front-matter key is no longer read. No production consumer has enabled docTabs, so nothing in production changes — this supersedes the prototype before its first real use. USAGE.md is rewritten to the directory model.
  • No production page — the feature stays available-but-dormant. Observable on the theme fixture: make server-oss, then compare /test/v3/api/authentication/ (the v3 version partitions into documentation/, api/, changelog/, so three tabs render and the nav is rooted in the active tab's directory) with /test/main/everything/ (no tab dirs → no band, full tree). Verified with hugo160 OSS + enterprise builds; the rewritten tests/docs-tabs.spec.ts pins both the enabled and disabled states plus the page-width wrapper, 9/9 on both brands. Takes effect when a consumer sets params.docTabs with ids, partitions its content, and bumps its extras pin.

Add — per-tab hideSidebar drops the left nav on a docTabs tab, desktop only (layouts/_partials/docs-tabs.html, layouts/partials/sidebar.html, assets/css/docs-theme-extras.css, hugo-*.toml, tests/docs-tabs-sidebar.spec.ts, USAGE.md)

  • Why. With docTabs, the left nav is rooted inside the active tab's directory — so a tab that owns a single page (a one-page changelog, one generated API reference) renders a one-item nav whose only link is the page the reader is already on, spending a 16rem column to say nothing. There was no way to say "this tab has no tree"; the choice was a full nav on every tab or no tabs at all.
  • What changed. [[params.docTabs]] takes an optional hideSidebar = true. docs-tabs.html resolves it for the ACTIVE tab (off the present-tab list, so a tab whose directory is missing in this version can't suppress a nav for pages it doesn't own) and puts it on the page store; sidebar.html turns it into a sidebar-desktop-hidden class on the <aside>; one rule in the existing @media (min-width: 1280px) block hides it. display: none rather than visibility/width, so the flex row gives the column back and the article widens instead of showing a blank gutter. Absent or false → nav renders, which is every existing tab, so nothing changes until a tab opts in.
  • Mobile always shows it, and that's the whole design constraint. Below xl the same <aside> is the slide-out drawer, and the drawer is the only route to the tab chips, the version chips, and the other tabs' pre-rendered trees — hiding it on a phone would strand the reader on the current page with no way off it. So the suppression is CSS inside the desktop media query and the markup is always emitted; skipping the markup instead (the obvious first implementation) would have killed the drawer. The desktop tab band also stays, since it's how a reader gets from a nav-less tab back to one that has a nav.
  • Bool flag, not isset/default. Read as a plain truth test. .hideSidebar | default false would misreport an explicit false the same as unset, and Hugo's isset has bitten this repo before (the warnMissingDescription opt-out needed a case-sensitivity fix), so neither is used. Verified: setting hideSidebar = false in the fixture fails the new tests exactly as removing the key does.
  • No production page — docTabs is still enabled in no consumer, so this ships dormant alongside the directory-model change above. Observable on the theme fixture: make server-oss, then compare /test/v3/changelog/ (the Changelog tab sets hideSidebar = true: no left nav at laptop width, article reclaims the column, band still there) with /test/v3/api/authentication/ (same config, no flag → nav intact). Narrow the window below 1280px on the changelog page and the drawer opens with all three tab chips and a tappable tree.
  • Verified with hugo160 OSS + enterprise builds. New tests/docs-tabs-sidebar.spec.ts (browser project — the behavior is CSS, which the HTML-only static project cannot see) asserts the desktop hide, the reclaimed column, that an unflagged tab keeps its nav, and that the drawer still opens with its chips and tree at 390px; docs-tabs.spec.ts gains a static check that the marker class lands on the flagged tab's pages and only those. docs-tabs specs 14/14 on both brands, and the full static + browser suites stay green (1438 passed on enterprise). Both guards were checked by breaking them: deleting the CSS rule fails the two desktop tests and leaves the mobile one passing; flipping the flag to false fails the static marker test too.

Add — the mobile drawer AJAX-swaps a section/version selection in place (assets/js/mobile-nav.js, assets/css/docs-theme-extras.css, tests/mobile-drawer.spec.ts, playwright.config.ts)

  • Why. Below the sidebar breakpoint, tapping a section (Kubernetes/Standalone) or version chip in the drawer navigated to the target page, which closed the drawer — so a reader working through section → version → topic was ejected and had to re-open and re-orient after every hop. Unlike the tab chips, whose trees are already pre-rendered in the page, those chips point at a content tree that isn't in the DOM.
  • What changed. mobile-nav.js now fetches the target page, lifts its .sidebar-mobile-panel nav out of the response, and swaps it into the open drawer, so the reader keeps drilling down; a brief .drawer-loading dim covers the fetch, and any fetch/parse failure falls back to plain navigation so a chip always does something. Drawer wiring moved behind a single bindDrawer(root) so listeners re-attach to the swapped-in markup.
  • Hardening the swap needed. (1) An in-flight request token, so two fast taps can't leave the drawer showing the earlier response's tree. (2) The loading lock widened to .sidebar-mobile-header — the chips sit above the dimmed nav wrapper, so they stayed clickable during a fetch. (3) Focus moves to the swapped-in .sidebar-nav; replacing panel.innerHTML dropped focus to <body>. (4) Closing the drawer restores the pre-swap markup, so a reader who peeks at another version and closes without picking a topic doesn't reopen onto a tree they aren't on (commit-on-close was rejected: it would navigate a reader who only wanted to look). The close is caught with a MutationObserver on the panel class rather than by wrapping toggleMobileSidebar/closeMobileSidebar, which consumers' own nav templates call and manipulate. (5) Per-binding AbortController teardown: the window resize listener and per-row ResizeObserver are the two registrations that survive an innerHTML swap, and they accumulated for as long as a reader kept hopping. (6) A 5s timeout on the swap fetch. .drawer-loading dims the header and nav wrapper and turns off their pointer events, with no spinner, so a fetch that neither resolves nor rejects — a phone that loses signal mid-tap — left the drawer dimmed and input-locked indefinitely. (Not a hard trap: the overlay is a sibling of the panel, so tap-outside still closed it, but the reader had to discover that.) The abort lands in the same catch as any other failure, so it reuses the navigate fallback rather than adding a second recovery path. AbortController + setTimeout rather than AbortSignal.timeout, which is newer than the APIs this file already feature-detects and would throw on a missing property instead of degrading to no timeout; the timer clears only after the body is read, so a response that starts streaming and then stalls also falls back. (7) Crossing UP past the breakpoint with the drawer open now closes it. restoreDrawer fires on the open→closed class edge and nothing was watching the viewport, so a swap at 390px followed by a widen past 1280px (tablet rotation, a desktop window drag) promoted the swapped tree into the desktop sidebar while the page, its URL, and the navbar version dropdown all still belonged to the original version — the drawer's deliberately temporary divergence made permanent. The resize handler calls the existing closeMobileSidebar, so clearing .mobile-sidebar-open is the same edge the observer already watches and the reset falls out of the path that was there. That also fixes a second, pre-existing symptom: .sidebar-mobile-overlay.active carries no media query, so the full-screen scrim used to survive onto the desktop layout.
  • Desktop is unaffected — these chips are hidden at xl and above, where the tab band and version dropdown navigate normally. The breakpoint is now a single DRAWER_MAX constant in mobile-nav.js instead of three hardcoded 1280 comparisons that all had to agree with the CSS bound.
  • Observable in production at phone width on any versioned page, e.g. Solo Enterprise for kgateway — Quickstart: tapping a version chip reloads the page and closes the drawer today; after a pin bump the nav swaps in place. Verified with hugo160 OSS + enterprise builds and a new tests/mobile-drawer.spec.ts — seven tests at 390px covering the in-place swap, a second hop (the only thing that exercises the bindDrawer re-bind), the fetch-failure fallback, close-and-reopen reset, ResizeObserver accumulation, a fetch that hangs rather than rejecting (route.abort() is immediate, so the existing failure test passed with no timeout at all — this one leaves the route unfulfilled and asserts the fallback happens anyway), and a widen past the breakpoint mid-swap; each fails with its guard disabled. The spec lives outside browser.spec.ts (whose file-level test.skip(!EVERYTHING) would have skipped it on every real consumer) and discovers its target by crawling the built output, so it also runs against consumer builds: kgateway-oss 5/5, agentgateway-oss 4/5 (second hop legitimately skipped, only one hop target). Unversioned consumers have no version chip row and skip all five.
  • Two discovery guards worth knowing about. npx serve resolves a URL whose final path segment contains a dot as a file, so a version-root landing like /docs/kubernetes/1.0.x/ returns a directory listing with no scripts and every assertion vacuous — discovery skips dotted last segments (harness quirk only; the real sites serve those landings fine). Discovery also requires a chip marked sidebar-mobile-version-active, because archived trees are still built but dropped from the switcher, so nothing is active and there's no version to swap away from and back to.

Fix — stop remapping keepVersion version blocks in reused content (layouts/_shortcodes/reuse.html, hugo-*.toml, fixture, tests/reuse-version-remap.spec.ts)

  • Why. A {{< version include-if="…" keepVersion="true" >}} block reused inside a {{< rebase >}} had its include-if tokens silently rewritten by the OSS→enterprise remap, so an author-supplied enterprise mapping resolved to the wrong version or none. keepVersion="true" means "these are already enterprise tokens — don't remap." The keepVersion transform converts such a block to percent form with a version="…" param, and v0.1.22 broadened the remap's Pass-1 anchor from angle-only to both forms (to fix the get_cookie rows), which started matching those blocks too. Since enterprise tokens overlap ossVersion values, the remap shifted the tokens, yielding empty, shifted, or doubled matches. rebase.html never had this bug — it bulk-converts percent→angle before keepVersion runs, so its angle-only remap can't see these blocks.
  • What changed. Before the remap, any percent-form block carrying a version="…" param (the keepVersion signature) has its condition attribute renamed to a remap-invisible token (include-if=kvincif=, exclude-if=kvexcif=, neither containing the clude-if the remap keys on), restored afterward. Genuine percent-form blocks like get_cookie carry no version= param and still remap as v0.1.22 intended.
  • Consumer note — the docs hub carries a LOCAL layouts/_shortcodes/reuse.html override that shadows this module file (it flattens reuse output to one line). The production defect is fixed by the identical edit to that override in solo-io/docs; this module change keeps the two copies in parity. A pin bump alone does NOT change hub output while the override exists.
  • Observable in production: on Solo Enterprise for kgateway — Sample app the httpbin kubectl apply command rendered refs/heads//examples/httpbin.yaml (empty branch), 2.1.x rendered a doubled refs/heads/v2.2.xv2.3.x/…, and 2.2.x rendered main — the branch comes from kgw-docs/versions/github-branch.md, which maps enterprise versions to branches with keepVersion. Verified with a local hugo160 kgateway build: the three pages now render main, v2.3.x, and v2.2.x, a site-wide sweep finds no empty or doubled branch tokens, and the v0.1.22 get_cookie remap still works. The fixture now reproduces the production shape (the v1 entry carries ossVersion = "v3", so the token v3 — itself a fixture version — remaps to v1) with a matched pair of inline blocks differing only in keepVersion; tests/reuse-version-remap.spec.ts asserts the plain block IS remapped onto v1 (the control, so the keepVersion assertion can't pass vacuously) while the keepVersion block stays on v3, and fails on all three counts without the guard. Takes effect on the hub via the override edit; for other consumers, on a pin bump.

Fix — capped reference tables stop folding one character per line on phones (assets/css/docs-theme-extras.css, fixture, tests/table-display.spec.ts)

  • Why. A wide reference table auto-tagged .table-capped (render-table.html applies it to any table with 3+ columns) collapsed into an unreadable vertical strip on phones: at 375px, table-layout:auto; width:100% squeezes the columns toward nothing and the overflow-wrap: anywhere cap folds the content — measured on the fixture at 1 character per line over 50 lines for a registry token and 1 over 146 for a prose Description cell.
  • What changed. Below the same 767px breakpoint main.css uses, capped cells switch from overflow-wrap: anywhere to break-word. The keywords differ in exactly the property that matters: anywhere lets a cell's min-content width collapse to one glyph, break-word floors it at the longest unbreakable token. Measured after: 13 chars/line over 4 lines, 10 over 21, no horizontal scroll. Desktop is unchanged (the rule is inside the media query).
  • Why not white-space: nowrap (now a comment in the CSS): .table-capped hits every 3+ column table, i.e. the Field | Type | Default | Description shape whose Description holds prose — 25% of capped cells in kgateway-oss exceed 60 characters, the longest ~2750. Forcing those onto one line measured a 5.7x-viewport horizontal scroll on the fixture and 33x against real agentgateway airgap/CRD tables. Prose has to keep wrapping; only the collapse floor needed fixing.
  • Observable in production: Solo Enterprise for kgateway — Air-gapped installation carries an image table whose Registry column holds long us-docker.pkg.dev/… tokens, folding one character per line on a phone today. Verified with hugo160 OSS + enterprise builds; tests/table-display.spec.ts now bounds the behavior from both sides at 375px — an unbreakable-token block asserting ≥4 chars/line, and a prose block (backed by a new fixture table with ~200-char sentences) asserting the cell isn't nowrap, wraps, clears the same floor, and keeps the table under 3x the viewport. Line counts come from real line boxes (Range client rects), since computed line-height on these cells is normal. The pair fails on anywhere and on nowrap. Takes effect on a pin bump.

Fix — mobile chip-row edge fade uses a content mask so chip text no longer slides under the ‹ / › arrows (assets/css/docs-theme-extras.css, assets/js/mobile-nav.js)

  • Why. The scrolling version/tab chip rows faded their edge with a solid linear-gradient background behind the arrows, so the gradient sat behind the text and a chip still slid visibly under the arrow — and the effect needed a hand-maintained dark-mode variant to match the panel color.
  • What changed. A mask-image on the scroll track fades the content itself toward whichever edge can still scroll, so chip text dissolves before reaching the arrow and no dark-mode color variant is needed. mobile-nav.js toggles .scroll-fade-start/.scroll-fade-end per edge and clears them at rest, so the first/last chip isn't faded where there's no arrow; the fade widths default to 0.
  • Observable in production at phone width, e.g. the drawer's version chip row on Solo Enterprise for kgateway — Quickstart. Verified with hugo160 OSS + enterprise builds: the built stylesheet carries the [data-scroll-track] mask rule and the two fade widths, and both solid-gradient rules (plus their .dark variants) are gone. Test gap: the per-edge toggle is verified by inspection, not by an assertion — the code runs on the path the AJAX-swap test exercises, but the fade itself is unasserted. Takes effect on a pin bump.

Fix — paint markdown links in the version banner so they read as links (assets/css/docs-theme-extras.css, hugo-*.toml, tests/version-banner-link.spec.ts)

  • Why. A markdown link in a consumer's [[params.versions]].banner rendered as a real <a href> but in the banner's own body color with no underline and no weight change — clickable but unfindable, which reads to an author as "the banner link is broken." Link generation was never the problem: the banner renders outside .content, and the theme's only anchor rules are scoped .content a, while Hextra's Tailwind preflight resets a to inherit color and text-decoration. The anchor therefore inherited --tw-prose-body from .version-banner.
  • What changed. New .version-banner a rules take color from the brand's runtime --theme-primary (both brand layers redefine it under .dark, so one rule covers both brands and both schemes) plus font-weight: 500 and an unconditional underline, since a color shift alone is weak against the banner's tinted fill. :hover moves to --theme-primary-hover and drops the underline, with a :where(.dark, .dark *) override holding the resting color in dark mode (--theme-primary-hover is defined only in the light :root, and reusing it would darken the link toward the banner background).
  • Why no test caught it. The fixture's main banner was link-free, so no build in the harness had ever rendered a banner anchor. All four fixture configs now carry an internal and an external markdown link there, which also exercises render-link.html's relURL and target="_blank" branches inside the banner.
  • Observable in production on Gloo Gateway 1.21.x, whose banner links to the kgateway docs: the served HTML has the anchor, but neither deployed stylesheet contains a .version-banner a rule, so it renders in gray body text. Verified with hugo160 OSS + enterprise builds and a new tests/version-banner-link.spec.ts, which auto-discovers a configured page whose banner holds an anchor and asserts, in both light and dark mode, that every anchor has a resolvable href, differs from the banner body color or is underlined, and clears 3:1 against the banner fill (compositing the translucent dark-mode background over its opaque ancestor). Confirmed failing without the CSS and passing with it; full make test-all green on both brands (1648 passed, 14 skipped each). Because the spec keys off the consumer's own config, it carries signal against consumer builds too. Takes effect on a pin bump.
  • Known limitation: on the enterprise brand the resting --theme-primary (#158bc2) clears only ~3.6:1 against the light banner fill, under WCAG AA's 4.5:1 for normal text — which is why the spec's floor is 3:1. That is the brand's existing .content a color, so darkening it is a brand-layer decision, not a banner fix.

Fix — link-hextra stops mangling reference/api-* sibling sections, and routes the agentgateway CEL reference to the enterprise page (layouts/_shortcodes/link-hextra.html, fixture/assets/conrefs/test/everything.md, tests/link-hextra-apiref.spec.ts)

  • Why. Two enterprise-only 404 classes in the agentgateway link report, solo-io/docs#3352. (1) The reference/api routing guard tests in $path "reference/api", a substring that also matches the sibling section reference/api-kubespec, so a shared-source link to /reference/api-kubespec/policies/#… was rewritten to /reference/api/api-kubespec/policies/ — a path that exists on no build. Live on /agentgateway/2026.7.1/security/backend-authn-cross-app-access/: the crossAppAccess field link points at /agentgateway/2026.7.1/reference/api/api-kubespec/policies/. (2) agentgateway OSS splits its CEL reference into /reference/cel/variables/ and /reference/cel/yaml-and-examples/; the enterprise docs serve one /reference/cel/ page carrying the same anchors, so every rebased OSS page linking the CEL functions list 404s — 8 of them across latest, 2026.7.1, and 2.3.x, e.g. the "CEL functions" link on /agentgateway/2026.7.1/traffic-management/transformations/rewrite/, which should land on /agentgateway/2026.7.1/reference/cel/#functions-policy-all.
  • What changed. reference/api- joins the $alreadyRouted list, so any reference/api-* sibling passes through untouched instead of being treated as the single-page reference. A new rule collapses reference/cel/(variables|yaml-and-examples)/ to reference/cel/, gated on the rebase-injected product == "agentgateway" — the same product-only signal the existing agentgateway branch uses, so the OSS site (which sets no product) keeps its own paths and no assumption is made about the OSS site config. Anchors ride along unchanged, which is the point: the enterprise page publishes the same #functions-policy-all IDs.
  • Verified with hugo160 on both fixture brands. tests/link-hextra-apiref.spec.ts grows five markers (the api-kubespec sibling, plus the CEL variables/yaml/already-collapsed/no-signal cases): 9/9 on OSS and enterprise. Both guards were break-tested — dropping the reference/api- term and disabling the CEL rule fails exactly the three new assertions and leaves the six pre-existing ones green. Takes effect in the docs hub when it bumps its extras pin (currently v0.1.25-beta.2, no local replace).

CI — parallelize the two brand layers and keep a single required status check (.github/workflows/test.yml, playwright.config.ts)

  • Why. make test-all chains build-oss + test-oss + build-enterprise + test-enterprise in one job, so every push paid ~2x the single-brand cost back-to-back; and a stalled sudo apt-get during the browser install could hang to the 15-minute job timeout while a stale run lingered on the same branch. The brands are independent (separate builds, publishDir, DOCS_TEST_CONFIG), so nothing required a shared runner.
  • What changed. The job fans out over matrix.brand: [oss, enterprise] with fail-fast: false; PW_WORKERS is tunable and set to 4 in CI; a concurrency group keyed on github.ref supersedes in-flight PR runs; the browser-install steps carry timeout-minutes: 5 so a hung apt-get fails fast and re-runnable; and failure artifacts are per-brand so the jobs don't collide. Nothing here touches the published Hugo module.
  • All three engines run on PRs, and workers stay at the core count. An earlier revision dropped firefox + webkit on PRs while raising PW_WORKERS to 6. ubuntu-latest is a 4-core runner for public repos, and firefox is the engine that shows oversubscription first — locally at high parallelism it produced three page.goto timeouts plus a cross-browser.spec.ts flake, all 11/11 at --workers=1. Making main the only home of firefox coverage and running it oversubscribed would mean engine regressions surface post-merge, in the runs most likely to be waved off as flake. So PW_BROWSERS is the full set on every event, PW_WORKERS is 4, and CROSS_BROWSER=chromium survives only as a local escape hatch CI never sets. The cache key drops its PW_BROWSER_TAG component, which existed only to keep a chromium-only PR cache from being restored by an all-engines main run.
  • cancel-in-progress is now PR-only. Cancellation is keyed on the branch, not the commit, so on main two quick merges would cancel the first one's run and leave a merged commit with no completed sweep.
  • A test-all aggregation job keeps branch protection stable. The matrix reports as brand (oss)/brand (enterprise), so requiring those directly would mean re-pointing branch protection whenever the matrix changes shape. The matrix job is renamed brand, and a dependent job (needs: [brand], if: always(), asserting needs.brand.result == 'success') re-exposes the single test-all context the rule already requires — cancelled and skipped fail the assertion too. No branch-protection edit is needed.
  • No production page: this is test-infra only, outside the module consumers pin, so no pin bump is involved. Verified locally with hugo160: the full suite passes on both fixtures with all three engines, CROSS_BROWSER=chromium drops firefox + webkit, and the workflow resolves to exactly two jobs. (Moved here from v0.1.23 — the code landed after that tag was cut.)

Fixture — give the link-hextra reference/api markers real link targets (fixture/content/en/test/{main,v1,v2}/reference/)

  • Why. The v0.1.20 routing markers on the Everything page pointed at /test/v2/reference/api/…#TypeA paths the fixture never published, so every fixture build shipped seven broken links, reported against the docs hub as solo-io/docs#3349. tests/link-hextra-apiref.spec.ts asserts the emitted href strings, so the markers were right — nothing had created the pages.
  • What changed. Each version gains a reference/api/ subtree with the three routed targets (single-page index, the kgateway enterprise subpage, the api agentgateway subpage). They exist in all three versions, not just v2, because the Rebased pages run the version="v2" links through the two-pass remap onto their own version — which is why the report listed v1 and main paths too. Anchors are explicit {#TypeA} heading attributes, not Goldmark slugs: generated API references emit CamelCase type IDs and the inbound links use that case, so ## TypeA alone would publish id="typea" and lychee's include_fragments pass would flag it. Each page carries build: {list: never, render: always} so the subtree renders as link targets without entering the sidebar or the auto-card counts that auto-cards.spec.ts and sidebar-rail.spec.ts pin.
  • No production page: the fixture is mounted only for the test product, which is excluded from firebase-hosting-merge.yml, so no pin bump is involved. Verified with hugo160 on both brands: all nine pages build with id="TypeA" intact, per-version auto-card counts unchanged, no warnMissingDescription warnings, static + content projects pass (1469 passed). Re-ran lychee 0.24.2 with the CI action's exact flags: all seven errors gone with zero fragment warnings, and a deliberately bogus #TypeZZZ probe still fails, so the anchors are genuinely checked.

kristin-kronstain-brown and others added 20 commits July 29, 2026 13:02
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
A tab whose directory holds only its _index (no child pages) rendered an
empty left nav — and an empty mobile drawer panel, leaving the tab
unreachable on mobile (drawer chips swap panels client-side rather than
navigating). render-sidebar-tree now falls back at depth 0 to a link to
the landing itself. Verified against the v3/changelog fixture + regression
test in docs-tabs.spec.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Section (Kubernetes/Standalone) and version chips are real links to a
different content tree, so tapping them reloads the page and would close
the drawer mid-selection. mobile-nav.js now flags the tap in sessionStorage
and re-opens the drawer on the next load, so a reader can pick section ->
version -> topic without the drawer closing between selections. Topic links
and tab chips don't set the flag, so tapping a topic still closes it.
Verified with a browser spec (reopen-on-load + one-shot flag clear).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Replaces the reload+reopen approach: tapping a section (Kubernetes/Standalone)
or version chip now fetches that tree's drawer nav and swaps it into the open
drawer in place — no page reload — so a reader can keep picking section ->
version -> topic without the drawer closing. The scroller and tab-swap wiring
are refactored behind bindDrawer(root) so they re-bind after each swap; any
fetch failure falls back to plain navigation. Adds a brief .drawer-loading dim
and a browser spec (in-place swap, no navigation, drawer stays open).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
@kristin-kronstain-brown kristin-kronstain-brown changed the title 0.1.24 0.1.25 Jul 31, 2026
Signed-off-by: Kristin Brown <kristin.brown@solo.io>

# Conflicts:
#	CHANGELOG.md
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
Signed-off-by: Kristin Brown <kristin.brown@solo.io>
@kristin-kronstain-brown
kristin-kronstain-brown merged commit 0a3ee98 into main Aug 4, 2026
3 checks passed
@kristin-kronstain-brown
kristin-kronstain-brown deleted the kkb-0.1.24 branch August 4, 2026 15:41
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.

2 participants