diff --git a/gcovr-templates/html/base.html b/gcovr-templates/html/base.html index fbd411a..cc5fe53 100644 --- a/gcovr-templates/html/base.html +++ b/gcovr-templates/html/base.html @@ -9,13 +9,10 @@ + Root / Functions{% endblock %} +{% block breadcrumb %}Index / Functions{% endblock %} {% block sidebar_tree %}
diff --git a/gcovr-templates/html/gcovr.js b/gcovr-templates/html/gcovr.js index 53ac063..f22423f 100644 --- a/gcovr-templates/html/gcovr.js +++ b/gcovr-templates/html/gcovr.js @@ -8,6 +8,7 @@ initTheme(); initFontSize(); initSidebar(); + initSidebarResize(); initMobileMenu(); initFileTree(); initBreadcrumbs(); @@ -21,34 +22,42 @@ // Breadcrumb Links // =========================================== + // Find a node in the tree by its link (HTML filename) and return + // the full ancestor path as an array of nodes from root to target. + function findPathInTree(nodes, targetLink) { + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + if (node.link === targetLink) { + return [node]; + } + if (node.children) { + var childPath = findPathInTree(node.children, targetLink); + if (childPath) { + return [node].concat(childPath); + } + } + } + return null; + } + function initBreadcrumbs() { var currentSpan = document.querySelector('.breadcrumb .current'); if (!currentSpan || !window.GCOVR_TREE_DATA) return; - var pathText = currentSpan.textContent.trim(); - var segments = pathText.split(' / '); - if (segments.length <= 1) return; - - // Auto-detect and skip prefix segments not in tree (e.g., "boost", "json") - // Find the first segment that matches a root node in the tree - var startIndex = 0; - var rootNames = window.GCOVR_TREE_DATA.map(function(n) { return n.name; }); - for (var i = 0; i < segments.length; i++) { - if (rootNames.indexOf(segments[i]) !== -1) { - startIndex = i; - break; - } - } - // Skip prefix segments - segments = segments.slice(startIndex); - if (segments.length === 0) return; + // Find current page in tree by its HTML filename — this is unambiguous + // since each page only appears once in the tree. + var currentPage = window.location.pathname.split('/').pop() || 'index.html'; + var treePath = findPathInTree(window.GCOVR_TREE_DATA, currentPage); - // Create linked breadcrumb by traversing tree + if (!treePath || treePath.length === 0) return; + + // Build breadcrumb from the tree path (ancestor nodes → current node) var fragment = document.createDocumentFragment(); - var currentNodes = window.GCOVR_TREE_DATA; + var matchedSegments = []; - for (var i = 0; i < segments.length; i++) { - var segment = segments[i]; + for (var i = 0; i < treePath.length; i++) { + var node = treePath[i]; + var isLast = (i === treePath.length - 1); if (i > 0) { var sep = document.createElement('span'); @@ -57,37 +66,29 @@ fragment.appendChild(sep); } - // Find this segment in current level of tree - var foundNode = null; - for (var j = 0; j < currentNodes.length; j++) { - if (currentNodes[j].name === segment) { - foundNode = currentNodes[j]; - break; - } - } + matchedSegments.push(node.name); - if (foundNode && foundNode.link && i < segments.length - 1) { - // Directory segment with link - make it clickable + if (node.link && !isLast) { var a = document.createElement('a'); - a.href = foundNode.link; - a.textContent = segment; + a.href = node.link; + a.textContent = node.name; fragment.appendChild(a); - // Move to children for next iteration - currentNodes = foundNode.children || []; } else { - // Last segment (current file) or no link found var span = document.createElement('span'); span.className = 'current-file'; - span.textContent = segment; + span.textContent = node.name; fragment.appendChild(span); - if (foundNode && foundNode.children) { - currentNodes = foundNode.children; - } } } currentSpan.innerHTML = ''; currentSpan.appendChild(fragment); + + // Update source-filename to match breadcrumb path + var sourceFilename = document.querySelector('.source-filename'); + if (sourceFilename) { + sourceFilename.textContent = matchedSegments.join('/'); + } } // =========================================== @@ -95,68 +96,52 @@ // =========================================== function initTheme() { - const selector = document.getElementById('theme-selector'); const toggle = document.getElementById('theme-toggle'); - const menu = document.getElementById('theme-menu'); const label = toggle ? toggle.querySelector('.theme-label') : null; - const options = menu ? menu.querySelectorAll('.theme-option') : []; - const savedTheme = localStorage.getItem('gcovr-theme') || 'system'; + const iconSun = toggle ? toggle.querySelector('.icon-sun') : null; + const iconMoon = toggle ? toggle.querySelector('.icon-moon') : null; // Get system preference function getSystemTheme() { return window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'; } + // Get effective theme: saved preference or OS default + function getEffectiveTheme() { + var saved = localStorage.getItem('gcovr-theme'); + return (saved === 'light' || saved === 'dark') ? saved : getSystemTheme(); + } + // Apply theme to document function applyTheme(theme) { - const effectiveTheme = theme === 'system' ? getSystemTheme() : theme; - document.documentElement.setAttribute('data-theme', effectiveTheme); - document.documentElement.setAttribute('data-theme-setting', theme); + document.documentElement.setAttribute('data-theme', theme); if (label) { label.textContent = theme.charAt(0).toUpperCase() + theme.slice(1); } - // Update active state in menu - options.forEach(function(opt) { - opt.classList.toggle('active', opt.getAttribute('data-theme') === theme); - }); + if (iconSun) iconSun.style.display = (theme === 'light') ? 'block' : 'none'; + if (iconMoon) iconMoon.style.display = (theme === 'dark') ? 'block' : 'none'; } - // Apply saved theme - applyTheme(savedTheme); + // Apply current theme + applyTheme(getEffectiveTheme()); - // Listen for system theme changes + // Listen for system theme changes — only apply if no stored preference window.matchMedia('(prefers-color-scheme: light)').addEventListener('change', function() { - const current = localStorage.getItem('gcovr-theme') || 'system'; - if (current === 'system') { - applyTheme('system'); + var saved = localStorage.getItem('gcovr-theme'); + if (saved !== 'light' && saved !== 'dark') { + applyTheme(getSystemTheme()); } }); - // Toggle menu - if (toggle && selector) { - toggle.addEventListener('click', function(e) { - e.stopPropagation(); - selector.classList.toggle('open'); + // Toggle between light and dark on click + if (toggle) { + toggle.addEventListener('click', function() { + var current = getEffectiveTheme(); + var next = (current === 'dark') ? 'light' : 'dark'; + localStorage.setItem('gcovr-theme', next); + applyTheme(next); }); } - - // Handle option selection - options.forEach(function(option) { - option.addEventListener('click', function(e) { - e.stopPropagation(); - const theme = option.getAttribute('data-theme'); - localStorage.setItem('gcovr-theme', theme); - applyTheme(theme); - selector.classList.remove('open'); - }); - }); - - // Close menu when clicking outside - document.addEventListener('click', function(e) { - if (selector && !selector.contains(e.target)) { - selector.classList.remove('open'); - } - }); } // =========================================== @@ -271,6 +256,7 @@ if (toggle) toggle.textContent = '−'; } }); + saveExpandedFolders(); }); } @@ -281,6 +267,7 @@ var toggle = item.querySelector(':scope > .tree-item-header > .tree-folder-toggle'); if (toggle) toggle.textContent = '+'; }); + saveExpandedFolders(); }); } } @@ -307,7 +294,15 @@ toggle.addEventListener('click', function() { sidebar.classList.toggle('collapsed'); sidebar.classList.remove('hover-expand'); - localStorage.setItem('sidebar-collapsed', sidebar.classList.contains('collapsed')); + var isNowCollapsed = sidebar.classList.contains('collapsed'); + localStorage.setItem('sidebar-collapsed', isNowCollapsed); + // Restore custom width when un-collapsing + if (!isNowCollapsed) { + var savedWidth = localStorage.getItem('gcovr-sidebar-width'); + if (savedWidth) { + document.documentElement.style.setProperty('--sidebar-width', savedWidth + 'px'); + } + } }); } @@ -371,6 +366,67 @@ }); } + // =========================================== + // Sidebar Resize + // =========================================== + + function initSidebarResize() { + var sidebar = document.getElementById('sidebar'); + var handle = document.getElementById('sidebar-resize-handle'); + if (!sidebar || !handle) return; + + var MIN_WIDTH = 200; + var startX, startWidth; + + // Restore saved width + var savedWidth = localStorage.getItem('gcovr-sidebar-width'); + if (savedWidth && !sidebar.classList.contains('collapsed')) { + var w = parseInt(savedWidth, 10); + if (w >= MIN_WIDTH) { + document.documentElement.style.setProperty('--sidebar-width', w + 'px'); + } + } + + function getMaxWidth() { + return Math.floor(window.innerWidth * 0.5); + } + + function onMouseMove(e) { + var newWidth = startWidth + (e.clientX - startX); + var maxW = getMaxWidth(); + if (newWidth < MIN_WIDTH) newWidth = MIN_WIDTH; + if (newWidth > maxW) newWidth = maxW; + document.documentElement.style.setProperty('--sidebar-width', newWidth + 'px'); + } + + function onMouseUp() { + document.body.classList.remove('sidebar-resizing'); + document.removeEventListener('mousemove', onMouseMove); + document.removeEventListener('mouseup', onMouseUp); + // Save the current width + var computed = parseInt(getComputedStyle(sidebar).width, 10); + localStorage.setItem('gcovr-sidebar-width', computed); + } + + handle.addEventListener('mousedown', function(e) { + if (sidebar.classList.contains('collapsed')) return; + e.preventDefault(); + startX = e.clientX; + startWidth = parseInt(getComputedStyle(sidebar).width, 10); + document.body.classList.add('sidebar-resizing'); + document.addEventListener('mousemove', onMouseMove); + document.addEventListener('mouseup', onMouseUp); + }); + + // Double-click to reset to default width + var DEFAULT_WIDTH = 320; + handle.addEventListener('dblclick', function() { + if (sidebar.classList.contains('collapsed')) return; + document.documentElement.style.setProperty('--sidebar-width', DEFAULT_WIDTH + 'px'); + localStorage.setItem('gcovr-sidebar-width', DEFAULT_WIDTH); + }); + } + // =========================================== // Mobile Menu // =========================================== @@ -419,6 +475,10 @@ // Check for embedded tree data first (works for local file:// access) if (window.GCOVR_TREE_DATA) { + window.GCOVR_TREE_DATA = normalizeTree(window.GCOVR_TREE_DATA); + deduplicateTree(window.GCOVR_TREE_DATA); + collapseSingleChildDirs(window.GCOVR_TREE_DATA); + deduplicateTree(window.GCOVR_TREE_DATA); renderTree(treeContainer, window.GCOVR_TREE_DATA); return; } @@ -430,7 +490,11 @@ return response.json(); }) .then(function(tree) { - renderTree(treeContainer, tree); + window.GCOVR_TREE_DATA = normalizeTree(tree); + deduplicateTree(window.GCOVR_TREE_DATA); + collapseSingleChildDirs(window.GCOVR_TREE_DATA); + deduplicateTree(window.GCOVR_TREE_DATA); + renderTree(treeContainer, window.GCOVR_TREE_DATA); }) .catch(function(err) { console.log('tree.json not found, using static sidebar'); @@ -438,6 +502,126 @@ }); } + // Collapse single-child directory chains: if a directory has exactly + // one child and that child is also a directory, absorb the grandchildren. + // e.g. include > boost > capy > [items] becomes include > [items] + function collapseSingleChildDirs(nodes) { + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + if (!node.isDirectory || !node.children) continue; + while (node.children.length === 1 && node.children[0].isDirectory && + node.children[0].children && node.children[0].children.length > 0) { + var child = node.children[0]; + if (!node.link && child.link) node.link = child.link; + node.children = child.children; + } + collapseSingleChildDirs(node.children); + } + } + + // Deduplicate tree: when a node has a child with the same name + // (e.g. include > include), merge the child's children upward. + // This happens when gcovr directory pages list entries with paths + // that include the parent directory name. + function deduplicateTree(nodes) { + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + if (!node.children || node.children.length === 0) continue; + for (var j = node.children.length - 1; j >= 0; j--) { + var child = node.children[j]; + if (child.name === node.name && child.isDirectory) { + node.children.splice(j, 1); + if (!node.link && child.link) node.link = child.link; + if (!node.coverage && child.coverage) node.coverage = child.coverage; + if (!node.coverageClass && child.coverageClass) node.coverageClass = child.coverageClass; + if (child.children) { + for (var k = 0; k < child.children.length; k++) { + node.children.push(child.children[k]); + } + } + } + } + deduplicateTree(node.children); + } + } + + // Normalize tree: expand multi-segment node names (e.g. "capy/buffers") + // into proper nested directory structures so the tree and breadcrumbs + // display correctly. + function normalizeTree(nodes) { + if (!nodes || nodes.length === 0) return nodes; + + var groups = {}; + var order = []; + + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + var slashIdx = node.name.indexOf('/'); + + if (slashIdx === -1) { + // Simple name — add directly or merge with existing group + if (groups[node.name]) { + var existing = groups[node.name]; + if (node.link) existing.link = node.link; + if (node.coverage) existing.coverage = node.coverage; + if (node.coverageClass) existing.coverageClass = node.coverageClass; + if (node.children && node.children.length > 0) { + existing.children = (existing.children || []).concat(node.children); + } + } else { + var copy = {}; + for (var key in node) { + if (node.hasOwnProperty(key)) copy[key] = node[key]; + } + groups[node.name] = copy; + order.push(node.name); + } + } else { + // Multi-segment name — split on first '/' and group + var prefix = node.name.substring(0, slashIdx); + var rest = node.name.substring(slashIdx + 1); + + if (!groups[prefix]) { + groups[prefix] = { + name: prefix, + isDirectory: true, + children: [] + }; + order.push(prefix); + } + if (!groups[prefix].children) groups[prefix].children = []; + + // Create child node with remaining path as name + var childNode = {}; + for (var key in node) { + if (node.hasOwnProperty(key)) childNode[key] = node[key]; + } + childNode.name = rest; + groups[prefix].children.push(childNode); + } + } + + // Build result with recursive normalization + var result = []; + for (var i = 0; i < order.length; i++) { + var node = groups[order[i]]; + if (node.children && node.children.length > 0) { + node.children = normalizeTree(node.children); + } + result.push(node); + } + return result; + } + + // Save expanded folder paths to localStorage + function saveExpandedFolders() { + var paths = []; + document.querySelectorAll('.tree-item.expanded[data-tree-path]').forEach(function(el) { + paths.push(el.getAttribute('data-tree-path')); + }); + localStorage.setItem('gcovr-expanded-folders', JSON.stringify(paths)); + } + function renderTree(container, tree) { container.innerHTML = ''; @@ -447,7 +631,7 @@ } tree.forEach(function(item) { - container.appendChild(createTreeItem(item)); + container.appendChild(createTreeItem(item, '')); }); // Auto-expand to current file and highlight it @@ -460,29 +644,48 @@ // Find the link matching current page var currentLink = container.querySelector('a[href="' + currentPage + '"]'); - if (!currentLink) return; - - // Mark as active - var treeItem = currentLink.closest('.tree-item'); - if (treeItem) { - treeItem.classList.add('active'); - } - - // Expand all parent folders - var parent = currentLink.closest('.tree-children'); - while (parent) { - var parentItem = parent.closest('.tree-item'); - if (parentItem) { - parentItem.classList.add('expanded'); - var toggle = parentItem.querySelector(':scope > .tree-item-header > .tree-folder-toggle'); - if (toggle) toggle.textContent = '−'; + + if (currentLink) { + // Mark as active + var treeItem = currentLink.closest('.tree-item'); + if (treeItem) { + treeItem.classList.add('active'); + } + + // Expand all parent folders + var parent = currentLink.closest('.tree-children'); + while (parent) { + var parentItem = parent.closest('.tree-item'); + if (parentItem) { + parentItem.classList.add('expanded'); + var toggle = parentItem.querySelector(':scope > .tree-item-header > .tree-folder-toggle'); + if (toggle) toggle.textContent = '−'; + } + parent = parentItem ? parentItem.parentElement.closest('.tree-children') : null; + } + } + + // Restore previously expanded folders from localStorage + try { + var saved = localStorage.getItem('gcovr-expanded-folders'); + if (saved) { + var paths = JSON.parse(saved); + paths.forEach(function(path) { + var el = container.querySelector('.tree-item[data-tree-path="' + CSS.escape(path) + '"]'); + if (el && !el.classList.contains('no-children')) { + el.classList.add('expanded'); + var toggle = el.querySelector(':scope > .tree-item-header > .tree-folder-toggle'); + if (toggle) toggle.textContent = '−'; + } + }); } - parent = parentItem ? parentItem.parentElement.closest('.tree-children') : null; + } catch (e) { + // Ignore localStorage errors } - // Scroll into view + // Scroll active item into view instantly if (currentLink) { - currentLink.scrollIntoView({ block: 'center', behavior: 'smooth' }); + currentLink.scrollIntoView({ block: 'center', behavior: 'instant' }); } } @@ -507,12 +710,15 @@ return lastSlash >= 0 ? cleaned.substring(lastSlash + 1) : cleaned; } - function createTreeItem(item) { + function createTreeItem(item, parentPath) { var hasChildren = item.children && item.children.length > 0; var isDirectory = item.isDirectory || hasChildren; + var cleanedName = cleanPathName(item.name); + var treePath = parentPath ? (parentPath + '/' + cleanedName) : cleanedName; var div = document.createElement('div'); div.className = 'tree-item' + (isDirectory ? ' is-folder' : '') + (hasChildren ? '' : ' no-children'); + div.setAttribute('data-tree-path', treePath); var header = document.createElement('div'); header.className = 'tree-item-header'; @@ -529,6 +735,7 @@ e.preventDefault(); var isExpanded = div.classList.toggle('expanded'); toggle.textContent = isExpanded ? '−' : '+'; + saveExpandedFolders(); }); header.appendChild(toggle); @@ -540,6 +747,7 @@ e.preventDefault(); var isExpanded = div.classList.toggle('expanded'); toggle.textContent = isExpanded ? '−' : '+'; + saveExpandedFolders(); }); } else { var spacer = document.createElement('span'); @@ -590,7 +798,7 @@ var childrenInner = document.createElement('div'); childrenInner.className = 'tree-children-inner'; item.children.forEach(function(child) { - childrenInner.appendChild(createTreeItem(child)); + childrenInner.appendChild(createTreeItem(child, treePath)); }); childrenWrapper.appendChild(childrenInner); diff --git a/gcovr-templates/html/source_page.html b/gcovr-templates/html/source_page.html index f0e25f7..58861e7 100644 --- a/gcovr-templates/html/source_page.html +++ b/gcovr-templates/html/source_page.html @@ -3,7 +3,7 @@ {% block html_title %}{{filename}} - {{info.head}}{% endblock %} -{% block breadcrumb %}Root/{{filename | replace("/", " / ")}}{% endblock %} +{% block breadcrumb %}Index/{{filename | replace("/", " / ")}}{% endblock %} {% block sidebar_tree %} {# Show current file in sidebar #} diff --git a/gcovr-templates/html/style.css b/gcovr-templates/html/style.css index 4073163..cd70c58 100644 --- a/gcovr-templates/html/style.css +++ b/gcovr-templates/html/style.css @@ -244,6 +244,37 @@ a:hover { width: var(--sidebar-width); } +/* Sidebar Resize Handle */ +.sidebar-resize-handle { + position: absolute; + top: 0; + right: -3px; + width: 6px; + height: 100%; + cursor: col-resize; + z-index: 101; + background: transparent; + transition: background var(--transition-fast); +} + +.sidebar-resize-handle:hover { + background: var(--accent-brand); +} + +.sidebar.collapsed .sidebar-resize-handle { + display: none; +} + +body.sidebar-resizing { + user-select: none; + cursor: col-resize; +} + +body.sidebar-resizing .sidebar, +body.sidebar-resizing .main-content { + transition: none; +} + /* Sidebar Header */ .sidebar-header { display: flex; @@ -278,7 +309,7 @@ a:hover { } .sidebar-logo .boost-wordmark { - height: 18px; + height: 32px; width: auto; flex-shrink: 0; transition: transform var(--transition-fast); @@ -299,7 +330,7 @@ a:hover { } .sidebar-library { - font-size: var(--font-size-lg); + font-size: var(--font-size-xl); font-weight: 600; color: var(--text-primary); overflow: hidden; @@ -307,7 +338,7 @@ a:hover { } .sidebar-subtitle { - font-size: var(--font-size-xs); + font-size: var(--font-size-sm); font-weight: 400; color: var(--text-muted); flex-shrink: 0; @@ -442,21 +473,6 @@ a:hover { width: 100%; } -/* Position theme menu to open to the right when collapsed */ -.sidebar.collapsed .theme-menu { - bottom: 0; - left: 100%; - right: auto; - top: auto; - transform: translateX(8px) translateY(0); - margin-bottom: 0; - min-width: 120px; -} - -.sidebar.collapsed .theme-selector.open .theme-menu { - transform: translateX(8px) translateY(0); -} - .sidebar.collapsed .theme-toggle { width: 36px; height: 36px; @@ -512,17 +528,10 @@ a:hover { flex-shrink: 0; } -/* Theme icons - show based on theme setting, not effective theme */ -.theme-toggle .icon-system { display: block; } +/* Theme icons - visibility managed by JS */ .theme-toggle .icon-sun { display: none; } .theme-toggle .icon-moon { display: none; } -[data-theme-setting="light"] .theme-toggle .icon-system { display: none; } -[data-theme-setting="light"] .theme-toggle .icon-sun { display: block; } - -[data-theme-setting="dark"] .theme-toggle .icon-system { display: none; } -[data-theme-setting="dark"] .theme-toggle .icon-moon { display: block; } - /* =========================================== Font Size Control =========================================== */ @@ -768,78 +777,6 @@ a:hover { } /* Theme Selector Dropdown */ -.theme-selector { - position: relative; -} - -.theme-menu { - position: absolute; - bottom: 100%; - left: 0; - right: 0; - margin-bottom: 8px; - background: var(--bg-secondary); - border: 1px solid var(--border-color); - border-radius: var(--radius-md); - padding: 4px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); - opacity: 0; - visibility: hidden; - transform: translateY(4px); - transition: opacity var(--transition-fast), transform var(--transition-fast), visibility var(--transition-fast); - z-index: 200; -} - -.theme-selector.open .theme-menu { - opacity: 1; - visibility: visible; - transform: translateY(0); -} - -.theme-option { - display: flex; - align-items: center; - gap: 8px; - width: 100%; - padding: 8px 10px; - background: transparent; - border: none; - border-radius: var(--radius-sm); - color: var(--text-primary); - font-size: var(--font-size-sm); - cursor: pointer; - transition: background var(--transition-fast); -} - -.theme-option:hover { - background: var(--bg-hover); -} - -.theme-option svg { - width: 16px; - height: 16px; - flex-shrink: 0; - color: var(--text-secondary); -} - -.theme-option:hover svg { - color: var(--text-primary); -} - -.theme-option span { - flex: 1; - text-align: left; -} - -.theme-option .check { - opacity: 0; - color: var(--accent-brand); -} - -.theme-option.active .check { - opacity: 1; -} - .theme-label { font-size: var(--font-size-xs); white-space: nowrap; @@ -1079,7 +1016,7 @@ a:hover { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - font-size: var(--font-size-sm); + font-size: var(--font-size-md); color: var(--text-primary); } @@ -1212,7 +1149,7 @@ a:hover { .content-wrapper { flex: 1; padding: 24px; - max-width: 1400px; + max-width: 1600px; width: 100%; margin: 0 auto; } @@ -1693,8 +1630,8 @@ a:hover { } .source-table td { - padding: 0 12px; - vertical-align: top; + padding: 4px 12px; + vertical-align: middle; border-bottom: 1px solid var(--border-muted); } @@ -1703,14 +1640,16 @@ a:hover { border-right: 1px solid var(--border-color); text-align: right; user-select: none; - width: 60px; + white-space: nowrap; + width: 1%; + padding: 4px 6px; } .source-table .col-lineno a { color: var(--text-muted); text-decoration: none; display: block; - padding: 2px 0; + padding: 0; } .source-table .col-lineno a:hover { @@ -1724,13 +1663,15 @@ a:hover { background: var(--bg-tertiary); border-right: 1px solid var(--border-color); text-align: center; - width: 60px; + width: 50px; } .source-table .col-count { text-align: right; - width: 60px; + white-space: nowrap; + width: 1%; color: var(--text-muted); + padding: 4px 6px; } .source-table .col-source { @@ -2026,11 +1967,15 @@ a:hover { display: flex; } - /* Hide sidebar toggle (pin) button */ + /* Hide sidebar toggle (pin) button and resize handle */ .sidebar-toggle { display: none; } + .sidebar-resize-handle { + display: none; + } + /* Show backdrop when sidebar open */ .sidebar.mobile-open ~ .sidebar-backdrop { opacity: 1;