Skip to content

Commit

Permalink
Add pages navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
reakaleek committed Feb 7, 2025
1 parent fad2f7a commit 3f9de52
Show file tree
Hide file tree
Showing 18 changed files with 251 additions and 48 deletions.
8 changes: 8 additions & 0 deletions docs/docset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,11 @@ toc:
children:
- file: first-page.md
- file: second-page.md
- folder: deeply-nested
children:
- file: index.md
- file: foo.md
- file: bar.md
- folder: baz
children:
- file: qux.md
1 change: 1 addition & 0 deletions docs/testing/deeply-nested/bar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Bar
1 change: 1 addition & 0 deletions docs/testing/deeply-nested/baz/qux.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Qux
1 change: 1 addition & 0 deletions docs/testing/deeply-nested/foo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Foo
1 change: 1 addition & 0 deletions docs/testing/deeply-nested/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Deeply Nested
19 changes: 17 additions & 2 deletions src/Elastic.Markdown/Assets/fonts.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
@font-face {
font-family: "Inter";
src: url("./fonts/InterVariable.woff2") format("woff2");
}

@font-face {
font-family: "Mier B";
src: url("./fonts/MierB-Regular.woff2") format("woff2");
font-weight: normal;
}

@font-face {
font-family: "Mier B";
src: url("./fonts/MierB-Bold.woff2") format("woff2");
font-weight: bold;
}

