Skip to content

Commit ec62146

Browse files
theletterfclaudecursoragent
committed
fix(nav-v2): resolve nav-v2-sections merge conflict in navigation-v2.yml
Take section: Release notes (with url: /release-notes/) from nav-v2-sections over the plain label: entry in nav-v2, preserving the sections feature this PR introduces. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
2 parents a84001d + 52a2874 commit ec62146

20 files changed

Lines changed: 4976 additions & 3895 deletions

File tree

config/navigation-v2.yml

Lines changed: 4227 additions & 3794 deletions
Large diffs are not rendered by default.

src/Elastic.Codex/Page/Index.cshtml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
Previous = Model.PreviousDocument,
5050
Next = Model.NextDocument,
5151
NavigationHtml = Model.NavigationHtml,
52+
NavV2Sections = Model.NavV2Sections,
53+
ActiveSectionId = Model.ActiveSectionId,
5254
UrlPathPrefix = Model.UrlPathPrefix,
5355
GithubEditUrl = Model.GithubEditUrl,
5456
MarkdownUrl = Model.MarkdownUrl,

src/Elastic.Documentation.Configuration/Toc/NavigationV2File.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,28 @@ IReadOnlyList<INavV2Item> Children
2727
/// </summary>
2828
public record PageNavV2Item(Uri? Page, string? Title) : INavV2Item;
2929

30+
/// <summary>
31+
/// A top-level section that owns an independent sidebar tree and (optionally) a tab in the
32+
/// secondary nav bar. When <see cref="Isolated"/> is <c>true</c> the section does not appear
33+
/// in the top bar and renders with a back-arrow instead.
34+
/// </summary>
35+
public record SectionNavV2Item(
36+
string Label,
37+
string Url,
38+
bool Isolated,
39+
IReadOnlyList<INavV2Item> Children
40+
) : INavV2Item;
41+
42+
/// <summary>
43+
/// A nav island nested inside a section. When a user navigates into pages belonging to
44+
/// this island's toc, the sidebar shows only the island's tree with a back arrow to the
45+
/// parent section. The island does not appear in the secondary nav bar.
46+
/// </summary>
47+
public record IslandNavV2Item(
48+
string Label,
49+
Uri Source
50+
) : INavV2Item;
51+
3052
/// <summary>
3153
/// A folder node — has a title and children, with an optional <c>page:</c> URI.
3254
/// When <see cref="Page"/> is set, the header is a real clickable link; otherwise it renders
@@ -110,6 +132,30 @@ private static IReadOnlyList<INavV2Item> ReadItemList(IParser parser, ObjectDese
110132
parser.SkipThisAndNestedEvents();
111133
}
112134

