Skip to content
Open
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
19 changes: 19 additions & 0 deletions docs/_docset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ toc:
- file: applies-switch.md
- file: automated_settings.md
- file: buttons.md
- file: card-group.md
- file: changelog.md
- file: code.md
- file: comments.md
Expand All @@ -120,10 +121,14 @@ toc:
- file: file_inclusion.md
- file: footnotes.md
- file: frontmatter.md
- file: hero.md
- file: hub-pages.md
- file: icons.md
- file: intro.md
- file: images.md
- file: videos.md
- file: kbd.md
- file: link-card.md
- file: math.md
- file: diagrams.md
- file: lists.md
Expand All @@ -132,6 +137,7 @@ toc:
- file: storybook.md
- file: links.md
- file: list-sub-pages.md
- file: on-this-page.md
- file: page-card.md
- file: stepper.md
- file: substitutions.md
Expand All @@ -140,6 +146,7 @@ toc:
- file: tables.md
- file: tabs.md
- file: titles.md
- file: whats-new.md

# Documentation builds
- folder: documentation
Expand Down Expand Up @@ -247,3 +254,15 @@ toc:

# Development
- toc: development

# Hub / product page fixtures used by local tests and assembler preview
- folder: testing
children:
- folder: products
children:
- folder: elasticsearch
children:
- file: v9.md
- folder: kibana
children:
- file: v9.md
2 changes: 1 addition & 1 deletion docs/syntax/hub-pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ links:

## Product badges

Every regular (non-hub) page that declares one or more `products:` in its frontmatter automatically gets a clickable badge above its H1, linking to that product's hub page. The badge → hub URL mapping is set per product in [`config/products.yml`](../configure/site/products.md):
Every regular (non-hub) page that declares one or more `products:` in its frontmatter automatically gets a clickable badge above its H1, linking to that product's hub page. The badge → hub URL mapping is set per product in [`config/products.yml`](../documentation/catalog/products.md):

```yaml
products:
Expand Down
2 changes: 1 addition & 1 deletion docs/syntax/whats-new.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A panel with a "New" badge, section title, optional release-notes link list on t

## Centralized lookup (recommended)

Edit content in one place — [`config/whats-new.yml`](../configure/site/products.md) — and any page can render a product's panel with a one-line directive:
Edit content in one place — [`config/whats-new.yml`](https://github.com/elastic/docs-builder/blob/main/config/whats-new.yml) — and any page can render a product's panel with a one-line directive:

```markdown
:::{whats-new}
Expand Down
13 changes: 10 additions & 3 deletions src/Elastic.ApiExplorer/Landing/LandingNavigationItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,14 @@ INodeNavigationItem<INavigationModel, INavigationItem> parent
}

