From 03dc3a433cf29452de204b84dbc00ae337637074 Mon Sep 17 00:00:00 2001 From: woeoio Date: Mon, 16 Feb 2026 13:00:11 +0800 Subject: [PATCH 1/6] feat: add floating table of contents with scroll spy Add a floating TOC sidebar that automatically updates based on scroll position. Includes responsive design and dark mode support. The TOC is generated from headings (h2-h4) and includes smooth scrolling to anchors. --- docs/_config.yml | 3 + docs/_includes/head_custom.html | 6 +- docs/_sass/custom/custom.scss | 93 +++++++++++++++++ docs/assets/js/toc.js | 176 ++++++++++++++++++++++++++++++++ 4 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 docs/assets/js/toc.js diff --git a/docs/_config.yml b/docs/_config.yml index 0a4deb4..99a2d6d 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -68,6 +68,9 @@ callouts: # For copy button on code enable_copy_code_button: true +# Configure heading anchor links +heading_anchors: true + # Waiting until it's needed. # # By default, consuming the theme as a gem leaves mermaid disabled; it is opt-in # mermaid: diff --git a/docs/_includes/head_custom.html b/docs/_includes/head_custom.html index 7ccf75d..982f863 100644 --- a/docs/_includes/head_custom.html +++ b/docs/_includes/head_custom.html @@ -1,3 +1,5 @@ - + + diff --git a/docs/_sass/custom/custom.scss b/docs/_sass/custom/custom.scss index 2b871b5..dfdc84d 100644 --- a/docs/_sass/custom/custom.scss +++ b/docs/_sass/custom/custom.scss @@ -1,3 +1,96 @@ .site-logo { padding-right: 3rem; } + +/* Page TOC (Table of Contents) */ +.page-toc { + position: fixed; + right: 2rem; + top: 6rem; + width: 250px; + max-height: calc(100vh - 8rem); + overflow-y: auto; + background-color: #fff; + border: 1px solid #e8e8e8; + border-radius: 6px; + padding: 1rem; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + font-size: 0.875rem; + z-index: 10; +} + +.page-toc-heading { + font-weight: 600; + font-size: 0.9rem; + color: #333; + margin-bottom: 0.75rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid #e8e8e8; +} + +.page-toc-list { + list-style: none; + padding: 0; + margin: 0; +} + +.page-toc-item { + margin: 0.25rem 0; +} + +.page-toc-link { + display: block; + color: #666; + text-decoration: none; + padding: 0.25rem 0; + transition: color 0.2s ease; +} + +.page-toc-link:hover { + color: #0050d0; +} + +.page-toc-link.active { + color: #0050d0; + font-weight: 500; + border-left: 2px solid #0050d0; + padding-left: 0.5rem; +} + +/* Dark mode support */ +.dark-mode .page-toc { + background-color: #1a1a1a; + border-color: #333; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); +} + +.dark-mode .page-toc-heading { + color: #e0e0e0; + border-color: #333; +} + +.dark-mode .page-toc-link { + color: #a0a0a0; +} + +.dark-mode .page-toc-link:hover { + color: #7dd3fc; +} + +.dark-mode .page-toc-link.active { + color: #7dd3fc; + border-color: #7dd3fc; +} + +/* Responsive - hide TOC on smaller screens */ +@media screen and (max-width: 1280px) { + .page-toc { + display: none; + } +} + +/* Smooth scrolling for anchor links */ +html { + scroll-behavior: smooth; +} + diff --git a/docs/assets/js/toc.js b/docs/assets/js/toc.js new file mode 100644 index 0000000..2c7cde1 --- /dev/null +++ b/docs/assets/js/toc.js @@ -0,0 +1,176 @@ +/** + * Just the Docs - In-page Table of Contents Generator + * Generates a floating TOC based on page headings (H1-H4) + */ + +(function() { + 'use strict'; + + // Configuration + const config = { + minLevel: 2, // Minimum heading level to include (h2) + maxLevel: 4, // Maximum heading level to include (h4) + containerId: 'page-toc', + containerClass: 'page-toc', + headingClass: 'page-toc-heading', + listClass: 'page-toc-list', + itemClass: 'page-toc-item', + linkClass: 'page-toc-link', + activeClass: 'active' + }; + + // Create TOC container + function createTOCContainer() { + const container = document.createElement('div'); + container.id = config.containerId; + container.className = config.containerClass; + return container; + } + + // Generate TOC from headings + function generateTOC() { + const content = document.querySelector('.main-content'); + if (!content) return null; + + const headings = content.querySelectorAll('h2, h3, h4'); + if (headings.length < 2) return null; + + const container = createTOCContainer(); + + // Add heading + const heading = document.createElement('div'); + heading.className = config.headingClass; + heading.textContent = 'On this page'; + container.appendChild(heading); + + // Create list + const list = document.createElement('ul'); + list.className = config.listClass; + + let currentList = list; + let lastLevel = config.minLevel; + const listStack = [list]; + + headings.forEach((heading, index) => { + const level = parseInt(heading.tagName.charAt(1)); + + if (level < config.minLevel || level > config.maxLevel) return; + + // Ensure heading has an ID for linking + if (!heading.id) { + heading.id = heading.textContent + .toLowerCase() + .replace(/\s+/g, '-') + .replace(/[^\w\-]/g, '') + .replace(/\-+/g, '-') + .replace(/^-+|-+$/g, '') + '-' + index; + } + + // Handle nested lists + if (level > lastLevel) { + const subList = document.createElement('ul'); + subList.className = config.listClass; + const lastItem = currentList.lastElementChild; + if (lastItem) { + lastItem.appendChild(subList); + currentList = subList; + listStack.push(subList); + } + } else if (level < lastLevel) { + while (listStack.length > 1) { + listStack.pop(); + currentList = listStack[listStack.length - 1]; + const stackTopLevel = getCurrentListLevel(currentList); + if (stackTopLevel <= level) break; + } + } + + // Create list item + const item = document.createElement('li'); + item.className = config.itemClass; + item.style.paddingLeft = ((level - config.minLevel) * 12) + 'px'; + + const link = document.createElement('a'); + link.className = config.linkClass; + link.href = '#' + heading.id; + link.textContent = heading.textContent; + link.dataset.target = heading.id; + + item.appendChild(link); + currentList.appendChild(item); + lastLevel = level; + }); + + container.appendChild(list); + return container; + } + + function getCurrentListLevel(list) { + let level = config.minLevel; + let parent = list.parentElement; + while (parent && parent.tagName !== 'DIV') { + if (parent.tagName === 'UL') level++; + parent = parent.parentElement; + } + return level; + } + + // Insert TOC into page + function insertTOC(toc) { + const mainContent = document.querySelector('.main-content'); + if (!mainContent) return; + + // Insert after the first h1 + const firstH1 = mainContent.querySelector('h1'); + if (firstH1) { + firstH1.parentNode.insertBefore(toc, firstH1.nextSibling); + } else { + mainContent.insertBefore(toc, mainContent.firstChild); + } + } + + // Highlight active heading on scroll + function setupScrollSpy() { + const headings = document.querySelectorAll('.main-content h2, .main-content h3, .main-content h4'); + const tocLinks = document.querySelectorAll(`.${config.linkClass}`); + + if (tocLinks.length === 0) return; + + const observerOptions = { + rootMargin: '-100px 0px -66%', + threshold: 0 + }; + + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const id = entry.target.id; + tocLinks.forEach(link => { + link.classList.remove(config.activeClass); + if (link.dataset.target === id) { + link.classList.add(config.activeClass); + } + }); + } + }); + }, observerOptions); + + headings.forEach(heading => observer.observe(heading)); + } + + // Initialize + function init() { + const toc = generateTOC(); + if (toc) { + insertTOC(toc); + setupScrollSpy(); + } + } + + // Run when DOM is ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})(); From 14818383a7fd8669180173a4de6799d434707b8b Mon Sep 17 00:00:00 2001 From: woeoio Date: Mon, 16 Feb 2026 13:03:40 +0800 Subject: [PATCH 2/6] style: improve dark mode table of contents specificity Add !important to dark mode TOC styles and update selectors for better specificity --- docs/_sass/custom/custom.scss | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/_sass/custom/custom.scss b/docs/_sass/custom/custom.scss index dfdc84d..ac316cf 100644 --- a/docs/_sass/custom/custom.scss +++ b/docs/_sass/custom/custom.scss @@ -51,35 +51,35 @@ } .page-toc-link.active { - color: #0050d0; + color: #0050d0 !important; font-weight: 500; border-left: 2px solid #0050d0; padding-left: 0.5rem; } /* Dark mode support */ -.dark-mode .page-toc { - background-color: #1a1a1a; - border-color: #333; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); +html.dark-mode .page-toc { + background-color: #1a1a1a !important; + border-color: #333 !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3) !important; } -.dark-mode .page-toc-heading { - color: #e0e0e0; - border-color: #333; +html.dark-mode .page-toc-heading { + color: #e0e0e0 !important; + border-color: #333 !important; } -.dark-mode .page-toc-link { - color: #a0a0a0; +html.dark-mode .page-toc-link { + color: #a0a0a0 !important; } -.dark-mode .page-toc-link:hover { - color: #7dd3fc; +html.dark-mode .page-toc-link:hover { + color: #7dd3fc !important; } -.dark-mode .page-toc-link.active { - color: #7dd3fc; - border-color: #7dd3fc; +html.dark-mode .page-toc-link.active { + color: #7dd3fc !important; + border-color: #7dd3fc !important; } /* Responsive - hide TOC on smaller screens */ From 6ebac18c59ee1f99ea03955edf1dd51a875418d0 Mon Sep 17 00:00:00 2001 From: woeoio Date: Mon, 16 Feb 2026 14:31:10 +0800 Subject: [PATCH 3/6] feat: add search modal functionality with keyboard shortcut Implement a search modal that moves the existing search component into an overlay. Includes styling for the modal, trigger button, and dark mode support. Adds keyboard shortcut (Cmd/Ctrl+K) to toggle the modal. --- docs/_includes/head_custom.html | 2 + docs/_sass/custom/custom.scss | 228 +++++++++++++++++++++++++++++++ docs/assets/js/search-modal.js | 231 ++++++++++++++++++++++++++++++++ 3 files changed, 461 insertions(+) create mode 100644 docs/assets/js/search-modal.js diff --git a/docs/_includes/head_custom.html b/docs/_includes/head_custom.html index 982f863..c3bcc82 100644 --- a/docs/_includes/head_custom.html +++ b/docs/_includes/head_custom.html @@ -3,3 +3,5 @@ href="{{ '/favicon.png' | relative_url }}" > + + diff --git a/docs/_sass/custom/custom.scss b/docs/_sass/custom/custom.scss index ac316cf..c11b9f2 100644 --- a/docs/_sass/custom/custom.scss +++ b/docs/_sass/custom/custom.scss @@ -2,6 +2,36 @@ padding-right: 3rem; } +/* Hide the original search container in main header */ +#main-header .search { + display: none; +} + +/* Show search container in modal */ +.search-modal .search { + display: flex !important; +} + +/* Style the compact search trigger button */ +.search-modal-trigger-wrapper { + display: flex; + align-items: center; +} + +#main-header .search-modal-trigger { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 6px; + color: #495057; + font-size: 0.875rem; + cursor: pointer; + transition: all 0.2s ease; +} + /* Page TOC (Table of Contents) */ .page-toc { position: fixed; @@ -94,3 +124,201 @@ html { scroll-behavior: smooth; } +/* Search Modal Styles */ +.search-modal-trigger-wrapper { + display: flex; + align-items: center; +} + +.search-modal-trigger { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + background: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 6px; + color: #495057; + font-size: 0.875rem; + cursor: pointer; + transition: all 0.2s ease; +} + +.search-modal-trigger:hover { + background: #e9ecef; + border-color: #adb5bd; +} + +.search-modal-trigger svg { + flex-shrink: 0; +} + +.search-modal-shortcut { + display: inline-flex; + align-items: center; + padding: 0.125rem 0.375rem; + background: #fff; + border: 1px solid #dee2e6; + border-radius: 4px; + font-size: 0.75rem; + font-weight: 500; + color: #6c757d; +} + +/* Modal Overlay */ +.search-modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 99998; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; +} + +.search-modal-overlay.active { + opacity: 1; + visibility: visible; +} + +/* Modal Container */ +.search-modal { + position: fixed; + top: 10%; + left: 50%; + transform: translateX(-50%) translateY(-20px); + width: 90%; + max-width: 700px; + max-height: 80vh; + background: #fff; + border-radius: 12px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + z-index: 99999; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.search-modal.active { + opacity: 1; + visibility: visible; + transform: translateX(-50%) translateY(0); +} + +/* Native search component in modal */ +.search-modal .search { + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; + height: auto !important; + padding: 1rem !important; +} + +/* Show search components when in modal */ +.search-modal .search .search-input-wrap { + display: flex !important; + width: 100%; + flex-shrink: 0; + height: auto !important; + position: relative !important; + max-width: none !important; + overflow: visible !important; +} + +.search-modal .search #search-results { + display: block !important; + flex: 1; + overflow-y: auto; + position: relative !important; + top: auto !important; + left: auto !important; + width: auto !important; + box-shadow: none !important; + border-radius: 0 !important; + background: transparent !important; +} + +/* Modal close button */ +.search-modal-close { + position: absolute; + top: 0.75rem; + right: 0.75rem; + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + border: none; + background: transparent; + color: #6c757d; + cursor: pointer; + border-radius: 6px; + transition: all 0.2s ease; + z-index: 10; +} + +.search-modal-close:hover { + background: #f8f9fa; + color: #212529; +} + +/* Dark mode */ +html.dark-mode .search-modal-trigger { + background: #2d2d2d; + border-color: #404040; + color: #e0e0e0; +} + +html.dark-mode .search-modal-trigger:hover { + background: #3d3d3d; + border-color: #505050; +} + +html.dark-mode .search-modal-shortcut { + background: #2d2d2d; + border-color: #404040; + color: #a0a0a0; +} + +html.dark-mode .search-modal-overlay { + background: rgba(0, 0, 0, 0.7); +} + +html.dark-mode .search-modal { + background: #1a1a1a; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); +} + +html.dark-mode .search-modal-close { + color: #a0a0a0; +} + +html.dark-mode .search-modal-close:hover { + background: #2d2d2d; + color: #fff; +} + +/* Responsive */ +@media (max-width: 640px) { + .search-modal { + top: 5%; + width: 95%; + max-height: 85vh; + } + + .search-modal-trigger { + padding: 0.375rem 0.75rem; + } + + .search-modal-shortcut { + display: none; + } +} + diff --git a/docs/assets/js/search-modal.js b/docs/assets/js/search-modal.js new file mode 100644 index 0000000..2c8993b --- /dev/null +++ b/docs/assets/js/search-modal.js @@ -0,0 +1,231 @@ +/** + * Search Modal - VitePress style search overlay + * Moves original Just the Docs search component into modal + */ + +(function() { + 'use strict'; + + let modal = null; + let modalOverlay = null; + let originalSearchContainer = null; + let isOpen = false; + + // Create modal HTML structure + function createModal() { + // Overlay + modalOverlay = document.createElement('div'); + modalOverlay.className = 'search-modal-overlay'; + modalOverlay.setAttribute('aria-hidden', 'true'); + + // Modal container + modal = document.createElement('div'); + modal.className = 'search-modal'; + modal.setAttribute('role', 'dialog'); + modal.setAttribute('aria-modal', 'true'); + modal.setAttribute('aria-label', 'Search'); + + // Close button + const closeButton = document.createElement('button'); + closeButton.className = 'search-modal-close'; + closeButton.setAttribute('aria-label', 'Close'); + closeButton.innerHTML = ` + + + `; + closeButton.addEventListener('click', closeModal); + + // Assemble modal + modal.appendChild(closeButton); + + // Add to document + document.body.appendChild(modalOverlay); + document.body.appendChild(modal); + + // Event listeners + modalOverlay.addEventListener('click', closeModal); + document.addEventListener('keydown', handleGlobalKeydown); + } + + // Move original search component to modal + function moveSearchToModal() { + const mainHeader = document.querySelector('#main-header'); + if (!mainHeader) return false; + + originalSearchContainer = mainHeader.querySelector('.search'); + if (!originalSearchContainer) return false; + + // Move search container to modal + modal.appendChild(originalSearchContainer); + + // Update input placeholder + const searchInput = document.getElementById('search-input'); + if (searchInput) { + searchInput.placeholder = 'Search twinBASIC Documentation'; + } + + // Force reflow to ensure styles apply + void modal.offsetHeight; + + console.log('Search moved to modal, modal children:', modal.children.length); + + return true; + } + + // Open modal + function openModal() { + // Ensure modal exists + if (!modal) { + createModal(); + } + + // Move search component to modal if not done + if (!modal.querySelector('.search')) { + if (!moveSearchToModal()) { + // Wait for search to be ready + const checkInterval = setInterval(() => { + if (moveSearchToModal()) { + clearInterval(checkInterval); + openModalNow(); + } + }, 200); + + // Timeout after 3 seconds + setTimeout(() => clearInterval(checkInterval), 3000); + return; + } + } + + openModalNow(); + } + + function openModalNow() { + if (!modal || !modalOverlay) { + console.error('Modal or overlay not found!'); + return; + } + + isOpen = true; + modalOverlay.classList.add('active'); + modal.classList.add('active'); + document.body.style.overflow = 'hidden'; + + // Focus on search input + setTimeout(() => { + const searchInput = document.getElementById('search-input'); + if (searchInput) { + searchInput.focus(); + } + }, 100); + } + + // Close modal + function closeModal() { + if (!modal) return; + + isOpen = false; + modalOverlay.classList.remove('active'); + modal.classList.remove('active'); + document.body.style.overflow = ''; + + // Clear search input + const searchInput = document.getElementById('search-input'); + if (searchInput) { + searchInput.value = ''; + const keyupEvent = new KeyboardEvent('keyup', { + bubbles: true, + cancelable: true, + keyCode: 65, + key: '' + }); + searchInput.dispatchEvent(keyupEvent); + } + } + + // Handle global keyboard events + function handleGlobalKeydown(e) { + // Cmd/Ctrl + K to open search + if ((e.metaKey || e.ctrlKey) && e.key === 'k') { + e.preventDefault(); + if (isOpen) { + closeModal(); + } else { + openModal(); + } + } + + // Escape to close + if (e.key === 'Escape' && isOpen) { + closeModal(); + } + } + + // Create search button in header + function createSearchButton() { + const mainHeader = document.querySelector('#main-header'); + if (!mainHeader) { + setTimeout(createSearchButton, 200); + return; + } + + // Check if button already exists + if (document.querySelector('.search-modal-trigger')) { + return; + } + + // Find original search container + const searchContainer = mainHeader.querySelector('.search'); + if (!searchContainer) { + setTimeout(createSearchButton, 200); + return; + } + + // Find aux-nav to place button next to it + const auxNav = mainHeader.querySelector('.aux-nav'); + if (!auxNav) { + // If no aux-nav, try to find the header nav + setTimeout(createSearchButton, 200); + return; + } + + // Create search button wrapper + const buttonWrapper = document.createElement('div'); + buttonWrapper.className = 'search-modal-trigger-wrapper'; + + // Create search button + const searchButton = document.createElement('button'); + searchButton.className = 'search-modal-trigger'; + searchButton.setAttribute('aria-label', 'Search'); + searchButton.innerHTML = ` + + + `; + + // Add keyboard shortcut hint + const shortcut = document.createElement('span'); + shortcut.className = 'search-modal-shortcut'; + shortcut.textContent = '⌘K'; + searchButton.appendChild(shortcut); + + searchButton.addEventListener('click', openModal); + buttonWrapper.appendChild(searchButton); + + // Insert button wrapper before aux-nav + auxNav.parentNode.insertBefore(buttonWrapper, auxNav); + } + + // Initialize + function init() { + // Wait for DOM to be ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', () => { + setTimeout(createSearchButton, 100); + }); + } else { + setTimeout(createSearchButton, 100); + } + } + + init(); + +})(); From 0676327adc577e60586ae3bcb7d24614506864d2 Mon Sep 17 00:00:00 2001 From: woeoio Date: Mon, 16 Feb 2026 14:47:50 +0800 Subject: [PATCH 4/6] feat: improve search modal styles and button placement Update search input and label styles for better UX, add dark mode support, and adjust search button placement in header --- docs/_sass/custom/custom.scss | 73 +++++++++++++++++++++++++++++++--- docs/assets/js/search-modal.js | 11 +++-- 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/docs/_sass/custom/custom.scss b/docs/_sass/custom/custom.scss index c11b9f2..ca0e8cb 100644 --- a/docs/_sass/custom/custom.scss +++ b/docs/_sass/custom/custom.scss @@ -230,6 +230,50 @@ html { position: relative !important; max-width: none !important; overflow: visible !important; + padding: 0 !important; +} + +/* Override search input styles */ +.search-modal .search .search-input { + position: relative !important; + width: 100%; + height: auto !important; + padding: 0.75rem 1rem 0.75rem 2.75rem !important; + font-size: 1rem; + border: 2px solid #dee2e6; + border-radius: 8px; + outline: none; + background: #fff; + color: #212529; + transition: none !important; +} + +.search-modal .search .search-input:focus { + border-color: #0050d0; + box-shadow: 0 0 0 4px rgba(0, 80, 208, 0.1); +} + +.search-modal .search .search-input::placeholder { + color: #adb5bd; +} + +/* Override search label styles */ +.search-modal .search .search-label { + position: absolute; + left: 0.875rem; + top: 50%; + transform: translateY(-50%); + z-index: 1; + color: #6c757d; + pointer-events: none; + padding: 0 !important; + transition: none !important; + height: auto !important; +} + +.search-modal .search .search-label .search-icon { + width: 1.25rem; + height: 1.25rem; } .search-modal .search #search-results { @@ -248,18 +292,18 @@ html { /* Modal close button */ .search-modal-close { position: absolute; - top: 0.75rem; - right: 0.75rem; + top: 1.25rem; + right: 1.25rem; display: flex; align-items: center; justify-content: center; - width: 32px; - height: 32px; + width: 40px; + height: 40px; border: none; background: transparent; color: #6c757d; cursor: pointer; - border-radius: 6px; + border-radius: 8px; transition: all 0.2s ease; z-index: 10; } @@ -296,6 +340,25 @@ html.dark-mode .search-modal { box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); } +html.dark-mode .search-modal .search .search-input { + background: #2d2d2d; + border-color: #404040; + color: #e0e0e0; +} + +html.dark-mode .search-modal .search .search-input:focus { + border-color: #7dd3fc; + box-shadow: 0 0 0 4px rgba(125, 211, 252, 0.1); +} + +html.dark-mode .search-modal .search .search-input::placeholder { + color: #666; +} + +html.dark-mode .search-modal .search .search-label { + color: #a0a0a0; +} + html.dark-mode .search-modal-close { color: #a0a0a0; } diff --git a/docs/assets/js/search-modal.js b/docs/assets/js/search-modal.js index 2c8993b..72f81e3 100644 --- a/docs/assets/js/search-modal.js +++ b/docs/assets/js/search-modal.js @@ -180,10 +180,9 @@ return; } - // Find aux-nav to place button next to it - const auxNav = mainHeader.querySelector('.aux-nav'); - if (!auxNav) { - // If no aux-nav, try to find the header nav + // Find nav element + const nav = mainHeader.querySelector('nav'); + if (!nav) { setTimeout(createSearchButton, 200); return; } @@ -210,8 +209,8 @@ searchButton.addEventListener('click', openModal); buttonWrapper.appendChild(searchButton); - // Insert button wrapper before aux-nav - auxNav.parentNode.insertBefore(buttonWrapper, auxNav); + // Insert button wrapper after nav + nav.parentNode.insertBefore(buttonWrapper, nav.nextSibling); } // Initialize From cd40d6825b9722d0e790dec965d176cb14f70346 Mon Sep 17 00:00:00 2001 From: woeoio Date: Mon, 16 Feb 2026 15:03:09 +0800 Subject: [PATCH 5/6] style: improve dark mode search modal styling consistency Add !important to all dark mode search modal styles and adjust colors for better visual consistency. Make search results background transparent. --- docs/_sass/custom/custom.scss | 50 ++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/docs/_sass/custom/custom.scss b/docs/_sass/custom/custom.scss index ca0e8cb..339d292 100644 --- a/docs/_sass/custom/custom.scss +++ b/docs/_sass/custom/custom.scss @@ -314,58 +314,66 @@ html { } /* Dark mode */ +html.dark-mode .search-modal-trigger-wrapper { + background: transparent; +} + html.dark-mode .search-modal-trigger { - background: #2d2d2d; - border-color: #404040; - color: #e0e0e0; + background: #2d2d2d !important; + border-color: #404040 !important; + color: #e0e0e0 !important; } html.dark-mode .search-modal-trigger:hover { - background: #3d3d3d; - border-color: #505050; + background: #3d3d3d !important; + border-color: #505050 !important; } html.dark-mode .search-modal-shortcut { - background: #2d2d2d; - border-color: #404040; - color: #a0a0a0; + background: #1a1a1a !important; + border-color: #404040 !important; + color: #a0a0a0 !important; } html.dark-mode .search-modal-overlay { - background: rgba(0, 0, 0, 0.7); + background: rgba(0, 0, 0, 0.7) !important; } html.dark-mode .search-modal { - background: #1a1a1a; - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); + background: #1a1a1a !important; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5) !important; } html.dark-mode .search-modal .search .search-input { - background: #2d2d2d; - border-color: #404040; - color: #e0e0e0; + background: #2d2d2d !important; + border-color: #404040 !important; + color: #e0e0e0 !important; } html.dark-mode .search-modal .search .search-input:focus { - border-color: #7dd3fc; - box-shadow: 0 0 0 4px rgba(125, 211, 252, 0.1); + border-color: #7dd3fc !important; + box-shadow: 0 0 0 4px rgba(125, 211, 252, 0.1) !important; } html.dark-mode .search-modal .search .search-input::placeholder { - color: #666; + color: #666 !important; } html.dark-mode .search-modal .search .search-label { - color: #a0a0a0; + color: #a0a0a0 !important; +} + +html.dark-mode .search-modal .search #search-results { + background: transparent !important; } html.dark-mode .search-modal-close { - color: #a0a0a0; + color: #a0a0a0 !important; } html.dark-mode .search-modal-close:hover { - background: #2d2d2d; - color: #fff; + background: #2d2d2d !important; + color: #fff !important; } /* Responsive */ From 779b41b484c124c6d3ca82537ede81a249305966 Mon Sep 17 00:00:00 2001 From: woeoio Date: Mon, 16 Feb 2026 15:34:14 +0800 Subject: [PATCH 6/6] style: add dark mode scrollbar styles --- docs/_sass/custom/custom.scss | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/_sass/custom/custom.scss b/docs/_sass/custom/custom.scss index 339d292..829d346 100644 --- a/docs/_sass/custom/custom.scss +++ b/docs/_sass/custom/custom.scss @@ -376,6 +376,40 @@ html.dark-mode .search-modal-close:hover { color: #fff !important; } +/* Dark mode scrollbar styles */ +html.dark-mode { + /* WebKit browsers (Chrome, Safari, Edge) */ + ::-webkit-scrollbar { + width: 10px; + height: 10px; + } + + ::-webkit-scrollbar-track { + background: #1a1a1a; + } + + ::-webkit-scrollbar-thumb { + background: #404040; + border-radius: 5px; + } + + ::-webkit-scrollbar-thumb:hover { + background: #505050; + } + + ::-webkit-scrollbar-corner { + background: #1a1a1a; + } +} + +/* Firefox scrollbar styles */ +@supports (scrollbar-width: thin) { + html.dark-mode { + scrollbar-color: #404040 #1a1a1a; + scrollbar-width: thin; + } +} + /* Responsive */ @media (max-width: 640px) { .search-modal {