Add loading state for links in file index and folder links

This commit is contained in:
2026-01-02 13:33:26 +11:00
parent 8d0a0fa50e
commit 7da85222c8
2 changed files with 79 additions and 0 deletions

View File

@@ -224,11 +224,13 @@ export class DOMService {
link.href = `?${doc.slug}`; link.href = `?${doc.slug}`;
link.textContent = doc.title || doc.path.split('/').pop().replace('.md', ''); link.textContent = doc.title || doc.path.split('/').pop().replace('.md', '');
link.dataset.path = doc.path; link.dataset.path = doc.path;
link.dataset.slug = doc.slug;
link.style.paddingLeft = `${(level * 0.6) + 0.8}rem`; link.style.paddingLeft = `${(level * 0.6) + 0.8}rem`;
link.setAttribute('role', 'treeitem'); link.setAttribute('role', 'treeitem');
link.onclick = (e) => { link.onclick = (e) => {
e.preventDefault(); e.preventDefault();
this.setLinkLoading(link);
this.eventBus.emit('navigation:requested', { slug: doc.slug }); this.eventBus.emit('navigation:requested', { slug: doc.slug });
history.pushState(null, '', link.href); history.pushState(null, '', link.href);
if (window.innerWidth <= 1000) { if (window.innerWidth <= 1000) {
@@ -239,11 +241,30 @@ export class DOMService {
container.appendChild(link); container.appendChild(link);
} }
/**
* Sets a link to loading state.
* @param {HTMLAnchorElement} link - The link element.
*/
setLinkLoading(link) {
this.clearAllLoading();
link.classList.add('loading');
}
/**
* Clears loading state from all links.
*/
clearAllLoading() {
this.elements.fileIndex.querySelectorAll('a.loading, .folder-link.loading').forEach(link => {
link.classList.remove('loading');
});
}
/** /**
* Updates the active document highlight in the sidebar. * Updates the active document highlight in the sidebar.
* @param {string} path - The path of the active document. * @param {string} path - The path of the active document.
*/ */
updateActiveDocument(path) { updateActiveDocument(path) {
this.clearAllLoading();
this.elements.fileIndex.querySelectorAll('a').forEach(link => { this.elements.fileIndex.querySelectorAll('a').forEach(link => {
const isActive = link.dataset.path === path; const isActive = link.dataset.path === path;
link.classList.toggle('active', isActive); link.classList.toggle('active', isActive);
@@ -326,6 +347,8 @@ export class DOMService {
folderHeader.addEventListener('click', (e) => { folderHeader.addEventListener('click', (e) => {
if (e.target.closest('.folder-link')) { if (e.target.closest('.folder-link')) {
e.preventDefault(); e.preventDefault();
const folderLink = e.target.closest('.folder-link');
this.setFolderLinkLoading(folderLink);
this.eventBus.emit('navigation:requested', { slug: doc.slug }); this.eventBus.emit('navigation:requested', { slug: doc.slug });
history.pushState(null, '', `?${doc.slug}`); history.pushState(null, '', `?${doc.slug}`);
if (window.innerWidth <= 1000) { if (window.innerWidth <= 1000) {
@@ -356,6 +379,15 @@ export class DOMService {
}); });
} }
/**
* Sets a folder link to loading state.
* @param {HTMLAnchorElement} link - The folder link element.
*/
setFolderLinkLoading(link) {
this.clearAllLoading();
link.classList.add('loading');
}
/** /**
* Scrolls smoothly to an element with header offset. * Scrolls smoothly to an element with header offset.
* @param {HTMLElement} element - The element to scroll to. * @param {HTMLElement} element - The element to scroll to.

View File

@@ -276,6 +276,38 @@ body {
display: block; display: block;
padding: 0.4rem 0.8rem; padding: 0.4rem 0.8rem;
font-size: 0.875rem; font-size: 0.875rem;
position: relative;
transition: background-color 0.2s ease;
}
#file-index a.loading {
pointer-events: none;
color: var(--ifm-color-content-secondary);
}
#file-index a.loading::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
height: 2px;
background: var(--ifm-color-primary);
animation: loading-progress 1s ease-in-out infinite;
}
@keyframes loading-progress {
0% {
width: 0%;
left: 0;
}
50% {
width: 70%;
left: 0;
}
100% {
width: 0%;
left: 100%;
}
} }
#file-index a:hover { #file-index a:hover {
@@ -334,6 +366,21 @@ body {
right: 0; right: 0;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
transition: opacity 0.2s ease;
}
.folder-link.loading {
opacity: 1;
color: var(--ifm-color-primary);
}
.folder-link.loading i {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
} }
.folder-header:hover .folder-link { .folder-header:hover .folder-link {