Skip to content

Findability - prototype - Hub pages#3223

Draft
florent-leborgne wants to merge 43 commits intonav-v2-sectionsfrom
hub-pages
Draft

Findability - prototype - Hub pages#3223
florent-leborgne wants to merge 43 commits intonav-v2-sectionsfrom
hub-pages

Conversation

@florent-leborgne
Copy link
Copy Markdown
Member

@florent-leborgne florent-leborgne commented Apr 30, 2026

Prototype for the docs Findability initiative -- workstream 2C (Hub Pages). Stacked on top of #2927 (nav-v2) and #3133 (nav-v2-sections), so review there first.

Important

This PR pairs with the hub-pages branch of elastic/docs-content. The assembler config (config/assembler.yml, narrative.current: hub-pages) clones that branch as the narrative source, so the docs-builder side and the docs-content side build together. Either both land, or both stay paired during review.

Thanks to @theletterf for landing the V2 nav-island wiring upstream, which is what made it possible to render real hub pages through the assembler and remove the gist-preview workaround.

Design handoff: hub-pages-design-handoff gist -- UX choices, technical notes, and what's open for proper design to refine.

What it does

Adds first-class support for product hub pages -- product-scoped 360° landing pages -- to docs-builder. A regular markdown page becomes a hub page by setting layout: hub in frontmatter; the body is then composed from a small set of new MyST directives. Companion docs-content hub-pages branch adds the actual hub markdown for Elasticsearch and Kibana at /products/<product>/v9/.

Alongside the hub layout, this PR reworks the page-top metadata model so pills (navigation) and applies_to (page-level requirements) coexist cleanly without piling loose badges at the top of every page.

What landed

New frontmatter layout

layout: hub New MarkdownPageLayout.Hub enum value. Selects _Layout.cshtml's RenderHub() branch -- same chrome as default minus right-rail TOC and prev/next nav. The body owns the full content-column width so directives can render full-bleed sections.

New directives (under Elastic.Markdown.Myst.Directives.Hub/)

