diff --git a/CHANGELOG.md b/CHANGELOG.md index b86527c..d9d8112 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## v1.x.x (unreleased) + +### Features + +- add content width toggle to collapse sidebars and widen the content area on desktop +- add table of contents collapse toggle with initial tooltip in the top right corner +- refactor styles to align better with styleguide + ## v1.2.1 (2026-05-27) ### Bug Fixes diff --git a/mkdocs_doubleslash_theme/assets/javascripts/content-width-toggle.js b/mkdocs_doubleslash_theme/assets/javascripts/content-width-toggle.js new file mode 100644 index 0000000..97dcee8 --- /dev/null +++ b/mkdocs_doubleslash_theme/assets/javascripts/content-width-toggle.js @@ -0,0 +1,156 @@ +(function () { + "use strict"; + + var STORAGE_KEY = "ds-content-wide"; + var DESKTOP_QUERY = "(min-width: 76.25em)"; + var LABEL_COLLAPSE = "Navigation ausblenden"; + var LABEL_EXPAND = "Navigation einblenden"; + + function isWideMode() { + return document.documentElement.hasAttribute("data-ds-content-wide"); + } + + function setWideMode(enabled) { + if (enabled) { + document.documentElement.setAttribute("data-ds-content-wide", ""); + try { + localStorage.setItem(STORAGE_KEY, "true"); + } catch (e) {} + } else { + document.documentElement.removeAttribute("data-ds-content-wide"); + try { + localStorage.removeItem(STORAGE_KEY); + } catch (e) {} + } + } + + function sidebarIsHidden(sidebar) { + return !sidebar || sidebar.hasAttribute("hidden"); + } + + function hasCollapsibleSidebars() { + var primary = document.querySelector(".md-sidebar--primary"); + return !sidebarIsHidden(primary); + } + + function updateButtonState(button) { + var wide = isWideMode(); + var collapseIcon = button.querySelector(".ds-content-width-toggle__icon--collapse"); + var expandIcon = button.querySelector(".ds-content-width-toggle__icon--expand"); + + button.setAttribute("aria-pressed", wide ? "true" : "false"); + button.setAttribute("aria-label", wide ? LABEL_EXPAND : LABEL_COLLAPSE); + button.setAttribute("title", wide ? LABEL_EXPAND : LABEL_COLLAPSE); + + if (collapseIcon) { + collapseIcon.hidden = wide; + } + if (expandIcon) { + expandIcon.hidden = !wide; + } + } + + function updateButtonVisibility(button, desktopMedia) { + var shouldShow = desktopMedia.matches && hasCollapsibleSidebars(); + button.hidden = !shouldShow; + + if (!shouldShow && isWideMode()) { + setWideMode(false); + updateButtonState(button); + document.dispatchEvent(new CustomEvent("ds-content-wide-change")); + } + } + + function updateButtonPosition(button) { + if (isWideMode() || button.hidden) { + button.style.removeProperty("left"); + return; + } + + var content = document.querySelector(".md-content"); + if (!content) { + button.style.removeProperty("left"); + return; + } + + // Align with .md-content border-left (the divider belongs to content, not the sidebar). + button.style.left = content.getBoundingClientRect().left + "px"; + } + + function scheduleButtonPositionUpdate(button) { + window.requestAnimationFrame(function () { + updateButtonPosition(button); + }); + } + + function init() { + var button = document.querySelector("[data-md-component='content-width-toggle']"); + if (!button) { + return; + } + + var desktopMedia = window.matchMedia(DESKTOP_QUERY); + + try { + if (localStorage.getItem(STORAGE_KEY) === "true") { + setWideMode(true); + } + } catch (e) {} + + function refreshButton(button, desktopMedia) { + updateButtonVisibility(button, desktopMedia); + updateButtonState(button); + updateButtonPosition(button); + } + + refreshButton(button, desktopMedia); + + button.addEventListener("click", function () { + setWideMode(!isWideMode()); + refreshButton(button, desktopMedia); + document.dispatchEvent(new CustomEvent("ds-content-wide-change")); + }); + + desktopMedia.addEventListener("change", function () { + refreshButton(button, desktopMedia); + }); + + window.addEventListener("resize", function () { + refreshButton(button, desktopMedia); + }); + + document.addEventListener("ds-toc-collapse-change", function () { + scheduleButtonPositionUpdate(button); + }); + + if (typeof MutationObserver !== "undefined") { + var layoutObserver = new MutationObserver(function () { + scheduleButtonPositionUpdate(button); + }); + layoutObserver.observe(document.documentElement, { + attributes: true, + attributeFilter: ["data-ds-toc-collapsed", "data-ds-content-wide"], + }); + } + + if (typeof ResizeObserver !== "undefined") { + var resizeObserver = new ResizeObserver(function () { + scheduleButtonPositionUpdate(button); + }); + var content = document.querySelector(".md-content"); + var mainInner = document.querySelector(".md-main__inner"); + if (content) { + resizeObserver.observe(content); + } + if (mainInner) { + resizeObserver.observe(mainInner); + } + } + } + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); + } else { + init(); + } +})(); diff --git a/mkdocs_doubleslash_theme/assets/javascripts/toc-collapse-toggle.js b/mkdocs_doubleslash_theme/assets/javascripts/toc-collapse-toggle.js new file mode 100644 index 0000000..74c74c9 --- /dev/null +++ b/mkdocs_doubleslash_theme/assets/javascripts/toc-collapse-toggle.js @@ -0,0 +1,162 @@ +(function () { + "use strict"; + + var STORAGE_KEY = "ds-toc-collapsed"; + var TOOLTIP_STORAGE_KEY = "ds-toc-toggle-tooltip-shown"; + var DESKTOP_QUERY = "(min-width: 76.25em)"; + var TOOLTIP_DURATION_MS = 3000; + var LABEL_COLLAPSE = "Inhaltsverzeichnis ausblenden"; + var LABEL_EXPAND = "Inhaltsverzeichnis einblenden"; + + function isTocCollapsed() { + return document.documentElement.hasAttribute("data-ds-toc-collapsed"); + } + + function setTocCollapsed(enabled) { + if (enabled) { + document.documentElement.setAttribute("data-ds-toc-collapsed", ""); + try { + localStorage.setItem(STORAGE_KEY, "true"); + } catch (e) {} + } else { + document.documentElement.removeAttribute("data-ds-toc-collapsed"); + try { + localStorage.removeItem(STORAGE_KEY); + } catch (e) {} + } + } + + function tocSidebarIsHidden() { + var secondary = document.querySelector(".md-sidebar--secondary"); + return !secondary || secondary.hasAttribute("hidden"); + } + + function updateButtonState(button) { + var collapsed = isTocCollapsed(); + var collapseIcon = button.querySelector(".ds-toc-toggle__icon--collapse"); + var expandIcon = button.querySelector(".ds-toc-toggle__icon--expand"); + + button.setAttribute("aria-pressed", collapsed ? "true" : "false"); + button.setAttribute("aria-label", collapsed ? LABEL_EXPAND : LABEL_COLLAPSE); + button.setAttribute("title", collapsed ? LABEL_EXPAND : LABEL_COLLAPSE); + + if (collapseIcon) { + collapseIcon.hidden = collapsed; + } + if (expandIcon) { + expandIcon.hidden = !collapsed; + } + } + + function hideTooltip(tooltip) { + if (!tooltip || tooltip.hidden) { + return; + } + tooltip.classList.remove("ds-toc-toggle__tooltip--visible"); + window.setTimeout(function () { + tooltip.hidden = true; + }, 200); + } + + function updateButtonVisibility(button, tooltip, desktopMedia) { + var wasVisible = !button.hidden; + var shouldShow = desktopMedia.matches && !tocSidebarIsHidden(); + button.hidden = !shouldShow; + + if (!shouldShow) { + if (wasVisible) { + hideTooltip(tooltip); + } + if (isTocCollapsed()) { + setTocCollapsed(false); + updateButtonState(button); + } + return; + } + + maybeShowInitialTooltip(button, tooltip); + } + + function maybeShowInitialTooltip(button, tooltip) { + if (!tooltip || button.hidden) { + return; + } + + try { + if (sessionStorage.getItem(TOOLTIP_STORAGE_KEY) === "true") { + return; + } + } catch (e) { + return; + } + + showInitialTooltip(tooltip, button); + } + + function showInitialTooltip(tooltip, button) { + if (!tooltip || tooltip.classList.contains("ds-toc-toggle__tooltip--visible")) { + return; + } + + try { + sessionStorage.setItem(TOOLTIP_STORAGE_KEY, "true"); + } catch (e) {} + + tooltip.hidden = false; + window.requestAnimationFrame(function () { + tooltip.classList.add("ds-toc-toggle__tooltip--visible"); + }); + + window.setTimeout(function () { + hideTooltip(tooltip); + }, TOOLTIP_DURATION_MS); + + button.addEventListener( + "click", + function () { + hideTooltip(tooltip); + }, + { once: true } + ); + } + + function init() { + var button = document.querySelector("[data-md-component='toc-collapse-toggle']"); + var tooltip = document.querySelector("[data-md-component='toc-collapse-tooltip']"); + if (!button) { + return; + } + + var desktopMedia = window.matchMedia(DESKTOP_QUERY); + + try { + if (localStorage.getItem(STORAGE_KEY) === "true") { + setTocCollapsed(true); + } + } catch (e) {} + + updateButtonState(button); + updateButtonVisibility(button, tooltip, desktopMedia); + + button.addEventListener("click", function () { + setTocCollapsed(!isTocCollapsed()); + updateButtonState(button); + document.dispatchEvent(new CustomEvent("ds-toc-collapse-change")); + }); + + desktopMedia.addEventListener("change", function () { + updateButtonVisibility(button, tooltip, desktopMedia); + updateButtonState(button); + }); + + window.addEventListener("resize", function () { + updateButtonVisibility(button, tooltip, desktopMedia); + }); + } + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); + } else { + init(); + } +})(); diff --git a/mkdocs_doubleslash_theme/assets/stylesheets/mkdocs-doubleslash-theme.css b/mkdocs_doubleslash_theme/assets/stylesheets/mkdocs-doubleslash-theme.css index 7b4c023..1426774 100644 --- a/mkdocs_doubleslash_theme/assets/stylesheets/mkdocs-doubleslash-theme.css +++ b/mkdocs_doubleslash_theme/assets/stylesheets/mkdocs-doubleslash-theme.css @@ -1,56 +1,88 @@ -[data-md-color-scheme="default"] { - /* Primary color shades */ - --md-primary-fg-color: #ffffff; /* Foreground color. Mainly used for header */ - --md-primary-bg-color: #00759e; /* Icon and text color (header) */ - --md-primary-bg-color--light: #00759e; /* Search placeholder text color */ - --md-default-fg-color--light: #000000; - - /* Accent color shades */ - --md-accent-fg-color: #00759e; /* Link hover color, search item match color */ - --md-accent-fg-color--transparent: #00a5e120; /* search item hover color */ - --md-accent-bg-color: #ffffff; /* text color for hovered items (back to top, linked tag, ..) */ - - --md-typeset-a-color: #00759e; /* Active link color */ - --md-custom-accent-color: #00759e; - --md-custom-text-color: #ffffff; - - --language-toggle-active-color: #ffffff; - --language-toggle-active-text-color: #00759e; - --language-toggle-inactive-text-color: #ffffff; - - --md-typeset-color: #000000; +/* Design system tokens — source: frontend/DESIGN.md (living-styleguide, ref=main) */ +:root { + --ds-color-primary: #00759e; + --ds-color-on-primary: #ffffff; + --ds-color-brand-cyan: #00a5e1; + --ds-color-canvas: #ffffff; + --ds-color-surface-bright: #f9f9f9; + --ds-color-surface-medium: #efefef; + --ds-color-ink: #000000; + --ds-color-tertiary: #6d6d6d; + --ds-color-border: #6d6d6d; + --ds-color-disabled-shape: #c6c6c6; + --ds-color-shadow-elevation: #0000001a; + --ds-color-shadow-token: #00000029; + --ds-color-dark-clickable: #77ddff; + --ds-color-dark-ink: #d7e9f4; + --ds-color-dark-ink-secondary: #afc1c7; + --ds-color-dark-canvas: #15202b; + --ds-color-dark-container: #22303c; + --ds-color-dark-hover: #2d3740; + --ds-color-dark-disabled: #84999f; + --ds-rounded-xs: 4px; + --ds-rounded-md: 10px; + --ds-rounded-pill: 32px; + --ds-spacing-xs: 4px; + --ds-spacing-sm: 6px; + --ds-spacing-md: 8px; + --ds-spacing-control-height: 43px; + --ds-spacing-xl: 16px; + --ds-spacing-xxl: 24px; + --ds-motion-duration: 0.3s; + --ds-motion-transition: var(--ds-motion-duration) ease all; +} - --md-footer-bg-color: #6d6d6d; +[data-md-color-scheme="default"] { + --md-primary-fg-color: var(--ds-color-on-primary); + --md-primary-bg-color: var(--ds-color-primary); + --md-primary-bg-color--light: var(--ds-color-primary); + --md-default-fg-color--light: var(--ds-color-ink); + + --md-accent-fg-color: var(--ds-color-primary); + --md-accent-fg-color--transparent: #00a5e120; + --md-accent-bg-color: var(--ds-color-canvas); + + --md-typeset-a-color: var(--ds-color-primary); + --md-custom-accent-color: var(--ds-color-primary); + --md-custom-text-color: var(--ds-color-on-primary); + + --language-toggle-active-color: var(--ds-color-on-primary); + --language-toggle-active-text-color: var(--ds-color-primary); + --language-toggle-inactive-text-color: var(--ds-color-on-primary); + + --md-typeset-color: var(--ds-color-ink); + --md-footer-bg-color: var(--ds-color-canvas); + --md-footer-bg-color--dark: var(--ds-color-tertiary); + --md-footer-fg-color: var(--ds-color-tertiary); } [data-md-color-scheme="slate"] { --md-hue: 210; - --md-default-fg-color: #d7e9f4; /* Text color */ - --md-default-bg-color: #15202b; /* Background color */ - --md-default-fg-color--light: #d7e9f4; - - /* Primary color shades */ - --md-primary-fg-color: #22303c; /* Foreground color. Mainly used for header */ - --md-primary-bg-color: #77ddff; /* Icon and text color (header) */ - --md-primary-bg-color--light: #77ddff; /* Search placeholder text color */ + --md-default-fg-color: var(--ds-color-dark-ink); + --md-default-bg-color: var(--ds-color-dark-canvas); + --md-default-fg-color--light: var(--ds-color-dark-ink); - /* Accent color shades */ - --md-accent-fg-color: #77ddff; /* Link/card hover color, search item match color */ - --md-accent-fg-color--transparent: #00a5e120; /* search item hover color */ - --md-accent-bg-color: #ffffff; /* text color for hovered items (back to top, linked tag, ..) */ + --md-primary-fg-color: var(--ds-color-dark-container); + --md-primary-bg-color: var(--ds-color-dark-clickable); + --md-primary-bg-color--light: var(--ds-color-dark-clickable); - --md-typeset-a-color: #77ddff; /* Active link color */ - --md-custom-accent-color: #15202b; - --md-custom-text-color: #d7e9f4; + --md-accent-fg-color: var(--ds-color-dark-clickable); + --md-accent-fg-color--transparent: #00a5e120; + --md-accent-bg-color: var(--ds-color-canvas); - --language-toggle-active-color: #22303c; - --language-toggle-active-text-color: #77ddff; - --language-toggle-inactive-text-color: #77ddff; + --md-typeset-a-color: var(--ds-color-dark-clickable); + --md-custom-accent-color: var(--ds-color-dark-canvas); + --md-custom-text-color: var(--ds-color-dark-ink); - --md-typeset-color: #ffffff; + --language-toggle-active-color: var(--ds-color-dark-container); + --language-toggle-active-text-color: var(--ds-color-dark-clickable); + --language-toggle-inactive-text-color: var(--ds-color-dark-clickable); - --md-footer-bg-color--dark: #22303c; + --md-typeset-color: var(--ds-color-dark-ink); + --md-footer-bg-color: var(--ds-color-dark-container); + --md-footer-bg-color--dark: var(--ds-color-dark-container); + --md-footer-fg-color: var(--ds-color-dark-ink-secondary); } @font-face { @@ -68,27 +100,40 @@ } :root { - --md-text-font: Inter; + --md-text-font: Inter, Arial, Helvetica, sans-serif; .md-header--shadow { - box-shadow: 0 0 6px #00000029; + box-shadow: 0 0 10px var(--ds-color-shadow-elevation); } .md-header { - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding-top: var(--ds-spacing-xs); + padding-bottom: var(--ds-spacing-xs); } .md-search__form { background-color: var(--md-primary-fg-color); border: 1px solid var(--md-primary-bg-color); - border-radius: 8px; + border-radius: var(--ds-rounded-md); + min-height: var(--ds-spacing-control-height); + } + + [data-md-toggle="search"]:checked ~ .md-header .md-search__form { + border-radius: var(--ds-rounded-md) var(--ds-rounded-md) 0 0; + } + + .md-search__output { + border: 1px solid var(--md-primary-bg-color); + border-radius: 0 0 var(--ds-rounded-md) var(--ds-rounded-md); } .md-tabs__item { color: var(--md-typeset-color); opacity: 1; - font-weight: bold; + font-family: "Inter SemiBold", Arial, Helvetica, sans-serif; + font-size: 15px; + font-weight: 600; + line-height: 24px; } .md-tabs__item a:hover { @@ -98,7 +143,7 @@ .md-tabs__item--active { color: var(--md-typeset-a-color); opacity: 1; - font-weight: bold; + font-weight: 600; } .md-top:hover { @@ -106,8 +151,8 @@ } .md-header__title { - margin-left: 0.5rem; - margin-right: 0.4rem; + margin-left: var(--ds-spacing-md); + margin-right: var(--ds-spacing-sm); } .md-logo svg { @@ -117,8 +162,8 @@ } .md-header__button.md-logo { - margin: 0.2rem; - padding: 0.2rem; + margin: var(--ds-spacing-xs); + padding: var(--ds-spacing-xs); } .md-status { @@ -129,10 +174,23 @@ border-left: none; } + /* Stretch main area on short pages so the content divider reaches the footer */ + .md-main { + display: flex; + flex-direction: column; + } + + .md-main__inner { + flex: 1; + width: 100%; + align-items: stretch; + } + .md-content { border-left: solid; - border-width: thin; - border-color: #6d6d6d80; + border-width: 1px; + border-color: var(--ds-color-border); + transition: border-color var(--ds-motion-duration) ease; } .md-content .md-typeset h1, @@ -141,38 +199,63 @@ .md-content .md-typeset h4, .md-content .md-typeset h5, .md-content .md-typeset h6 { - font-family: "Inter SemiBold", sans-serif; + font-family: "Inter SemiBold", Arial, Helvetica, sans-serif; font-weight: 600; } + /* Website typography — source: typography.body-website, heading-h*-website */ body { + font-family: Inter, Arial, Helvetica, sans-serif; font-size: 18px; line-height: 27px; } .md-content .md-typeset h1 { font-size: 45px; + line-height: 58.5px; margin-bottom: 30px; } .md-content .md-typeset h2 { - font-size: 25px; + font-size: 40px; + line-height: 52px; margin-bottom: 15px; } .md-content .md-typeset h3 { font-size: 25px; + line-height: 40px; + margin-bottom: 12px; + } + + .md-content .md-typeset h4 { + font-size: 23px; + line-height: 29.9px; + margin-bottom: 12px; + } + + .md-content .md-typeset h5 { + font-size: 20px; + line-height: 26px; + margin-bottom: 12px; + } + + .md-content .md-typeset h6 { + font-size: 18px; + line-height: 24px; margin-bottom: 12px; } + /* link-primary — no underline at rest */ .md-typeset a { - text-decoration: underline; + text-decoration: none; color: var(--md-typeset-a-color); - transition: text-decoration-thickness 0.2s ease; + transition: var(--ds-motion-transition); } .md-typeset a:hover { - text-decoration-thickness: 2px; + text-decoration: underline; + text-decoration-thickness: 1px; } [data-md-color-scheme="default"] .md-typeset ul:not([class]) > li { @@ -180,24 +263,92 @@ } [data-md-color-scheme="slate"] .md-typeset ul:not([class]) > li { - list-style-image: url("data:image/svg+xml;utf8,"); + list-style-image: url("data:image/svg+xml;utf8,"); } + /* table-default — source: docs/components-html-css/Molecules/table.md */ .md-typeset table:not([class]) { + border: none; border-collapse: collapse; - border-radius: 10px; + border-radius: var(--ds-rounded-md); + box-shadow: none; + font-size: 15px; + line-height: 19px; + white-space: nowrap; + } + + .md-typeset table:not([class]) thead { + font-family: "Inter SemiBold", Arial, Helvetica, sans-serif; + font-weight: 600; + color: var(--md-typeset-color); + } + + /* Rahmen um tbody per Pseudo-Elemente (Default-Stil) */ + .md-typeset table:not([class]) tbody { + position: relative; + } + + .md-typeset table:not([class]) tbody::before, + .md-typeset table:not([class]) tbody::after { + content: ""; + position: absolute; + inset: 0; + border: 1px solid var(--ds-color-disabled-shape); + border-radius: var(--ds-rounded-md); + pointer-events: none; + } + + .md-typeset table:not([class]) th { + padding: 0 15px 7px 15px; + background-color: transparent; + text-align: left; + } + + .md-typeset table:not([class]) td { + padding: 15px; + border: none; } - tr:last-child { + .md-typeset table:not([class]) tbody tr { + height: 50px; + border-bottom: 1px solid var(--ds-color-disabled-shape); + text-align: left; + } + + .md-typeset table:not([class]) tbody tr:last-child { border-bottom: none; } - td:last-child { - border-right: none; + .md-typeset table:not([class]) tbody tr:hover { + background-color: var(--ds-color-surface-bright); + } + + [data-md-color-scheme="slate"] .md-typeset table:not([class]) tbody::before, + [data-md-color-scheme="slate"] .md-typeset table:not([class]) tbody::after { + border-color: var(--ds-color-dark-disabled); + } + + [data-md-color-scheme="slate"] .md-typeset table:not([class]) tbody tr { + border-bottom-color: var(--ds-color-dark-disabled); + } + + [data-md-color-scheme="slate"] .md-typeset table:not([class]) tbody tr:hover { + background-color: var(--ds-color-dark-hover); } .md-path__item:not(:first-child) { align-items: center; + font-size: 13px; + line-height: 16px; + } + + .md-footer { + font-size: 15px; + line-height: 19px; + } + + .md-footer-meta { + border-top: 1px solid var(--ds-color-disabled-shape); } } @@ -208,6 +359,406 @@ width: 1rem; } +/* switch-icon-3 — source: docs/components-html-css/Molecules/switch.md (Icon-3) */ +.ds-switch-wrapper.md-header__option { + width: auto; + flex-shrink: 0; + overflow: visible; +} + +.ds-switch-wrapper { + padding: 0; + margin: 0 var(--ds-spacing-md) 0 0; +} + +.ds-switch-wrapper *, +.ds-switch-wrapper *::before, +.ds-switch-wrapper *::after { + box-sizing: border-box; +} + +.ds-switch-wrapper .switch-field { + display: flex; + overflow: hidden; + position: relative; + border-radius: 1rem; + align-items: center; + user-select: none; +} + +.ds-switch-wrapper .switch-field input[type="radio"] { + position: absolute; + clip: rect(0, 0, 0, 0); + height: 0.0625rem; + width: 0.0625rem; + border: 0; + overflow: hidden; +} + +.ds-switch-wrapper .switch-field label.option { + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 2rem; + width: 2rem; + min-width: 0; + background-color: var(--ds-color-primary); + color: var(--ds-color-on-primary); + font: normal normal 600 0.75rem/1.563rem Inter, Arial, Helvetica, sans-serif; + text-align: center; + padding: 0.25rem; + margin-right: -0.0625rem; + cursor: pointer; + transition: all 0.1s ease-in-out; +} + +.ds-switch-wrapper .switch-field label.option:last-of-type { + margin-right: 0; +} + +.ds-switch-wrapper .switch-field label.option:hover { + cursor: pointer; +} + +.ds-switch-wrapper .switch { + display: flex; + align-items: center; + justify-content: center; + width: 1.75rem; + height: 1.25rem; + padding: 0; + background-color: var(--ds-color-on-primary); + color: var(--ds-color-primary); + border-radius: 2rem; + position: absolute; + z-index: 2; + border: 0; + transition: 0.3s ease all; + left: 0.125rem; + pointer-events: none; +} + +.ds-switch-wrapper .switch__icon { + display: none; + align-items: center; + justify-content: center; +} + +.ds-switch-wrapper .switch__icon svg { + height: 0.875rem; + width: 0.875rem; +} + +.ds-switch-wrapper svg.lucide-circle-half path { + fill: currentColor; +} + +.ds-switch-wrapper .switch-field:hover .switch { + transform: translateX(0.125rem); +} + +.ds-switch-wrapper:has(#__palette_1:checked) .switch-field:hover .switch { + transform: none; +} + +.ds-switch-wrapper:has(#__palette_2:checked) .switch-field:hover .switch { + transform: translateX(-0.125rem); +} + +.ds-switch-wrapper:has(#__palette_0:checked) .switch { + left: 0.125rem; +} + +.ds-switch-wrapper:has(#__palette_1:checked) .switch { + left: 2.0625rem; +} + +.ds-switch-wrapper:has(#__palette_2:checked) .switch { + left: 4rem; +} + +.ds-switch-wrapper:has(#__palette_0:checked) .switch__icon--0, +.ds-switch-wrapper:has(#__palette_1:checked) .switch__icon--1, +.ds-switch-wrapper:has(#__palette_2:checked) .switch__icon--2 { + display: flex; +} + +.ds-switch-wrapper .switch-field label.option:focus-visible { + outline: none; + box-shadow: + 0 0 0 2px var(--ds-color-on-primary), + 0 0 0 4px var(--ds-color-primary); + border-radius: 2rem; +} + +/* Dark mode: darker track distinct from header, rounded sliding pill for the active segment */ +[data-md-color-scheme="slate"] .ds-switch-wrapper .switch-field { + background-color: var(--ds-color-dark-canvas); +} + +[data-md-color-scheme="slate"] .ds-switch-wrapper .switch-field label.option { + background-color: var(--ds-color-dark-canvas); + color: var(--ds-color-dark-clickable); +} + +[data-md-color-scheme="slate"] .ds-switch-wrapper .switch { + background-color: var(--ds-color-dark-container); + color: var(--ds-color-dark-clickable); +} + +[data-md-color-scheme="slate"] .ds-switch-wrapper .switch-field label.option:focus-visible { + box-shadow: + 0 0 0 2px var(--ds-color-dark-canvas), + 0 0 0 4px var(--ds-color-dark-clickable); +} + .md-grid { max-width: min(1800px, 100% - 4rem); } + +@media screen and (min-width: 76.25em) { + .md-content { + padding-left: 40px; + } + + .md-sidebar--primary, + .md-sidebar--secondary { + transition: + width var(--ds-motion-duration) ease, + min-width var(--ds-motion-duration) ease, + opacity var(--ds-motion-duration) ease, + visibility 0s linear 0s; + } + + .md-main__inner { + transition: margin var(--ds-motion-duration) ease; + } + + html[data-ds-content-wide] .md-sidebar--primary { + width: 0; + min-width: 0; + opacity: 0; + overflow: hidden; + pointer-events: none; + visibility: hidden; + transition: + width var(--ds-motion-duration) ease, + min-width var(--ds-motion-duration) ease, + opacity var(--ds-motion-duration) ease, + visibility 0s linear var(--ds-motion-duration); + } + + html[data-ds-toc-collapsed] .md-sidebar--secondary { + width: 0; + min-width: 0; + opacity: 0; + overflow: hidden; + pointer-events: none; + visibility: hidden; + transition: + width var(--ds-motion-duration) ease, + min-width var(--ds-motion-duration) ease, + opacity var(--ds-motion-duration) ease, + visibility 0s linear var(--ds-motion-duration); + } + + html[data-ds-content-wide] .md-main__inner { + margin-left: 0; + } + + html[data-ds-toc-collapsed] .md-main__inner { + margin-right: 80px; + } + + html[data-ds-content-wide] .md-content { + border-left-color: transparent; + } + + .ds-content-width-toggle { + --ds-toggle-size: 2rem; + position: fixed; + top: 50%; + margin-top: calc(var(--ds-toggle-size) / -2); + margin-left: calc(var(--ds-toggle-size) / -2); + display: flex; + align-items: center; + justify-content: center; + width: var(--ds-toggle-size); + height: var(--ds-toggle-size); + padding: 0; + border: 2px solid var(--ds-color-border); + border-radius: 50px; + background-color: var(--md-default-bg-color); + color: var(--md-default-fg-color); + cursor: pointer; + transition: var(--ds-motion-transition); + } + + .ds-content-width-toggle:hover { + color: white; + background-color: var(--ds-color-primary); + + } + + .ds-content-width-toggle:focus-visible { + outline: none; + box-shadow: + 0 0 0 2px var(--ds-color-on-primary), + 0 0 0 4px var(--ds-color-primary); + } + + [data-md-color-scheme="slate"] .ds-content-width-toggle:focus-visible { + box-shadow: + 0 0 0 2px var(--ds-color-dark-canvas), + 0 0 0 4px var(--ds-color-dark-clickable); + } + + .ds-content-width-toggle[hidden] { + display: none; + } + + .ds-content-width-toggle__icon { + display: flex; + align-items: center; + justify-content: center; + } + + .ds-content-width-toggle__icon[hidden] { + display: none; + } + + html[data-ds-content-wide] .ds-content-width-toggle { + --ds-toggle-size: var(--ds-spacing-control-height); + left: var(--ds-spacing-xl); + margin-left: 0; + border: inset 0 0 0 2px var(--ds-color-primary); + border-radius: 50px; + } + + [data-md-color-scheme="slate"] html[data-ds-content-wide] .ds-content-width-toggle { + border-color: var(--ds-color-dark-clickable); + } + + .ds-toc-toggle-wrapper { + position: fixed; + top: 6rem; + right: var(--ds-spacing-xl); + } + + .ds-toc-toggle { + display: flex; + align-items: center; + justify-content: center; + width: var(--ds-spacing-control-height); + height: var(--ds-spacing-control-height); + padding: 0; + margin: 5px 0 0 0; + border: inset 0 0 0 2px var(--ds-color-primary); + border-radius: 50px; + background-color: var(--md-default-bg-color); + color: var(--md-default-fg-color); + cursor: pointer; + transition: var(--ds-motion-transition); + } + + [data-md-color-scheme="slate"] .ds-toc-toggle { + border-color: var(--ds-color-dark-clickable); + } + + .ds-toc-toggle:hover { + color: white; + background-color: var(--ds-color-primary); + } + + .ds-toc-toggle:focus-visible { + outline: none; + box-shadow: + 0 0 0 2px var(--ds-color-on-primary), + 0 0 0 4px var(--ds-color-primary); + } + + [data-md-color-scheme="slate"] .ds-toc-toggle:focus-visible { + box-shadow: + 0 0 0 2px var(--ds-color-dark-canvas), + 0 0 0 4px var(--ds-color-dark-clickable); + } + + .ds-toc-toggle[hidden], + .ds-toc-toggle-wrapper:has(.ds-toc-toggle[hidden]) { + display: none; + } + + .ds-toc-toggle__icon { + display: flex; + align-items: center; + justify-content: center; + } + + .ds-toc-toggle__icon[hidden] { + display: none; + } + + /* tooltip-light */ + .ds-toc-toggle__tooltip { + position: absolute; + top: calc(100% + var(--ds-spacing-xl)); + right: 0; + width: min(14rem, calc(100vw - 2 * var(--ds-spacing-xl))); + padding: var(--ds-spacing-xl) var(--ds-spacing-xxl); + border-radius: var(--ds-rounded-md); + background-color: var(--ds-color-surface-medium); + color: var(--ds-color-ink); + font-size: 15px; + line-height: 24px; + text-align: left; + white-space: normal; + overflow-wrap: break-word; + word-wrap: break-word; + hyphens: auto; + box-sizing: border-box; + box-shadow: 0 0 10px var(--ds-color-shadow-elevation); + opacity: 0; + pointer-events: none; + transition: opacity 0.3s ease; + } + + .ds-toc-toggle__tooltip::before { + content: ""; + position: absolute; + bottom: 100%; + right: calc(var(--ds-spacing-control-height) / 2); + transform: translateX(50%); + border: 8px solid transparent; + border-bottom-color: var(--ds-color-surface-medium); + filter: drop-shadow(0 -2px 1px var(--ds-color-shadow-elevation)); + } + + [data-md-color-scheme="slate"] .ds-toc-toggle__tooltip { + background-color: var(--ds-color-disabled-shape); + color: var(--ds-color-ink); + } + + [data-md-color-scheme="slate"] .ds-toc-toggle__tooltip::before { + border-bottom-color: var(--ds-color-disabled-shape); + } + + .ds-toc-toggle__tooltip--visible { + opacity: 1; + } + + .ds-toc-toggle__tooltip[hidden] { + display: none; + } + + @media (prefers-reduced-motion: reduce) { + .md-sidebar--primary, + .md-sidebar--secondary, + .md-main__inner, + .md-content, + .ds-content-width-toggle, + .ds-toc-toggle, + .ds-switch-wrapper .switch { + transition: none !important; + } + } +} diff --git a/mkdocs_doubleslash_theme/overrides/.icons/lucide/chevrons-left.svg b/mkdocs_doubleslash_theme/overrides/.icons/lucide/chevrons-left.svg new file mode 100644 index 0000000..3786f5e --- /dev/null +++ b/mkdocs_doubleslash_theme/overrides/.icons/lucide/chevrons-left.svg @@ -0,0 +1 @@ + diff --git a/mkdocs_doubleslash_theme/overrides/.icons/lucide/chevrons-right.svg b/mkdocs_doubleslash_theme/overrides/.icons/lucide/chevrons-right.svg new file mode 100644 index 0000000..2fe0cbc --- /dev/null +++ b/mkdocs_doubleslash_theme/overrides/.icons/lucide/chevrons-right.svg @@ -0,0 +1 @@ + diff --git a/mkdocs_doubleslash_theme/overrides/.icons/lucide/circle-half.svg b/mkdocs_doubleslash_theme/overrides/.icons/lucide/circle-half.svg new file mode 100644 index 0000000..4bd6c80 --- /dev/null +++ b/mkdocs_doubleslash_theme/overrides/.icons/lucide/circle-half.svg @@ -0,0 +1 @@ + diff --git a/mkdocs_doubleslash_theme/overrides/partials/content-width-toggle.html b/mkdocs_doubleslash_theme/overrides/partials/content-width-toggle.html new file mode 100644 index 0000000..cbeb24b --- /dev/null +++ b/mkdocs_doubleslash_theme/overrides/partials/content-width-toggle.html @@ -0,0 +1,16 @@ + diff --git a/mkdocs_doubleslash_theme/overrides/partials/header.html b/mkdocs_doubleslash_theme/overrides/partials/header.html index 61bd393..1e5e00c 100644 --- a/mkdocs_doubleslash_theme/overrides/partials/header.html +++ b/mkdocs_doubleslash_theme/overrides/partials/header.html @@ -30,6 +30,18 @@ {% endif %} +{% if config.extra.ds_content_width_toggle | default(true) %} + +{% endif %}
+{% if config.extra.ds_content_width_toggle | default(true) %} + {% include "partials/content-width-toggle.html" %} + {% include "partials/toc-collapse-toggle.html" %} +{% endif %} \ No newline at end of file diff --git a/mkdocs_doubleslash_theme/overrides/partials/palette.html b/mkdocs_doubleslash_theme/overrides/partials/palette.html new file mode 100644 index 0000000..759ff3e --- /dev/null +++ b/mkdocs_doubleslash_theme/overrides/partials/palette.html @@ -0,0 +1,56 @@ + + +
+
+
+ + + {% for option in config.theme.palette %} + {% set scheme = option.scheme | d("default", true) %} + {% set primary = option.primary | d("indigo", true) %} + {% set accent = option.accent | d("indigo", true) %} + + {% if option.toggle %} + + {% endif %} + {% endfor %} +
+
+
diff --git a/mkdocs_doubleslash_theme/overrides/partials/toc-collapse-toggle.html b/mkdocs_doubleslash_theme/overrides/partials/toc-collapse-toggle.html new file mode 100644 index 0000000..26de683 --- /dev/null +++ b/mkdocs_doubleslash_theme/overrides/partials/toc-collapse-toggle.html @@ -0,0 +1,26 @@ +
+ + +
diff --git a/mkdocs_doubleslash_theme/plugin.py b/mkdocs_doubleslash_theme/plugin.py index c6fcb89..1908056 100644 --- a/mkdocs_doubleslash_theme/plugin.py +++ b/mkdocs_doubleslash_theme/plugin.py @@ -1,5 +1,6 @@ import os +from mkdocs.config import config_options from mkdocs.plugins import BasePlugin from mkdocs.structure.files import File @@ -7,6 +8,10 @@ class DoubleSlashThemePlugin(BasePlugin): """MkDocs plugin that applies doubleSlash corporate styling to Material theme.""" + config_scheme = ( + ("content_width_toggle", config_options.Type(bool, default=True)), + ) + def __init__(self): super().__init__() plugin_dir = os.path.dirname(__file__) @@ -17,6 +22,16 @@ def on_config(self, config): theme = config["theme"] config["extra_css"].append("stylesheets/mkdocs-doubleslash-theme.css") + content_width_toggle = self.config.get("content_width_toggle", True) + config.setdefault("extra", {})["ds_content_width_toggle"] = content_width_toggle + if content_width_toggle: + config["extra_javascript"].append( + "javascripts/content-width-toggle.js" + ) + config["extra_javascript"].append( + "javascripts/toc-collapse-toggle.js" + ) + # Insert overrides after user's custom_dir (if any) so user overrides take precedence if self.overrides_dir not in theme.dirs: insert_pos = ( @@ -30,30 +45,30 @@ def on_config(self, config): if not theme.get("palette"): theme["palette"] = [ { - "media": "(prefers-color-scheme)", + "media": "(prefers-color-scheme: dark)", + "primary": "custom", + "accent": "custom", + "scheme": "slate", "toggle": { - "icon": "lucide/sun-moon", - "name": "Switch to light mode", + "icon": "lucide/moon-star", + "name": "Dark mode", }, }, { - "media": "(prefers-color-scheme: light)", - "primary": "custom", - "accent": "custom", - "scheme": "default", + "media": "(prefers-color-scheme)", "toggle": { - "icon": "lucide/sun", - "name": "Switch to dark mode", + "icon": "lucide/circle-half", + "name": "System color scheme", }, }, { - "media": "(prefers-color-scheme: dark)", + "media": "(prefers-color-scheme: light)", "primary": "custom", "accent": "custom", - "scheme": "slate", + "scheme": "default", "toggle": { - "icon": "lucide/moon-star", - "name": "Switch to system preference", + "icon": "lucide/sun", + "name": "Light mode", }, }, ]