Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 7 additions & 16 deletions src/Elastic.Markdown/Assets/copybutton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,19 +95,6 @@ if (!iconCopy) {
/**
* Set up copy/paste for code blocks
*/

const runWhenDOMLoaded = cb => {
if (document.readyState != 'loading') {
cb()
} else if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', cb)
} else {
document.attachEvent('onreadystatechange', function() {
if (document.readyState == 'complete') cb()
})
}
}

const codeCellId = index => `codecell${index}`

// Clears selected text since ClipboardJS will select the text when copying
Expand Down Expand Up @@ -145,9 +132,14 @@ const addCopyButtonToCodeCells = () => {
// happens because we load ClipboardJS asynchronously.

// Add copybuttons to all of our code cells
const COPYBUTTON_SELECTOR = 'div.highlight pre';
const COPYBUTTON_SELECTOR = '.markdown-content div.highlight pre';
const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR)
codeCells.forEach((codeCell, index) => {

if (codeCell.id != "") {
return
}

const id = codeCellId(index)
codeCell.setAttribute('id', id)

Expand Down Expand Up @@ -256,6 +248,5 @@ var copyTargetText = (trigger) => {
}

export function initCopyButton() {
console.log("initCopyButton");
runWhenDOMLoaded(addCopyButtonToCodeCells)
addCopyButtonToCodeCells()
}
4 changes: 2 additions & 2 deletions src/Elastic.Markdown/Assets/hljs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,6 @@ hljs.registerLanguage('esql', function() {

hljs.addPlugin(mergeHTMLPlugin);
export function initHighlight() {

hljs.highlightAll();
document.querySelectorAll('.markdown-content pre code:not(.hljs)')
.forEach((block) => { hljs.highlightElement(block as HTMLElement); });
}
24 changes: 19 additions & 5 deletions src/Elastic.Markdown/Assets/main.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
import {initTocNav} from "./toc-nav";
import {initHighlight} from "./hljs";
import {initTabs} from "./tabs";
import {initCopyButton} from "./copybutton";
import {initNav} from "./pages-nav";
import {initHighlight} from "./hljs";



up.link.config.followSelectors.push('a[href]')
up.link.config.preloadSelectors.push('a[href]')


initTocNav();
initHighlight();
initCopyButton();
initTabs();
up.compiler('.markdown-content, #toc-nav', () => {
window.scrollTo(0, 0);
const destroyTocNav = initTocNav();
initNav();
initHighlight();
initCopyButton();
initTabs();
return () => {
destroyTocNav();
}
})
98 changes: 12 additions & 86 deletions src/Elastic.Markdown/Assets/pages-nav.ts
Original file line number Diff line number Diff line change
@@ -1,87 +1,21 @@
import {$, $$} from "select-dom";

type NavExpandState = {
current:string,
selected: Record<string, boolean>
};
const PAGE_NAV_EXPAND_STATE_KEY = 'pagesNavState';

// Initialize the nav state from the session storage
// Return a function to keep the nav state in the session storage that should be called before the page is unloaded
function keepNavState(nav: HTMLElement): () => void {

const currentNavigation = nav.dataset.currentNavigation;
const currentPageId = nav.dataset.currentPageId;

let navState = JSON.parse(sessionStorage.getItem(PAGE_NAV_EXPAND_STATE_KEY) ?? "{}") as NavExpandState
if (navState.current !== currentNavigation)
{
sessionStorage.removeItem(PAGE_NAV_EXPAND_STATE_KEY);
navState = { current: currentNavigation } as NavExpandState;
}
if (currentPageId)
{
const currentPageLink = $('a[id="page-' + currentPageId + '"]', nav);
currentPageLink.classList.add('current');
currentPageLink.classList.add('pointer-events-none');
currentPageLink.classList.add('text-blue-elastic!');
currentPageLink.classList.add('font-semibold');

const parentIds = nav.dataset.currentPageParentIds?.split(',') ?? [];
for (const parentId of parentIds)
{
const input = $('input[type="checkbox"][id=\"'+parentId+'\"]', nav) as HTMLInputElement;
if (input) {
input.checked = true;
const link = input.nextElementSibling as HTMLAnchorElement;
link.classList.add('font-semibold');
}
import {$} from "select-dom";

function expandAllParents(navItem: HTMLElement) {
let parent = navItem.closest('li');
while (parent) {
const input = parent.querySelector('input');
if (input) {
(input as HTMLInputElement).checked = true;
}
}

// expand items previously selected
for (const groupId in navState.selected)
{
const input = $('input[type="checkbox"][id=\"'+groupId+'\"]', nav) as HTMLInputElement;
input.checked = navState.selected[groupId];
}

return () => {
// store all expanded groups
const inputs = $$('input[type="checkbox"]:checked', nav);
const selectedMap: Record<string, boolean> = inputs
.filter(input => input.checked)
.reduce((state: Record<string, boolean>, input) => {
const key = input.id;
const value = input.checked;
return { ...state, [key]: value};
}, {});
const state = { current: currentNavigation, selected: selectedMap };
sessionStorage.setItem(PAGE_NAV_EXPAND_STATE_KEY, JSON.stringify(state));
}
}

type NavScrollPosition = number;
const PAGE_NAV_SCROLL_POSITION_KEY = 'pagesNavScrollPosition';
const pagesNavScrollPosition: NavScrollPosition = parseInt(
sessionStorage.getItem(PAGE_NAV_SCROLL_POSITION_KEY) ?? '0'
);


// Initialize the nav scroll position from the session storage
// Return a function to keep the nav scroll position in the session storage that should be called before the page is unloaded
function keepNavPosition(nav: HTMLElement): () => void {
if (pagesNavScrollPosition) {
nav.scrollTop = pagesNavScrollPosition;
}
return () => {
sessionStorage.setItem(PAGE_NAV_SCROLL_POSITION_KEY, nav.scrollTop.toString());
parent = parent.parentElement?.closest('li');
}
}

function scrollCurrentNaviItemIntoView(nav: HTMLElement, delay: number) {
const currentNavItem = $('.up-current', nav);
expandAllParents(currentNavItem);
setTimeout(() => {
const currentNavItem = $('.current', nav);

if (currentNavItem && !isElementInViewport(currentNavItem)) {
currentNavItem.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
Expand All @@ -102,13 +36,5 @@ export function initNav() {
if (!pagesNav) {
return;
}
const keepNavStateCallback = keepNavState(pagesNav);
const keepNavPositionCallback = keepNavPosition(pagesNav);
scrollCurrentNaviItemIntoView(pagesNav, 100);
window.addEventListener('beforeunload', () => {
keepNavStateCallback();
keepNavPositionCallback();
}, true);
}

initNav();
17 changes: 14 additions & 3 deletions src/Elastic.Markdown/Assets/styles.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import "tailwindcss";
/*@import "unpoly/unpoly.css";*/
@import "./fonts.css";
@import "./theme.css";
@import "./markdown/typography.css";
Expand Down Expand Up @@ -85,7 +86,7 @@
}

.content-container {
@apply w-full max-w-[80ch] lg:w-[80ch];
@apply w-full max-w-[80ch];
}

.applies {
Expand Down Expand Up @@ -119,9 +120,9 @@

:root {
--outline-size: max(2px, 0.08em);
--outline-style: auto;
--outline-style: solid;
--outline-color: var(--color-blue-elastic);
--outline-offset: 5;
--outline-offset: 10;
}

:is(a, button, input, textarea, summary):focus {
Expand All @@ -137,3 +138,13 @@
:is(a, button, input, textarea, summary):focus:not(:focus-visible) {
outline: none;
}

up-progress-bar {
@apply bg-pink-90!;
}

#pages-nav {
.up-current {
@apply text-blue-elastic!;
}
}
15 changes: 2 additions & 13 deletions src/Elastic.Markdown/Assets/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function ready() {
/** @type {string[]} */
let groups = [];

document.querySelectorAll(".tabs-label").forEach((label) => {
document.querySelectorAll(".markdown-content .tabs-label").forEach((label) => {
if (label instanceof HTMLElement) {
let data = create_key(label);
if (data) {
Expand All @@ -57,12 +57,6 @@ function ready() {
group
);
if (tabParam) {
console.log(
"sphinx-design: Selecting tab id for group '" +
group +
"' from URL parameter: " +
tabParam
);
window.sessionStorage.setItem(storageKeyPrefix + group, tabParam);
}
}
Expand All @@ -72,10 +66,6 @@ function ready() {
storageKeyPrefix + group
);
if (previousId === id) {
// console.log(
// "sphinx-design: Selecting tab from session storage: " + id
// );
// @ts-ignore
label.previousElementSibling.checked = true;
}
}
Expand All @@ -101,6 +91,5 @@ function onSDLabelClick() {
}

export function initTabs() {
console.log("inittabs");
document.addEventListener("DOMContentLoaded", ready, false);
ready();
}
44 changes: 29 additions & 15 deletions src/Elastic.Markdown/Assets/toc-nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,31 +110,45 @@ function updateIndicator(elements: TocElements) {
}
}

function setupSmoothScrolling(elements: TocElements) {
elements.tocLinks.forEach(link => {
link.addEventListener('click', (e) => {
const href = link.getAttribute('href');
if (href?.charAt(0) === '#') {
e.preventDefault();
const target = document.getElementById(href.slice(1));
if (target) {
target.scrollIntoView({ behavior: 'smooth' });
history.pushState(null, '', href);
}
function setupSmoothScrolling(elements: TocElements): () => void {
const clickHandler = (e: Event) => {
const link = e.currentTarget as HTMLAnchorElement;
const href = link.getAttribute('href');
if (href?.charAt(0) === '#') {
e.preventDefault();
const target = document.getElementById(href.slice(1));
if (target) {
target.scrollIntoView({ behavior: 'smooth' });
history.pushState(null, '', href);
}
});
}
};

elements.tocLinks.forEach(link => {
link.addEventListener('click', clickHandler);
});

return () => {
elements.tocLinks.forEach(link => {
link.removeEventListener('click', clickHandler);
});
};
}

export function initTocNav() {
export function initTocNav(): () => void {
const elements = initializeTocElements();
if (elements.progressIndicator != null) {
elements.progressIndicator.style.height = '0';
elements.progressIndicator.style.top = '0';
}
const update = () => updateIndicator(elements)
const update = () => updateIndicator(elements);
update();
window.addEventListener('scroll', update);
window.addEventListener('resize', update);
setupSmoothScrolling(elements);
const removeSmoothScrolling = setupSmoothScrolling(elements);
return () => {
window.removeEventListener('scroll', update);
window.removeEventListener('resize', update);
removeSmoothScrolling();
};
}
4 changes: 2 additions & 2 deletions src/Elastic.Markdown/Slices/Layout/_PagesNav.cshtml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
@inherits RazorSlice<LayoutViewModel>
<aside class="sidebar hidden lg:block order-1 w-100 border-r-1 border-r-gray-200">
<aside class="sidebar hidden lg:block order-1 border-r-1 border-r-gray-200">
<nav id="pages-nav" class="sidebar-nav pr-6"
data-current-page-id="@Model.CurrentDocument.Id"
data-current-page-parent-ids="@(string.Join(",",Model.ParentIds))"
data-current-page-parent-ids="@(string.Join(",", Model.ParentIds))"
@* used to invalidate session storage *@
data-current-navigation="@LayoutViewModel.CurrentNavigationId">

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@inherits RazorSlice<LayoutViewModel>
<aside class="sidebar hidden lg:block order-3 border-l-1 border-l-gray-200 w-80">
<nav id="toc-nav" class="sidebar-nav pl-6">
<nav id="toc-nav" class="sidebar-nav pl-6" up-hungry>
<div class="pt-6 pb-20">
@if (Model.PageTocItems.Count > 0)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Elastic.Markdown/Slices/Layout/_TocTree.cshtml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@inherits RazorSlice<NavigationViewModel>
<div class="pt-6 pb-20">
<div class="pt-6 pb-20 w-60">
<div class="font-bold">Elastic Docs</div>
<ul class="block w-full">
<ul class="block">
@await RenderPartialAsync(_TocTreeNav.Create(new NavigationTreeItem
{
Level = Model.Tree.Depth,
Expand Down
Loading