Update template

This commit is contained in:
Fabien POLLY
2026-01-23 10:48:35 +01:00
parent 57d4b5b540
commit 695cf6671b
7 changed files with 342 additions and 103 deletions

View File

@@ -324,10 +324,13 @@
.nav-link.active { .nav-link.active {
background-color: var(--accent-dim); background-color: var(--accent-dim);
color: var(--accent-green); color: var(--accent-green);
border-left: 2px solid var(--accent-green);
padding-left: 0.5rem !important; padding-left: 0.5rem !important;
} }
.nav-link.active span {
background-color: var(--accent-green) !important;
}
/* TOC & Scroll */ /* TOC & Scroll */
.toc-link.active { .toc-link.active {
color: var(--accent-green); color: var(--accent-green);
@@ -464,6 +467,19 @@
} }
} }
/* Hide scrollbar for breadcrumbs */
#breadcrumbs {
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}
#breadcrumbs::-webkit-scrollbar {
display: none;
/* Chrome, Safari and Opera */
}
/* Toast Notification */ /* Toast Notification */
#toast-container { #toast-container {
position: fixed; position: fixed;
@@ -700,8 +716,9 @@
<aside id="mobile-toc-sidebar" <aside id="mobile-toc-sidebar"
class="sidebar-mobile fixed top-0 bottom-0 right-0 z-[70] w-[280px] bg-hack-sidebar border-l border-hack-border transform translate-x-full md:hidden flex flex-col shadow-2xl transition-transform duration-300"> class="sidebar-mobile fixed top-0 bottom-0 right-0 z-[70] w-[280px] bg-hack-sidebar border-l border-hack-border transform translate-x-full md:hidden flex flex-col shadow-2xl transition-transform duration-300">
<div class="p-4 border-b border-hack-border flex justify-between items-center bg-hack-bg/50"> <div class="p-4 border-b border-hack-border flex justify-between items-center bg-hack-bg/50">
<span id="label-mobile-toc" <div id="label-mobile-toc"
class="text-xs font-bold text-gray-500 uppercase tracking-widest font-mono">Table of Contents</span> class="text-[10px] font-bold text-hack-green uppercase tracking-widest px-3 py-1 bg-hack-greenDim border border-hack-border rounded-full font-mono truncate max-w-[200px]">
</div>
<button id="close-toc-btn" class="text-gray-400 hover:text-white"> <button id="close-toc-btn" class="text-gray-400 hover:text-white">
<i data-lucide="x" class="w-5 h-5"></i> <i data-lucide="x" class="w-5 h-5"></i>
</button> </button>
@@ -717,7 +734,7 @@
<div class="flex-1 min-w-0 content-transition-area"> <div class="flex-1 min-w-0 content-transition-area">
<div <div
class="flex flex-col md:flex-row md:items-center justify-between mb-6 gap-2 border-b border-hack-border/50 pb-4"> class="flex flex-col md:flex-row md:items-center justify-between mb-6 gap-2 border-b border-hack-border/50 pb-4">
<div class="flex items-center gap-2 text-xs font-mono text-gray-500 overflow-x-auto whitespace-nowrap pb-2 md:pb-0" <div class="flex items-center gap-2 text-xs font-mono text-gray-500 overflow-x-auto whitespace-nowrap md:pb-0"
id="breadcrumbs"></div> id="breadcrumbs"></div>
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
@@ -744,15 +761,18 @@
<aside class="hidden xl:block w-64 shrink-0"> <aside class="hidden xl:block w-64 shrink-0">
<div class="sticky top-6"> <div class="sticky top-6">
<h4 id="label-on-this-page" <div class="mb-6">
class="text-xs font-bold text-gray-500 uppercase tracking-widest mb-4 border-b border-hack-border pb-2"> <button id="label-on-this-page"
On this page</h4> class="text-[10px] font-bold text-hack-green uppercase tracking-widest px-3 py-1.5 bg-hack-greenDim border border-hack-border rounded-full transition-all hover:bg-hack-green hover:text-white text-left max-w-full truncate"
onclick="document.getElementById('scroll-container').scrollTo({top: 0, behavior: 'smooth'})">
</button>
</div>
<div class="relative"> <div class="relative">
<svg id="toc-svg"> <svg id="toc-svg">
<path id="toc-path" fill="none" stroke="var(--accent-green)" stroke-width="2" <path id="toc-path" fill="none" stroke="var(--accent-green)" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round" /> stroke-linecap="round" stroke-linejoin="round" />
</svg> </svg>
<ul id="toc-container" class="space-y-2 text-xs border-l border-hack-border pl-3"></ul> <ul id="toc-container" class="space-y-2 text-xs pl-3"></ul>
</div> </div>
</div> </div>
</aside> </aside>
@@ -793,7 +813,10 @@
searchIndex: [], searchIndex: [],
expandedSections: new Set(), expandedSections: new Set(),
repo: CONFIG.repo, repo: CONFIG.repo,
branch: CONFIG.branch branch: CONFIG.branch,
currentTitle: "",
currentFolder: "",
currentFilename: ""
}; };
// --- 1.5 INITIALIZE CONFIG --- // --- 1.5 INITIALIZE CONFIG ---
@@ -1074,20 +1097,24 @@
if (pageParam === 'changelog') { if (pageParam === 'changelog') {
toggleVersionsPage(null, false); toggleVersionsPage(null, false);
} else if (pageParam) { } else if (pageParam) {
let found = false; const flatList = getFlatPageList();
for (const [folder, files] of Object.entries(STATE.wikiData)) { const found = flatList.find(item => `${item.folder}/${item.file}` === pageParam || item.file === pageParam);
for (const [title, file] of Object.entries(files)) {
if (`${folder}/${file}` === pageParam || file === pageParam) { if (found) {
loadContent(folder, title, file, false); loadContent(found.folder, found.title, found.file, false);
STATE.expandedSections.add(folder); // Expand all parent folders
const parts = found.folder.split('/');
let current = "";
parts.forEach(p => {
if (p) {
current = current ? `${current}/${p}` : p;
STATE.expandedSections.add(current);
}
});
renderSidebar(); renderSidebar();
found = true; } else {
break; loadDefault();
} }
}
if (found) break;
}
if (!found) loadDefault();
} else { } else {
loadDefault(); loadDefault();
} }
@@ -1095,9 +1122,16 @@
async function buildSearchIndex() { async function buildSearchIndex() {
const promises = []; const promises = [];
for (const [folder, files] of Object.entries(STATE.wikiData)) {
for (const [title, filename] of Object.entries(files)) { function indexRecursive(data, currentPath = '') {
if (!filename.endsWith('.md')) continue; for (const [key, value] of Object.entries(data)) {
if (typeof value === 'object' && value !== null) {
const folderPath = currentPath ? `${currentPath}/${key}` : key;
indexRecursive(value, folderPath);
} else if (typeof value === 'string' && value.endsWith('.md')) {
const filename = value;
const title = key;
const folder = currentPath;
promises.push( promises.push(
fetch(`./wiki/${folder}/${filename}`) fetch(`./wiki/${folder}/${filename}`)
@@ -1114,18 +1148,33 @@
); );
} }
} }
}
indexRecursive(STATE.wikiData);
await Promise.all(promises); await Promise.all(promises);
} }
function loadDefault() { function getFlatPageList() {
const folders = Object.keys(STATE.wikiData); const flatList = [];
if (folders.length === 0) return; function traverse(data, currentPath = '') {
const firstFolder = folders[0]; for (const [key, value] of Object.entries(data)) {
const files = Object.keys(STATE.wikiData[firstFolder]); if (typeof value === 'object' && value !== null) {
if (files.length === 0) return; const folderPath = currentPath ? `${currentPath}/${key}` : key;
traverse(value, folderPath);
} else if (typeof value === 'string' && value.endsWith('.md')) {
flatList.push({ folder: currentPath, title: key, file: value });
}
}
}
traverse(STATE.wikiData);
return flatList;
}
const firstTitle = files[0]; function loadDefault() {
loadContent(firstFolder, firstTitle, STATE.wikiData[firstFolder][firstTitle], true); const flatList = getFlatPageList();
if (flatList.length === 0) return;
const first = flatList[0];
loadContent(first.folder, first.title, first.file, true);
} }
function showErrorState(msg) { function showErrorState(msg) {
@@ -1155,11 +1204,63 @@
const pageNav = document.getElementById('page-nav'); const pageNav = document.getElementById('page-nav');
const scrollContainer = document.getElementById('scroll-container'); const scrollContainer = document.getElementById('scroll-container');
const cleanFolder = folder.replace(/^\d+_/, '').replace(/_/g, ' '); STATE.currentTitle = title;
document.getElementById('breadcrumbs').innerHTML = ` STATE.currentFolder = folder;
<span class="hover:text-hack-heading cursor-pointer" onclick="loadDefault()">wiki</span> <span>/</span> STATE.currentFilename = filename;
<span>${cleanFolder}</span> <span>/</span> <span class="text-hack-green font-bold">${title}</span> document.getElementById('label-on-this-page').innerText = title;
document.getElementById('label-mobile-toc').innerText = title;
const flatList = getFlatPageList();
const idx = flatList.findIndex(item => item.folder === folder && item.title === title);
const prev = idx > 0 ? flatList[idx - 1] : null;
const next = idx < flatList.length - 1 ? flatList[idx + 1] : null;
const segments = folder.split('/').filter(s => s).map(s => s.replace(/^\d+_/, '').replace(/_/g, ' '));
const breadcrumbs = document.getElementById('breadcrumbs');
let breadcrumbParts = [];
breadcrumbParts.push(`<span class="hover:text-hack-heading cursor-pointer" onclick="loadDefault()">wiki</span>`);
if (segments.length > 2) {
breadcrumbParts.push(`<span class="opacity-50 cursor-help" title="${segments.slice(0, -1).join(' / ')}">...</span>`);
// For the last folder segment, find its first page
const lastFolderKey = folder.split('/').pop();
const folderData = folder.split('/').reduce((obj, key) => obj[key], STATE.wikiData);
const firstPage = Object.entries(folderData).find(([k, v]) => typeof v === 'string');
if (firstPage) {
breadcrumbParts.push(`<span class="hover:text-hack-heading cursor-pointer" onclick="loadContent('${folder}', '${firstPage[0]}', '${firstPage[1]}')">${segments[segments.length - 1]}</span>`);
} else {
breadcrumbParts.push(`<span>${segments[segments.length - 1]}</span>`);
}
} else {
let currentPath = "";
const folderParts = folder.split('/').filter(s => s);
segments.forEach((seg, i) => {
const partKey = folderParts[i];
currentPath = currentPath ? `${currentPath}/${partKey}` : partKey;
// Find first page in this specific folder level
const folderData = currentPath.split('/').reduce((obj, key) => obj[key], STATE.wikiData);
const firstPage = Object.entries(folderData).find(([k, v]) => typeof v === 'string');
if (firstPage) {
breadcrumbParts.push(`<span class="hover:text-hack-heading cursor-pointer" onclick="loadContent('${currentPath}', '${firstPage[0]}', '${firstPage[1]}')">${seg}</span>`);
} else {
breadcrumbParts.push(`<span>${seg}</span>`);
}
});
}
breadcrumbParts.push(`<span class="text-hack-green font-bold">${title}</span>`);
breadcrumbs.innerHTML = `
${prev ? `<button onclick="loadContent('${prev.folder}', '${prev.title}', '${prev.file}')" class="hover:text-hack-green transition-colors mr-1" title="Previous: ${prev.title}"><i data-lucide="chevron-left" class="w-3.5 h-3.5"></i></button>` : ''}
${breadcrumbParts.join(' <span class="opacity-30">/</span> ')}
${next ? `<button onclick="loadContent('${next.folder}', '${next.title}', '${next.file}')" class="hover:text-hack-green transition-colors ml-1" title="Next: ${next.title}"><i data-lucide="chevron-right" class="w-3.5 h-3.5"></i></button>` : ''}
`; `;
lucide.createIcons();
// Only show loader if not in RAM cache // Only show loader if not in RAM cache
if (!STATE.contentCache[`${folder}/${filename}`]) { if (!STATE.contentCache[`${folder}/${filename}`]) {
@@ -1303,12 +1404,7 @@
} }
function preloadAdjacent(currentFolder, currentTitle) { function preloadAdjacent(currentFolder, currentTitle) {
let flatList = []; const flatList = getFlatPageList();
for (const [folder, files] of Object.entries(STATE.wikiData)) {
for (const [title, file] of Object.entries(files)) {
flatList.push({ folder, title, file });
}
}
const idx = flatList.findIndex(item => item.folder === currentFolder && item.title === currentTitle); const idx = flatList.findIndex(item => item.folder === currentFolder && item.title === currentTitle);
[idx - 1, idx + 1].forEach(i => { [idx - 1, idx + 1].forEach(i => {
@@ -1403,12 +1499,7 @@
function renderPagination(currentFolder, currentTitle) { function renderPagination(currentFolder, currentTitle) {
const navContainer = document.getElementById('page-nav'); const navContainer = document.getElementById('page-nav');
let flatList = []; const flatList = getFlatPageList();
for (const [folder, files] of Object.entries(STATE.wikiData)) {
for (const [title, file] of Object.entries(files)) {
flatList.push({ folder, title, file });
}
}
const idx = flatList.findIndex(item => item.folder === currentFolder && item.title === currentTitle); const idx = flatList.findIndex(item => item.folder === currentFolder && item.title === currentTitle);
if (idx === -1) return; if (idx === -1) return;
@@ -1440,8 +1531,18 @@
const createTOCItem = (h, isMobile) => { const createTOCItem = (h, isMobile) => {
const li = document.createElement('li'); const li = document.createElement('li');
const link = document.createElement('a'); const link = document.createElement('a');
link.textContent = h.childNodes[0].textContent;
link.href = `#${h.id}`; // Extract text content excluding anchor links and other UI elements
let text = "";
h.childNodes.forEach(node => {
if (node.nodeType === Node.TEXT_NODE) {
text += node.textContent;
} else if (node.nodeType === Node.ELEMENT_NODE && !node.classList.contains('anchor-link')) {
text += node.innerText || node.textContent;
}
});
link.textContent = text.trim();
link.href = h.id ? `#${h.id}` : '#';
// Indentation based on tag // Indentation based on tag
let indentClass = ''; let indentClass = '';
@@ -1457,8 +1558,13 @@
link.onclick = (e) => { link.onclick = (e) => {
e.preventDefault(); e.preventDefault();
if (isMobile) closeTOC(); if (isMobile) closeTOC();
if (h.id) {
document.getElementById(h.id).scrollIntoView({ behavior: 'smooth' }); document.getElementById(h.id).scrollIntoView({ behavior: 'smooth' });
history.pushState(null, null, `#${h.id}`); history.pushState(null, null, `#${h.id}`);
} else {
document.getElementById('scroll-container').scrollTo({ top: 0, behavior: 'smooth' });
history.pushState(null, null, window.location.pathname + window.location.search);
}
}; };
li.appendChild(link); li.appendChild(link);
return li; return li;
@@ -1567,50 +1673,64 @@
container.innerHTML = ''; container.innerHTML = '';
let hasContent = false; let hasContent = false;
Object.keys(STATE.wikiData).forEach(folder => { function renderRecursive(data, parentContainer, currentPath = '', level = 0) {
if (searchResults && !searchResults[folder]) return; Object.keys(data).forEach(key => {
const value = data[key];
const isFolder = typeof value === 'object' && value !== null;
const cleanName = key.replace(/^\d+_/, '').replace(/_/g, ' ');
if (isFolder) {
const folderPath = currentPath ? `${currentPath}/${key}` : key;
if (searchResults && !searchResults[key]) return;
const cleanName = folder.replace(/^\d+_/, '').replace(/_/g, ' ');
const group = document.createElement('div'); const group = document.createElement('div');
group.className = 'nav-group mb-1'; group.className = `nav-group mb-1 ${level > 0 ? 'ml-2' : ''}`;
const btn = document.createElement('button'); const btn = document.createElement('button');
const isExpanded = STATE.expandedSections.has(folder) || searchResults; const isExpanded = STATE.expandedSections.has(folderPath) || searchResults;
btn.className = `section-header w-full flex items-center justify-between px-2 py-2 text-gray-500 hover:text-hack-heading transition-colors rounded hover:bg-hack-bg focus:outline-none focus:bg-hack-bg ${isExpanded ? 'active' : ''}`; btn.className = `section-header w-full flex items-center justify-between px-2 py-2 text-gray-500 hover:text-hack-heading transition-colors rounded hover:bg-hack-bg focus:outline-none focus:bg-hack-bg ${isExpanded ? 'active' : ''}`;
btn.innerHTML = ` btn.innerHTML = `
<span class="flex items-center gap-2 text-[11px] font-bold uppercase tracking-widest font-mono"><i data-lucide="folder" class="w-3 h-3"></i> ${cleanName}</span> <span class="flex items-center gap-2 text-[11px] font-bold uppercase tracking-widest font-mono"><i data-lucide="${level === 0 ? 'folder' : 'folder-open'}" class="w-3 h-3"></i> ${cleanName}</span>
<i data-lucide="chevron-right" class="section-arrow w-3 h-3 transition-transform"></i> <i data-lucide="chevron-right" class="section-arrow w-3 h-3 transition-transform"></i>
`; `;
btn.onclick = () => { btn.onclick = () => {
if (STATE.expandedSections.has(folder)) STATE.expandedSections.delete(folder); if (STATE.expandedSections.has(folderPath)) STATE.expandedSections.delete(folderPath);
else STATE.expandedSections.add(folder); else STATE.expandedSections.add(folderPath);
renderSidebar(searchResults); renderSidebar(searchResults);
}; };
const list = document.createElement('div'); const list = document.createElement('div');
list.className = `nav-list pl-2 border-l border-hack-border/30 ml-1 ${isExpanded ? 'expanded' : 'collapsed'}`; list.className = `nav-list ${isExpanded ? 'expanded' : 'collapsed'}`;
Object.keys(STATE.wikiData[folder]).forEach(title => { renderRecursive(value, list, folderPath, level + 1);
if (searchResults && !searchResults[folder][title]) return;
hasContent = true;
const filename = STATE.wikiData[folder][title];
const link = document.createElement('a');
link.href = `?page=${folder}/${filename}`;
link.className = 'nav-link group flex items-center gap-3 px-2 py-1.5 rounded-md text-sm font-medium text-gray-400 hover:text-hack-heading hover:bg-hack-bg transition-all outline-none focus:bg-hack-bg';
link.innerHTML = `<span class="w-1.5 h-1.5 rounded-full bg-hack-border group-hover:bg-hack-green flex-shrink-0 transition-colors"></span> ${title}`;
link.onclick = (e) => {
e.preventDefault();
loadContent(folder, title, filename);
document.querySelectorAll('.nav-link').forEach(l => l.classList.remove('active'));
link.classList.add('active');
};
list.appendChild(link);
});
group.appendChild(btn); group.appendChild(btn);
group.appendChild(list); group.appendChild(list);
container.appendChild(group); parentContainer.appendChild(group);
} else {
if (searchResults && !searchResults[currentPath]?.[key]) return;
hasContent = true;
const filename = value;
const link = document.createElement('a');
const fullPath = currentPath ? `${currentPath}/${filename}` : filename;
link.href = `?page=${fullPath}`;
const isActive = STATE.currentFolder === currentPath && STATE.currentFilename === filename;
link.className = `nav-link group flex items-center gap-3 px-2 py-1.5 rounded-md text-sm font-medium text-gray-400 hover:text-hack-heading hover:bg-hack-bg transition-all outline-none focus:bg-hack-bg ${isActive ? 'active' : ''}`;
link.innerHTML = `<span class="w-1.5 h-1.5 rounded-full bg-hack-border group-hover:bg-hack-green flex-shrink-0 transition-colors"></span> ${key}`;
link.onclick = (e) => {
e.preventDefault();
loadContent(currentPath, key, filename);
document.querySelectorAll('.nav-link').forEach(l => l.classList.remove('active'));
link.classList.add('active');
};
parentContainer.appendChild(link);
}
}); });
}
renderRecursive(STATE.wikiData, container);
if (!hasContent && searchResults) noResults.classList.remove('hidden'); if (!hasContent && searchResults) noResults.classList.remove('hidden');
else noResults.classList.add('hidden'); else noResults.classList.add('hidden');
@@ -1673,12 +1793,27 @@
async function performToggleVersionsPage(btn, pushHistory = true) { async function performToggleVersionsPage(btn, pushHistory = true) {
const viewer = document.getElementById('markdown-viewer'); const viewer = document.getElementById('markdown-viewer');
// Update state and UI labels
STATE.currentFolder = "";
STATE.currentFilename = "";
STATE.currentTitle = CONFIG.ui.changelogTitle;
document.getElementById('label-on-this-page').innerText = CONFIG.ui.changelogTitle;
document.getElementById('label-mobile-toc').innerText = CONFIG.ui.changelogTitle;
document.getElementById('breadcrumbs').innerHTML = `<span class="hover:text-hack-heading cursor-pointer" onclick="loadDefault()">${CONFIG.projectName}</span> <span>/</span> <span class="text-hack-green font-bold">${CONFIG.ui.changelogTitle}</span>`; document.getElementById('breadcrumbs').innerHTML = `<span class="hover:text-hack-heading cursor-pointer" onclick="loadDefault()">${CONFIG.projectName}</span> <span>/</span> <span class="text-hack-green font-bold">${CONFIG.ui.changelogTitle}</span>`;
document.getElementById('page-nav').innerHTML = ''; document.getElementById('page-nav').innerHTML = '';
document.getElementById('reading-time').innerHTML = ''; document.getElementById('reading-time').innerHTML = '';
document.getElementById('last-updated').innerHTML = ''; document.getElementById('last-updated').innerHTML = '';
viewer.innerHTML = `<h1>${CONFIG.ui.changelogTitle}</h1><div id="versions-list" class="space-y-4 mt-6"><div class="animate-pulse text-hack-green">${CONFIG.ui.fetchingReleasesText}</div></div>`; viewer.innerHTML = `<h1>${CONFIG.ui.changelogTitle}</h1><div id="versions-list" class="space-y-4 mt-6"><div class="animate-pulse text-hack-green">${CONFIG.ui.fetchingReleasesText}</div></div>`;
// Update TOC with initial H1
enhanceMarkdownContent();
generateTOC();
// Update sidebar to clear active links
renderSidebar();
if (pushHistory) window.history.pushState({ page: 'versions' }, "", "?page=changelog"); if (pushHistory) window.history.pushState({ page: 'versions' }, "", "?page=changelog");
try { try {
@@ -1704,8 +1839,15 @@
`; `;
list.appendChild(div); list.appendChild(div);
}); });
// Update TOC with new H2s
enhanceMarkdownContent();
generateTOC();
} catch (e) { } catch (e) {
document.getElementById('versions-list').innerHTML = `<p class="text-red-400">Unable to load changelog. Check back later.</p>`; document.getElementById('versions-list').innerHTML = `<p class="text-red-400">Unable to load changelog. Check back later.</p>`;
enhanceMarkdownContent();
generateTOC();
} }
} }

View File

@@ -0,0 +1 @@
# Test1

View File

@@ -0,0 +1 @@
# Test1

View File

@@ -0,0 +1,72 @@
# Long Page Test CSS
This page is designed to test the CSS rendering of various markdown elements, especially headings and long content.
## Level 2 Heading
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
### Level 3 Heading
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
#### Level 4 Heading
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
##### Level 5 Heading
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
###### Level 6 Heading
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.
## Lists and Formatting
### Unordered List
- Item 1
- Item 2
- Sub-item 2.1
- Sub-item 2.2
- Item 3
### Ordered List
1. First item
2. Second item
3. Third item
### Blockquotes
> This is a blockquote.
> It can span multiple lines.
> -- Someone Famous
### Code Blocks
```javascript
function helloWorld() {
console.log("Hello, world!");
}
```
Inline code: `const x = 10;`
### Tables
| Header 1 | Header 2 | Header 3 |
|----------|----------|----------|
| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |
| Row 2 Col 1 | Row 2 Col 2 | Row 2 Col 3 |
## More Content to Test Scrolling
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia ac.
### Another H3
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
#### Another H4
Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus.

View File

@@ -0,0 +1,7 @@
# Sub Page
This is a sub page located in a sub-category to test nested navigation.
## Content
Testing nested sidebar levels.

View File

@@ -0,0 +1,7 @@
# Sub Sub Page
This is a sub-sub page located in a sub-sub-category to test deep nested navigation.
## Content
Testing deep nested sidebar levels (3 levels deep).

View File

@@ -4,5 +4,14 @@
}, },
"02_Setup": { "02_Setup": {
"Installation": "Installation.md" "Installation": "Installation.md"
},
"03_Test_CSS": {
"Long Page": "Long_Page.md",
"Sub_Category": {
"Sub Page": "Sub_Page.md",
"Sub_Sub_Category": {
"Sub Sub Page": "Sub_Sub_Page.md"
}
}
} }
} }