mirror of
https://github.com/litruv/Docs-Viewer.git
synced 2026-07-24 02:36:07 +10:00
accessibility stuff, printing, search
This commit is contained in:
152
index.html
152
index.html
@@ -13,45 +13,49 @@
|
|||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Add skip to content link -->
|
||||||
|
<a href="#document-content" class="skip-to-content">Skip to content</a>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="title-bar">
|
<div class="title-bar" role="banner">
|
||||||
<button class="menu-button" aria-label="Toggle Menu">
|
<button class="menu-button" aria-label="Toggle Menu" aria-expanded="false" aria-controls="left-sidebar">
|
||||||
<i class="fas fa-bars"></i>
|
<i class="fas fa-bars" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="title-text">
|
<div class="title-text">
|
||||||
<img src="./img/logo.png" alt="Litruv" class="brand-logo">
|
<img src="./img/logo.png" alt="Litruv" class="brand-logo">
|
||||||
<span class="divider">/</span>
|
<span class="divider" aria-hidden="true">/</span>
|
||||||
<span class="page-title">Documentation</span>
|
<span class="page-title">Documentation</span>
|
||||||
</div>
|
</div>
|
||||||
<span style="width: 24px;"></span>
|
<span style="width: 24px;"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<nav class="sidebar left-sidebar">
|
<nav class="sidebar left-sidebar" id="left-sidebar" role="navigation" aria-label="Main Navigation">
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<div class="search-box">
|
<div class="search-box" role="search">
|
||||||
<i class="fas fa-search"></i>
|
<i class="fas fa-search" aria-hidden="true"></i>
|
||||||
<input type="text" id="search-input" placeholder="Search docs...">
|
<input type="text" id="search-input" placeholder="Search docs..." aria-label="Search documentation">
|
||||||
<i class="fas fa-times" id="clear-search"></i>
|
<div class="keyboard-shortcut keyboard-shortcut-alt" aria-hidden="true">Alt+S</div>
|
||||||
|
<i class="fas fa-times" id="clear-search" aria-label="Clear search"></i>
|
||||||
</div>
|
</div>
|
||||||
<div id="search-results"></div>
|
<div id="search-results" role="region" aria-label="Search results" aria-live="polite"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="file-index"></div>
|
<div id="file-index" role="tree" aria-label="Documentation files"></div>
|
||||||
<div class="subtitle">
|
<div class="subtitle" aria-label="Author information">
|
||||||
<span class="name"></span>
|
<span class="name"></span>
|
||||||
<span class="role"></span>
|
<span class="role"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="social-links"></div>
|
<div class="social-links" aria-label="Social media links"></div>
|
||||||
<div class="github-link">
|
<div class="github-link">
|
||||||
<a href="https://github.com/litruv/docs" target="_blank" title="Docs Viewer GitHub">
|
<a href="https://github.com/litruv/docs" target="_blank" title="Docs Viewer GitHub" aria-label="GitHub repository for Docs Viewer">
|
||||||
<i class="fab fa-github"></i> Docs Viewer
|
<i class="fab fa-github" aria-hidden="true"></i> Docs Viewer
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<main class="content">
|
<main class="content" role="main" aria-label="Document Content">
|
||||||
<div id="document-content"></div>
|
<div id="document-content" tabindex="-1"></div>
|
||||||
</main>
|
</main>
|
||||||
<nav class="sidebar right-sidebar">
|
<nav class="sidebar right-sidebar" role="navigation" aria-label="Table of Contents">
|
||||||
<div id="document-outline"></div>
|
<div id="document-outline" role="tree" aria-label="Document outline"></div>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -61,5 +65,115 @@
|
|||||||
hljs.highlightAll();
|
hljs.highlightAll();
|
||||||
</script>
|
</script>
|
||||||
<script src="index.js"></script>
|
<script src="index.js"></script>
|
||||||
|
|
||||||
|
<!-- Print title capture script -->
|
||||||
|
<script>
|
||||||
|
// Capture page title for printing
|
||||||
|
window.addEventListener('beforeprint', function() {
|
||||||
|
// Get the current page title
|
||||||
|
const pageTitle = document.querySelector('.title-text .page-title').textContent;
|
||||||
|
const brandLogo = document.querySelector('.brand-logo').cloneNode(true);
|
||||||
|
|
||||||
|
// Create print header with logo
|
||||||
|
const printHeader = document.createElement('div');
|
||||||
|
printHeader.className = 'print-header';
|
||||||
|
|
||||||
|
// Add the logo image
|
||||||
|
printHeader.appendChild(brandLogo);
|
||||||
|
|
||||||
|
// Add the divider and page title
|
||||||
|
const titleText = document.createElement('div');
|
||||||
|
titleText.className = 'print-title-text';
|
||||||
|
titleText.innerHTML = `<span class="divider">/</span> <span class="page-title">${pageTitle}</span>`;
|
||||||
|
printHeader.appendChild(titleText);
|
||||||
|
|
||||||
|
// Insert at the beginning of content
|
||||||
|
const content = document.getElementById('document-content');
|
||||||
|
if (content.firstChild) {
|
||||||
|
content.insertBefore(printHeader, content.firstChild);
|
||||||
|
} else {
|
||||||
|
content.appendChild(printHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any existing print elements to avoid duplication
|
||||||
|
const existingTitle = document.querySelector('.print-title');
|
||||||
|
if (existingTitle) existingTitle.remove();
|
||||||
|
|
||||||
|
// Make sure the print header is accessible
|
||||||
|
brandLogo.setAttribute('alt', 'Litruv logo');
|
||||||
|
printHeader.setAttribute('aria-hidden', 'true'); // Hide from screen readers when printing
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clean up after printing
|
||||||
|
window.addEventListener('afterprint', function() {
|
||||||
|
const printHeader = document.querySelector('.print-header');
|
||||||
|
if (printHeader) {
|
||||||
|
printHeader.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add accessibility enhancements script -->
|
||||||
|
<script>
|
||||||
|
// Enhance keyboard navigation
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Make folders and navigation keyboard accessible
|
||||||
|
function enhanceTreeKeyboardNavigation() {
|
||||||
|
const folders = document.querySelectorAll('.folder-header');
|
||||||
|
const links = document.querySelectorAll('#file-index a, #document-outline a');
|
||||||
|
|
||||||
|
folders.forEach(folder => {
|
||||||
|
// Add ARIA attributes
|
||||||
|
const folderDiv = folder.closest('.folder');
|
||||||
|
const isOpen = folderDiv.classList.contains('open');
|
||||||
|
folder.setAttribute('role', 'treeitem');
|
||||||
|
folder.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
|
||||||
|
|
||||||
|
// Handle keyboard events
|
||||||
|
folder.addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault();
|
||||||
|
folder.click();
|
||||||
|
folder.setAttribute('aria-expanded',
|
||||||
|
folderDiv.classList.contains('open') ? 'true' : 'false');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
folder.setAttribute('tabindex', '0');
|
||||||
|
});
|
||||||
|
|
||||||
|
links.forEach(link => {
|
||||||
|
link.setAttribute('role', 'treeitem');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle menu button accessibility
|
||||||
|
const menuButton = document.querySelector('.menu-button');
|
||||||
|
if (menuButton) {
|
||||||
|
menuButton.addEventListener('click', function() {
|
||||||
|
const expanded = document.querySelector('.left-sidebar').classList.contains('show');
|
||||||
|
menuButton.setAttribute('aria-expanded', expanded ? 'true' : 'false');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// If using a MutationObserver to watch for DOM changes, call enhanceTreeKeyboardNavigation
|
||||||
|
// after the navigation tree is populated
|
||||||
|
const observer = new MutationObserver(function(mutations) {
|
||||||
|
mutations.forEach(function(mutation) {
|
||||||
|
if (mutation.addedNodes.length) {
|
||||||
|
enhanceTreeKeyboardNavigation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(document.getElementById('file-index'), {
|
||||||
|
childList: true,
|
||||||
|
subtree: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initially enhance any existing navigation
|
||||||
|
enhanceTreeKeyboardNavigation();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
129
index.js
129
index.js
@@ -193,8 +193,10 @@ class DOMService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setupMobileMenu() {
|
setupMobileMenu() {
|
||||||
this.elements.menuButton.addEventListener('click', () =>
|
this.elements.menuButton.addEventListener('click', () => {
|
||||||
this.elements.leftSidebar.classList.toggle('show'));
|
const isExpanded = this.elements.leftSidebar.classList.toggle('show');
|
||||||
|
this.elements.menuButton.setAttribute('aria-expanded', isExpanded ? 'true' : 'false');
|
||||||
|
});
|
||||||
|
|
||||||
this.elements.content.addEventListener('click', () =>
|
this.elements.content.addEventListener('click', () =>
|
||||||
this.elements.leftSidebar.classList.remove('show'));
|
this.elements.leftSidebar.classList.remove('show'));
|
||||||
@@ -224,6 +226,9 @@ class DOMService {
|
|||||||
|
|
||||||
const folderHeader = document.createElement('div');
|
const folderHeader = document.createElement('div');
|
||||||
folderHeader.className = 'folder-header';
|
folderHeader.className = 'folder-header';
|
||||||
|
folderHeader.setAttribute('role', 'treeitem');
|
||||||
|
folderHeader.setAttribute('aria-expanded', doc.defaultOpen !== false ? 'true' : 'false');
|
||||||
|
folderHeader.setAttribute('tabindex', '0');
|
||||||
const iconClass = doc.icon || `fas fa-folder${doc.defaultOpen !== false ? '-open' : ''}`;
|
const iconClass = doc.icon || `fas fa-folder${doc.defaultOpen !== false ? '-open' : ''}`;
|
||||||
|
|
||||||
// Only add folder click handler if showfolderpage is not false
|
// Only add folder click handler if showfolderpage is not false
|
||||||
@@ -235,12 +240,22 @@ class DOMService {
|
|||||||
// Only setup the folder open/close functionality
|
// Only setup the folder open/close functionality
|
||||||
folderHeader.addEventListener('click', () => {
|
folderHeader.addEventListener('click', () => {
|
||||||
folderDiv.classList.toggle('open');
|
folderDiv.classList.toggle('open');
|
||||||
|
const isExpanded = folderDiv.classList.contains('open');
|
||||||
|
folderHeader.setAttribute('aria-expanded', isExpanded ? 'true' : 'false');
|
||||||
if (!doc.icon) {
|
if (!doc.icon) {
|
||||||
const icon = folderHeader.querySelector('.folder-icon');
|
const icon = folderHeader.querySelector('.folder-icon');
|
||||||
icon.classList.toggle('fa-folder-closed');
|
icon.classList.toggle('fa-folder-closed');
|
||||||
icon.classList.toggle('fa-folder-open');
|
icon.classList.toggle('fa-folder-open');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add keyboard accessibility
|
||||||
|
folderHeader.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault();
|
||||||
|
folderHeader.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const folderContent = document.createElement('div');
|
const folderContent = document.createElement('div');
|
||||||
@@ -261,6 +276,7 @@ class DOMService {
|
|||||||
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.style.paddingLeft = `${(level * 0.6) + 0.8}rem`; // Add base padding of 0.8rem
|
link.style.paddingLeft = `${(level * 0.6) + 0.8}rem`; // Add base padding of 0.8rem
|
||||||
|
link.setAttribute('role', 'treeitem');
|
||||||
|
|
||||||
link.onclick = (e) => {
|
link.onclick = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -304,19 +320,19 @@ class DOMService {
|
|||||||
const showFolderPage = doc.showfolderpage !== 'false';
|
const showFolderPage = doc.showfolderpage !== 'false';
|
||||||
return `
|
return `
|
||||||
<div class="folder-icons">
|
<div class="folder-icons">
|
||||||
<i class="${iconClass} folder-icon"></i>
|
<i class="${iconClass} folder-icon" aria-hidden="true"></i>
|
||||||
</div>
|
</div>
|
||||||
<span>${doc.title}</pan>
|
<span>${doc.title}</span>
|
||||||
${showFolderPage ? `
|
${showFolderPage ? `
|
||||||
<a href="?${doc.slug}" class="folder-link" title="View folder page">
|
<a href="?${doc.slug}" class="folder-link" title="View folder page" aria-label="View ${doc.title} folder page">
|
||||||
<i class="fas fa-file-alt"></i>
|
<i class="fas fa-file-alt" aria-hidden="true"></i>
|
||||||
</a>` : ''}`;
|
</a>` : ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
createFolderHeaderBasic(iconClass, doc) {
|
createFolderHeaderBasic(iconClass, doc) {
|
||||||
return `
|
return `
|
||||||
<div class="folder-icons">
|
<div class="folder-icons">
|
||||||
<i class="${iconClass} folder-icon"></i>
|
<i class="${iconClass} folder-icon" aria-hidden="true"></i>
|
||||||
</div>
|
</div>
|
||||||
<span>${doc.title}</span>`;
|
<span>${doc.title}</span>`;
|
||||||
}
|
}
|
||||||
@@ -334,12 +350,26 @@ class DOMService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
folderDiv.classList.toggle('open');
|
folderDiv.classList.toggle('open');
|
||||||
|
const isExpanded = folderDiv.classList.contains('open');
|
||||||
|
folderHeader.setAttribute('aria-expanded', isExpanded ? 'true' : 'false');
|
||||||
if (!doc.icon) {
|
if (!doc.icon) {
|
||||||
const icon = folderHeader.querySelector('.folder-icon');
|
const icon = folderHeader.querySelector('.folder-icon');
|
||||||
icon.classList.toggle('fa-folder-closed');
|
icon.classList.toggle('fa-folder-closed');
|
||||||
icon.classList.toggle('fa-folder-open');
|
icon.classList.toggle('fa-folder-open');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add keyboard support
|
||||||
|
folderHeader.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault();
|
||||||
|
if (e.target.closest('.folder-link')) {
|
||||||
|
e.target.closest('.folder-link').click();
|
||||||
|
} else {
|
||||||
|
folderHeader.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollToElement(element) {
|
scrollToElement(element) {
|
||||||
@@ -425,6 +455,8 @@ class DOMService {
|
|||||||
this.elements.searchInput.value = '';
|
this.elements.searchInput.value = '';
|
||||||
this.elements.searchResults.innerHTML = '';
|
this.elements.searchResults.innerHTML = '';
|
||||||
this.elements.searchResults.style.display = 'none';
|
this.elements.searchResults.style.display = 'none';
|
||||||
|
// Announce to screen readers
|
||||||
|
this.elements.searchResults.setAttribute('aria-hidden', 'true');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,9 +466,18 @@ class DOMService {
|
|||||||
|
|
||||||
if (results.length === 0 || !this.elements.searchInput.value) {
|
if (results.length === 0 || !this.elements.searchInput.value) {
|
||||||
container.style.display = 'none';
|
container.style.display = 'none';
|
||||||
|
container.setAttribute('aria-hidden', 'true');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update for screen readers
|
||||||
|
container.setAttribute('aria-hidden', 'false');
|
||||||
|
if (results.length === 1) {
|
||||||
|
container.setAttribute('aria-label', '1 search result found');
|
||||||
|
} else {
|
||||||
|
container.setAttribute('aria-label', `${results.length} search results found`);
|
||||||
|
}
|
||||||
|
|
||||||
results.forEach(result => {
|
results.forEach(result => {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.className = 'search-result';
|
div.className = 'search-result';
|
||||||
@@ -686,6 +727,7 @@ class Documentation {
|
|||||||
this.navigationService = new NavigationService(this.eventBus, this.documentService);
|
this.navigationService = new NavigationService(this.eventBus, this.documentService);
|
||||||
|
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
|
this.setupKeyboardShortcuts();
|
||||||
}
|
}
|
||||||
|
|
||||||
setupEventListeners() {
|
setupEventListeners() {
|
||||||
@@ -713,6 +755,79 @@ class Documentation {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupKeyboardShortcuts() {
|
||||||
|
// Add keyboard shortcut for search (S key)
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
// Only trigger if user is not typing in an input, textarea, or contenteditable element
|
||||||
|
const isTyping = ['INPUT', 'TEXTAREA'].includes(document.activeElement.tagName) ||
|
||||||
|
document.activeElement.isContentEditable;
|
||||||
|
|
||||||
|
// Search shortcut (S key or Alt+S)
|
||||||
|
if (((e.key === 's' || e.key === 'S') && !e.ctrlKey && !e.metaKey &&
|
||||||
|
(!e.altKey || (e.altKey && (e.key === 's' || e.key === 'S')))) &&
|
||||||
|
!isTyping) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Focus the search input
|
||||||
|
const searchInput = document.getElementById('search-input');
|
||||||
|
if (searchInput) {
|
||||||
|
searchInput.focus();
|
||||||
|
|
||||||
|
// If sidebar is closed on mobile, open it
|
||||||
|
const leftSidebar = document.querySelector('.left-sidebar');
|
||||||
|
const menuButton = document.querySelector('.menu-button');
|
||||||
|
if (window.innerWidth <= 1000 && leftSidebar &&
|
||||||
|
!leftSidebar.classList.contains('show')) {
|
||||||
|
leftSidebar.classList.add('show');
|
||||||
|
if (menuButton) {
|
||||||
|
menuButton.setAttribute('aria-expanded', 'true');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigation with Alt+Up/Down to move between pages
|
||||||
|
if ((e.key === 'ArrowUp' || e.key === 'ArrowDown') && e.altKey && !isTyping) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Get all links from the file index
|
||||||
|
const fileLinks = Array.from(document.querySelectorAll('#file-index a'));
|
||||||
|
if (fileLinks.length === 0) return;
|
||||||
|
|
||||||
|
// Find the current active link
|
||||||
|
const activeLink = document.querySelector('#file-index a.active');
|
||||||
|
if (!activeLink) return;
|
||||||
|
|
||||||
|
// Find the index of the active link
|
||||||
|
const activeIndex = fileLinks.indexOf(activeLink);
|
||||||
|
if (activeIndex === -1) return;
|
||||||
|
|
||||||
|
// Determine the target link based on direction
|
||||||
|
let targetLink;
|
||||||
|
if (e.key === 'ArrowDown') {
|
||||||
|
// Go to next link (or first if at the end)
|
||||||
|
targetLink = activeIndex < fileLinks.length - 1 ?
|
||||||
|
fileLinks[activeIndex + 1] :
|
||||||
|
fileLinks[0];
|
||||||
|
} else {
|
||||||
|
// Go to previous link (or last if at the beginning)
|
||||||
|
targetLink = activeIndex > 0 ?
|
||||||
|
fileLinks[activeIndex - 1] :
|
||||||
|
fileLinks[fileLinks.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigate to the target page
|
||||||
|
if (targetLink) {
|
||||||
|
// Simulate a click on the link
|
||||||
|
targetLink.click();
|
||||||
|
|
||||||
|
// Ensure the target link is visible in the sidebar
|
||||||
|
targetLink.scrollIntoView({ block: 'nearest' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async initialize() {
|
async initialize() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
434
styles.css
434
styles.css
@@ -90,6 +90,7 @@ body {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-box .fa-times:hover {
|
.search-box .fa-times:hover {
|
||||||
@@ -691,4 +692,437 @@ social-links a:hover {
|
|||||||
@keyframes highlight-fade {
|
@keyframes highlight-fade {
|
||||||
0% { background-color: rgba(52, 152, 219, 0.2); }
|
0% { background-color: rgba(52, 152, 219, 0.2); }
|
||||||
100% { background-color: transparent; }
|
100% { background-color: transparent; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a skip link for keyboard navigation */
|
||||||
|
.skip-to-content {
|
||||||
|
position: absolute;
|
||||||
|
top: -40px;
|
||||||
|
left: 0;
|
||||||
|
padding: 8px;
|
||||||
|
z-index: 2000;
|
||||||
|
background: var(--ifm-color-primary);
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: top 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-to-content:focus {
|
||||||
|
top: 0;
|
||||||
|
outline: 2px solid white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Improve focus styles for better keyboard navigation */
|
||||||
|
/* Remove the conflicting focus style rules */
|
||||||
|
/* Remove these conflicting rules */
|
||||||
|
*:focus {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
*:focus-visible {
|
||||||
|
outline: 2px solid var(--ifm-color-primary) !important;
|
||||||
|
outline-offset: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:focus,
|
||||||
|
button:focus,
|
||||||
|
input:focus,
|
||||||
|
.folder-header:focus,
|
||||||
|
.clickable-header:focus {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:focus-visible,
|
||||||
|
button:focus-visible,
|
||||||
|
input:focus-visible,
|
||||||
|
.folder-header:focus-visible,
|
||||||
|
.clickable-header:focus-visible {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add clean focus style rules */
|
||||||
|
/* This allows keyboard focus to be visible but hides it for mouse clicks */
|
||||||
|
:focus {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only show focus styles for keyboard navigation */
|
||||||
|
:focus-visible {
|
||||||
|
outline: 2px solid var(--ifm-color-primary) !important;
|
||||||
|
outline-offset: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force focus visible off for mouse interaction */
|
||||||
|
:focus:not(:focus-visible) {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure contrast for links and interactive elements */
|
||||||
|
.folder-header:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep the skip link visible when it gets focus */
|
||||||
|
.skip-to-content:focus {
|
||||||
|
top: 0;
|
||||||
|
outline: 2px solid white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't hide keyboard focus styles on mobile */
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
:focus-visible {
|
||||||
|
outline: 2px solid var(--ifm-color-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-button {
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-sidebar {
|
||||||
|
left: -100%;
|
||||||
|
width: min(var(--doc-sidebar-width), 80vw);
|
||||||
|
transition: left 0.3s ease;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-sidebar.show {
|
||||||
|
left: 0;
|
||||||
|
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-sidebar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content {
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#file-index {
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure aria-hidden elements aren't focusable */
|
||||||
|
[aria-hidden="true"] {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't hide focus-visible on mobile */
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
*:focus-visible {
|
||||||
|
outline: 2px solid var(--ifm-color-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-button {
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-sidebar {
|
||||||
|
left: -100%;
|
||||||
|
width: min(var(--doc-sidebar-width), 80vw);
|
||||||
|
transition: left 0.3s ease;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-sidebar.show {
|
||||||
|
left: 0;
|
||||||
|
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-sidebar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content {
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#file-index {
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the keyboard shortcut indicator */
|
||||||
|
.keyboard-shortcut {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border: 1px solid var(--ifm-color-content-secondary);
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
color: var(--ifm-color-content-secondary);
|
||||||
|
opacity: 0.7;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the Alt+S keyboard shortcut */
|
||||||
|
.keyboard-shortcut-alt {
|
||||||
|
width: auto;
|
||||||
|
padding: 0 4px;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide keyboard shortcut on mobile */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.keyboard-shortcut {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print styles... */
|
||||||
|
@media print {
|
||||||
|
.title-bar,
|
||||||
|
.left-sidebar,
|
||||||
|
.right-sidebar,
|
||||||
|
.menu-button,
|
||||||
|
.social-links,
|
||||||
|
.github-link,
|
||||||
|
.subtitle {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-container {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: white !important;
|
||||||
|
color: black !important;
|
||||||
|
font-size: 12pt !important;
|
||||||
|
line-height: 1.5 !important;
|
||||||
|
margin: 0.25in !important; /* Reduced margins */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the logo and redundant breadcrumb display */
|
||||||
|
.content-container::before,
|
||||||
|
.content-container::after {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple print header */
|
||||||
|
.print-header {
|
||||||
|
display: block !important;
|
||||||
|
margin-bottom: 15pt;
|
||||||
|
border-bottom: 1pt solid #ddd;
|
||||||
|
padding-bottom: 8pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.print-header .site-name {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.print-header .page-title {
|
||||||
|
font-size: 12pt;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content {
|
||||||
|
padding: 0 !important;
|
||||||
|
font-size: 11pt !important;
|
||||||
|
line-height: 1.4 !important;
|
||||||
|
max-width: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content a {
|
||||||
|
color: #000 !important;
|
||||||
|
text-decoration: underline !important;
|
||||||
|
word-wrap: break-word !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content a[href^="http"]:after {
|
||||||
|
content: " (" attr(href) ")";
|
||||||
|
font-size: 9pt;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content pre,
|
||||||
|
.markdown-content code {
|
||||||
|
white-space: pre-wrap !important;
|
||||||
|
border: 1px solid #ddd !important;
|
||||||
|
page-break-inside: avoid !important;
|
||||||
|
background-color: #f5f5f5 !important;
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content img {
|
||||||
|
max-width: 100% !important;
|
||||||
|
page-break-inside: avoid !important;
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content h1,
|
||||||
|
.markdown-content h2,
|
||||||
|
.markdown-content h3,
|
||||||
|
.markdown-content h4,
|
||||||
|
.markdown-content h5,
|
||||||
|
.markdown-content h6 {
|
||||||
|
page-break-after: avoid !important;
|
||||||
|
break-after: avoid !important;
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content p,
|
||||||
|
.markdown-content ul,
|
||||||
|
.markdown-content ol,
|
||||||
|
.markdown-content table {
|
||||||
|
page-break-inside: avoid !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content h1 {
|
||||||
|
font-size: 20pt !important;
|
||||||
|
margin: 20pt 0 15pt 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content h2 {
|
||||||
|
font-size: 16pt !important;
|
||||||
|
margin: 16pt 0 10pt 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content h3 {
|
||||||
|
font-size: 14pt !important;
|
||||||
|
margin: 14pt 0 8pt 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content p,
|
||||||
|
.markdown-content ul,
|
||||||
|
.markdown-content ol {
|
||||||
|
margin: 6pt 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content pre,
|
||||||
|
.markdown-content blockquote {
|
||||||
|
margin: 10pt 0 !important;
|
||||||
|
padding: 8pt 10pt !important;
|
||||||
|
border-left: 4pt solid #ddd !important;
|
||||||
|
background-color: #f8f8f8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content table {
|
||||||
|
margin: 10pt 0 !important;
|
||||||
|
font-size: 10pt !important;
|
||||||
|
border-collapse: collapse !important;
|
||||||
|
width: 100% !important;
|
||||||
|
border: 1px solid #ddd !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content td,
|
||||||
|
.markdown-content th {
|
||||||
|
padding: 6pt 8pt !important;
|
||||||
|
border: 1px solid #ddd !important;
|
||||||
|
background-color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-content th {
|
||||||
|
background-color: #f0f0f0 !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix clickable header styles for print */
|
||||||
|
.clickable-header:hover {
|
||||||
|
color: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add page breaks before major sections */
|
||||||
|
.markdown-content h1 {
|
||||||
|
page-break-before: always !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First h1 shouldn't have a page break before it */
|
||||||
|
.markdown-content h1:first-child {
|
||||||
|
page-break-before: avoid !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide interactive elements */
|
||||||
|
.markdown-content video,
|
||||||
|
.markdown-content .header-anchor,
|
||||||
|
.markdown-content svg {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make URLs for links visible */
|
||||||
|
@page {
|
||||||
|
margin: 0.5in !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple print header with logo */
|
||||||
|
.print-header {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15pt;
|
||||||
|
border-bottom: 1pt solid #ddd;
|
||||||
|
padding-bottom: 8pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the logo in print mode */
|
||||||
|
.print-header .brand-logo {
|
||||||
|
height: 30px;
|
||||||
|
width: auto;
|
||||||
|
display: block;
|
||||||
|
filter: brightness(0); /* Make logo black */
|
||||||
|
border-radius: 0 !important; /* Remove any border radius */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the title text section */
|
||||||
|
.print-header .print-title-text {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.print-header .divider {
|
||||||
|
padding: 0 5px;
|
||||||
|
font-size: 14pt;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.print-header .page-title {
|
||||||
|
font-size: 14pt;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the old print title elements */
|
||||||
|
.print-title,
|
||||||
|
.content-container::before,
|
||||||
|
.content-container::after {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add this rule to specifically remove the outline from the document content area when clicked */
|
||||||
|
#document-content:focus {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* But keep it for keyboard navigation */
|
||||||
|
#document-content:focus-visible {
|
||||||
|
outline: 2px solid var(--ifm-color-primary) !important;
|
||||||
|
outline-offset: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also make sure any other clickable elements in the document content don't get outlines */
|
||||||
|
#document-content *:focus:not(:focus-visible) {
|
||||||
|
outline: none !important;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user