Skip to content

Commit 994339d

Browse files
committed
Add links to tocs
1 parent 8eb4417 commit 994339d

File tree

5 files changed

+90
-8
lines changed

5 files changed

+90
-8
lines changed

docs/configure/content-set/navigation.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,39 @@ It [may be linked to locally however](../../developer-notes.md)
148148

149149
#### Nesting `toc`
150150

151+
The `toc` key can include nested `toc.yml` files.
152+
153+
The following example includes two sub-`toc.yml` files located in directories named `elastic-basics` and `solutions`:
154+
155+
```yml
156+
toc:
157+
- file: index.md
158+
- toc: elastic-basics
159+
- toc: solutions
160+
```
161+
162+
#### External links
163+
164+
You can include links to external websites directly in your navigation tree. Use the `link` key with a valid URL, and provide a human-friendly `title`.
165+
166+
```yaml
167+
toc:
168+
- link: https://elastic.co
169+
title: Elastic Website
170+
- toc: getting-started
171+
- link: https://github.com/elastic/docs-builder
172+
title: Docs Builder Repository
173+
```
174+
175+
Docs-builder renders external links with an icon, opens them in a new tab, and adds `rel="noopener noreferrer"` for security.
176+
177+
Best practices:
178+
179+
* Use external links sparingly in your primary navigation, placing them near the bottom of a section when possible.
180+
* Provide clear titles that indicate the link leads to an external resource.
181+
* Periodically verify that external URLs remain valid, and update them if destinations change.
182+
183+
151184
The `toc` key can include nested `toc.yml` files.
152185

153186
The following example includes two sub-`toc.yml` files located in directories named `elastic-basics` and `solutions`:

src/Elastic.Documentation.Configuration/Builder/TableOfContentsConfiguration.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ private IReadOnlyCollection<ITocItem> ReadChildren(YamlStreamReader reader, KeyV
130130
{
131131
string? file = null;
132132
string? folder = null;
133+
string? link = null;
134+
string? linkTitle = null;
133135
string[]? detectionRules = null;
134136
TableOfContentsConfiguration? toc = null;
135137
var detectionRulesFound = false;
@@ -148,6 +150,12 @@ private IReadOnlyCollection<ITocItem> ReadChildren(YamlStreamReader reader, KeyV
148150
hiddenFile = key == "hidden";
149151
file = ReadFile(reader, entry, parentPath);
150152
break;
153+
case "link":
154+
link = reader.ReadString(entry);
155+
break;
156+
case "title":
157+
linkTitle = reader.ReadString(entry);
158+
break;
151159
case "folder":
152160
folder = ReadFolder(reader, entry, parentPath);
153161
parentPath += $"{Path.DirectorySeparatorChar}{folder}";
@@ -199,6 +207,15 @@ private IReadOnlyCollection<ITocItem> ReadChildren(YamlStreamReader reader, KeyV
199207
return [new FileReference(this, path, hiddenFile, children ?? [])];
200208
}
201209

210+
if (link is not null)
211+
{
212+
// external links cannot have children
213+
if (children is not null)
214+
reader.EmitWarning("'link' entries may not contain 'children'", tocEntry);
215+
216+
return [new LinkReference(this, link, linkTitle ?? link)];
217+
}
218+
202219
if (folder is not null)
203220
{
204221
if (children is null)

src/Elastic.Documentation.Configuration/TableOfContents/ITocItem.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ public record TocReference(Uri Source, ITableOfContentsScope TableOfContentsScop
2727
/// A phantom table of contents is a table of contents that is not rendered in the UI but is used to generate the TOC.
2828
/// This should be used sparingly and needs explicit configuration in navigation.yml.
2929
/// It's typically used for container TOC that holds various other TOC's where its children are rehomed throughout the navigation.
30-
/// <para>Examples of phantom toc's:</para>
31-
/// <list type="">
32-
/// <item> - toc: elasticsearch://reference</item>
33-
/// <item> - toc: docs-content://</item>
34-
/// </list>
35-
/// <para>Because navigation.yml does exhaustive checks to ensure all toc.yml files are referenced, marking these containers as phantoms
36-
/// ensures that these skip validation checks
37-
/// </para>
3830
/// </summary>
3931
public bool IsPhantom { get; init; }
4032
}
4133

34+
/// <summary>
35+
/// Represents an external link in the table of contents.
36+
/// </summary>
37+
/// <param name="TableOfContentsScope">Scope this link belongs to.</param>
38+
/// <param name="Url">Absolute URL of the external resource.</param>
39+
/// <param name="Title">Display title for the link.</param>
40+
public record LinkReference(ITableOfContentsScope TableOfContentsScope, string Url, string Title) : ITocItem;
41+

src/Elastic.Markdown/IO/Navigation/DocumentationGroup.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Elastic.Documentation;
77
using Elastic.Documentation.Configuration;
88
using Elastic.Documentation.Configuration.TableOfContents;
9+
using Elastic.Markdown.IO.Navigation; // for ExternalLinkNavigationItem
910
using Elastic.Documentation.Extensions;
1011
using Elastic.Documentation.Site.Navigation;
1112

@@ -178,6 +179,11 @@ void AddToNavigationItems(INavigationItem item, ref int fileIndex)
178179
if (indexFile != md)
179180
AddToNavigationItems(new FileNavigationItem(md, this, file.Hidden), ref fileIndex);
180181
}
182+
else if (tocItem is LinkReference extLink)
183+
{
184+
var nav = new ExternalLinkNavigationItem(extLink.Url, extLink.Title, this);
185+
AddToNavigationItems(nav, ref fileIndex);
186+
}
181187
else if (tocItem is FolderReference folder)
182188
{
183189
var children = folder.Children;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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.Site.Navigation;
6+
7+
namespace Elastic.Markdown.IO.Navigation;
8+
9+
/// <summary>
10+
/// Navigation item representing an external URL in the TOC.
11+
/// </summary>
12+
public record ExternalLinkNavigationItem(string ExternalUrl, string Title, DocumentationGroup Group)
13+
: INavigationItem
14+
{
15+
public INodeNavigationItem<INavigationModel, INavigationItem>? Parent { get; set; } = Group;
16+
17+
public IRootNavigationItem<INavigationModel, INavigationItem> NavigationRoot { get; } = Group.NavigationRoot;
18+
19+
public string Url => ExternalUrl;
20+
21+
public string NavigationTitle => Title;
22+
23+
public int NavigationIndex { get; set; }
24+
25+
public bool Hidden => false;
26+
}

0 commit comments

Comments
 (0)