135+
if (dict.TryGetValue("section", out var sectionVal) && sectionVal is string sectionStr)
136+
{
137+
var sectionUrl = dict.TryGetValue("url", out var suVal) && suVal is string suStr ? suStr : "/";
138+
var isolated = dict.TryGetValue("isolated", out var isoVal)
139+
&& isoVal is string isoStr
140+
&& bool.TryParse(isoStr, out var isoBool)
141+
&& isoBool;
142+
var sectionChildren = dict.TryGetValue("children", out var sch) && sch is IReadOnlyList<INavV2Item> sChildList
143+
? sChildList
144+
: [];
145+
return new SectionNavV2Item(sectionStr, sectionUrl, isolated, sectionChildren);
146+
}
147+
148+
if (dict.TryGetValue("island", out var islandVal) && islandVal is string islandStr)
149+
{
150+
if (dict.TryGetValue("toc", out var itVal) && itVal is string itStr)
151+
{
152+
var itUriString = itStr.Contains("://") ? itStr : $"docs-content://{itStr}";
153+
if (Uri.TryCreate(itUriString, UriKind.Absolute, out var itSource))
154+
return new IslandNavV2Item(islandStr, itSource);
155+
}
156+
return null;
157+
}
158+
113159
if (dict.TryGetValue("label", out var labelVal) && labelVal is string labelStr)
114160
{
115161
var expanded = dict.TryGetValue("expanded", out var expVal)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using Elastic.Documentation.Extensions;
6+
7+
namespace Elastic.Documentation.Navigation.V2;
8+
9+
/// <summary>
10+
/// A nav island that wraps an existing toc node. When a page belongs to this island,
11+
/// the sidebar shows only the island's tree with a back arrow to the parent section.
12+
/// In the parent section's sidebar, the island renders as a normal folder link.
13+
/// </summary>
14+
public class IslandNavigationNode(
15+
string label,
16+
IRootNavigationItem<IDocumentationFile, INavigationItem> source,
17+
INodeNavigationItem<INavigationModel, INavigationItem>? parent
18+
) : INodeNavigationItem<INavigationModel, INavigationItem>
19+
{
20+
/// <summary>The Id of the wrapped toc root, used for island lookup by nav ownership.</summary>
21+
public string SourceTocRootId { get; } = source.Id;
22+
23+
/// <summary>
24+
/// The URL to use for the back arrow when this island is active.
25+
/// Walks up the parent chain to find the nearest ancestor with a meaningful URL,
26+
/// falling back to "/" if none is found.
27+
/// </summary>
28+
public string ParentUrl { get; } = ResolveParentUrl(parent);
29+
30+
private static string ResolveParentUrl(INodeNavigationItem<INavigationModel, INavigationItem>? parent)
31+
{
32+
var current = parent;
33+
while (current is not null)
34+
{
35+
if (!string.IsNullOrEmpty(current.Url) && current.Url != "/")
36+
return current.Url;
37+
current = current.Parent;
38+
}
39+
return "/";
40+
}
41+
42+
/// <inheritdoc />
43+
public string Id { get; } = ShortId.Create("island", label);
44+
45+
/// <inheritdoc />
46+
public string Url => source.Url;
47+
48+
/// <inheritdoc />
49+
public string NavigationTitle { get; } = label;
50+
51+
/// <inheritdoc />
52+
public IRootNavigationItem<INavigationModel, INavigationItem> NavigationRoot { get; } = parent?.NavigationRoot!;
53+
54+
/// <inheritdoc />
55+
public INodeNavigationItem<INavigationModel, INavigationItem>? Parent { get; set; } = parent;
56+
57+
/// <inheritdoc />
58+
public bool Hidden => source.Hidden;
59+
60+
/// <inheritdoc />
61+
public int NavigationIndex { get; set; }
62+
63+
/// <inheritdoc />
64+
public ILeafNavigationItem<INavigationModel> Index => source.Index;
65+
66+
/// <inheritdoc />
67+
public IReadOnlyCollection<INavigationItem> NavigationItems => source.NavigationItems;
68+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
namespace Elastic.Documentation.Navigation.V2;
6+
7+
/// <summary>
8+
/// Lightweight data carrier for a navigation section, used by the rendering layer
9+
/// to drive the secondary nav bar tabs and resolve which sidebar to show.
10+
/// </summary>
11+
public record NavigationSection(
12+
string Id,
13+
string Label,
14+
string Url,
15+
bool Isolated,
16+
IReadOnlyList<INavigationItem> NavigationItems
17+
);
18+
19+
/// <summary>
20+
/// A nav island nested within a parent section. When a page belongs to an island,
21+
/// the sidebar shows only the island's tree with a back arrow to the parent section.
22+
/// </summary>
23+
public record NavigationIsland(
24+
string Id,
25+
string Label,
26+
string Url,
27+
string SourceTocRootId,
28+
NavigationSection ParentSection,
29+
string BackUrl,
30+
IReadOnlyList<INavigationItem> NavigationItems
31+
);
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using Elastic.Documentation.Extensions;
6+
7+
namespace Elastic.Documentation.Navigation.V2;
8+
9+
/// <summary>
10+
/// A top-level section that owns an independent sidebar nav tree.
11+
/// Unlike <see cref="LabelNavigationNode"/>, a section has a real URL (the tab link)
12+
/// and an <see cref="Isolated"/> flag that controls whether it appears in the top bar.
13+
/// </summary>
14+
public class SectionNavigationNode : INodeNavigationItem<INavigationModel, INavigationItem>
15+
{
16+
private readonly SectionIndexLeaf _index;
17+
18+
public SectionNavigationNode(
19+
string label,
20+
string url,
21+
bool isolated,
22+
IReadOnlyCollection<INavigationItem> children,
23+
INodeNavigationItem<INavigationModel, INavigationItem>? parent
24+
)
25+
{
26+
Id = ShortId.Create("section", label);
27+
NavigationTitle = label;
28+
Url = url;
29+
Isolated = isolated;
30+
NavigationItems = children;
31+
Parent = parent;
32+
NavigationRoot = parent?.NavigationRoot!;
33+
_index = new SectionIndexLeaf(this);
34+
}
35+
36+
/// <summary>Whether this section is excluded from the top bar and renders with a back arrow.</summary>
37+
public bool Isolated { get; }
38+
39+
/// <inheritdoc />
40+
public string Id { get; }
41+
42+
/// <inheritdoc />
43+
public string Url { get; }
44+
45+
/// <inheritdoc />
46+
public string NavigationTitle { get; }
47+
48+
/// <inheritdoc />
49+
public IRootNavigationItem<INavigationModel, INavigationItem> NavigationRoot { get; }
50+
51+
/// <inheritdoc />
52+
public INodeNavigationItem<INavigationModel, INavigationItem>? Parent { get; set; }
53+
54+
/// <inheritdoc />
55+
public bool Hidden => false;
56+
57+
/// <inheritdoc />
58+
public int NavigationIndex { get; set; }
59+
60+
/// <inheritdoc />
61+
public ILeafNavigationItem<INavigationModel> Index => _index;
62+
63+
/// <inheritdoc />
64+
public IReadOnlyCollection<INavigationItem> NavigationItems { get; }
65+
66+
private sealed class SectionIndexLeaf(SectionNavigationNode owner)
67+
: ILeafNavigationItem<INavigationModel>, INavigationModel
68+
{
69+
public INavigationModel Model => this;
70+
public string Url => owner.Url;
71+
public string NavigationTitle => owner.NavigationTitle;
72+
public IRootNavigationItem<INavigationModel, INavigationItem> NavigationRoot => owner.NavigationRoot;
73+
public INodeNavigationItem<INavigationModel, INavigationItem>? Parent { get; set; } = owner;
74+
public bool Hidden => true;
75+
public int NavigationIndex { get; set; }
76+
}
77+
}

0 commit comments

Comments
 (0)