public class ClassificationNavigationItem(ApiClassification classification, LandingNavigationItem rootNavigation, LandingNavigationItem parent)
: ApiGroupingNavigationItem<ApiClassification, INavigationItem>(classification, rootNavigation, parent), IRootNavigationItem<ApiClassification, INavigationItem>
: ApiGroupingNavigationItem<ApiClassification, INavigationItem>(classification, rootNavigation, parent),
IRootNavigationItem<ApiClassification, INavigationItem>,
ISidebarHeadingNavigationItem
{
/// <summary>Section titles from <c>x-tagGroups</c> are not their own page; the sidebar link targets the main API overview for the product, not a tag (or the first child) page.</summary>
/// <summary>
/// Classifications have no dedicated page. Kept as the product overview URL for any code that still
/// reads <see cref="INavigationItem.Url"/>; Nav V2 renders these as non-clickable sidebar headings.
/// </summary>
public override string Url => rootNavigation.Index.Url;

/// <inheritdoc />
Expand Down Expand Up @@ -144,7 +149,9 @@ INodeNavigationItem<INavigationModel, INavigationItem> parent
public interface IEndpointOrOperationNavigationItem : INavigationItem;

public class EndpointNavigationItem(ApiEndpoint endpoint, IRootNavigationItem<IApiGroupingModel, INavigationItem> rootNavigation, INodeNavigationItem<INavigationModel, INavigationItem> parent)
: IApiGroupingNavigationItem<ApiEndpoint, OperationNavigationItem>, IEndpointOrOperationNavigationItem
: IApiGroupingNavigationItem<ApiEndpoint, OperationNavigationItem>,
IEndpointOrOperationNavigationItem,
IMultiOperationNavigationItem
{
/// <inheritdoc />
public string Url => NavigationItems.First().Url;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@

namespace Elastic.ApiExplorer.Operations;

public record ApiOperation(HttpMethod OperationType, OpenApiOperation Operation, string Route, IOpenApiPathItem Path, string ApiName) : IApiModel
public record ApiOperation(HttpMethod OperationType, OpenApiOperation Operation, string Route, IOpenApiPathItem Path, string ApiName)
: IApiModel, IHttpMethodNavigationModel
{
string IHttpMethodNavigationModel.HttpMethod => OperationType.Method.ToLowerInvariant();

public async Task RenderAsync(FileSystemStream stream, ApiRenderContext context, Cancel ctx = default)
{
var viewModel = new OperationViewModel(context)
Expand Down
32 changes: 17 additions & 15 deletions src/Elastic.ApiExplorer/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,25 @@ else
{
@(await RenderPartialAsync(_IsolatedHeader.Create(Model)))
}
<div id="main-container" class="flex flex-col items-center">
<div class="max-w-(--max-layout-width) w-full h-full grid
grid-cols-1
md:grid-cols-[var(--max-sidebar-width)_1fr]
">
<div class="lg:grid lg:grid-cols-[1fr_var(--max-sidebar-width)] md:order-2">
<div class="justify-center px-6 lg:px-0">
<main id="content-container" class="w-full flex flex-col relative pb-12 overflow-x-hidden">
<article id="markdown-content" class="content-container markdown-content md:px-4">
<input type="checkbox" class="hidden" id="pages-nav-hamburger">
@await RenderBodyAsync()
</article>
</main>
@* Match Markdown Nav V2 shell so shared aside height / 279px chrome selectors apply. *@
<div id="main-container">
<div class="relative">
<div class="min-h-screen w-full max-w-(--max-layout-width) mx-auto md:px-4">
<div class="min-h-screen grid grid-cols-1 md:grid-cols-[var(--max-sidebar-width)_1fr] gap-4">
<div class="min-w-0 lg:grid lg:grid-cols-[minmax(0,1fr)_minmax(0,var(--max-sidebar-width))] md:order-2 gap-4">
<div class="justify-center px-6 lg:px-0 min-w-0">
<main id="content-container" class="w-full flex flex-col relative pb-12 overflow-x-hidden">
<article id="markdown-content" class="content-container markdown-content md:px-4 min-w-0">
<input type="checkbox" class="hidden" id="pages-nav-hamburger">
@await RenderBodyAsync()
</article>
</main>
</div>
@await RenderPartialAsync(_ApiToc.Create(Model.TocItems.ToArray()))
</div>
@await RenderPartialAsync(_PagesNav.Create(Model))
</div>
@await RenderPartialAsync(_ApiToc.Create(Model.TocItems.ToArray()))
</div>
@await RenderPartialAsync(_ApiPagesNav.Create(Model))
</div>
</div>
@if (Model.BuildType == BuildType.Assembler)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

namespace Elastic.Documentation.Navigation;

/// <summary>
/// Navigation model for an API operation leaf that exposes its HTTP method for sidebar chrome.
/// </summary>
public interface IHttpMethodNavigationModel : INavigationModel
{
/// <summary>Lowercase HTTP method name (e.g. <c>get</c>, <c>post</c>).</summary>
string HttpMethod { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

namespace Elastic.Documentation.Navigation;

/// <summary>
/// Marker for API navigation rows that group multiple HTTP operations under one logical endpoint.
/// Nav V2 shows a neutral multi-method badge (grid) instead of a single HTTP-method glyph.
/// </summary>
public interface IMultiOperationNavigationItem : INavigationItem;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

namespace Elastic.Documentation.Navigation;

/// <summary>
/// Marker for sidebar headings that group children without a dedicated page of their own.
/// Nav V2 renders these as label spans (<c>docs-sidebar-nav-v2__label--*</c>), not accordion folder links.
/// </summary>
/// <remarks>
/// Used by docs <c>label:</c> nodes and API OpenAPI <c>x-tagGroups</c> classifications.
/// Implement alongside <see cref="INodeNavigationItem{TIndex,TChildNavigation}"/>.
/// </remarks>
public interface ISidebarHeadingNavigationItem;
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ string DetermineUrl()
? relativePath[..^3] // Remove last 3 characters (.md)
: relativePath;

path = CollapseDotSegments(path);

// If a path ends with /index or is just index, omit it from the URL
if (path.EndsWith("/index", StringComparison.OrdinalIgnoreCase))
path = path[..^6]; // Remove "/index"
Expand All @@ -62,6 +64,24 @@ string DetermineUrl()
}
}

/// <summary>
/// Collapse <c>.</c> segments (<c>./foo</c>, <c>a/./b</c>) so site URLs never contain <c>/./</c>.
/// </summary>
private static string CollapseDotSegments(string path)
{
if (string.IsNullOrEmpty(path) || path.IndexOf('.', StringComparison.Ordinal) < 0)
return path;

path = path.Replace('\\', '/');
while (path.StartsWith("./", StringComparison.Ordinal))
path = path[2..];
while (path.Contains("/./", StringComparison.Ordinal))
path = path.Replace("/./", "/", StringComparison.Ordinal);
if (path is "." or "./")
return string.Empty;
return path;
}

/// <inheritdoc />
public bool Hidden { get; } = args.Hidden;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Elastic.Documentation.Navigation.V2;
/// A non-clickable section heading in the V2 navigation sidebar.
/// Has children but no URL of its own.
/// </summary>
public class LabelNavigationNode : INodeNavigationItem<INavigationModel, INavigationItem>
public class LabelNavigationNode : INodeNavigationItem<INavigationModel, INavigationItem>, ISidebarHeadingNavigationItem
{
private readonly LabelIndexLeaf _index;

Expand Down
60 changes: 60 additions & 0 deletions src/Elastic.Documentation.Site/Assets/api-docs.css
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,66 @@
.api-method-delete {
@apply border-red-30 bg-red-10 text-red-90;
}

/*
* Nav V2 method badges — Figma APIs (node 10065:6317):
* GET green + pivot 180°; POST blue; PUT/PATCH orange; DELETE red + X;
* multi-operation (and HEAD/OPTIONS) gray + branch glyph.
*/
#pages-nav nav[data-nav-v2] .nav-v2-api-method {
display: inline-flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
border: 1px solid;
border-radius: 6px;
box-sizing: border-box;
}

#pages-nav nav[data-nav-v2] .nav-v2-api-method svg {
display: block;
}

/* Only GET flips the pivot arrow (incoming). */
#pages-nav nav[data-nav-v2] .nav-v2-api-method-get svg {
transform: rotate(180deg);
}

#pages-nav nav[data-nav-v2] .nav-v2-api-method-get {
background-color: #c9f3e3;
border-color: #aee8d2;
color: #008a5e;
}

#pages-nav nav[data-nav-v2] .nav-v2-api-method-post {
background-color: #d9e8ff;
border-color: #bfdbff;
color: #0b64dd;
}