Directive Purpose
{hero} Full-bleed dark-navy hero band. Explicit options: :title:, :description:, :icon:, :version:, :versions: (dropdown), :quick-links:, :releases:, :search:. Inline product-icon SVGs for elasticsearch/kibana/observability/security, with single-letter fallback.
{on-this-page} Auto-generated inline TOC chip -- collects every {card-group} and {whats-new} on the page that has both id and title.
{intro} Small "getting started" callout panel with a teal accent bar. Body = inline markdown.
{whats-new} "What's new" panel. Centralized lookup via :product: from a single source-of-truth config/whats-new.yml (any page can render any product's panel with one line); inline YAML body still works as override.
{card-group} Section heading + card grid container. Options: :title:, :intro:, :id:.
{link-card} Rich card. YAML body with a fixed schema -- title, link, description, links[], aside, plus optional icon/variant for solution-style accent borders.

Page-top metadata: single "This page applies to" box

The page top is now a single labeled container (Page/MetadataBox.cshtml) rendered below the H1 on regular pages. Stacking pills + applies_to badges loose at the page top would be a noisy, unstructured strip; the box gives both systems an explicit place and frees room for future page-level metadata (e.g. licensing).

Title row: The bold "This page applies to" label, with product hub pills rendered next to it (one per products: frontmatter entry whose product has hub: set in config/products.yml). Pills carry a brand-color dot, the product name, and a arrow. They're nav affordances, not body links -- styled dark-grey + semi-bold + no underline (override of .markdown-content a).

Below the title row: applies_to-driven rows, separated by a thin divider. Native <details open> makes the rows collapsible (chevron at far right of the title row, expanded by default).

Row Content
Versions applies_to.stack entries, plus applies_to.serverless iff no deployment is specified.
Deployments applies_to.deployment entries, plus applies_to.serverless iff a deployment is specified (so Serverless lands in only one row).

Entries render as plain comma-separated text with a small ? icon after each value (CSS-only reskin of the existing <applies-to-popover> -- the rich tooltip behavior is preserved on hover/click). Items are sorted with Serverless first, then other available items, then unavailable items at the end (struck-through and dimmed).

Three new ApplicabilityBadgePlacement modes (StackVersionsRow, DeploymentsRow, OtherProductsRow) drive the per-row collection logic.

Tooltip copy: Stack and Serverless product descriptions in ProductDescriptions.cs were updated. The Stack description uses {base} / {current} / {base-major} placeholders interpolated from the VersioningSystem at render time (e.g. "This documentation applies to Elastic Stack 9.0.0 to 9.4.0...") so it tracks versions.yml. Serverless descriptions append a sentence noting that Serverless UI/capabilities can differ from versioned Elastic Stack.

Note

The current visual language (pill shape, grey-tinted box, divider, chevron position, "?" icon) is a working baseline so we can reason about layout. Final styling, spacing, and placement are for proper design to refine -- see the design handoff gist for the rationale and what's open for iteration.

Centralized "What's new" feed

  • config/whats-new.yml (embedded as a resource so the binary always carries it).
  • Loaded through ConfigurationFileProvider (WhatsNewFile property) and exposed via BuildContext -- the same pattern used by products.yml.
  • Schema: products.<key> -> { title, id, badge, release-links[], items[] }.

Page-title detection

  • MarkdownFile.cs falls back to descendant H1s if no top-level H1 is found, then to {hero}'s :title: option. Hub pages can therefore be purely directive-driven (no body H1) and still get correct page titles.

Navigation

  • config/navigation-v2.yml: new Product hubs top-bar section with internal page: references to the docs-content hub markdown (docs-content://products/{kibana,elasticsearch}/v9.md). Wires through the assembler now that the V2-nav fix landed upstream (20a3966d feat(hub-pages): wire hub pages through assembler preview).
  • config/products.yml: Product.Hub field set to relative slugs (products/elasticsearch/v9, products/kibana/v9) so pills resolve against the site path prefix.

Source location

  • Hub markdown lives in docs-content at products/{elasticsearch,kibana}/v9.md (on the hub-pages branch).
  • URL convention: /products/<product>/<major>/ -- e.g. v9, v8. v9+ is cumulative for v9 minors and Serverless, so a single hub covers the active surface; older majors are stubbed in the version dropdown until last-release hubs (8.19, 7.17) get content.

Styling

  • New src/Elastic.Documentation.Site/Assets/markdown/hub.css and metadata-box.css, modeled on the visual prototype, using docs-builder design tokens. Imported from styles.css.
  • Hero icon-aligned-with-H1 layout via CSS Grid + display: contents.
  • Version chip dropdown via native <details>/<summary> (no JS), with a 28px chevron puck for clear affordance.
  • Cards and "What's new" rows use grid layouts so columns line up across rows.

Documentation

  • 7 new pages under docs/syntax/:
    • hub-pages.md -- overview + skeleton + product-badge mapping
    • hero.md, whats-new.md, intro.md, on-this-page.md, card-group.md, link-card.md
  • All wired into _docset.yml alphabetically.

How to preview

Preview builds are published automatically for this PR. Open:

The hub pages render through the assembler preview at their target URL shape (/products/<product>/<major>/), so no local isolated or assembler build is required for review.

Known limitations

  • {link-card} URLs bypass crosslink validation. Because the card body is YAML, the URLs inside links[] and aside.links[] aren't seen by the markdown link-validator. They'll render and click, but typos won't fail the build. Worth re-evaluating before this becomes a content authoring path beyond the prototype.

  • No tests. No unit/snapshot tests for the new directives, view models, or page-title fallback. Should land before promoting to non-prototype.

Out of scope (per the original Findability plan, by design)

  • Dynamic v9 hub generation from metadata.
  • Versioned hubs other than the v9 prototype.
  • Hub-internal "What's new" auto-population from {changelog} bundles.
  • Final visual design of the page-top metadata model (pills + Availability box) -- structure landed; styling refinement is for proper design.

🤖 Generated with Claude Code

florent-leborgne and others added 18 commits April 30, 2026 18:01
Maps each product to an optional hub page URL slug, used by the upcoming
product badge renderer to link page-level product metadata to a 360°
landing page. Elasticsearch and Kibana wired to /hubs/{product}/9.0 for
the prototype; other products leave the field null and render no badge.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a new MarkdownPageLayout.Hub value selected by frontmatter
'layout: hub'. The hub layout shares the section sidebar with regular
pages but drops the right-hand TOC and prev/next nav, and renders the
markdown body in a full-width <article class="hub-content"> wrapper so
hero and card-group directives can manage their own widths.

Two placeholder hub pages are wired in at /hubs/elasticsearch/9.0/ and
/hubs/kibana/9.0/, listed as hidden entries in docs/_docset.yml. They
are reached only via the upcoming Product hubs nav section and the
product-badge links; their bodies will be filled by hero/card-group
directives in subsequent commits.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Generic, reusable directive that renders a full-bleed hero region with
optional icon, version badge, search box, and quick links. Body content
(typically an H1 plus a short description paragraph) renders inside the
hero, so the page's H1 stays the canonical title.

Title detection in MarkdownFile falls back to descendant H1s when no
top-level H1 is present, so a {hero}-wrapped H1 is still picked up as
the page title without spurious 'no title' warnings.

The wired-up Elasticsearch placeholder hub now drives the hero. Cards
and card-group come in subsequent commits.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
{card-group} is a container with optional :title:, :intro:, 🆔, and
:variant: options that wraps a grid of {link-card} children. {link-card}
is a leaf with a required title argument and 🔗 option, plus an
optional :badge: pill, and renders the directive body as the card
description.

Both are generic enough to be used outside hub pages -- any landing or
section page can render a titled card grid with these.

The Elasticsearch placeholder hub is wired up with three card groups
(What's new in news variant, Install and deploy, Index and ingest data)
to exercise the rendering end to end.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New section in navigation-v2.yml that surfaces the prototype hub pages
in the V2 secondary nav. The Elasticsearch and Kibana hubs are wired up
as page references; Observability, Security, and the three deployment
runbooks are placeholder title leaves until their hub markdown lands.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a ProductBadges partial that renders a clickable pill for each
frontmatter product whose Product.Hub field is set, linking to that
product's hub page. Skipped on layouts that own their own chrome
(hub, landing, archive, full-search). For products without a hub
configured, no badge is rendered, so the feature lights up
incrementally as more products get hub URLs in products.yml.

The mapping is centralized: products.yml is the single source of
truth for which products have hubs and where they live.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds hub.css with Tailwind component layer rules for hero, card-group,
link-card, and product-badges. The hero is full-bleed dark navy with
icon and version chips, content rail constrained to the standard text
width. Cards are a responsive 1/2/3-column grid; the news variant
collapses to a tighter 1/2-column list. Product badges are subtle
grey pills that hover blue.

The Kibana hub markdown is filled in with seven sections (What's new,
Install and administer, Explore visualize and analyze, Track and
respond, AI and automation, Management and developer tools) mirroring
the gist prototype.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Index.cshtml skips its auto-rendered H1, product-badges, and applies-to
  block when the page declares 'layout: hub' so the hero owns the page
  header and there is no duplicate H1.
- hub.css drops the article-level max-width and lets hero/card-group
  manage their own inner rails. Hero goes edge-to-edge of the content
  area; card grids open up to a 5xl rail so 3 columns render.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Aligns the hub-page directives with the HTML gist prototypes' DOM and
visual structure. The card / what's new / hero shapes were too thin to
reproduce the gists; this commit replaces them with richer directives:

- {hero}: adds inline product-icon SVGs (kibana/elasticsearch/observability/
  security via ProductIcons lookup; first-letter fallback otherwise),
  a version pill with status dot, quick-action pill bar, and a release
  status line rendered as inline markdown.
- {link-card}: now consumes a YAML body with title/link/description plus a
  primary link list and an optional aside (label + inline link list with
  middle-dot separators). Adds optional :icon: / :variant: for solution
  cards (es / obs / sec accent borders).
- {whats-new}: new directive for the gist's "New" panel -- header with pink
  badge, section title, optional release-notes link list on the right,
  and items rendered as link rows with title / description / right-side
  meta pill.
- {intro}: new directive for the teal-bar tip panel below the hero.
- {on-this-page}: new directive that auto-collects every {card-group} and
  {whats-new} on the page (by id+title) and renders a single inline-link
  TOC chip.

Both YAML-bodied directives use the existing YamlSerialization static
context (AOT-safe) with new types registered.

The two hub markdown files (Elasticsearch and Kibana) are rewritten to
exercise the full directive set, mirroring the gists' content and shape.
hub.css is rewritten to model the gists' rules with the project's design
tokens.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the sections that were dropped during the directive rewrite so the
hub markdown matches the gist HTML one-to-one:

- Elasticsearch: Index and ingest data, Aggregations, Data modeling,
  Manage data, AI and vector search, Security, Clients and integrations,
  Reference (8 sections previously missing).
- Kibana: Track and respond, AI and automation, Management and developer
  tools, Reference (4 sections previously missing).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the inert navigation-search web component placeholder with a
styled fake search box that matches the gist prototypes (white pill
with magnifying-glass icon, contextual placeholder, disabled input).
The input is disabled until search is wired up, but visually it's now
indistinguishable from the gist.

Placeholder text uses the hero :icon: key (e.g. 'Search Kibana docs...').

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switches .hub-hero-top from flex to a 2-col grid and uses
display:contents on .hub-hero-title so its children become direct grid
items. The icon vertically centers with the H1 (row 1), and the
description spans both columns in row 2 -- matching the gist layout
where the description starts at the left edge below the icon row, not
hanging-indented next to the H1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a :versions: option to {hero} taking comma-separated 'Label[=URL]'
entries. When non-empty, the version chip renders as a <details>
dropdown -- click to reveal a menu listing the current version (with a
checkmark) plus each entry. Entries with a URL are clickable links;
entries without a URL render as greyed-out 'soon' rows.

ES 9.4 / Kibana 9.4 hubs are wired with v8 and v7 as disabled entries
so reviewers can see the dropdown shape without yet-built hub pages.

Also bumps Elasticsearch examples to 9.4 and adds a Serverless
release-notes link in the What's new header (matching the Kibana hub).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The {whats-new} directive now accepts a :product: option that looks the
content up in a single source-of-truth file. Authors edit one YAML in
config/, and any page can render that product's panel with a one-line
directive:

    :::{whats-new}
    :product: kibana
    :::

Inline YAML body still works as a fallback / override for one-offs.

The new file is loaded through ConfigurationFileProvider (with embedded-
resource fallback so the binary always has it) and made available to
the directive via BuildContext. Configuration is cached per-build so
multiple {whats-new} blocks share one parse pass.

Both hub markdowns are slimmed down to the one-line shape; their
previous inline data is now in config/whats-new.yml.

Also:
- Switches the What's new item layout to grid with a fixed-width meta
  column (130px), so version/date pills line up across rows and
  descriptions don't run into them.
- Makes the hero version chip read more clearly as a dropdown: caret is
  bigger and lives in a translucent circle, the chip itself has a
  brighter idle / hover / open state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Moves docs/hubs/{es,kibana}/9.0.md to docs/testing/hubs/{es,kibana}/9.0.md
  so they appear in the docs-builder docs sidebar under the Testing
  group, while still rendering with layout: hub.
- Adds matching folder children in _docset.yml.
- Updates products.yml hub slugs to the new paths so the product badges
  link to /testing/hubs/{product}/9.0/.

Also:
- Drops the description truncation in What's new items so long
  descriptions wrap onto a second line cleanly under the title (meta
  pill stays right-aligned with align-items: baseline).
- Bigger hero version dropdown caret: 28x28 puck with a 16px SVG
  chevron (replacing the small ▾ character) so it's clearly a
  click target.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Establishes the production-target URL convention. The 'hub' page type
keeps its name internally (frontmatter layout: hub, products.yml
'hub:' field), but the published path segment becomes /products/.

- Files moved: docs/testing/hubs/{...} -> docs/testing/products/{...}
- _docset.yml: folder hubs -> products
- products.yml hub slugs updated
- nav-v2.yml Product hubs section: url /hubs/ -> /products/, page
  references updated to docs-builder://testing/products/{...}

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds one syntax/ doc per new directive plus a hub-pages.md overview:

- syntax/hub-pages.md  -- enables the layout, lists the directive set,
  shows a full skeleton, documents the product-badge mapping.
- syntax/hero.md       -- :icon:, :version:, :versions:, :quick-links:,
  :releases:, :search:; version dropdown shape.
- syntax/whats-new.md  -- centralized lookup via :product: + the inline
  YAML override schema.
- syntax/intro.md      -- markdown body, when to use vs. admonitions.
- syntax/on-this-page.md -- auto-collection rules and item ordering.
- syntax/card-group.md -- :title:, :intro:, 🆔, fence-depth tip for
  nested cards, grid layout note.
- syntax/link-card.md  -- full YAML schema, variants, aside, errors.

All seven pages registered alphabetically under docs/syntax/ in
_docset.yml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The hero directive's body convention (first H1 = title, paragraphs =
description) was not intuitive. This commit replaces it with explicit
:title: (required) and :description: (inline markdown) options.

- HeroBlock parses :title: and :description: from options; the body is
  now ignored.
- HeroView renders <h1>@title</h1> and <p>@DescriptionHtml</p> directly,
  no nested heading-wrapper. CSS targets .hub-hero-title h1 instead of
  .heading-wrapper.
- DescriptionHtml is rendered as inline markdown so links/bold/italic
  inside the description still work.
- MarkdownFile.cs falls back to the first {hero} block's :title: when no
  document H1 is present, preserving page-title detection.

Both hub markdowns are updated. The hero.md and hub-pages.md syntax
docs show the new shape.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The assembler can't yet route through the V2 nav for our hub pages
(known limitation -- AssembleSources still wires file output via the V1
toc chain), so the previous in-repo page: references caused
'Could not find ... in navigation' errors during assembler builds.

Replace the section's internal /products/ URL + nested page references
with a single external URL pointing at the Kibana gist preview. The
secondary nav already renders any section whose URL starts with http
as an external link with the ↗ icon (see _SecondaryNav.cshtml).

Effect:
- Assembler build: 0 errors. Top-bar now shows 'Product hubs ↗'.
- Isolated build: unchanged. The real hub pages still render at
  /testing/products/{elasticsearch,kibana}/9.0/ in docs-builder's own
  meta-docs, which is how reviewers preview them today.

Once the V2 nav-wiring lands upstream, this will revert to internal
section + page references.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Old badges were small underlined pills above the H1 with default <li>
bullets leaking through and ambiguous semantics ('Applies to' clashed
with the existing applies_to lifecycle/version system).

New design:
- Sit inline with the page H1 (.page-title-row flex container, align
  baseline + translateY(-0.45em) to land at the H1 x-height).
- Per pill: brand-color accent dot, product name, right-arrow chevron
  that slides on hover.
- Hover state: border picks up the brand color, faint background tint,
  arrow color and position shift -- reads clearly as 'click to navigate
  there'.
- No more SVG product icons in the chip (Elasticsearch tricolor read
  like a tiny flag at 14px). The accent dot carries the identity at
  any size.

Per-product accents reuse the solution-card brand colors:
elasticsearch=#FEC514, kibana=#F04E98, observability=#0077CC,
security=#00BFB3.

The hub-pages syntax doc now declares products: [elasticsearch, kibana]
in its frontmatter so the new rendering is visible in the docs-builder
docs build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
florent-leborgne and others added 5 commits May 1, 2026 12:44
Until hub pages render through the assembler, product badges now link
to the rendered gist previews (htmlpreview.github.io). The gists are
the visual reference for the prototype anyway, so badges land on a
representative page even when the assembler can't yet wire in our own
hub markdown.

ProductBadges.cshtml detects absolute URLs (http(s)://) and:
- Opens them in a new tab (target=_blank rel=noopener)
- Renders an external-link arrow (↗) instead of the chevron
- Otherwise keeps the existing internal-pill rendering

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Aligns with the v9/v8 URL convention (v9+ is cumulative for v9 minors and
Serverless; older majors are only worth a single 8.19 / 7.17 entry).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A single white card with a thin grey outline sits below the H1 and renders
up to four labeled rows, hidden when empty:

- Stack products: hub pills for products with `hub:` set in products.yml.
- Stack versions: applies_to.stack badges, plus applies_to.serverless when
  no deployment is specified.
- Deployments: applies_to.deployment badges, plus applies_to.serverless
  when a deployment is specified (so serverless lands in only one row).
- Other products: applies_to.product and per-component applicabilities
  (EDOT, APM agents, ECCTL, etc.).

Three new ApplicabilityBadgePlacement values drive the row-specific
collection logic; the existing renderer handles the rest. The hub layout
opts out via the Layout frontmatter check, same as before.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ox below

The previous metadata box mixed product pills (navigation) with applies_to
badges (metadata) in one container, which conflated two distinct concerns.
Splitting them gives each a clear role:

- ProductPills.cshtml renders the brand-dotted hub pills above the H1,
  styled as nav affordances (dark-grey label, → arrow, no link underline).
- MetadataBox.cshtml renders applies_to data below the H1 in a collapsible
  "Requirements" box (Versions / Deployments / Subscription rows). The
  Subscription row is a placeholder ("Enterprise") until that metadata
  exists. Multiple values within a row are separated by an italic "or".
- A thin divider sits between the H1 and the box to mark the page-top
  chrome boundary.

Final styling and placement are a working baseline; refinement is for the
design pass. The structural split is the part that matters and unblocks
adding more page-level metadata systems (e.g. licensing) without piling
loose badges at the page top.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…ntry

When the configured branch (e.g. a prototype/dev branch) has never been
published, it won't have a link index entry. Fall back to checking out
the branch directly by name rather than blocking the entire build with
an error. Cross-link resolution will use whatever entries are available.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…fetching

For prototype/dev branches (e.g. hub-pages) that have never been deployed
and therefore have no link index entry:

- RepositoryPublishValidationService: emit warnings instead of errors so
  validate-assembler doesn't block the build
- CrossLinkFetcher.FetchCrossLinks: fall back to main/master cross-link
  data rather than throwing when the requested branch isn't in the index

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
V2 page links need to register their source files after the V2 tree is built so assembler layouts can position pages that are only surfaced through navigation-v2.yml.

Co-Authored-By: GPT-5.5 <noreply@openai.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Assembler builds can process pages from nested TOCs that are not explicitly declared in global navigation, so register those files for positional lookup and let V2 page entries replace them when present.

Co-Authored-By: GPT-5.5 <noreply@openai.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@theletterf
Copy link
Copy Markdown
Member

I took a pass at fixing the previews rather than keeping this as a local-only prototype.

Summary of the approach:

  • The hub pages now render through the assembler preview at the target URL shape, for example /products/elasticsearch/v9/ and /products/kibana/v9/.
  • The underlying fix was to wire V2 page: entries back into the global navigation lookup after the V2 tree is built. Without that, HtmlWriter.RenderLayout() could process the Markdown file but could not find its positional navigation item.
  • The integration failure exposed a second case: assembler builds can process files from nested TOCs that are not explicitly declared in navigation.yml. SiteNavigation now registers files from those unseen child TOCs for lookup, and SiteNavigationV2 can replace those entries when a V2 page: item is the intended owner.
  • I added regression coverage for both cases: V2 page: entries resolving files from nested TOCs, and V1/global navigation resolving files from unseen child TOCs.

What may be temporary:

  • The docs-content branch pin in config/assembler.yml is preview scaffolding so this PR can build against the hub-page content before that content is on the default branch.
  • The current navigation.yml/navigation-v2.yml wiring for the product hubs is likely transitional while we prove the URL shape and V2 nav behavior.
  • The prototype content/location may still move as planned; the durable target is docs-content-owned product hub pages under /products/<product>/<major>/.

What I do not think is temporary:

  • Registering V2 page: entries in NavigationDocumentationFileLookup looks like a real assembler/V2 integration fix.
  • Registering files from unseen child TOCs also looks like a real assembler behavior fix, because the builder can process those files today and layout rendering needs a navigation owner for them.

florent-leborgne and others added 2 commits May 4, 2026 19:28
Successive refinements after the initial restructure:

- Move product pills from above the H1 into the box's title row, alongside
  the "This page applies to" label. Drops ProductPills.cshtml partial and
  the page-meta divider; the box is now the single page-top metadata zone.
- Drop the Subscription placeholder row and its CSS.
- Render applies_to entries as plain text + a small "?" icon (CSS-only
  reskin of the existing applies-to-popover), comma-separated. The "?"
  still triggers the rich tooltip on hover/click. No more "or" separator.
- Sort items so Serverless lands first, then other available items, with
  unavailable items at the end (struck-through + dimmed).
- Title typography lifts the row above the rest of the box without
  shouting (15px / 700 / ink-dark vs 13px / 600 / grey-80 row labels).
- Stack tooltip description now substitutes {base}/{current}/{base-major}
  from the VersioningSystem so the tooltip surfaces the actual range
  ("Elastic Stack 9.0.0 to 9.4.0...") instead of a static blurb.
- All four Serverless tooltip descriptions append a sentence noting that
  Serverless UI/capabilities can differ from versioned Elastic Stack.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The two hub gist HTML files were a stand-in while the V2 nav wiring was
unresolved. That's fixed upstream and the docs-content `hub-pages` branch
now serves the real hub markdown, so product pills should link to the
canonical URLs (`/products/elasticsearch/v9`, `/products/kibana/v9`)
instead of the gist previews.

The two visual-reference gists are no longer used by any code path. The
design handoff gist is still referenced in the PR and remains the
human-facing UX/technical write-up.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
florent-leborgne added a commit to elastic/docs-content that referenced this pull request May 4, 2026
Flat list of Elastic Stack products and Deployment runbooks, matching
the sidebar of the prototype gists. Active hubs (Elasticsearch, Kibana)
link to their v9 page; the rest are stubbed as "coming soon" so the
landing reads as the canonical entry into the hubs section.

Pairs with elastic/docs-builder#3223 which now references this page in
config/navigation-v2.yml so the Product hubs top-bar URL resolves.
References docs-content://products/index.md so /products/ resolves to
the landing page instead of 404. The landing lists Elasticsearch and
Kibana hubs alongside stubs for upcoming products and deployment
runbooks. Companion docs-content commit lands the index.md itself on
the hub-pages branch.
Stack and Serverless productDescription text changed (Stack interpolates
{base}/{current}/{base-major} from the VersioningSystem; Serverless
appends a sentence about UI/capabilities differing from versioned
Stack), so the popover-data attribute in 40 snapshot fixtures across
ApplicableToComponent.fs, AppliesToRole.fs, and Admonitions.fs needed
to be updated to match. The test fixture's stack VersioningSystem has
base==current==8.0.0, so the substituted string reads "Elastic Stack
8.0.0 to 8.0.0... prior to v8".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The product pill <a> lives inside <details>/<summary>, so a native
click on the pill toggles the box and the link doesn't navigate.
`onclick="event.stopPropagation()"` lets the link navigate while
the toggle is suppressed. Toggle still works on every other part of
the summary (label, chevron, empty space).
Three small fixes triggered by clicking through to hub pages:

- MetadataBox.cshtml: product pill <a> now carries hx-boost="false"
  so the body-level hx-boost="true" doesn't intercept the click. The
  onclick="event.stopPropagation()" still suppresses the <details>
  toggle so the click navigates rather than collapsing the box.

- _Layout.cshtml: hub layout adds an empty <aside id="toc-nav"
  hidden> so htmx's hx-select-oob="#content-container,#toc-nav"
  swap doesn't fail on missing target when boosting from a regular
  page. Hub pages have their own inline {on-this-page} chip, so the
  TOC slot stays empty.

- hub.css: drop the grey + dotted page background. It made the page
  read inconsistently between full-load and htmx-boosted swap (the
  swap leaves the regular layout's white body intact). Hero stays
  dark navy; section cards keep their own visual separation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants