Prototype nav-v2: new IA with label sections, accordion sidebar#2927
Prototype nav-v2: new IA with label sections, accordion sidebar#2927theletterf wants to merge 159 commits into
Conversation
Adds a new `navigation-v2.yml`-driven sidebar behind the `nav-v2`
feature flag (enabled by default in dev/preview environments).
- New YAML format: label sections (non-clickable headings), toc entries
that resolve to existing navigation nodes at their original URL paths,
page crosslinks, and title-only placeholder (disabled) links
- `SiteNavigationV2` extends `SiteNavigation`, passes the original
nav file to the base constructor so content URLs are unchanged; builds
a separate `V2NavigationItems` tree for sidebar rendering
- `GlobalNavigationHtmlWriter` detects `SiteNavigationV2` and returns
the same full V2 nav HTML (cached once) for every page
- `_TocTreeNavV2.cshtml` renders labels as `<span>`, placeholders as
`aria-disabled` anchors, folders/leaves same as V1
- `pages-nav-v2.ts` adds accordion collapse (open one section → others
collapse) and current-page marking with no auto-expand
- Feature flag key normalisation: assembler.yml uses `NAV_V2` (underscore)
but lookup uses `nav-v2` (hyphen); fixed by calling `featureFlags.Set`
which normalises via `ToLowerInvariant().Replace('_', '-')`
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ShortId.Create("label") always produced the same SHA256 hash, so all
8 label checkboxes shared id="v2-label-1ACA80E8". Every <label for="">
targeted the first checkbox, making only "Get Started" expandable.
Fix: include the label text in the hash — ShortId.Create("label", label).
Also updates nav-v2-status.md to reflect verified accordion behaviour.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d labels)
Translates the team's proposed information architecture into the V2 nav:
Top-level labels:
• Elasticsearch fundamentals (get-started + placeholder concepts)
• Install, deploy, and administer (deploy-manage + cloud-account)
• The Elasticsearch Platform (container for nested labels)
• Solutions and project types (solutions)
• Reference (elasticsearch + kibana)
• Troubleshooting (troubleshoot)
"The Elasticsearch Platform" has three nested labels:
• Ingest and manage data → toc: manage-data
• Search, visualize, and analyze → toc: explore-analyze
• AI and machine learning → title: placeholders (content lives in
explore-analyze today; dedicated toc roots needed to wire up)
Nested labels work with no code changes — the YAML parser, SiteNavigationV2
builder, and _TocTreeNavV2 partial already recurse through children at any
depth. The Razor partial applies level-aware styling (font-semibold at
level 0, lighter weight at depth 1+).
Also documents the proposed IA mapping and content split analysis
in nav-v2-status.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Labels at any depth are now unconditionally expanded — no checkbox, no chevron, children always visible. This applies to both top-level labels (Elasticsearch fundamentals, The Elasticsearch Platform, etc.) and nested labels (Ingest and manage data, Search/visualize, AI/ML). _TocTreeNavV2.cshtml: for LabelNavigationNode, removed the peer div / checkbox / chevron pattern; render a plain <span> heading followed by an always-visible <ul> of children. Removed data-v2-accordion from label <li> elements since labels no longer participate in accordion. TOC folder nodes (INodeNavigationItem) retain their existing checkbox-driven expand/collapse toggle unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Verified behaviours: labels always expanded (no toggle), nested labels same, placeholders render as disabled, TOC folders still toggle, accordion scoped to TOC siblings - Mark nested label support as done - Correct build/serve commands to dotnet run invocations - Note LabelNavigationNode.ExpandedByDefault is now unused Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Level-1 labels (top-level sections): font-semibold text-sm text-ink — bold, 14px, full ink colour. Level-2+ labels (sub-section dividers): text-[10px] font-semibold uppercase tracking-widest text-ink/50 — all-caps, 10px, wide letter-spacing, 50% opacity. This is the standard sidebar sub-group treatment (VS Code, Linear, Notion style) and makes the hierarchy immediately legible at a glance. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Level-1 label text: text-xs uppercase tracking-widest font-semibold text-ink — same small-caps treatment as level-2 but full ink colour, making them clearly structural dividers not clickable links - Level-1 label <li>: border-t border-grey-20 pt-4 mt-4 to draw a thin horizontal rule between each top-level section; first: variant removes the border/padding from the first item Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Was text-[10px] text-ink/50 — too small and too dim to read comfortably. Now text-xs (12px) text-ink/65 — same small-caps uppercase treatment, clearly subordinate to level-1 but readable at a glance. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🔍 Preview links for changed docs |
Introduces `GroupNavV2Item` — a YAML `group:` item that renders as an expandable folder with a disabled (cursor-not-allowed) link and a chevron toggle. Unlike `label:` (always-expanded section heading), `group:` behaves like a regular TOC folder but with no real URL. Changes: - `NavigationV2File.cs`: add `GroupNavV2Item` record + `group:` YAML parsing - `PlaceholderNavigationNode.cs`: new nav node implementing INodeNavigationItem - `SiteNavigationV2.cs`: `CreateGroup` builder (mirrors `CreateLabel`) - `_TocTreeNavV2.cshtml`: render PlaceholderNavigationNode as disabled folder - `navigation-v2.yml`: replace `toc: manage-data` in "Ingest and manage data" with the full "Ingest or migrate: bring your data into Elasticsearch" tree (placeholder titles only; no toc/page refs yet) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Translates the complete card-sort JSON into navigation-v2.yml using group:/title: placeholders throughout. All 6 top-level labels are populated with the full proposed IA structure — no toc/page refs yet. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Switch NavV2Deserializer from DeserializerBuilder to StaticDeserializerBuilder — our NavV2FileYamlConverter parses manually via parser events so the static context is sufficient; fixes IL3050/IL2055 AOT errors in the native build - Remove unused `$` import from pages-nav-v2.ts; fixes ESLint @typescript-eslint/no-unused-vars error in the npm check Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Keep the preview header guard from breaking the frontend Prettier check on the PR merge result. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
After merging main, IDE0028 is enforced across the merged branch, so use the repo's collection expression syntax where the analyzer now requires it. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve the content date enrichment JsonArray conflict by keeping the explicit JsonNode cast from nav-v2. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Port the core navigation wording cleanup from PR #3326 so the base nav branch carries the latest IA label refinements. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Port the core navigation wording cleanup from PR #3326 while preserving the nav-v2-sections structure. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the nav-v2-sections navigation structure after applying the shared PR #3326 label refinements. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the HTMX swap target class stable so section navigation does not briefly render with the landing-page content layout before settling. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the HTMX swap target class stable so section navigation does not briefly render with the landing-page content layout before settling. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the single aggregate docs-content://reference TOC with explicit per-subdirectory entries so each reference area loads independently without duplicating top-level sections in the sidebar. Logstash plugin entries remain as nav islands with back-arrow. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the single aggregate docs-content://reference TOC with explicit per-subdirectory entries so each reference area loads independently without duplicating top-level sections in the sidebar. Logstash plugin entries added as nav islands with back-arrow. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Back arrow: instead of always pointing at the parent *section* URL (which is "/" for the Guides section), walk up the IslandNavigationNode parent chain to the nearest ancestor that has a real URL. Store it as BackUrl on NavigationIsland and use it in GlobalNavigationHtmlWriter. Parent nav: render island entries as plain links with no expandable subtree. The island's own sidebar (loaded via HTMX full-swap) already shows the full tree; expanding it inline was duplicate and confusing. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Accept main's DOM reorder (nav after </main>, md:order-2 on main, order-2 lg:order-1 on article) while keeping the stable min-w-0 class on #content-container and wrapping the grid CSS in an inner <div> to prevent the HTMX-swap layout jump. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Accept main's DOM reorder (nav after </main>, md:order-2 on main, order-2 lg:order-1 on article) while keeping the stable min-w-0 class on #content-container and wrapping the grid CSS in an inner <div> to prevent the HTMX-swap layout jump. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Take section: Release notes (with url: /release-notes/) from nav-v2-sections over the plain label: entry in nav-v2, preserving the sections feature this PR introduces. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve PR #2927 mergeability by updating nav-v2 with the latest main changes so the branch merges cleanly without conflict. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Register section root URLs as authoritative owners and normalize site-prefixed lookups so section landing pages keep their own sidebar. Make island back links preserve the active site prefix, including nested reference islands such as Logstash plugins. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the query language reference TOC as the single sidebar entry so the narrative pages no longer duplicate the reference structure. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Only auto-open a section root sidebar when it has a single top-level folder, avoiding the fully expanded Reference nav while preserving single-TOC sections. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
* Keep nav-v2 focused on the active section Same-section navigation could leave stale folders expanded, which made the sidebar show multiple open branches. Recomputing expansion from the active page path keeps one relevant branch open and preserves accordion behavior when folders are opened manually. Co-Authored-By: OpenAI GPT-5.4 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Auto-scroll nav-v2 to the active branch Opening a lower section could still leave part of the active branch clipped below the sidebar viewport. Re-scrolling after the nav layout settles keeps the selected branch fully visible and locks in the behavior with a focused regression test. Co-Authored-By: OpenAI GPT-5.4 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Re-scroll nav-v2 after sidebar chrome resizes The Jump to page web component can alter the sidebar chrome after the active branch scroll is first calculated. Observing the sidebar chrome and scroll container makes the active branch scroll correction respond to those late layout changes. Co-Authored-By: OpenAI GPT-5.4 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com> * Format nav-v2 scroll observer Prettier wrapped the ResizeObserver map type so the npm formatting check passes in CI. Co-Authored-By: OpenAI GPT-5.4 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: OpenAI GPT-5.4 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Bring nav-v2 up to date with main so shared unit test fixes are included before continuing prototype work. Co-Authored-By: OpenAI GPT-5.4 <noreply@openai.com>
Inline callouts can contain Markdown links, but the parser rejected slash characters and skipped those callouts. Allow slashes in inline callout text and render inline callout Markdown without splitting the list item body so the existing formatting expectation passes. Co-Authored-By: OpenAI GPT-5.4 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Allow selected Nav V2 folders to stay open by default without losing manual collapse behavior, so high-priority guide sections remain visible while deeper folders stay collapsed. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Constrain the page grid and mobile nav chrome so wide header content does not force the docs viewport to scroll horizontally. Co-Authored-By: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Store the clicked sidebar occurrence so duplicate page links keep the user's chosen nav context, while direct loads use a stable canonical fallback. Co-Authored-By: OpenAI GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
|
Added a temporary workaround for duplicate Nav V2 page entries. Some pages intentionally appear in more than one sidebar location while the IA is still being validated. Instead of removing those duplicates now, the sidebar now assigns each rendered nav link a stable This keeps one page URL and avoids duplicate search results, while preventing multiple duplicate sidebar entries from being highlighted or expanded at the same time. We can remove or explicitly canonicalize duplicate nav entries later as a separate IA decision. |
Co-Authored-By: OpenAI GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Only treat same-page folder-row clicks as expand toggles when that exact row is already focused, so duplicate rows can still update the selected nav location. Co-Authored-By: OpenAI GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Prototypes a new information architecture sidebar gated behind the
nav-v2feature flag (auto-enabled indevandpreviewenvironments). Content is served at the same URL paths as V1 — only the sidebar layout changes.Demo: https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/2927/get-started
Contributes to: https://github.com/elastic/docs-content-internal/issues/1015
What's included
This branch now incorporates the work from PR #3133 (
nav-v2-sections, merged intonav-v2), which adds independent sidebar islands and a dynamic data-driven top bar on top of the base nav-v2 prototype.From this PR (nav-v2 base)
navigation-v2.ymlfile drives the sidebar, separate fromnavigation.yml.label:,toc:,page:,group:,title:.title:leaf andgroup:folder without apage:gets a generated stub at/{sitePrefix}/_placeholder/{hash}/.From PR #3133 (nav-v2-sections, merged)
section:item type: each section owns its own sidebar HTML — pages in one section never include another section's nav links in the DOM.island:item type: intra-section subtrees that get their own focused sidebar when entered, with a back arrow pointing to the nearest ancestor page. Island detection uses toc root identity, not URL matching.isolated: true) do not appear in the top bar.GlobalNavigationHtmlWriter— each section's sidebar is rendered and cached independently.url:fields open in a new tab with a ↗ indicator.Tab ordering
Guides | APIs ↗ | Reference | Troubleshoot | Release notes
Sections (top bar tabs)
Isolated sections (not in top bar)
Nav islands (intra-section, with back arrow)
Navigation YAML format (
config/navigation-v2.yml)The remaining item types (
label:,toc:,page:,group:,title:) behave as documented below.Placeholder stub pages
Every
title:leaf andgroup:folder that lacks apage:gets a generated stub page at/{sitePrefix}/_placeholder/{hash}/. The stub renders the full site chrome with an<h1>of the placeholder title and a "This content is coming soon." paragraph. All placeholder nav items are greyed but clickable.Filling the gaps
title: Foowithtoc: repo://pathwhen a whole TOC root covers the topic.title: Foowithpage: docs-content://path/to/file.mdwhen a specific existing page covers the topic.group: Foowithtoc:when the folder gains a real root, or keep it asgroup:with children if the folder itself has no canonical URL.Sidebar behaviour
group:nodes: expand/collapse toggle; accordion at top level; greyed link → stub page.toc:nodes: full live tree, same expand/collapse as V1.page:leaves: clickable link to the canonical page URL.title:leaves: greyed link → stub page.URL scheme — known limitation and future direction
toc:entries currently use the same URL paths as V1 (navigation.yml), because the file-writing pipeline derives output paths fromNavigationTocMappings, which is populated fromnavigation.ymlbeforeSiteNavigationV2is constructed. The intended final scheme ({scheme}/{host}/{path}) requires wiring the V2 nav file intoAssembleSources.AssembleAsync. That work is out of scope for this PR.🤖 Generated with Claude Code