#pages-nav nav[data-nav-v2] .nav-v2-api-method-put,
#pages-nav nav[data-nav-v2] .nav-v2-api-method-patch {
background-color: #ffdebf;
border-color: #ffcda1;
color: #ed6723;
}

/* Neutral gray reserved for multi-operation endpoints (and rare HEAD/OPTIONS). */
#pages-nav nav[data-nav-v2] .nav-v2-api-method-head,
#pages-nav nav[data-nav-v2] .nav-v2-api-method-options,
#pages-nav nav[data-nav-v2] .nav-v2-api-method-multi {
background-color: #fff;
border-color: #cad3e2;
color: #5a6d8c;
}

#pages-nav nav[data-nav-v2] .nav-v2-api-method-delete {
background-color: #fdddd8;
border-color: #ffc9c2;
color: #c61e25;
}
.api-url {
margin-left: calc(var(--spacing) * 2);
display: inline-block;
Expand Down
8 changes: 6 additions & 2 deletions src/Elastic.Documentation.Site/Assets/assembler.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/* Assembler build type specific styles */

/* Elastic global nav is position:static (scrolls with page).
The secondary nav (Docs sub-header) is sticky on md+ viewports — match its height. */
/*
* Elastic global nav is position:static (scrolls with page).
* Secondary nav (Guides / APIs / …) is sticky on md+ — --offset-top matches that
* sticky top only. Panel height also subtracts live elastic-nav while visible
* (see updatePagesNavAsideViewportHeight in pages-nav-v2.ts).
*/
:root {
--secondary-nav-height: 55px;
--offset-top: 0px;
Expand Down
Loading
Loading