Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/_docset.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
project: 'doc-builder'
max_toc_depth: 2
dev_docs: true
Expand Down Expand Up @@ -120,6 +120,8 @@
- file: file_inclusion.md
- file: footnotes.md
- file: frontmatter.md
- file: hero.md
- file: hub-pages.md
- file: icons.md
- file: images.md
- file: videos.md
Expand All @@ -141,6 +143,14 @@
- file: tabs.md
- file: titles.md

# Examples
- folder: examples
children:
- file: index.md
- folder: products
children:
- file: docs-builder.md

# Documentation builds
- folder: documentation
children:
Expand Down
11 changes: 11 additions & 0 deletions docs/examples/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Examples

Complete pages that show docs-builder syntax rendering in context. Each syntax page explains one directive in isolation. These pages show how directives combine into a finished page.

Use them to check what a page type looks like before you author one, and to verify rendering changes against a realistic page rather than a fixture.

## Hubs

Hub pages use `layout: hub` and are composed entirely from directives. See [Hub pages](../syntax/hub-pages.md).

- [docs-builder documentation hub](products/docs-builder.md)
12 changes: 12 additions & 0 deletions docs/examples/products/docs-builder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
layout: hub
description: docs-builder documentation. Build, validate, and publish Elastic documentation from Markdown across many repositories.
---

