Skip to content

Commit 64e89ce

Browse files
committed
Add htmx to dynamicaly load content
1 parent 9dc8805 commit 64e89ce

File tree

11 files changed

+167
-151
lines changed

11 files changed

+167
-151
lines changed

src/Elastic.Markdown/Assets/copybutton.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,5 @@ var copyTargetText = (trigger) => {
256256
}
257257

258258
export function initCopyButton() {
259-
console.log("initCopyButton");
260259
runWhenDOMLoaded(addCopyButtonToCodeCells)
261260
}
Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +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";
7+
import {initNav} from "./pages-nav";
8+
import {$$} from "select-dom"
59

6-
initTocNav();
7-
initHighlight();
8-
initCopyButton();
9-
initTabs();
10+
document.addEventListener('htmx:load', function() {
11+
initTocNav();
12+
initHighlight();
13+
initCopyButton();
14+
initTabs();
15+
initNav();
16+
});
17+
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: 16 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,21 @@
11
import {$, $$} from "select-dom";
22

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

8214
function scrollCurrentNaviItemIntoView(nav: HTMLElement, delay: number) {
15+
const currentNavItem = $('.current', nav);
16+
expandAllParents(currentNavItem);
8317
setTimeout(() => {
84-
const currentNavItem = $('.current', nav);
18+
8519
if (currentNavItem && !isElementInViewport(currentNavItem)) {
8620
currentNavItem.scrollIntoView({ behavior: 'smooth', block: 'center' });
8721
}
@@ -102,13 +36,12 @@ export function initNav() {
10236
if (!pagesNav) {
10337
return;
10438
}
105-
const keepNavStateCallback = keepNavState(pagesNav);
106-
const keepNavPositionCallback = keepNavPosition(pagesNav);
39+
const navItems = $$('a[href="' + window.location.pathname + '"]', pagesNav);
40+
navItems.forEach(el => {
41+
el.classList.add('current');
42+
});
10743
scrollCurrentNaviItemIntoView(pagesNav, 100);
108-
window.addEventListener('beforeunload', () => {
109-
keepNavStateCallback();
110-
keepNavPositionCallback();
111-
}, true);
11244
}
11345

114-
initNav();
46+
47+
// initNav();

src/Elastic.Markdown/Assets/styles.css

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
}
8686

8787
.content-container {
88-
@apply w-full max-w-[80ch] lg:w-[80ch];
88+
@apply w-full max-w-[80ch];
8989
}
9090

9191
.applies {
@@ -137,3 +137,35 @@
137137
:is(a, button, input, textarea, summary):focus:not(:focus-visible) {
138138
outline: none;
139139
}
140+
141+
.htmx-indicator {
142+
display:none;
143+
}
144+
.htmx-request .htmx-indicator,
145+
.htmx-request.htmx-indicator{
146+
display:block;
147+
z-index: 9999;
148+
}
149+
150+
.progress {
151+
animation: progress 1s infinite linear;
152+
}
153+
154+
.left-right {
155+
transform-origin: 0% 50%;
156+
}
157+
@keyframes progress {
158+
0% {
159+
transform: translateX(0) scaleX(0);
160+
}
161+
40% {
162+
transform: translateX(0) scaleX(0.4);
163+
}
164+
100% {
165+
transform: translateX(100%) scaleX(0.5);
166+
}
167+
}
168+
169+
#pages-nav .current {
170+
@apply text-blue-elastic!;
171+
}

src/Elastic.Markdown/Assets/tabs.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,6 @@ function ready() {
5757
group
5858
);
5959
if (tabParam) {
60-
console.log(
61-
"sphinx-design: Selecting tab id for group '" +
62-
group +
63-
"' from URL parameter: " +
64-
tabParam
65-
);
6660
window.sessionStorage.setItem(storageKeyPrefix + group, tabParam);
6761
}
6862
}
@@ -72,9 +66,6 @@ function ready() {
7266
storageKeyPrefix + group
7367
);
7468
if (previousId === id) {
75-
// console.log(
76-
// "sphinx-design: Selecting tab from session storage: " + id
77-
// );
7869
// @ts-ignore
7970
label.previousElementSibling.checked = true;
8071
}
@@ -101,6 +92,5 @@ function onSDLabelClick() {
10192
}
10293

10394
export function initTabs() {
104-
console.log("inittabs");
105-
document.addEventListener("DOMContentLoaded", ready, false);
95+
ready();
10696
}
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
@inherits RazorSlice<LayoutViewModel>
2-
<aside class="sidebar hidden lg:block order-1 w-100 border-r-1 border-r-gray-200">
3-
<nav id="pages-nav" class="sidebar-nav pr-6"
2+
<aside class="sidebar hidden lg:block order-1 w-100 border-r-1 border-r-gray-200"
3+
>
4+
<nav
5+
id="pages-nav"
6+
class="sidebar-nav pr-6"
47
data-current-page-id="@Model.CurrentDocument.Id"
58
data-current-page-parent-ids="@(string.Join(",",Model.ParentIds))"
69
@* used to invalidate session storage *@
710
data-current-navigation="@LayoutViewModel.CurrentNavigationId">
8-
911
@(new HtmlString(Model.NavigationHtml))
1012
</nav>
11-
<script src="@Model.Static("pages-nav.js")"></script>
1213
</aside>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@inherits RazorSlice<NavigationViewModel>
22
<div class="pt-6 pb-20">
33
<div class="font-bold">Elastic Docs</div>
4-
<ul class="block w-full">
4+
<ul class="block">
55
@await RenderPartialAsync(_TocTreeNav.Create(new NavigationTreeItem
66
{
77
Level = Model.Tree.Depth,

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

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,19 @@
88
var f = file.File;
99
<li class="block ml-2 pl-2 border-l-1 border-l-gray-200 group/li">
1010
<div class="flex">
11-
<a class="sidebar-link my-1 ml-5 group-[.current]/li:text-blue-elastic!"
12-
id="page-@id" href="@f.Url">@f.NavigationTitle</a>
11+
<a
12+
hx-get="@f.Url"
13+
hx-select-oob="#markdown-content,#toc-nav,#prev-next-nav"
14+
hx-swap="none"
15+
hx-push-url="true"
16+
hx-indicator="#htmx-indicator"
17+
hx-swap="show:unset"
18+
preload="mouseover"
19+
class="sidebar-link my-1 ml-5 group-[.current]/li:text-blue-elastic!"
20+
id="page-@id"
21+
href="@f.Url">
22+
@f.NavigationTitle
23+
</a>
1324
</div>
1425
</li>
1526
}
@@ -38,6 +49,12 @@
3849
>
3950
<a
4051
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"
4158
4259
class="sidebar-link inline-block my-1 @(g.Depth == 1 ? "uppercase tracking-[0.05em] text-ink-light font-semibold" : string.Empty)">
4360
@g.Index?.NavigationTitle

0 commit comments

Comments
 (0)