Findability - prototype - Hub pages#3223
Draft
florent-leborgne wants to merge 56 commits into
Draft
Conversation
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>
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: GPT-5.5 <noreply@openai.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…unbooks Group the Product hubs sidebar by category and surface upcoming products as non-clickable stubs, matching the gist's prototype island. Uses the existing nav-v2 grammar: - '- label: <name>' creates a non-clickable section header - '- title: <name>' creates a non-clickable leaf entry (used for stubs) Stack products: Elasticsearch, Kibana (linked) + Logstash, Beats (soon). Deployment runbooks: Cloud Hosted, Cloud Serverless, Self-managed (all soon).
Two related changes that go together: 1. Add a `dropdown: true` opt-in to V2 nav sections. When set, the secondary nav renders the section as a <details>/<summary> with a chevron, and the open panel lists the section's children grouped by `- label:` subsections. `- title:` items without a `page:` render as muted "soon" stubs. Affects: - SectionNavV2Item (parser) reads `dropdown:`. - SectionNavigationNode + NavigationSection thread the flag. - _SecondaryNav.cshtml renders the dropdown UI when set. - secondary-nav-dropdown.css covers the visual layer. 2. Restore commit 588260f ("Update top navigation order") that was silently reverted during an earlier rebase resolution. Section renamed Product hubs -> Products, moved to second position right after Guides. Release notes moved before Troubleshoot. Final order: Guides -> Products -> APIs -> Reference -> Release notes -> Troubleshoot -> Extension points. Wires Products as the first user of the new dropdown so reviewers can jump straight from the top bar to a specific product hub without going through the /products/ landing page. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The `- page: docs-content://products/index.md / title: Product hubs` crosslink pointed at a file that does not exist in docs-content, which caused /products/ to 404. Replace it with `- title: Product hubs` (no page key) so the placeholder system generates a "Coming soon" stub at that URL, per the mechanism documented in PR #2927. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This reverts commit 6d5be8b. The Products dropdown is the discovery surface, so /products/ doesn't need a placeholder landing page. Drops the index entry from the Products section's children entirely, and switches the dropdown summary in _SecondaryNav.cshtml from an <a> to a non-clickable <span> so clicking the title row toggles the dropdown instead of trying to navigate to a non-existent landing.
The secondary-nav-dropdown-group-label was rendering as uppercase with letter-spacing (UI-pattern look), which Florent didn't want. Plain title case at 12px / weight 700 / grey-80 reads cleaner and matches the rest of the menu typography.
# Conflicts: # config/navigation-v2.yml # docs/_docset.yml
{hero}, {link-card}, and {whats-new} emit YAML body URLs verbatim
into <a href> attributes — they don't go through Markdig's link
resolver. So root-relative URLs like \`/deploy-manage/...\` landed
on the page as-is and broke under the \`/docs/\` path prefix the
assembler builds with.
Add a HubUrl.Prefix helper that prepends the site path prefix to
root-relative URLs (leaves absolute http/https/mailto and anchors
alone, and won't double-prefix). Pass block.Build.UrlPathPrefix into
the three view models, and call Model.PrefixUrl(...) in the cshtml
where hrefs are emitted.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The body has hx-boost=\"true\" hx-swap=\"none\" so boosted clicks
need an explicit hx-select-oob to swap anything. Hub-directive
links don't carry those attributes — clicks pushed the URL but
swapped no content, so the page appeared to just scroll to the top.
Add hx-boost=\"false\" to every <a> in {hero}, {link-card}, and
{whats-new} so they fall back to native navigation. Same fix
already in place for the page-top product pills.
Hub directives ({hero}, {link-card}, {whats-new}) emit URLs verbatim
into <a href>. Authors naturally write .md file paths (matching how
body markdown works) but the assembler serves clean URLs without
.md. So /reference/elasticsearch-clients/index.md 404'd on the
assembled site.
HubUrl.Prefix now strips trailing .md and /index.md before
prepending the site path prefix. Anchors are preserved.
Also fixes 4 source URLs whose docs-content folder names differ
from the slug the assembler serves (e.g. /release-notes/elastic-
security/ -> /release-notes/security), and the wrong fleet-
integrations target.
All 193 internal hub-page links now resolve (76/76 elasticsearch,
117/117 kibana, validated against the local assembler serve).
The RegisterV2PageLookups machinery from d556dff was dropped when nav-v2-sections was merged into hub-pages. Without it, V2 page: entries referencing files in unseen child TOCs are shadowed by the V1 TableOfContentsNavigation registration, breaking positional layout for those pages. Restores the original logic and uses Remove + Add so V2 entries override V1 toc entries on collision. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
URL fields in hub directive YAML bodies and options never went through Markdig's link parser, so cross-link resolution, missing-file checks, and link-index emission were all skipped — broken hub links shipped as silent 404s. Adds HubLinkValidator, invoked from each hub block's FinalizeAndValidate for every URL field. It: - resolves declared cross-link schemes via CrossLinkResolver.TryResolve, rewrites the value with the resolved URL, and registers via Build.Collector.EmitCrossLink - emits errors for undeclared schemes (with cursor:/vscode: passthrough) - checks internal absolute paths against the docset source dir in isolated builds (skipped under assembler/codex where cross-docset paths are legal — assembler-aware validation is a follow-up) - honours configured redirects with a warning suggesting the new path Wired only into HeroBlock, LinkCardBlock, and WhatsNewBlock. Surfaces ~40 previously-silent broken cross-link references in docs-content's kibana/elasticsearch hub pages. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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-pagesbranch ofelastic/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: hubin frontmatter; the body is then composed from a small set of new MyST directives. Companion docs-contenthub-pagesbranch 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: hubMarkdownPageLayout.Hubenum value. Selects_Layout.cshtml'sRenderHub()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/){hero}:title:,:description:,:icon:,:version:,:versions:(dropdown),:quick-links:,:releases:,:search:. Inline product-icon SVGs forelasticsearch/kibana/observability/security, with single-letter fallback.{on-this-page}{card-group}and{whats-new}on the page that has bothidandtitle.{intro}{whats-new}:product:from a single source-of-truthconfig/whats-new.yml(any page can render any product's panel with one line); inline YAML body still works as override.{card-group}:title:,:intro:,:id:.{link-card}title,link,description,links[],aside, plus optionalicon/variantfor 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_tobadges 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 hashub:set inconfig/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).applies_to.stackentries, plusapplies_to.serverlessiff no deployment is specified.applies_to.deploymententries, plusapplies_to.serverlessiff 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
ApplicabilityBadgePlacementmodes (StackVersionsRow,DeploymentsRow,OtherProductsRow) drive the per-row collection logic.Tooltip copy: Stack and Serverless product descriptions in
ProductDescriptions.cswere updated. The Stack description uses{base}/{current}/{base-major}placeholders interpolated from theVersioningSystemat render time (e.g. "This documentation applies to Elastic Stack 9.0.0 to 9.4.0...") so it tracksversions.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).ConfigurationFileProvider(WhatsNewFileproperty) and exposed viaBuildContext-- the same pattern used byproducts.yml.products.<key>->{ title, id, badge, release-links[], items[] }.Page-title detection
MarkdownFile.csfalls 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: newProductstop-bar section in the second slot (right after Guides). The section uses a newdropdown: trueopt-in that renders it as a top-bar dropdown listing the section's children (grouped by- label:subsections, with- title:items rendering as muted "soon" stubs). No/products/landing page — the dropdown is the discovery surface.dropdown: trueon a section): adds aDropdownflag throughSectionNavV2Item→SectionNavigationNode→NavigationSection, andLayout/_SecondaryNav.cshtmlrenders the section as a<details>/<summary>with a chevron + menu when set. Styled byAssets/secondary-nav-dropdown.css. The summary is a non-clickable<span>so the whole row toggles the dropdown._Layout.cshtml's hub branch includes an empty<aside id="toc-nav" hidden>so htmx-boosted swaps from regular pages (which select#content-container,#toc-nav) don't bail when navigating into a hub. Hub pages have their own inline{on-this-page}chip, so the slot stays empty.config/products.yml:Product.Hubfield set to relative slugs (products/elasticsearch/v9,products/kibana/v9) so pills resolve against the site path prefix.hx-boost(the body-level htmx default) so click → full native navigation; otherwise htmx swallowed the click before navigation.Source location
products/{elasticsearch,kibana}/v9.md(on thehub-pagesbranch)./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
src/Elastic.Documentation.Site/Assets/markdown/hub.cssandmetadata-box.css, modeled on the visual prototype, using docs-builder design tokens. Imported fromstyles.css.display: contents.<details>/<summary>(no JS), with a 28px chevron puck for clear affordance.Documentation
docs/syntax/:hub-pages.md-- overview + skeleton + product-badge mappinghero.md,whats-new.md,intro.md,on-this-page.md,card-group.md,link-card.md_docset.ymlalphabetically.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 insidelinks[]andaside.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.{hero}directive emits:quick-links:and:releases:URLs verbatim. The hero CSV/inline values don't go through docs-builder's cross-link or.md-path resolver, so authors can't use<repo>://...or/path.mdthere — they have to write full elastic.co URLs. Worth fixing in the directive so authors can use the same conventions everywhere.No tests. No unit/snapshot tests for the new directives, view models, page-title fallback, metadata box, or top-bar dropdown. Should land before promoting to non-prototype.
Out of scope (per the original Findability plan, by design)
{changelog}bundles.🤖 Generated with Claude Code