:::{hero}
:icon: docs-builder
:title: docs-builder documentation hub
:description: The toolchain that builds Elastic's documentation. Author in Markdown, validate cross-repository links, preview locally, and publish one unified site.
:primary-action: [Install docs-builder](/getting-started/installation.md)
:secondary-action: [Elastic documentation](docs-content://get-started/index.md)
:::
64 changes: 64 additions & 0 deletions docs/syntax/hero.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Hero

A full-bleed identity band with a product icon, page title, description, and up to three actions. It is designed for the [hub layout](hub-pages.md), and it works on any page.

All hero content comes from options. The directive body is not used.

See the [Elasticsearch documentation hub](../examples/products/docs-builder.md) for a rendered hero.

## Basic

```markdown
:::{hero}
:icon: elasticsearch
:title: Elasticsearch documentation hub
:description: The distributed search and analytics engine at the heart of the Elastic platform.
:::
```

The `:title:` option doubles as the page title, so a hub page needs no body H1. See [Page title](hub-pages.md#page-title).

## Options

| Option | Type | Notes |
|---|---|---|
| `:title:` | string | **Required.** Renders as the page `<h1>` next to the icon. Also used as the document title. |
| `:description:` | inline markdown | One-line summary below the title. Supports bold, italics, and links. |
| `:icon:` | string | Product key. Resolves to an inline SVG. Known keys: `elasticsearch`, `kibana`, `observability`, `security`. An unknown key falls back to a single-letter chip. |
| `:primary-action:` | markdown link | First action. Format: `[Label](/url)` or `[Label](#anchor)`. |
| `:secondary-action:` | markdown link | Second action. |
| `:tertiary-action:` | markdown link | Third action. |

## Actions

Each action is a single markdown link. Actions render left to right, in the order primary, secondary, tertiary. Actions are optional. Omit them for a pure identity hero.

The option names set the order, not the weight. All three render as neutral buttons, the monochrome variant of the [button](/syntax/buttons.md) directive. A blue variant would make each action claim to be the call to action.

```markdown
:::{hero}
:icon: elasticsearch
:title: Elasticsearch documentation hub
:description: The distributed search and analytics engine.
:primary-action: [Install Elasticsearch](https://www.elastic.co/downloads/elasticsearch)
:secondary-action: [Get started](#get-started)
:tertiary-action: [Syntax reference](/syntax/hero.md)
:::
```

Actions render as buttons, and no button on the site carries an arrow. The arrow belongs to the eyebrow link, which sends the reader onward to the docs home.

Action URLs validate at build time. Use one of these forms:

| Form | Example | Behavior |
|---|---|---|
| In-page anchor | `#get-started` | Jumps to a section on the same page. Does not preload. |
| Site-absolute path | `/syntax/hero.md` | The markdown extension is stripped. The link preloads on hover. |
| Cross-link scheme | `docs-content://get-started/index.md` | Resolves through the link index. Not treated as external, so it does not open in a new tab. |
| External URL | `https://www.elastic.co/downloads/elasticsearch` | Opens in a new tab, with `rel="noopener noreferrer"`. Does not preload. |

A relative path such as `foo.md` is rejected. This differs from an inline markdown link, where a relative path resolves against the source file's directory.

## Description markup

`:description:` is a directive option, not a body block, so it never reaches the document pipeline. It renders with the default Markdown pipeline. Basic inline markup works. Substitutions, roles, and link validation do not apply inside it. Keep the description to plain prose.
70 changes: 70 additions & 0 deletions docs/syntax/hub-pages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Hub pages

A hub page is a product-scoped landing page. It gives a reader one 360° view of a product across versions, deployment types, and surfaces.

Hub pages are composed entirely from directives. There is no free-form body content. That constraint is deliberate. It lets every link validate at build time, and it keeps every hub structurally consistent whoever authors it.

See the [Elasticsearch documentation hub](../examples/products/docs-builder.md) for a complete page.

## Enable the layout

Set `layout: hub` in the page frontmatter:

```yaml
---
layout: hub
---
```

A page with `layout: hub` must contain a `{hero}` directive. The build fails without one, because the layout removes the page H1 and leaves the page with no title.

## What the layout changes

The hub layout differs from the default page layout in three ways:

- The right-rail table of contents is removed. The version dropdown lives in that rail, so a hub page does not show it.
- The previous and next page navigation is removed.
- The body owns the full width of the content column, so directives can render full-bleed sections.

The left sidebar stays. A reader can move between sibling hubs from there.

## Page title

A hub page has no authored H1. The page title comes from the first `{hero}` directive's `:title:` option.

Title detection tries three sources in order:

1. A top-level H1 in the body.
2. An H1 nested inside a directive.
3. The `:title:` option of the first `{hero}`.

One field therefore drives both the on-page heading and the browser tab title.

## Search

A hub page exists to answer generic queries such as "Elasticsearch docs". Two fields carry that:

- The `{hero}` `:title:` option, which becomes the indexed page title.
- The frontmatter `description`, which becomes the indexed description.

Write both deliberately. The search body indexes the hero title and description only. Section and card titles stay out, so a hub does not compete with the pages it links to on specific queries.

## Directives

| Directive | Purpose |
|---|---|
| [`{hero}`](hero.md) | Identity band. Carries the product icon, the page title, a description, and up to three actions. |

## Page skeleton

```markdown
---
layout: hub
---

:::{hero}
:icon: elasticsearch
:title: Elasticsearch documentation hub
:description: The distributed search and analytics engine at the heart of the Elastic platform.
:::
```
170 changes: 170 additions & 0 deletions src/Elastic.Documentation.Site/Assets/markdown/hub.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
* Hub-page styling. Class names mirror the directive output:
*
* .hub-page page wrapper, set by RenderHub in _Layout.cshtml
* .hub-content article wrapper inside the content column
* .hub-hero hero section, light, with a divider below
*
* Later hub directives append their own sections to this file.
*/

@layer components {
/* Page wrapper: full-width content. Stays white so the page reads
consistently whether the user lands via full navigation or via an
htmx-boosted swap from a regular docs page.

The content column supplies the horizontal gutter. No hub section adds one
of its own: a section that did would inset itself alone and break alignment
with the rest below the shared max-width. */
.hub-page .hub-content {
@apply mb-20 w-full max-w-none p-0;
}

/* Hero ------------------------------------------------------------- */
/* Light hero on the page background, separated from the body by a rule
(matches the redesign, no dark band). */
.hub-hero {
background-color: transparent;
color: var(--color-ink-dark);
padding: 40px 0 28px;
margin-bottom: 44px;
border-bottom: 1px solid var(--color-grey-20);
}
.hub-hero .hub-hero-inner {
@apply mx-auto w-full max-w-5xl;
}
.hub-hero .hub-hero-eyebrow {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px 14px;
margin: 0 0 20px;
font-size: var(--text-base);
letter-spacing: 0.02em;
}
.hub-hero .hub-hero-eyebrow-label {
font-weight: 600;
color: var(--color-ink-light);
}
.hub-hero .hub-hero-eyebrow-link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 4px 12px;
font-weight: 600;
color: var(--color-ink-dark);
text-decoration: none;
background: var(--color-white);
/* grey-70 is the lightest token clearing the 3:1 non-text contrast ratio, which
the border needs because it is what identifies this control. Same reasoning as
the neutral button in button.css. */
border: 1px solid var(--color-grey-70);
border-radius: 999px;
transition:
background 0.15s ease,
border-color 0.15s ease;
}
.hub-hero .hub-hero-eyebrow-link:hover,
.hub-hero .hub-hero-eyebrow-link:focus-visible {
background: var(--color-grey-10);
border-color: var(--color-ink-dark);
}
/* Shared arrow -----------------------------------------------------
The site puts an arrow on exactly two kinds of link: one that sends the
reader onward out of a section, and a row that is itself the target. It
never marks an ordinary link, and never a button. Hub links that qualify
use this class.

The glyph and the hover slide come from `.link-arrow` in styles.css. The
class is not reused directly because it is nested under `.link`, which
also forces a blue semibold type treatment that a pill or a card would
have to undo. */
.hub-arrow {
flex-shrink: 0;
width: 1.25em;
height: 1.25em;
transition: transform 0.15s ease-out;
}
a:hover .hub-arrow,
a:focus-visible .hub-arrow {
transform: translateX(4px);
}
.hub-hero .hub-hero-top {
display: flex;
align-items: center;
column-gap: 14px;
margin-bottom: 16px;
}
.hub-hero .hub-hero-icon {
@apply inline-flex h-13 w-13 shrink-0 items-center justify-center rounded-xl text-2xl font-bold;
width: 48px;
height: 48px;
background-color: var(--color-grey-10);
color: var(--color-ink-dark);
}
/* The letter fallback keeps the fixed chip. A product mark does not: its box hugs
the glyph, so the mark's left edge lines up with the eyebrow and the description
below it. Each icon's viewBox is cropped to its glyph, so there is no transparent
padding left to absorb. Width follows from the glyph's own aspect ratio. */
.hub-hero .hub-hero-icon-svg {
width: auto;
height: 40px;
background-color: transparent;
border-radius: 0;
}
.hub-hero .hub-hero-icon-svg svg {
width: auto;
height: 40px;
}
.hub-hero .hub-hero-top h1 {
font-size: var(--text-4xl);
font-weight: 700;
line-height: 1.2;
letter-spacing: -0.5px;
color: var(--color-ink-dark);
margin: 0;
}
.hub-hero .hub-hero-top h1 a.headerlink {
color: var(--color-ink-dark);
text-decoration: none;
}
.hub-hero .hub-hero-desc {
font-size: var(--text-base);
color: var(--color-ink-light);
max-width: 760px;
line-height: 1.6;
margin: 0;
}

.hub-hero .hub-hero-actions {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: 24px;
}
/* The three actions carry equal weight, so they all take the neutral button
treatment from the {button} directive rather than a bespoke hero button. A blue
variant would make each one claim to be the call to action. Only the layout
properties the hero needs are set here: the type, height, colour and radius come
from `.doc-button-neutral`. */
.hub-hero .hub-hero-action {
gap: 8px;
}
.hub-hero .hub-hero-action svg {
flex-shrink: 0;
}

/* The arrow slides and the hero animates its hover states. Honour a reduced-motion
preference. Nothing about the resting appearance changes. */
@media (prefers-reduced-motion: reduce) {
.hub-hero .hub-hero-eyebrow-link,
.hub-hero .hub-hero-action,
.hub-arrow {
transition: none;
}
a:hover .hub-arrow,
a:focus-visible .hub-arrow {
transform: none;
}
}
}
1 change: 1 addition & 0 deletions src/Elastic.Documentation.Site/Assets/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
@import './markdown/cli-modifiers.css';
@import './markdown/contributors.css';
@import './markdown/storybook.css';
@import './markdown/hub.css';
@import './api-docs.css';
@import 'tippy.js/dist/tippy.css';

Expand Down
Loading
Loading