@font-face {
font-family: "Mier B";
src: url("./fonts/MierB-Regular.woff2") format("woff2")
src: url("./fonts/MierB-Demi.woff2") format("woff2");
font-weight: 600;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
39 changes: 39 additions & 0 deletions src/Elastic.Markdown/Assets/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import hljs from "highlight.js";
import {mergeHTMLPlugin} from "./hljs-merge-html-plugin";
import {$, $$} from 'select-dom/strict.js'

hljs.registerLanguage('apiheader', function() {
return {
Expand All @@ -16,3 +17,41 @@ hljs.registerLanguage('apiheader', function() {

hljs.addPlugin(mergeHTMLPlugin);
hljs.highlightAll();


type NavState = { [key: string]: boolean };


function keepNavState(element: HTMLElement) {
const inputs = $$('input[type="checkbox"]', element);
const sessionState = JSON.parse(sessionStorage.getItem('pagesNavState')) as NavState
if (sessionState) {
inputs.forEach(input => {
const key = input.id;
input.checked = input.checked || sessionState[key];
});
}
window.addEventListener('beforeunload', () => {
const state = inputs.reduce((state: NavState, input) => {
const key = input.id;
const value = input.checked;
return { ...state, [key]: value};
}, {});
sessionStorage.setItem('pagesNavState', JSON.stringify(state));
});
}

function keepNavPosition(element: HTMLElement) {
const scrollPosition = sessionStorage.getItem('pagesNavScrollPosition');
if (scrollPosition) {
element.scrollTop = parseInt(scrollPosition);
}
window.addEventListener('beforeunload', () => {
sessionStorage.setItem('pagesNavScrollPosition', element.scrollTop.toString());
});
}

const pagesNav = $('#pages-nav');

keepNavState(pagesNav);
keepNavPosition(pagesNav);
17 changes: 17 additions & 0 deletions src/Elastic.Markdown/Assets/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,20 @@
cursor: pointer;
background-repeat: no-repeat;
}

#pages-nav {
scrollbar-gutter: stable;
&::-webkit-scrollbar-track {
background-color: transparent;
}
&:hover::-webkit-scrollbar-thumb {
background-color: var(--color-gray-light);
}
&::-webkit-scrollbar {
width: 8px;
height: 8px;
}
&::-webkit-scrollbar-thumb {
border-radius: 4px;
}
}
7 changes: 7 additions & 0 deletions src/Elastic.Markdown/IO/Navigation/DocumentationGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ public class DocumentationGroup

public int Depth { get; }

public bool ContainsCurrentPage(MarkdownFile current) => NavigationItems.Any(n => n switch
{
FileNavigation f => f.File == current,
GroupNavigation g => g.Group.ContainsCurrentPage(current),
_ => false
});

public DocumentationGroup(
BuildContext context,
IReadOnlyCollection<ITocItem> toc,
Expand Down
51 changes: 34 additions & 17 deletions src/Elastic.Markdown/Slices/Layout/_TocTree.cshtml
Original file line number Diff line number Diff line change
@@ -1,20 +1,37 @@
@inherits RazorSlice<NavigationViewModel>
<aside id="lside" class="sy-lside md:w-72 md:shrink-0 print:hidden">
<div class="sy-lside-inner md:sticky">
<div class="sy-scrollbar p-6">
<div class="globaltoc" data-expand-depth="0">
<p class="caption" role="heading" aria-level="3">
<span class="caption-text">Elastic Docs Guide</span>
</p>
<ul class="current">@await RenderPartialAsync(_TocTreeNav.Create(new NavigationTreeItem
{
Level = Model.Tree.Depth,
SubTree = Model.Tree,
CurrentDocument = Model.CurrentDocument
}))
</ul>

@if (Model.IsRedesign)
{
<div class="pt-6 sticky">
<ul class="block w-full">
@await RenderPartialAsync(_TocTreeNav.Create(new NavigationTreeItem
{
Level = Model.Tree.Depth,
SubTree = Model.Tree,
CurrentDocument = Model.CurrentDocument
}))
</ul>
</div>
}
else
{
<aside id="lside" class="sy-lside md:w-72 md:shrink-0 print:hidden">
<div class="sy-lside-inner md:sticky">
<div class="sy-scrollbar p-6">
<div class="globaltoc" data-expand-depth="0">
<p class="caption" role="heading" aria-level="3">
<span class="caption-text">Elastic Docs Guide</span>
</p>
<ul class="current">@await RenderPartialAsync(_TocTreeNav.Create(new NavigationTreeItem
{
Level = Model.Tree.Depth,
SubTree = Model.Tree,
CurrentDocument = Model.CurrentDocument
}))
</ul>
</div>
</div>
</div>
</div>
</aside>
<div class="lside-overlay js-menu" role="button" aria-label="Close left sidebar" aria-controls="lside" aria-expanded="false"></div>
</aside>
<div class="lside-overlay js-menu" role="button" aria-label="Close left sidebar" aria-controls="lside" aria-expanded="false"></div>
}
106 changes: 87 additions & 19 deletions src/Elastic.Markdown/Slices/Layout/_TocTreeNav.cshtml
Original file line number Diff line number Diff line change
@@ -1,27 +1,95 @@
@using Elastic.Markdown.IO.Navigation
@inherits RazorSlice<NavigationTreeItem>
@foreach (var item in Model.SubTree.NavigationItems)
@if (Model.IsRedesign)
{
if (item is FileNavigation file)
@foreach (var item in Model.SubTree.NavigationItems)
{
var f = file.File;
var current = f == Model.CurrentDocument ? " current" : string.Empty;
<li class="toctree-l@(Model.SubTree.Depth + 1)@current"><a class="@(current.Trim()) reference internal" href="@f.Url">@f.NavigationTitle</a></li>
if (item is FileNavigation file)
{
var f = file.File;
var isCurrent = f == Model.CurrentDocument;
<li class="block pl-6 pb-2 w-full @(isCurrent ? "current" : string.Empty)">
<div class="flex">
<div class="w-6">
</div>
<a
class="block w-full hover:font-bold @(isCurrent ? "font-bold text-blue-elastic" : string.Empty) "
href="@f.Url">
@f.NavigationTitle
</a>
</div>

</li>
}
else if (item is GroupNavigation folder)
{
var g = folder.Group;
var isCurrent = g.Index == Model.CurrentDocument;
const int initialExpandLevel = 1;
var shouldExpand = g.HoldsCurrent(Model.CurrentDocument) || g.Depth <= initialExpandLevel || g.ContainsCurrentPage(Model.CurrentDocument);
<li class="block pl-6 pb-2">
<div class="flex items-center">
<div class="w-6">
@if (g.NavigationItems.Count > 0)
{
<label for="@g.Index?.Title">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 cursor-pointer">
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5"/>
</svg>
</label>
}
</div>
<a
href="@g.Index?.Url"
class="block w-full hover:font-bold @(isCurrent ? "font-bold text-blue-elastic" : string.Empty) ">
@g.Index?.NavigationTitle
</a>
</div>
<input
id="@g.Index?.Title"
type="checkbox"
class="peer hidden"
@(shouldExpand ? "checked" : string.Empty)>
@if (g.NavigationItems.Count > 0)
{
<ul class="h-0 peer-checked:h-auto w-full overflow-hidden mt-2" data-has-current="@g.ContainsCurrentPage(Model.CurrentDocument)">
@await RenderPartialAsync(_TocTreeNav.Create(new NavigationTreeItem
{
Level = g.Depth,
CurrentDocument = Model.CurrentDocument,
SubTree = g
}))
</ul>
}
</li>
}
}
else if (item is GroupNavigation folder)
}
else
{
@foreach (var item in Model.SubTree.NavigationItems)
{
var g = folder.Group;
var current = g.HoldsCurrent(Model.CurrentDocument) ? " current" : string.Empty;
var currentFile = g.Index == Model.CurrentDocument ? " current" : string.Empty;
<li class="toctree-l@(g.Depth)@current"><a class="reference internal@(currentFile)" href="@g.Index?.Url">@g.Index?.NavigationTitle</a>@if (@g.NavigationItems.Count > 0) {<ul class="@(current.Trim())">
@await RenderPartialAsync(_TocTreeNav.Create(new NavigationTreeItem
{
Level = g.Depth,
CurrentDocument = Model.CurrentDocument,
SubTree = g
}))
</ul>
}
</li>
if (item is FileNavigation file)
{
var f = file.File;
var current = f == Model.CurrentDocument ? " current" : string.Empty;
<li class="toctree-l@(Model.SubTree.Depth + 1)@current"><a class="@(current.Trim()) reference internal" href="@f.Url">@f.NavigationTitle</a></li>
}
else if (item is GroupNavigation folder)
{
var g = folder.Group;
var current = g.HoldsCurrent(Model.CurrentDocument) ? " current" : string.Empty;
var currentFile = g.Index == Model.CurrentDocument ? " current" : string.Empty;
<li class="toctree-l@(g.Depth)@current"><a class="reference internal@(currentFile)" href="@g.Index?.Url">@g.Index?.NavigationTitle</a>@if (@g.NavigationItems.Count > 0) {<ul class="@(current.Trim())">
@await RenderPartialAsync(_TocTreeNav.Create(new NavigationTreeItem
{
Level = g.Depth,
CurrentDocument = Model.CurrentDocument,
SubTree = g
}))
</ul>
}
</li>
}
}
}
14 changes: 9 additions & 5 deletions src/Elastic.Markdown/Slices/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@
</div>
</div>
</header>
<main class="container mx-auto">

<div class="markdown-content w-[100ch] max-w-screen mx-auto pt-6 pb-6 px-6">
<div class="container mx-auto flex">
<aside>
<nav id="pages-nav" class="sticky top-22 z-10 max-h-[calc(100vh-var(--spacing)*22)] overflow-y-auto">
@(new HtmlString(Model.NavigationHtml))
</nav>
</aside>
<main class="markdown-content w-[100ch] max-w-screen pt-6 pb-6 px-6">
<ol class="flex-1 mb-6" itemscope="" itemtype="https://schema.org/BreadcrumbList">
<li class="inline text-gray-500" itemprop="itemListElement" itemscope="" itemtype="https://schema.org/ListItem">
<a itemprop="item" href="/">
Expand All @@ -60,8 +64,8 @@
}
</ol>
@await RenderBodyAsync()
</div>
</main>
</main>
</div>
<script src="@Model.Static("main.js")"></script>
</body>
</html>
Expand Down
13 changes: 8 additions & 5 deletions src/Elastic.Markdown/Slices/_ViewModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ public class IndexViewModel
public required bool AllowIndexing { get; init; }
}

public class LayoutViewModel
public abstract class RedsignViewModel
{
public bool IsRedesign => Environment.GetEnvironmentVariable("REDESIGN") == "true";
}

public class LayoutViewModel : RedsignViewModel
{
public string Title { get; set; } = "Elastic Documentation";
public string RawTitle { get; set; } = "Elastic Documentation";
Expand All @@ -38,8 +43,6 @@ public class LayoutViewModel
public required string? GithubEditUrl { get; set; }
public required bool AllowIndexing { get; init; }

public bool IsRedesign => Environment.GetEnvironmentVariable("REDESIGN") == "true";

private MarkdownFile[]? _parents;
public MarkdownFile[] Parents
{
Expand Down Expand Up @@ -73,13 +76,13 @@ public class PageTocItem
}


public class NavigationViewModel
public class NavigationViewModel : RedsignViewModel
{
public required DocumentationGroup Tree { get; init; }
public required MarkdownFile CurrentDocument { get; init; }
}

public class NavigationTreeItem
public class NavigationTreeItem : RedsignViewModel
{
public required int Level { get; init; }
public required MarkdownFile CurrentDocument { get; init; }
Expand Down
Loading

0 comments on commit 3f9de52

Please sign in to comment.