Skip to content

Commit 0ad21fa

Browse files
committed
ok
1 parent d16dcc0 commit 0ad21fa

File tree

10 files changed

+119
-154
lines changed

10 files changed

+119
-154
lines changed
Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
1+
import "htmx.org"
2+
import "htmx-ext-preload"
13
import {initTocNav} from "./toc-nav";
24
import {initHighlight} from "./hljs";
35
import {initTabs} from "./tabs";
46
import {initCopyButton} from "./copybutton";
57
import {initNav} from "./pages-nav";
8+
import {$$} from "select-dom"
69

7-
document.body.addEventListener('htmx:load', function(evt) {
8-
document.querySelector("#content").scrollIntoView({ behavior: 'instant', block: 'start' });
10+
document.addEventListener('htmx:load', function() {
911
initTocNav();
1012
initHighlight();
1113
initCopyButton();
1214
initTabs();
1315
initNav();
1416
});
1517

16-
// initNav();
18+
19+
document.body.addEventListener('htmx:pushedIntoHistory', function(event) {
20+
const currentNavItem = $$('.current');
21+
currentNavItem.forEach(el => {
22+
el.classList.remove('current');
23+
})
24+
// @ts-ignore
25+
const navItems = $$('a[href="' + event.detail.path + '"]');
26+
navItems.forEach(navItem => {
27+
navItem.classList.add('current');
28+
});
29+
});
Lines changed: 15 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,21 @@
11
import {$, $$} from "select-dom";
2-
import {initHighlight} from "./hljs";
3-
import {initCopyButton} from "./copybutton";
4-
import {initTabs} from "./tabs";
5-
import {initTocNav} from "./toc-nav";
62

7-
type NavExpandState = {
8-
current:string,
9-
selected: Record<string, boolean>
10-
};
11-
const PAGE_NAV_EXPAND_STATE_KEY = 'pagesNavState';
12-
13-
// Initialize the nav state from the session storage
14-
// Return a function to keep the nav state in the session storage that should be called before the page is unloaded
15-
function keepNavState(nav: HTMLElement): () => void {
16-
17-
const currentNavigation = nav.dataset.currentNavigation;
18-
const currentPageId = nav.dataset.currentPageId;
19-
20-
let navState = JSON.parse(sessionStorage.getItem(PAGE_NAV_EXPAND_STATE_KEY) ?? "{}") as NavExpandState
21-
if (navState.current !== currentNavigation)
22-
{
23-
sessionStorage.removeItem(PAGE_NAV_EXPAND_STATE_KEY);
24-
navState = { current: currentNavigation } as NavExpandState;
25-
}
26-
if (currentPageId)
27-
{
28-
const currentPageLink = $('a[id="page-' + currentPageId + '"]', nav);
29-
currentPageLink.classList.add('current');
30-
currentPageLink.classList.add('pointer-events-none');
31-
currentPageLink.classList.add('text-blue-elastic!');
32-
currentPageLink.classList.add('font-semibold');
33-
34-
const parentIds = nav.dataset.currentPageParentIds?.split(',') ?? [];
35-
for (const parentId of parentIds)
36-
{
37-
const input = $('input[type="checkbox"][id=\"'+parentId+'\"]', nav) as HTMLInputElement;
38-
if (input) {
39-
input.checked = true;
40-
const link = input.nextElementSibling as HTMLAnchorElement;
41-
link.classList.add('font-semibold');
42-
}
3+
function expandAllParents(navItem: HTMLElement) {
4+
let parent = navItem.closest('li');
5+
while (parent) {
6+
const input = parent.querySelector('input');
7+
if (input) {
8+
(input as HTMLInputElement).checked = true;
439
}
44-
}
45-
46-
// expand items previously selected
47-
for (const groupId in navState.selected)
48-
{
49-
const input = $('input[type="checkbox"][id=\"'+groupId+'\"]', nav) as HTMLInputElement;
50-
input.checked = navState.selected[groupId];
51-
}
52-
53-
return () => {
54-
// store all expanded groups
55-
const inputs = $$('input[type="checkbox"]:checked', nav);
56-
const selectedMap: Record<string, boolean> = inputs
57-
.filter(input => input.checked)
58-
.reduce((state: Record<string, boolean>, input) => {
59-
const key = input.id;
60-
const value = input.checked;
61-
return { ...state, [key]: value};
62-
}, {});
63-
const state = { current: currentNavigation, selected: selectedMap };
64-
sessionStorage.setItem(PAGE_NAV_EXPAND_STATE_KEY, JSON.stringify(state));
65-
}
66-
}
67-
68-
type NavScrollPosition = number;
69-
const PAGE_NAV_SCROLL_POSITION_KEY = 'pagesNavScrollPosition';
70-
const pagesNavScrollPosition: NavScrollPosition = parseInt(
71-
sessionStorage.getItem(PAGE_NAV_SCROLL_POSITION_KEY) ?? '0'
72-
);
73-
74-
75-
// Initialize the nav scroll position from the session storage
76-
// Return a function to keep the nav scroll position in the session storage that should be called before the page is unloaded
77-
function keepNavPosition(nav: HTMLElement): () => void {
78-
if (pagesNavScrollPosition) {
79-
nav.scrollTop = pagesNavScrollPosition;
80-
}
81-
return () => {
82-
sessionStorage.setItem(PAGE_NAV_SCROLL_POSITION_KEY, nav.scrollTop.toString());
10+
parent = parent.parentElement?.closest('li');
8311
}
8412
}
8513

8614
function scrollCurrentNaviItemIntoView(nav: HTMLElement, delay: number) {
15+
const currentNavItem = $('.current', nav);
16+
expandAllParents(currentNavItem);
8717
setTimeout(() => {
88-
const currentNavItem = $('.current', nav);
18+
8919
if (currentNavItem && !isElementInViewport(currentNavItem)) {
9020
currentNavItem.scrollIntoView({ behavior: 'smooth', block: 'center' });
9121
}
@@ -106,13 +36,12 @@ export function initNav() {
10636
if (!pagesNav) {
10737
return;
10838
}
109-
const keepNavStateCallback = keepNavState(pagesNav);
110-
const keepNavPositionCallback = keepNavPosition(pagesNav);
39+
const navItems = $$('a[href="' + window.location.pathname + '"]', pagesNav);
40+
navItems.forEach(el => {
41+
el.classList.add('current');
42+
});
11143
scrollCurrentNaviItemIntoView(pagesNav, 100);
112-
window.addEventListener('beforeunload', () => {
113-
keepNavStateCallback();
114-
keepNavPositionCallback();
115-
}, true);
11644
}
11745

46+
11847
// initNav();

src/Elastic.Markdown/Assets/styles.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@
144144
.htmx-request .htmx-indicator,
145145
.htmx-request.htmx-indicator{
146146
display:block;
147+
z-index: 9999;
147148
}
148149

149150
.progress {
@@ -164,3 +165,7 @@
164165
transform: translateX(100%) scaleX(0.5);
165166
}
166167
}
168+
169+
#pages-nav .current {
170+
@apply text-blue-elastic!;
171+
}

src/Elastic.Markdown/Assets/tabs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,5 @@ function onSDLabelClick() {
9292
}
9393

9494
export function initTabs() {
95-
document.addEventListener("DOMContentLoaded", ready, { once: true });
95+
ready();
9696
}

src/Elastic.Markdown/Slices/Layout/_PagesNav.cshtml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
@inherits RazorSlice<LayoutViewModel>
2-
<aside class="sidebar hidden lg:block order-1 w-100 border-r-1 border-r-gray-200" hx-swap="morphdom"
2+
<aside class="sidebar hidden lg:block order-1 w-100 border-r-1 border-r-gray-200"
33
>
44
<nav
5-
id="pages-nav"
6-
class="sidebar-nav pr-6"
5+
id="pages-nav"
6+
class="sidebar-nav pr-6"
77
data-current-page-id="@Model.CurrentDocument.Id"
88
data-current-page-parent-ids="@(string.Join(",",Model.ParentIds))"
99
@* used to invalidate session storage *@

src/Elastic.Markdown/Slices/Layout/_TableOfContents.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@inherits RazorSlice<LayoutViewModel>
2-
<aside class="sidebar hidden lg:block order-3 basis-80">
2+
<aside class="sidebar hidden lg:block order-3 border-l-1 border-l-gray-200 w-80">
33
<nav id="toc-nav" class="sidebar-nav pl-6">
44
<div class="pt-6 pb-20">
55
@if (Model.PageTocItems.Count > 0)

src/Elastic.Markdown/Slices/Layout/_TocTreeNav.cshtml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
@using Elastic.Markdown.Helpers
21
@using Elastic.Markdown.IO.Navigation
32
@inherits RazorSlice<NavigationTreeItem>
43
@foreach (var item in Model.SubTree.NavigationItems)
@@ -11,10 +10,12 @@
1110
<div class="flex">
1211
<a
1312
hx-get="@f.Url"
14-
hx-target="#content"
15-
hx-select="#content"
13+
hx-select-oob="#markdown-content,#toc-nav,#prev-next-nav"
14+
hx-swap="none"
1615
hx-push-url="true"
17-
hx-indicator="#indicator"
16+
hx-indicator="#htmx-indicator"
17+
hx-swap="show:unset"
18+
preload="mouseover"
1819
class="sidebar-link my-1 ml-5 group-[.current]/li:text-blue-elastic!"
1920
id="page-@id"
2021
href="@f.Url">
@@ -48,6 +49,12 @@
4849
>
4950
<a
5051
href="@g.Index?.Url"
52+
hx-get="@g.Index?.Url"
53+
hx-select-oob="#markdown-content,#toc-nav,#prev-next-nav"
54+
hx-swap="none"
55+
hx-push-url="true"
56+
hx-indicator="#htmx-indicator"
57+
preload="mouseover"
5158
5259
class="sidebar-link inline-block my-1 @(g.Depth == 1 ? "uppercase tracking-[0.05em] text-ink-light font-semibold" : string.Empty)">
5360
@g.Index?.NavigationTitle

src/Elastic.Markdown/Slices/_Layout.cshtml

Lines changed: 50 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,67 +7,61 @@
77
<meta charset="utf-8">
88
<meta name="viewport" content="width=device-width, initial-scale=1.0">
99
<meta name="robots" content="@(Model.AllowIndexing ? "index, follow" : "noindex, nofollow")">
10-
<script src="https://unpkg.com/[email protected]/dist/htmx.js" integrity="sha384-oeUn82QNXPuVkGCkcrInrS1twIxKhkZiFfr2TdiuObZ3n3yIeMiqcRzkIcguaof1" crossorigin="anonymous"></script>
11-
<script src="https://unpkg.com/[email protected]" integrity="sha384-fkzubQiTB69M7XTToqW6tplvxAOJkqPl5JmLAbumV2EacmuJb8xEP9KnJafk/rg8" crossorigin="anonymous"></script>
12-
<script src="https://unpkg.com/[email protected]/dist/ext/morphdom-swap.js"></script>
13-
<meta name="htmx-config" content='{"scrollIntoViewOnBoost":false, "selfRequestsOnly": true}'>
10+
<meta name="htmx-config" content='{"scrollIntoViewOnBoost": false, "selfRequestsOnly": true}'>
1411
</head>
15-
<body class="text-ink">
12+
<body class="text-ink" hx-ext="preload">
13+
<div class="w-full fixed top-0 left-0 right-0 htmx-indicator" id="htmx-indicator">
14+
<div class="h-1.5 w-full bg-pink-10 overflow-hidden">
15+
<div class="progress w-full h-full bg-pink-50 left-right"></div>
16+
</div>
17+
</div>
1618
@(await RenderPartialAsync(_Header.Create(Model)))
1719
<div class="flex flex-col items-center px-6">
18-
<div class="container flex">
19-
@await RenderPartialAsync(_PagesNav.Create(Model))
20-
<main class="w-full order-2">
21-
<div class="content-container relative">
22-
<div class="w-full htmx-indicator absolute top-0 left-0 right-0" id="indicator">
23-
<div class="h-1 w-full bg-pink-10 overflow-hidden">
24-
<div class="progress w-full h-full bg-pink-50 left-right"></div>
25-
</div>
26-
</div>
27-
</div>
28-
<div id="content" class="w-full flex justify-between">
29-
@await RenderPartialAsync(_TableOfContents.Create(Model))
30-
<div class="content-container order-first px-6 pt-6 pb-12">
20+
<div class="container flex">
21+
@await RenderPartialAsync(_PagesNav.Create(Model))
22+
@await RenderPartialAsync(_TableOfContents.Create(Model))
23+
<main class="w-full pt-6 pb-30 px-6 order-2">
24+
25+
<div class="content-container">
3126
@await RenderPartialAsync(_Breadcrumbs.Create(Model))
32-
<article class="markdown-content">
33-
@await RenderBodyAsync()
34-
</article>
35-
<footer class="mt-20">
36-
<div class="flex flex-wrap lg:flex-nowrap gap-2 mt-2">
37-
<div class="basis-full">
38-
@if (Model.Previous != null)
39-
{
40-
<a href="@Model.Previous.Url" hx-get="@Model.Previous.Url" hx-select="#content" hx-target="#content" class="flex h-full items-center text-ink-light hover:black border-1 border-gray-300 hover:border-gray-500 rounded-lg p-6 shadow-md">
41-
<svg class="size-6 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
42-
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"/>
43-
</svg>
44-
<div>
45-
<div class="text-xs lg:text-sm">Previous</div>
46-
<div class="text-base lg:text-xl text-black">@Model.Previous.NavigationTitle</div>
47-
</div>
48-
</a>
49-
}
50-
</div>
51-
<div class="basis-full">
52-
@if (Model.Next != null)
53-
{
54-
<a href="@Model.Next.Url" hx-get="@Model.Next.Url" hx-select="#content" hx-target="#content" class="flex h-full items-center justify-end text-ink-light hover:black border-1 border-gray-300 hover:border-gray-500 rounded-lg p-6 shadow-md text-right">
55-
<div>
56-
<div class="text-xs lg:text-sm">Next</div>
57-
<div class="text-base lg:text-xl text-black">@Model.Next.NavigationTitle</div>
58-
</div>
59-
<svg class="size-6 ml-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
60-
<path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5"/>
61-
</svg>
62-
</a>
63-
}
64-
</div>
65-
</div>
66-
</footer>
6727
</div>
68-
</div>
69-
</main>
70-
</div>
28+
<article id="markdown-content" class="content-container markdown-content">
29+
@await RenderBodyAsync()
30+
</article>
31+
<footer id="prev-next-nav" class="content-container mt-20">
32+
<div class="flex flex-wrap lg:flex-nowrap gap-2 mt-2">
33+
<div class="w-full">
34+
@if (Model.Previous != null)
35+
{
36+
<a href="@Model.Previous.Url" class="flex h-full items-center text-ink-light hover:black border-1 border-gray-300 hover:border-gray-500 rounded-lg p-6 shadow-md">
37+
<svg class="size-6 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
38+
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"/>
39+
</svg>
40+
<div>
41+
<div class="text-xs lg:text-sm">Previous</div>
42+
<div class="text-base lg:text-xl text-black">@Model.Previous.NavigationTitle</div>
43+
</div>
44+
</a>
45+
}
46+
</div>
47+
<div class="w-full">
48+
@if (Model.Next != null)
49+
{
50+
<a href="@Model.Next.Url" class="flex h-full items-center justify-end text-ink-light hover:black border-1 border-gray-300 hover:border-gray-500 rounded-lg p-6 shadow-md text-right">
51+
<div>
52+
<div class="text-xs lg:text-sm">Next</div>
53+
<div class="text-base lg:text-xl text-black">@Model.Next.NavigationTitle</div>
54+
</div>
55+
<svg class="size-6 ml-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
56+
<path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5"/>
57+
</svg>
58+
</a>
59+
}
60+
</div>
61+
</div>
62+
</footer>
63+
</main>
64+
</div>
7165
</div>
7266
@(await RenderPartialAsync(_Footer.Create(Model)))
7367
<script src="@Model.Static("main.js")"></script>

src/Elastic.Markdown/package-lock.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Elastic.Markdown/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
"dependencies": {
4040
"clipboard": "^2.0.11",
4141
"highlight.js": "^11.11.1",
42+
"htmx-ext-preload": "^2.1.1",
43+
"htmx.org": "^2.0.4",
4244
"select-dom": "^9.3.0",
4345
"tailwindcss": "^4.0.3"
4446
}

0 commit comments

Comments
 (0)