diff options
| author | 2023-10-07 06:48:07 +0800 | |
|---|---|---|
| committer | 2023-10-07 06:48:07 +0800 | |
| commit | 991fd7a6d67ee017c57beaaa21fc31c4bee7944d (patch) | |
| tree | e895202203fcaa50b0052f60ef6fc7d6d2928cf9 /src/templates/assets/stylesheets | |
| parent | d62900046bb6f754a8e6e7e670a66a90134055d9 (diff) | |
| download | infini-991fd7a6d67ee017c57beaaa21fc31c4bee7944d.tar.gz infini-991fd7a6d67ee017c57beaaa21fc31c4bee7944d.zip | |
feat(version): versions
Diffstat (limited to 'src/templates/assets/stylesheets')
51 files changed, 8203 insertions, 0 deletions
diff --git a/src/templates/assets/stylesheets/_config.scss b/src/templates/assets/stylesheets/_config.scss new file mode 100644 index 00000000..e64b8e29 --- /dev/null +++ b/src/templates/assets/stylesheets/_config.scss @@ -0,0 +1,42 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Variables: breakpoints +// ---------------------------------------------------------------------------- + +// Device-specific breakpoints +$break-devices: ( + mobile: ( + portrait: px2em(220px) px2em(479.75px), + landscape: px2em(480px) px2em(719.75px) + ), + tablet: ( + portrait: px2em(720px) px2em(959.75px), + landscape: px2em(960px) px2em(1219.75px) + ), + screen: ( + small: px2em(1220px) px2em(1599.75px), + medium: px2em(1600px) px2em(1999.75px), + large: px2em(2000px) + ) +); diff --git a/src/templates/assets/stylesheets/main.scss b/src/templates/assets/stylesheets/main.scss new file mode 100644 index 00000000..2b203d3d --- /dev/null +++ b/src/templates/assets/stylesheets/main.scss @@ -0,0 +1,86 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Dependencies +// ---------------------------------------------------------------------------- + +@import "material-color"; +@import "material-shadows"; + +// ---------------------------------------------------------------------------- +// Local imports +// ---------------------------------------------------------------------------- + +@import "utilities/break"; +@import "utilities/convert"; + +@import "config"; + +@import "main/resets"; +@import "main/colors"; +@import "main/icons"; +@import "main/typeset"; + +@import "main/components/author"; +@import "main/components/banner"; +@import "main/components/base"; +@import "main/components/clipboard"; +@import "main/components/consent"; +@import "main/components/content"; +@import "main/components/dialog"; +@import "main/components/feedback"; +@import "main/components/footer"; +@import "main/components/form"; +@import "main/components/header"; +@import "main/components/meta"; +@import "main/components/nav"; +@import "main/components/pagination"; +@import "main/components/post"; +@import "main/components/progress"; +@import "main/components/search"; +@import "main/components/select"; +@import "main/components/sidebar"; +@import "main/components/source"; +@import "main/components/status"; +@import "main/components/tabs"; +@import "main/components/tag"; +@import "main/components/tooltip"; +@import "main/components/top"; +@import "main/components/version"; + +@import "main/extensions/markdown/admonition"; +@import "main/extensions/markdown/footnotes"; +@import "main/extensions/markdown/toc"; + +@import "main/extensions/pymdownx/arithmatex"; +@import "main/extensions/pymdownx/critic"; +@import "main/extensions/pymdownx/details"; +@import "main/extensions/pymdownx/emoji"; +@import "main/extensions/pymdownx/highlight"; +@import "main/extensions/pymdownx/keys"; +@import "main/extensions/pymdownx/tabbed"; +@import "main/extensions/pymdownx/tasklist"; + +@import "main/integrations/mermaid"; + +@import "main/modifiers"; diff --git a/src/templates/assets/stylesheets/main/_colors.scss b/src/templates/assets/stylesheets/main/_colors.scss new file mode 100644 index 00000000..68969fe9 --- /dev/null +++ b/src/templates/assets/stylesheets/main/_colors.scss @@ -0,0 +1,153 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Color variables +:root { + @extend %root; + + // Primary color shades + --md-primary-fg-color: hsla(#{hex2hsl($clr-indigo-500)}, 1); + --md-primary-fg-color--light: hsla(#{hex2hsl($clr-indigo-400)}, 1); + --md-primary-fg-color--dark: hsla(#{hex2hsl($clr-indigo-700)}, 1); + --md-primary-bg-color: hsla(0, 0%, 100%, 1); + --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7); + + // Accent color shades + --md-accent-fg-color: hsla(#{hex2hsl($clr-indigo-a200)}, 1); + --md-accent-fg-color--transparent: hsla(#{hex2hsl($clr-indigo-a200)}, 0.1); + --md-accent-bg-color: hsla(0, 0%, 100%, 1); + --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7); +} + +// ---------------------------------------------------------------------------- + +// Allow to explicitly use color schemes in nested content +[data-md-color-scheme="default"] { + @extend %root; + + // Indicate that the site is rendered with a light color scheme + color-scheme: light; + + // Hide images for dark mode + img[src$="#only-dark"], + img[src$="#gh-dark-mode-only"] { + display: none; + } +} + +// ---------------------------------------------------------------------------- +// Placeholders +// ---------------------------------------------------------------------------- + +// Default theme, i.e. light mode +%root { + + // Color hue in the range [0,360] - change this variable to alter the tone + // of the theme, e.g. to make it more redish or greenish + --md-hue: 225deg; + + // Default color shades + --md-default-fg-color: hsla(0, 0%, 0%, 0.87); + --md-default-fg-color--light: hsla(0, 0%, 0%, 0.54); + --md-default-fg-color--lighter: hsla(0, 0%, 0%, 0.32); + --md-default-fg-color--lightest: hsla(0, 0%, 0%, 0.07); + --md-default-bg-color: hsla(0, 0%, 100%, 1); + --md-default-bg-color--light: hsla(0, 0%, 100%, 0.7); + --md-default-bg-color--lighter: hsla(0, 0%, 100%, 0.3); + --md-default-bg-color--lightest: hsla(0, 0%, 100%, 0.12); + + // Code color shades + --md-code-fg-color: hsla(200, 18%, 26%, 1); + --md-code-bg-color: hsla(200, 0%, 96%, 1); + + // Code highlighting color shades + --md-code-hl-color: hsla(#{hex2hsl($clr-blue-a200)}, 1); + --md-code-hl-color--light: hsla(#{hex2hsl($clr-blue-a200)}, 0.1); + --md-code-hl-number-color: hsla(0, 67%, 50%, 1); + --md-code-hl-special-color: hsla(340, 83%, 47%, 1); + --md-code-hl-function-color: hsla(291, 45%, 50%, 1); + --md-code-hl-constant-color: hsla(250, 63%, 60%, 1); + --md-code-hl-keyword-color: hsla(219, 54%, 51%, 1); + --md-code-hl-string-color: hsla(150, 63%, 30%, 1); + --md-code-hl-name-color: var(--md-code-fg-color); + --md-code-hl-operator-color: var(--md-default-fg-color--light); + --md-code-hl-punctuation-color: var(--md-default-fg-color--light); + --md-code-hl-comment-color: var(--md-default-fg-color--light); + --md-code-hl-generic-color: var(--md-default-fg-color--light); + --md-code-hl-variable-color: var(--md-default-fg-color--light); + + // Typeset color shades + --md-typeset-color: var(--md-default-fg-color); + + // Typeset `a` color shades + --md-typeset-a-color: var(--md-primary-fg-color); + + // Typeset `del` and `ins` color shades + --md-typeset-del-color: hsla(6, 90%, 60%, 0.15); + --md-typeset-ins-color: hsla(150, 90%, 44%, 0.15); + + // Typeset `kbd` color shades + --md-typeset-kbd-color: hsla(0, 0%, 98%, 1); + --md-typeset-kbd-accent-color: hsla(0, 100%, 100%, 1); + --md-typeset-kbd-border-color: hsla(0, 0%, 72%, 1); + + // Typeset `mark` color shades + --md-typeset-mark-color: hsla(#{hex2hsl($clr-yellow-a200)}, 0.5); + + // Typeset `table` color shades + --md-typeset-table-color: hsla(0, 0%, 0%, 0.12); + --md-typeset-table-color--light: hsla(0, 0%, 0%, 0.035); + + // Admonition color shades + --md-admonition-fg-color: var(--md-default-fg-color); + --md-admonition-bg-color: var(--md-default-bg-color); + + // Warning color shades + --md-warning-fg-color: hsla(0, 0%, 0%, 0.87); + --md-warning-bg-color: hsla(60, 100%, 80%, 1); + + // Footer color shades + --md-footer-fg-color: hsla(0, 0%, 100%, 1); + --md-footer-fg-color--light: hsla(0, 0%, 100%, 0.7); + --md-footer-fg-color--lighter: hsla(0, 0%, 100%, 0.45); + --md-footer-bg-color: hsla(0, 0%, 0%, 0.87); + --md-footer-bg-color--dark: hsla(0, 0%, 0%, 0.32); + + // Shadow depth 1 + --md-shadow-z1: + 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.05), + 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.1); + + // Shadow depth 2 + --md-shadow-z2: + 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.1), + 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.25); + + // Shadow depth 3 + --md-shadow-z3: + 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.2), + 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.35); +} diff --git a/src/templates/assets/stylesheets/main/_icons.scss b/src/templates/assets/stylesheets/main/_icons.scss new file mode 100644 index 00000000..9853e93d --- /dev/null +++ b/src/templates/assets/stylesheets/main/_icons.scss @@ -0,0 +1,37 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Icon +.md-icon { + + // SVG defaults + svg { + display: block; + width: px2rem(24px); + height: px2rem(24px); + fill: currentcolor; + } +} diff --git a/src/templates/assets/stylesheets/main/_modifiers.scss b/src/templates/assets/stylesheets/main/_modifiers.scss new file mode 100644 index 00000000..4b2b046a --- /dev/null +++ b/src/templates/assets/stylesheets/main/_modifiers.scss @@ -0,0 +1,48 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // [tablet +]: Allow for rendering content as sidebars + @include break-from-device(tablet) { + + // Modifier to float block elements + .inline { + float: inline-start; + width: px2rem(234px); + margin-inline-end: px2rem(16px); + margin-top: 0; + margin-bottom: px2rem(16px); + + // Modifier to move to end (ltr: right, rtl: left) + &.end { + float: inline-end; + margin-inline: px2rem(16px) 0; + } + } + } +} diff --git a/src/templates/assets/stylesheets/main/_resets.scss b/src/templates/assets/stylesheets/main/_resets.scss new file mode 100644 index 00000000..c6fc4b28 --- /dev/null +++ b/src/templates/assets/stylesheets/main/_resets.scss @@ -0,0 +1,118 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Enforce correct box model and prevent adjustments of font size after +// orientation changes in IE and iOS +html { + box-sizing: border-box; + text-size-adjust: none; +} + +// All elements shall inherit the document default +*, +*::before, +*::after { + box-sizing: inherit; + + // [reduced motion]: Disable all transitions + @media (prefers-reduced-motion) { + transition: none !important; // stylelint-disable-line + } +} + +// Remove margin in all browsers +body { + margin: 0; +} + +// Reset tap outlines on iOS and Android +a, +button, +label, +input { + -webkit-tap-highlight-color: transparent; +} + +// Reset link styles +a { + color: inherit; + text-decoration: none; +} + +// Normalize horizontal separator styles +hr { + box-sizing: content-box; + display: block; + height: px2rem(1px); + padding: 0; + overflow: visible; + border: 0; +} + +// Normalize font-size in all browsers +small { + font-size: 80%; +} + +// Prevent subscript and superscript from affecting line-height +sub, +sup { + line-height: 1em; +} + +// Remove border on image +img { + border-style: none; +} + +// Reset table styles +table { + border-spacing: 0; + border-collapse: separate; +} + +// Reset table cell styles +td, +th { + font-weight: 400; + vertical-align: top; +} + +// Reset button styles +button { + padding: 0; + margin: 0; + font-family: inherit; + font-size: inherit; + background: transparent; + border: 0; +} + +// Reset input styles +input { + border: 0; + outline: none; +} diff --git a/src/templates/assets/stylesheets/main/_typeset.scss b/src/templates/assets/stylesheets/main/_typeset.scss new file mode 100644 index 00000000..1c322859 --- /dev/null +++ b/src/templates/assets/stylesheets/main/_typeset.scss @@ -0,0 +1,603 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules: font definitions +// ---------------------------------------------------------------------------- + +// Enable font-smoothing in Webkit and FF +body { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + // Font with fallback for body copy + --md-text-font-family: + var(--md-text-font, _), + -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif; + + // Font with fallback for code + --md-code-font-family: + var(--md-code-font, _), + SFMono-Regular, Consolas, Menlo, monospace; +} + +// Define default fonts +body, +input, +aside { + font-family: var(--md-text-font-family); + font-feature-settings: "kern", "liga"; + color: var(--md-typeset-color); +} + +// Define monospaced fonts +code, +pre, +kbd { + font-family: var(--md-code-font-family); + font-feature-settings: "kern"; +} + +// ---------------------------------------------------------------------------- +// Rules: typesetted content +// ---------------------------------------------------------------------------- + +// General variables +:root { + --md-typeset-table-sort-icon: svg-load("material/sort.svg"); + --md-typeset-table-sort-icon--asc: svg-load("material/sort-ascending.svg"); + --md-typeset-table-sort-icon--desc: svg-load("material/sort-descending.svg"); +} + +// ---------------------------------------------------------------------------- + +// Content that is typeset - if possible, all margins, paddings and font sizes +// should be set in ems, so nested blocks (e.g. admonitions) render correctly. +.md-typeset { + font-size: px2rem(16px); + line-height: 1.6; + color-adjust: exact; + + // [print]: We'll use a smaller `font-size` for printing, so code examples + // don't break too early, and `16px` looks too big anyway. + @media print { + font-size: px2rem(13.6px); + } + + // Default spacing + ul, + ol, + dl, + figure, + blockquote, + pre { + margin-block: 1em; + } + + // Headline on level 1 + h1 { + margin: 0 0 px2em(40px, 32px); + font-size: px2em(32px); + font-weight: 300; + line-height: 1.3; + color: var(--md-default-fg-color--light); + letter-spacing: -0.01em; + } + + // Headline on level 2 + h2 { + margin: px2em(40px, 25px) 0 px2em(16px, 25px); + font-size: px2em(25px); + font-weight: 300; + line-height: 1.4; + letter-spacing: -0.01em; + } + + // Headline on level 3 + h3 { + margin: px2em(32px, 20px) 0 px2em(16px, 20px); + font-size: px2em(20px); + font-weight: 400; + line-height: 1.5; + letter-spacing: -0.01em; + } + + // Headline on level 3 following level 2 + h2 + h3 { + margin-top: px2em(16px, 20px); + } + + // Headline on level 4 + h4 { + margin: px2em(16px) 0; + font-weight: 700; + letter-spacing: -0.01em; + } + + // Headline on level 5-6 + h5, + h6 { + margin: px2em(16px, 12.8px) 0; + font-size: px2em(12.8px); + font-weight: 700; + color: var(--md-default-fg-color--light); + letter-spacing: -0.01em; + } + + // Headline on level 5 + h5 { + text-transform: uppercase; + } + + // Horizontal separator + hr { + display: flow-root; + margin: 1.5em 0; + border-bottom: px2rem(1px) solid var(--md-default-fg-color--lightest); + } + + // Text link + a { + color: var(--md-typeset-a-color); + word-break: break-word; + + // Also enable color transition on pseudo elements + &, + &::before { + transition: color 125ms; + } + + // Text link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + + // Inline code block + code { + background-color: var(--md-accent-fg-color--transparent); + } + } + + // Inline code block + code { + color: currentcolor; + transition: background-color 125ms; + } + + // Show outline for keyboard devices + &.focus-visible { + outline-color: var(--md-accent-fg-color); + outline-offset: px2rem(4px); + } + } + + // Code block + code, + pre, + kbd { + font-variant-ligatures: none; + color: var(--md-code-fg-color); + direction: ltr; + + // [print]: Wrap text and hide scollbars + @media print { + white-space: pre-wrap; + } + } + + // Inline code block + code { + padding: 0 px2em(4px, 13.6px); + font-size: px2em(13.6px); + word-break: break-word; + background-color: var(--md-code-bg-color); + border-radius: px2rem(2px); + box-decoration-break: clone; + + // Hide outline for pointer devices + &:not(.focus-visible) { + outline: none; + -webkit-tap-highlight-color: transparent; + } + } + + // Unformatted content + pre { + position: relative; + display: flow-root; + line-height: 1.4; + + // Code block + > code { + display: block; + padding: px2em(10.5px, 13.6px) px2em(16px, 13.6px); + margin: 0; + overflow: auto; + word-break: normal; + touch-action: auto; + outline-color: var(--md-accent-fg-color); + box-shadow: none; + box-decoration-break: slice; + scrollbar-width: thin; + scrollbar-color: var(--md-default-fg-color--lighter) transparent; + + // Code block on hover + &:hover { + scrollbar-color: var(--md-accent-fg-color) transparent; + } + + // Webkit scrollbar + &::-webkit-scrollbar { + width: px2rem(4px); + height: px2rem(4px); + } + + // Webkit scrollbar thumb + &::-webkit-scrollbar-thumb { + background-color: var(--md-default-fg-color--lighter); + + // Webkit scrollbar thumb on hover + &:hover { + background-color: var(--md-accent-fg-color); + } + } + } + } + + // Keyboard key + kbd { + display: inline-block; + padding: 0 px2em(8px, 12px); + font-size: px2em(12px); + color: var(--md-default-fg-color); + word-break: break-word; + vertical-align: text-top; + background-color: var(--md-typeset-kbd-color); + border-radius: px2rem(2px); + box-shadow: + 0 px2rem(2px) 0 px2rem(1px) var(--md-typeset-kbd-border-color), + 0 px2rem(2px) 0 var(--md-typeset-kbd-border-color), + 0 px2rem(-2px) px2rem(4px) var(--md-typeset-kbd-accent-color) inset; + } + + // Text highlighting marker + mark { + color: inherit; + word-break: break-word; + background-color: var(--md-typeset-mark-color); + box-decoration-break: clone; + } + + // Abbreviation + abbr { + text-decoration: none; + cursor: help; + border-bottom: px2rem(1px) dotted var(--md-default-fg-color--light); + + // Show tooltip for touch devices + @media (hover: none) { + + // Tooltip + &[title]:is(:focus, :hover)::after { + position: absolute; + inset-inline: px2rem(16px); + padding: px2rem(4px) px2rem(6px); + margin-top: 2em; + font-size: px2rem(14px); + color: var(--md-default-bg-color); + content: attr(title); + background-color: var(--md-default-fg-color); + border-radius: px2rem(2px); + box-shadow: var(--md-shadow-z3); + } + } + } + + // Small text + small { + opacity: 0.75; + } + + // Superscript and subscript + sup, + sub { + margin-inline-start: px2em(1px, 12.8px); + } + + // Blockquotes, possibly nested + blockquote { + padding-inline-start: px2rem(12px); + margin-inline: 0; + color: var(--md-default-fg-color--light); + border-inline-start: px2rem(4px) solid var(--md-default-fg-color--lighter); + } + + // Unordered list + ul { + list-style-type: disc; + } + + // Unordered and ordered list + ul, + ol { + padding: 0; + margin-inline-start: px2em(10px); + + // Adjust display mode if not hidden + &:not([hidden]) { + display: flow-root; + } + + // Nested ordered list + ol { + list-style-type: lower-alpha; + + // Triply nested ordered list + ol { + list-style-type: lower-roman; + } + } + + // List element + li { + margin-inline-start: px2em(20px); + margin-bottom: 0.5em; + + // Adjust spacing + p, + blockquote { + margin: 0.5em 0; + } + + // Adjust spacing on last child + &:last-child { + margin-bottom: 0; + } + + // Nested list + :is(ul, ol) { + margin-block: 0.5em; + margin-inline-start: px2em(10px); + } + } + } + + // Definition list + dd { + margin-block: 1em 1.5em; + margin-inline-start: px2em(30px); + } + + // Image or video + img, + svg, + video { + max-width: 100%; + height: auto; + } + + // Image + img { + + // Adjust spacing when left-aligned + &[align="left"] { + margin: 1em; + margin-left: 0; + } + + // Adjust spacing when right-aligned + &[align="right"] { + margin: 1em; + margin-right: 0; + } + + // Adjust spacing when sole children + &[align]:only-child { + margin-top: 0; + } + } + + // Figure + figure { + display: flow-root; + width: fit-content; + max-width: 100%; + margin: 1em auto; + text-align: center; + + // Figure images + img { + display: block; + } + } + + // Figure caption + figcaption { + max-width: px2rem(480px); + margin: 1em auto; + font-style: italic; + } + + // Limit width to container + iframe { + max-width: 100%; + } + + // Data table + table:not([class]) { + display: inline-block; + max-width: 100%; + overflow: auto; + font-size: px2rem(12.8px); + touch-action: auto; + background-color: var(--md-default-bg-color); + border: px2rem(1px) solid var(--md-typeset-table-color); + border-radius: px2rem(2px); + + // [print]: Reset display mode so table header wraps when printing + @media print { + display: table; + } + + // Due to margin collapse because of the necessary inline-block hack, we + // cannot increase the bottom margin on the table, so we just increase the + // top margin on the following element + + * { + margin-top: 1.5em; + } + + // Elements in table heading and cell + :is(th, td) > * { + + // Adjust spacing on first child + &:first-child { + margin-top: 0; + } + + // Adjust spacing on last child + &:last-child { + margin-bottom: 0; + } + } + + // Table heading and cell + :is(th, td):not([align]) { + text-align: left; + + // Adjust for right-to-left languages + [dir="rtl"] & { + text-align: right; + } + } + + // Table heading + th { + min-width: px2rem(100px); + padding: px2em(12px, 12.8px) px2em(16px, 12.8px); + font-weight: 700; + vertical-align: top; + } + + // Table cell + td { + padding: px2em(12px, 12.8px) px2em(16px, 12.8px); + vertical-align: top; + border-top: px2rem(1px) solid var(--md-typeset-table-color); + } + + // Table body row + tbody tr { + transition: background-color 125ms; + + // Table row on hover + &:hover { + background-color: var(--md-typeset-table-color--light); + box-shadow: 0 px2rem(1px) 0 var(--md-default-bg-color) inset; + } + } + + // Text link in table + a { + word-break: normal; + } + } + + // Sortable table + table th[role="columnheader"] { + cursor: pointer; + + // Sort icon + &::after { + display: inline-block; + width: 1.2em; + height: 1.2em; + margin-inline-start: 0.5em; + vertical-align: text-bottom; + content: ""; + transition: background-color 125ms; + mask-image: var(--md-typeset-table-sort-icon); + mask-repeat: no-repeat; + mask-size: contain; + } + + // Show sort icon on hover + &:hover::after { + background-color: var(--md-default-fg-color--lighter); + } + + // Sort ascending icon + &[aria-sort="ascending"]::after { + background-color: var(--md-default-fg-color--light); + mask-image: var(--md-typeset-table-sort-icon--asc); + } + + // Sort descending icon + &[aria-sort="descending"]::after { + background-color: var(--md-default-fg-color--light); + mask-image: var(--md-typeset-table-sort-icon--desc); + } + } + + // Data table scroll wrapper + &__scrollwrap { + margin: 1em px2rem(-16px); + overflow-x: auto; + touch-action: auto; + } + + // Data table wrapper + &__table { + display: inline-block; + padding: 0 px2rem(16px); + margin-bottom: 0.5em; + + // [print]: Reset display mode so table header wraps when printing + @media print { + display: block; + } + + // Data table + html & table { + display: table; + width: 100%; + margin: 0; + overflow: hidden; + } + } +} + +// ---------------------------------------------------------------------------- +// Rules: top-level +// ---------------------------------------------------------------------------- + +// [mobile -]: Align with body copy +@include break-to-device(mobile) { + + // Top-level unformatted content + .md-content__inner > pre { + margin: 1em px2rem(-16px); + + // Code block + code { + border-radius: 0; + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_author.scss b/src/templates/assets/stylesheets/main/components/_author.scss new file mode 100644 index 00000000..111baf40 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_author.scss @@ -0,0 +1,86 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Author, i.e., GitHub user + .md-author { + position: relative; + display: block; + flex-shrink: 0; + width: px2rem(32px); + height: px2rem(32px); + overflow: hidden; + transition: + color 125ms, + transform 125ms; + + // Author image + img { + display: block; + border-radius: 100%; + } + + // More authors + &--more { + font-size: px2rem(12px); + font-weight: 700; + line-height: px2rem(32px); + color: var(--md-default-fg-color--lighter); + text-align: center; + background: var(--md-default-fg-color--lightest); + } + + // Enlarge image + &--long { + width: px2rem(48px); + height: px2rem(48px); + } + } + + // Author link + a.md-author { + transform: scale(1); + + // Author image + img { + filter: grayscale(100%) opacity(75%); + transition: filter 125ms; + } + + // Author on focus/hover + &:is(:focus, :hover) { + z-index: 1; + transform: scale(1.1); + + // Author image + img { + filter: grayscale(0%); + } + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_banner.scss b/src/templates/assets/stylesheets/main/components/_banner.scss new file mode 100644 index 00000000..8fe08c0f --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_banner.scss @@ -0,0 +1,68 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Banner for announcements and warnings +.md-banner { + overflow: auto; + color: var(--md-footer-fg-color); + background-color: var(--md-footer-bg-color); + + // [print]: Hide banner + @media print { + display: none; + } + + // Banner with warning + &--warning { + color: var(--md-warning-fg-color); + background-color: var(--md-warning-bg-color); + } + + // Banner wrapper + &__inner { + padding: 0 px2rem(16px); + margin: px2rem(12px) auto; + font-size: px2rem(14px); + } + + // Banner button + &__button { + float: inline-end; + color: inherit; + cursor: pointer; + transition: opacity 250ms; + + // [no-js]: Hide button + .no-js & { + display: none; + } + + // Button on hover + &:hover { + opacity: 0.7; + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_base.scss b/src/templates/assets/stylesheets/main/components/_base.scss new file mode 100644 index 00000000..33f834ed --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_base.scss @@ -0,0 +1,182 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules: base grid and containers +// ---------------------------------------------------------------------------- + +// Stretch container to viewport and set base `font-size` +html { + height: 100%; + overflow-x: hidden; + // Hack: normally, we would set the base `font-size` to `62.5%`, so we can + // base all calculations on `10px`, but Chromium and Chrome define a minimal + // `font-size` of `12px` if the system language is set to Chinese. For this + // reason we just double the `font-size` and set it to `20px`. + // + // See https://github.com/squidfunk/mkdocs-material/issues/911 + font-size: 125%; + + // [screen medium +]: Set base `font-size` to `11px` + @include break-from-device(screen medium) { + font-size: 137.5%; + } + + // [screen large +]: Set base `font-size` to `12px` + @include break-from-device(screen large) { + font-size: 150%; + } +} + +// Stretch body to container - flexbox is used, so the footer will always be +// aligned to the bottom of the viewport +body { + position: relative; + display: flex; + flex-direction: column; + width: 100%; + min-height: 100%; + // Hack: reset `font-size` to `10px`, so the spacing for all inline elements + // is correct again. Otherwise the spacing would be based on `20px`. + font-size: px2rem(10px); + background-color: var(--md-default-bg-color); + + // [print]: Omit flexbox layout due to a Firefox bug (https://mzl.la/39DgR3m) + @media print { + display: block; + } + + // Body in locked state + &[data-md-scrolllock] { + + // [tablet portrait -]: Omit scroll bubbling + @include break-to-device(tablet portrait) { + position: fixed; + } + } +} + +// ---------------------------------------------------------------------------- + +// Grid container - this class is applied to wrapper elements within the +// header, content area and footer, and makes sure that their width is limited +// to `1220px`, and they are rendered centered if the screen is larger. +.md-grid { + max-width: px2rem(1220px); + margin-inline: auto; +} + +// Main container +.md-container { + display: flex; + flex-direction: column; + flex-grow: 1; + + // [print]: Omit flexbox layout due to a Firefox bug (https://mzl.la/39DgR3m) + @media print { + display: block; + } +} + +// Main area - stretch to remaining space of container +.md-main { + flex-grow: 1; + + // Main area wrapper + &__inner { + display: flex; + height: 100%; + margin-top: px2rem(24px + 6px); + } +} + +// Add ellipsis in case of overflowing text +.md-ellipsis { + overflow: hidden; + text-overflow: ellipsis; +} + +// ---------------------------------------------------------------------------- +// Rules: navigational elements +// ---------------------------------------------------------------------------- + +// Toggle - this class is applied to checkbox elements, which are used to +// implement the CSS-only drawer and navigation, as well as the search +.md-toggle { + display: none; +} + +// Option - this class is applied to radio elements, which are used to +// implement the color palette toggle +.md-option { + position: absolute; + width: 0; + height: 0; + opacity: 0; + + // Option label for checked radio button + &:checked + label:not([hidden]) { + display: block; + } + + // Show outline for keyboard devices + &.focus-visible + label { + outline-style: auto; + outline-color: var(--md-accent-fg-color); + } +} + +// Skip link +.md-skip { + position: fixed; + // Hack: if we don't set the negative `z-index`, the skip link will force the + // creation of new layers when code blocks are near the header on scrolling + z-index: -1; + padding: px2rem(6px) px2rem(10px); + margin: px2rem(10px); + font-size: px2rem(12.8px); + color: var(--md-default-bg-color); + background-color: var(--md-default-fg-color); + border-radius: px2rem(2px); + outline-color: var(--md-accent-fg-color); + opacity: 0; + transform: translateY(px2rem(8px)); + + // Show skip link on focus + &:focus { + z-index: 10; + opacity: 1; + transition: + transform 250ms cubic-bezier(0.4, 0, 0.2, 1), + opacity 175ms 75ms; + transform: translateY(0); + } +} + +// ---------------------------------------------------------------------------- +// Rules: print styles +// ---------------------------------------------------------------------------- + +// Add margins to page +@page { + margin: 25mm; +} diff --git a/src/templates/assets/stylesheets/main/components/_clipboard.scss b/src/templates/assets/stylesheets/main/components/_clipboard.scss new file mode 100644 index 00000000..c07c9c67 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_clipboard.scss @@ -0,0 +1,102 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Clipboard button variables +:root { + --md-clipboard-icon: svg-load("material/content-copy.svg"); +} + +// ---------------------------------------------------------------------------- + +// Clipboard button +.md-clipboard { + position: absolute; + top: px2em(8px); + right: px2em(8px); + z-index: 1; + width: px2em(24px); + height: px2em(24px); + color: var(--md-default-fg-color--lightest); + cursor: pointer; + border-radius: px2rem(2px); + outline-color: var(--md-accent-fg-color); + outline-offset: px2rem(2px); + transition: color 250ms; + + // [print]: Hide button + @media print { + display: none; + } + + // Hide outline for pointer devices + &:not(.focus-visible) { + outline: none; + -webkit-tap-highlight-color: transparent; + } + + // Darken color on code block hover + :hover > & { + color: var(--md-default-fg-color--light); + } + + // Button on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + + // Button icon - the width and height are defined in `em`, so the size is + // automatically adjusted for nested code blocks (e.g. in admonitions) + &::after { + display: block; + width: px2em(18px); + height: px2em(18px); + margin: 0 auto; + content: ""; + background-color: currentcolor; + mask-image: var(--md-clipboard-icon); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + } + + // Inline clipboard button + &--inline { + cursor: pointer; + + // Code block + code { + transition: + color 250ms, + background-color 250ms; + } + + // Code block on focus/hover + &:is(:focus, :hover) code { + color: var(--md-accent-fg-color); + background-color: var(--md-accent-fg-color--transparent); + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_consent.scss b/src/templates/assets/stylesheets/main/components/_consent.scss new file mode 100644 index 00000000..5502460c --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_consent.scss @@ -0,0 +1,127 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Keyframes +// ---------------------------------------------------------------------------- + +// Show consent +@keyframes consent { + 0% { + opacity: 0; + transform: translateY(100%); + } + + 100% { + opacity: 1; + transform: translateY(0); + } +} + +// Show consent overlay +@keyframes overlay { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Consent +.md-consent { + + // Consent overlay + &__overlay { + position: fixed; + top: 0; + z-index: 5; + width: 100%; + height: 100%; + background-color: hsla(0, 0%, 0%, 0.54); + opacity: 1; + backdrop-filter: blur(px2rem(2px)); + animation: overlay 250ms both; + } + + // Consent wrapper + &__inner { + position: fixed; + bottom: 0; + z-index: 5; + width: 100%; + max-height: 100%; + padding: 0; + overflow: auto; + background-color: var(--md-default-bg-color); + border: 0; + border-radius: px2rem(2px); + box-shadow: + 0 0 px2rem(4px) rgba(0, 0, 0, 0.1), + 0 px2rem(4px) px2rem(8px) rgba(0, 0, 0, 0.2); + animation: consent 500ms cubic-bezier(0.1, 0.7, 0.1, 1) both; + } + + // Consent form + &__form { + padding: px2rem(16px); + } + + // Consent settings + &__settings { + display: none; + margin: 1em 0; + + // Show settings + input:checked + & { + display: block; + } + } + + // Consent controls + &__controls { + margin-bottom: px2rem(16px); + + // Consent control button + .md-typeset & .md-button { + display: inline; + + // [tablet +]: Align buttons horizontally + @include break-to-device(mobile) { + display: block; + width: 100%; + margin-top: px2rem(8px); + text-align: center; + } + } + } + + // Ensure users realize that labels are clickaböe + label { + cursor: pointer; + } +} diff --git a/src/templates/assets/stylesheets/main/components/_content.scss b/src/templates/assets/stylesheets/main/components/_content.scss new file mode 100644 index 00000000..7c945749 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_content.scss @@ -0,0 +1,97 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Content area +.md-content { + flex-grow: 1; + // Hack: we must use `min-width: 0`, so the content area is capped by the + // dimensions of its parent. Otherwise, long code blocks might lead to a + // wider content area which will overflow. See https://bit.ly/3bP3f8k + min-width: 0; + + // Content wrapper + &__inner { + padding-top: px2rem(12px); + margin: 0 px2rem(16px) px2rem(24px); + + // [screen +]: Adjust spacing between content area and sidebars + @include break-from-device(screen) { + + // Sidebar with navigation is visible + .md-sidebar--primary:not([hidden]) ~ .md-content > & { + margin-inline-start: px2rem(24px); + } + + // Sidebar with table of contents is visible + .md-sidebar--secondary:not([hidden]) ~ .md-content > & { + margin-inline-end: px2rem(24px); + } + } + + // Hack: add pseudo element for spacing, as the overflow of the content + // container may not be hidden due to an imminent offset error on targets + &::before { + display: block; + height: px2rem(8px); + content: ""; + } + + // Adjust spacing on last child + > :last-child { + margin-bottom: 0; + } + } + + // Button inside of the content area - these buttons are meant for actions on + // a document-level, i.e. linking to related source code files, printing etc. + &__button { + float: inline-end; + padding: 0; + margin: px2rem(8px) 0; + margin-inline-start: px2rem(8px); + + // [print]: Hide buttons + @media print { + display: none; + } + + // Adjust default link color for icons + .md-typeset & { + color: var(--md-default-fg-color--lighter); + } + + // Align with body copy located next to icon + svg { + display: inline; + vertical-align: top; + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: scaleX(-1); + } + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_dialog.scss b/src/templates/assets/stylesheets/main/components/_dialog.scss new file mode 100644 index 00000000..16782ede --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_dialog.scss @@ -0,0 +1,65 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Dialog +.md-dialog { + position: fixed; + bottom: px2rem(16px); + z-index: 4; + min-width: px2rem(222px); + padding: px2rem(8px) px2rem(12px); + pointer-events: none; + background-color: var(--md-default-fg-color); + border-radius: px2rem(2px); + box-shadow: var(--md-shadow-z3); + opacity: 0; + transition: + transform 0ms 400ms, + opacity 400ms; + transform: translateY(100%); + inset-inline-end: px2rem(16px); + + // [print]: Hide dialog + @media print { + display: none; + } + + // Active dialog + &--active { + pointer-events: initial; + opacity: 1; + transition: + transform 400ms cubic-bezier(0.075, 0.85, 0.175, 1), + opacity 400ms; + transform: translateY(0); + } + + // Dialog wrapper + &__inner { + font-size: px2rem(14px); + color: var(--md-default-bg-color); + } +} diff --git a/src/templates/assets/stylesheets/main/components/_feedback.scss b/src/templates/assets/stylesheets/main/components/_feedback.scss new file mode 100644 index 00000000..bbcd00e9 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_feedback.scss @@ -0,0 +1,110 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Was this page helpful? +.md-feedback { + margin: 2em 0 1em; + text-align: center; + + // Feedback fieldset + fieldset { + padding: 0; + margin: 0; + border: none; + } + + // Feedback title + &__title { + margin: 1em auto; + font-weight: 700; + } + + // Feedback wrapper + &__inner { + position: relative; + } + + // Feedback list + &__list { + position: relative; + display: flex; + flex-wrap: wrap; + align-content: baseline; + justify-content: center; + + // Feedback icon on hover + &:hover .md-icon:not(:disabled) { + color: var(--md-default-fg-color--lighter); + } + + // Adjust height after submission + :disabled & { + min-height: px2rem(36px); + } + } + + // Feedback icon + &__icon { + flex-shrink: 0; + margin: 0 px2rem(2px); + color: var(--md-default-fg-color--light); + cursor: pointer; + transition: color 125ms; + + // Feedback icon on hover + &:not(:disabled).md-icon:hover { + color: var(--md-accent-fg-color); + } + + // Feedback icon after submit + &:disabled { + color: var(--md-default-fg-color--lightest); + pointer-events: none; + } + } + + // Feedback note + &__note { + position: relative; + opacity: 0; + transition: + transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 150ms; + transform: translateY(px2rem(8px)); + + // Feedback note value + > * { + max-width: px2rem(320px); + margin: 0 auto; + } + + // Show after submission + :disabled & { + opacity: 1; + transform: translateY(0); + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_footer.scss b/src/templates/assets/stylesheets/main/components/_footer.scss new file mode 100644 index 00000000..9fabc05b --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_footer.scss @@ -0,0 +1,201 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Footer +.md-footer { + color: var(--md-footer-fg-color); + background-color: var(--md-footer-bg-color); + + // [print]: Hide footer + @media print { + display: none; + } + + // Footer wrapper + &__inner { + justify-content: space-between; + padding: px2rem(4px); + overflow: auto; + + // Footer is visible + &:not([hidden]) { + display: flex; + } + } + + // Footer link to previous and next page + &__link { + display: flex; + // Hack: some browsers induce ellipsis on flex children that are set to + // `overflow: hidden` and `text-overflow: ellipsis`. Enforcing growth by + // a tiny factor seems to get rid of the ellipsis and renders the text as + // it should - see https://bit.ly/2ZUCXQ8 + flex-grow: 0.01; + align-items: end; + max-width: 100%; + margin-block: px2rem(20px) px2rem(8px); + overflow: hidden; + outline-color: var(--md-accent-fg-color); + transition: opacity 250ms; + + // Footer link on focus/hover + &:is(:focus, :hover) { + opacity: 0.7; + } + + // Adjust for right-to-left languages + [dir="rtl"] & svg { + transform: scaleX(-1); + } + + // [mobile -]: Adjust width to 25/75 and hide title + @include break-to-device(mobile) { + + // Footer link to previous page + &--prev { + flex-shrink: 0; + + // Hide footer title + .md-footer__title { + display: none; + } + } + } + + // Footer link to next page + &--next { + margin-inline-start: auto; + text-align: right; + + // Adjust for right-to-left languages + [dir="rtl"] & { + text-align: left; + } + } + } + + // Footer title + &__title { + flex-grow: 1; + max-width: calc(100% - #{px2rem(48px)}); + padding: 0 px2rem(20px); + margin-bottom: px2rem(14px); + font-size: px2rem(18px); + white-space: nowrap; + } + + // Footer link button + &__button { + padding: px2rem(8px); + margin: px2rem(4px); + } + + // Footer link direction (i.e. prev and next) + &__direction { + font-size: px2rem(12.8px); + opacity: 0.7; + } +} + +// Footer metadata +.md-footer-meta { + background-color: var(--md-footer-bg-color--dark); + + // Footer metadata wrapper + &__inner { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + padding: px2rem(4px); + } + + // Lighten color for non-hovered text links + html &.md-typeset a { + color: var(--md-footer-fg-color--light); + + // Text link on focus/hover + &:is(:focus, :hover) { + color: var(--md-footer-fg-color); + } + } +} + +// ---------------------------------------------------------------------------- + +// Copyright and theme information +.md-copyright { + width: 100%; + padding: px2rem(8px) 0; + margin: auto px2rem(12px); + font-size: px2rem(12.8px); + color: var(--md-footer-fg-color--lighter); + + // [tablet portrait +]: Show copyright and social links in one line + @include break-from-device(tablet portrait) { + width: auto; + } + + // Footer copyright highlight - this is the upper part of the copyright and + // theme information, which will include a darker color than the theme link + &__highlight { + color: var(--md-footer-fg-color--light); + } +} + +// ---------------------------------------------------------------------------- + +// Social links +.md-social { + display: inline-flex; + gap: px2rem(4px); + padding: px2rem(4px) 0 px2rem(12px); + margin: 0 px2rem(8px); + + // [tablet portrait +]: Show copyright and social links in one line + @include break-from-device(tablet portrait) { + padding: px2rem(12px) 0; + } + + // Footer social link + &__link { + display: inline-block; + width: px2rem(32px); + height: px2rem(32px); + text-align: center; + + // Adjust line-height to match height for correct alignment + &::before { + line-height: 1.9; + } + + // Fill icon with current color + svg { + max-height: px2rem(16px); + vertical-align: -25%; + fill: currentcolor; + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_form.scss b/src/templates/assets/stylesheets/main/components/_form.scss new file mode 100644 index 00000000..49b59e42 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_form.scss @@ -0,0 +1,83 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Form button + .md-button { + display: inline-block; + padding: px2em(10px) px2em(32px); + font-weight: 700; + color: var(--md-primary-fg-color); + cursor: pointer; + border: px2rem(2px) solid currentcolor; + border-radius: px2rem(2px); + transition: + color 125ms, + background-color 125ms, + border-color 125ms; + + // Primary button + &--primary { + color: var(--md-primary-bg-color); + background-color: var(--md-primary-fg-color); + border-color: var(--md-primary-fg-color); + } + + // Button on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-bg-color); + background-color: var(--md-accent-fg-color); + border-color: var(--md-accent-fg-color); + } + } + + // Form input + .md-input { + height: px2rem(36px); + padding: 0 px2rem(12px); + font-size: px2rem(16px); + border-bottom: px2rem(2px) solid var(--md-default-fg-color--lighter); + border-start-start-radius: px2rem(2px); + border-start-end-radius: px2rem(2px); + box-shadow: var(--md-shadow-z1); + transition: + border 250ms, + box-shadow 250ms; + + // Input on focus/hover + &:is(:focus, :hover) { + border-bottom-color: var(--md-accent-fg-color); + box-shadow: var(--md-shadow-z2); + } + + // Stretch to full width + &--stretch { + width: 100%; + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_header.scss b/src/templates/assets/stylesheets/main/components/_header.scss new file mode 100644 index 00000000..e51f3f99 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_header.scss @@ -0,0 +1,270 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Header - by default, the header will be sticky and stay always on top of the +// viewport. If this behavior is not desired, just set `position: static`. +.md-header { + position: sticky; + inset-inline: 0; + top: 0; + z-index: 4; + display: block; + color: var(--md-primary-bg-color); + background-color: var(--md-primary-fg-color); + // Hack: reduce jitter by adding a transparent box shadow of the same size + // so the size of the layer doesn't change during animation + box-shadow: + 0 0 px2rem(4px) rgba(0, 0, 0, 0), + 0 px2rem(4px) px2rem(8px) rgba(0, 0, 0, 0); + + // [print]: Hide header + @media print { + display: none; + } + + // Header is hidden + &[hidden] { + transition: + transform 250ms cubic-bezier(0.8, 0, 0.6, 1), + box-shadow 250ms; + transform: translateY(-100%); + } + + // Header in shadow state, i.e. shadow is visible + &--shadow { + box-shadow: + 0 0 px2rem(4px) rgba(0, 0, 0, 0.1), + 0 px2rem(4px) px2rem(8px) rgba(0, 0, 0, 0.2); + transition: + transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1), + box-shadow 250ms; + } + + // Header wrapper + &__inner { + display: flex; + align-items: center; + padding: 0 px2rem(4px); + } + + // Header button + &__button { + position: relative; + z-index: 1; + padding: px2rem(8px); + margin: px2rem(4px); + color: currentcolor; + vertical-align: middle; + cursor: pointer; + outline-color: var(--md-accent-fg-color); + transition: opacity 250ms; + + // Button on hover + &:hover { + opacity: 0.7; + } + + // Header button is visible + &:not([hidden]) { + display: inline-block; + } + + // Hide outline for pointer devices + &:not(.focus-visible) { + outline: none; + -webkit-tap-highlight-color: transparent; + } + + // Button with logo, pointing to `config.site_url` + &.md-logo { + padding: px2rem(8px); + margin: px2rem(4px); + + // [tablet -]: Hide button + @include break-to-device(tablet) { + display: none; + } + + // Image or icon + :is(img, svg) { + display: block; + width: auto; + height: px2rem(24px); + fill: currentcolor; + } + } + + // Button for search + &[for="__search"] { + + // [tablet landscape +]: Hide button + @include break-from-device(tablet landscape) { + display: none; + } + + // [no-js]: Hide button + .no-js & { + display: none; + } + + // Adjust for right-to-left languages + [dir="rtl"] & svg { + transform: scaleX(-1); + } + } + + // Button for drawer + &[for="__drawer"] { + + // [screen +]: Hide button + @include break-from-device(screen) { + display: none; + } + } + } + + // Header topic + &__topic { + position: absolute; + display: flex; + max-width: 100%; + white-space: nowrap; + transition: + transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 150ms; + + // Second header topic - title of the current page + & + & { + z-index: -1; + pointer-events: none; + opacity: 0; + transition: + transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1), + opacity 150ms; + transform: translateX(px2rem(25px)); + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translateX(px2rem(-25px)); + } + } + + // Adjust font weight of site title + &:first-child { + font-weight: 700; + } + } + + // Header title + &__title { + flex-grow: 1; + height: px2rem(48px); + margin-inline-start: px2rem(20px); + margin-inline-end: px2rem(8px); + font-size: px2rem(18px); + line-height: px2rem(48px); + + // Header title in active state, i.e. page title is visible + &--active .md-header__topic { + z-index: -1; + pointer-events: none; + opacity: 0; + transition: + transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1), + opacity 150ms; + transform: translateX(px2rem(-25px)); + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translateX(px2rem(25px)); + } + + // Second header topic - title of the current page + + .md-header__topic { + z-index: 0; + pointer-events: initial; + opacity: 1; + transition: + transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 150ms; + transform: translateX(0); + } + } + + // Add ellipsis in case of overflowing text + > .md-header__ellipsis { + position: relative; + width: 100%; + height: 100%; + } + } + + // Header option + &__option { + display: flex; + flex-shrink: 0; + max-width: 100%; + white-space: nowrap; + transition: + max-width 0ms 250ms, + opacity 250ms 250ms; + + // Hide toggle when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + max-width: 0; + opacity: 0; + transition: + max-width 0ms, + opacity 0ms; + } + + // Hack: Firefox 117 introduces a bug where the browser scrolls the page by + // a small amount to the top every time the header button is focused. After + // investigating, we're confident that it seems to be caused by the input + // field being too close to the border - see https://t.ly/APO8l + > input { + bottom: 0; + } + } + + // Repository information container + &__source { + display: none; + + // [tablet landscape +]: Show repository information + @include break-from-device(tablet landscape) { + display: block; + width: px2rem(234px); + max-width: px2rem(234px); + margin-inline-start: px2rem(20px); + } + + // [screen +]: Adjust spacing of search bar + @include break-from-device(screen) { + margin-inline-start: px2rem(28px); + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_meta.scss b/src/templates/assets/stylesheets/main/components/_meta.scss new file mode 100644 index 00000000..aaeae8df --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_meta.scss @@ -0,0 +1,67 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Metadata +.md-meta { + font-size: px2rem(14px); + line-height: 1.3; + color: var(--md-default-fg-color--light); + + // Metadata list + &__list { + display: inline-flex; + flex-wrap: wrap; + padding: 0; + margin: 0; + list-style: none; + } + + // Metadata item separator + &__item:not(:last-child)::after { + margin-inline: px2rem(4px); + content: "·"; + } + + // Metadata link + &__link { + color: var(--md-typeset-a-color); + + // Metadata link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + } +} + +// Draft +.md-draft { + display: inline-block; + padding-inline: px2em(8px, 14px); + font-weight: 700; + color: hsla(255, 100%, 100%); + background-color: $clr-red-a400; + border-radius: px2em(2px); +} diff --git a/src/templates/assets/stylesheets/main/components/_nav.scss b/src/templates/assets/stylesheets/main/components/_nav.scss new file mode 100644 index 00000000..673918af --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_nav.scss @@ -0,0 +1,761 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Navigation variables +:root { + --md-nav-icon--prev: svg-load("material/arrow-left.svg"); + --md-nav-icon--next: svg-load("material/chevron-right.svg"); + --md-toc-icon: svg-load("material/table-of-contents.svg"); +} + +// ---------------------------------------------------------------------------- + +// Navigation +.md-nav { + font-size: px2rem(14px); + line-height: 1.3; + + // Navigation title + &__title { + display: block; + padding: 0 px2rem(12px); + overflow: hidden; + font-weight: 700; + color: var(--md-default-fg-color--light); + text-overflow: ellipsis; + + // Navigaton button + .md-nav__button { + display: none; + + // Stretch images based on height, as it's the smaller dimension + img { + width: auto; + height: 100%; + } + + // Button with logo, pointing to `config.site_url` + &.md-logo { + + // Image or icon + :is(img, svg) { + display: block; + width: auto; + max-width: 100%; + height: px2rem(48px); + object-fit: contain; + fill: currentcolor; + } + } + } + } + + // Navigation list + &__list { + padding: 0; + margin: 0; + list-style: none; + } + + // Navigation link + &__link { + display: flex; + gap: px2rem(8px); + align-items: flex-start; + margin-top: 0.625em; + transition: color 125ms; + scroll-snap-align: start; + + // Navigation link that was passed + &--passed { + color: var(--md-default-fg-color--light); + } + + // Active link + .md-nav__item &--active { + + // Also enable color transitions on inline code blocks + &, + code { + color: var(--md-typeset-a-color); + } + } + + // Navigation link title + .md-ellipsis { + // Hack: Safari exhibits a bug where the text will sometimes disappear + // and the element will become unclickable. Setting `position: relative` + // seems to fix the issue - see https://bit.ly/3HljM1T + position: relative; + } + + // Always align navigation icons to the end + .md-icon:last-child { + margin-inline-start: auto; + } + + // Navigation link icon + svg { + flex-shrink: 0; + height: 1.3em; + fill: currentcolor; + } + + // Navigation link on focus/hover + &:is([href], [for]):is(:focus, :hover) { + color: var(--md-accent-fg-color); + cursor: pointer; + } + + // Show outline for keyboard devices + &.focus-visible { + outline-color: var(--md-accent-fg-color); + outline-offset: px2rem(4px); + } + + // Navigation link for table of contents + .md-nav--primary &[for="__toc"] { + display: none; + + // Table of contents icon + .md-icon::after { + display: block; + width: 100%; + height: 100%; + mask-image: var(--md-toc-icon); + background-color: currentcolor; + } + + // Hide table of contents + ~ .md-nav { + display: none; + } + } + } + + // Navigation container (for section index pages) + &__container > .md-nav__link { + margin-top: 0; + + // Stretch first child + &:first-child { + flex-grow: 1; + // Hack: if a very long word is used, it can push the arrow out of sight. + // Setting this property contains the text - see https://t.ly/E02vp + min-width: 0; + } + } + + // Navigation icon + &__icon { + flex-shrink: 0; + } + + // Repository information container + &__source { + display: none; + } + + // [tablet -]: Layered navigation + @include break-to-device(tablet) { + + // Primary and nested navigation + &--primary, + &--primary & { + position: absolute; + inset-inline: 0; + top: 0; + z-index: 1; + display: flex; + flex-direction: column; + height: 100%; + background-color: var(--md-default-bg-color); + } + + // Primary navigation + &--primary { + + // Navigation title and item + :is(.md-nav__title, .md-nav__item) { + font-size: px2rem(16px); + line-height: 1.5; + } + + // Navigation title + .md-nav__title { + position: relative; + height: px2rem(112px); + padding: px2rem(60px) px2rem(16px) px2rem(4px); + line-height: px2rem(48px); + color: var(--md-default-fg-color--light); + white-space: nowrap; + cursor: pointer; + background-color: var(--md-default-fg-color--lightest); + + // Navigation icon + .md-nav__icon { + position: absolute; + top: px2rem(8px); + inset-inline-start: px2rem(8px); + display: block; + width: px2rem(24px); + height: px2rem(24px); + margin: px2rem(4px); + + // Navigation icon in link to previous level + &::after { + display: block; + width: 100%; + height: 100%; + content: ""; + background-color: currentcolor; + mask-image: var(--md-nav-icon--prev); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + } + } + + // Navigation list + ~ .md-nav__list { + overflow-y: auto; + touch-action: pan-y; + background-color: var(--md-default-bg-color); + box-shadow: + 0 px2rem(1px) 0 var(--md-default-fg-color--lightest) inset; + scroll-snap-type: y mandatory; + + // Omit border on first child + > :first-child { + border-top: 0; + } + } + + // Top-level navigation title + &[for="__drawer"] { + font-weight: 700; + color: var(--md-primary-bg-color); + background-color: var(--md-primary-fg-color); + } + + // Button with logo, pointing to `config.site_url` + .md-logo { + position: absolute; + inset-inline: px2rem(4px); + top: px2rem(4px); + display: block; + padding: px2rem(8px); + margin: px2rem(4px); + } + } + + // Navigation list + .md-nav__list { + flex: 1; + } + + // Navigation item + .md-nav__item { + border-top: px2rem(1px) solid var(--md-default-fg-color--lightest); + + // Navigation link in active navigation + &--active > .md-nav__link { + color: var(--md-typeset-a-color); + + // Navigation link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + } + } + + // Navigation link + .md-nav__link { + padding: px2rem(12px) px2rem(16px); + margin-top: 0; + + // Navigation link icon + svg { + margin-top: 0.1em; + } + + // Adjust spacing on nested link + > .md-nav__link { + padding: 0; + } + + // Navigation icon + .md-nav__icon { + width: px2rem(24px); + height: px2rem(24px); + margin-inline-end: px2rem(-4px); + font-size: px2rem(24px); + + // Navigation icon in link to next level + &::after { + display: block; + width: 100%; + height: 100%; + content: ""; + background-color: currentcolor; + mask-image: var(--md-nav-icon--next); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + } + } + } + + // Flip icon vertically + .md-nav__icon { + + // Adjust for right-to-left languages + [dir="rtl"] &::after { + transform: scale(-1); + } + } + + // Table of contents contained in primary navigation + .md-nav--secondary { + + // Navigation on level 2-6 + .md-nav { + position: static; + background-color: transparent; + + // Navigation link on level 3 + .md-nav__link { + padding-inline-start: px2rem(28px); + } + + // Navigation link on level 4 + .md-nav .md-nav__link { + padding-inline-start: px2rem(40px); + } + + // Navigation link on level 5 + .md-nav .md-nav .md-nav__link { + padding-inline-start: px2rem(52px); + } + + // Navigation link on level 6 + .md-nav .md-nav .md-nav .md-nav__link { + padding-inline-start: px2rem(64px); + } + } + } + } + + // Table of contents + &--secondary { + background-color: transparent; + } + + // Hide nested navigation + &__toggle ~ & { + display: flex; + opacity: 0; + transition: + transform 250ms cubic-bezier(0.8, 0, 0.6, 1), + opacity 125ms 50ms; + transform: translateX(100%); + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translateX(-100%); + } + } + + // Show nested navigation when toggle is active + &__toggle:checked ~ & { + opacity: 1; + transition: + transform 250ms cubic-bezier(0.4, 0, 0.2, 1), + opacity 125ms 125ms; + transform: translateX(0); + + // Navigation list + > .md-nav__list { + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + } + } + } + + // [tablet portrait -]: Layered navigation with table of contents + @include break-to-device(tablet portrait) { + + // Show link to table of contents + &--primary &__link[for="__toc"] { + display: flex; + + // Show table of contents icon + .md-icon::after { + content: ""; + } + + // Hide navigation link to current page + + .md-nav__link { + display: none; + } + + // Show table of contents + ~ .md-nav { + display: flex; + } + } + + // Repository information container + &__source { + display: block; + padding: 0 px2rem(4px); + color: var(--md-primary-bg-color); + background-color: var(--md-primary-fg-color--dark); + } + } + + // [tablet landscape]: Layered navigation with table of contents + @include break-at-device(tablet landscape) { + + // Show link to integrated table of contents + &--integrated &__link[for="__toc"] { + display: flex; + + // Show table of contents icon + .md-icon::after { + content: ""; + } + + // Hide navigation link to current page + + .md-nav__link { + display: none; + } + + // Show table of contents + ~ .md-nav { + display: flex; + } + } + } + + // [tablet landscape +]: Tree-like table of contents + @include break-from-device(tablet landscape) { + margin-bottom: px2rem(-8px); + + // Table of contents + &--secondary { + + // Navigation title + .md-nav__title { + position: sticky; + top: 0; + // Hack: because of the hack that we need to make .md-ellipsis work in + // Safari, we need to set `z-index` here as - see https://bit.ly/3s5M2jm + z-index: 1; + background: var(--md-default-bg-color); + box-shadow: 0 0 px2rem(8px) px2rem(8px) var(--md-default-bg-color); + + // Adjust snapping behavior + &[for="__toc"] { + scroll-snap-align: start; + } + + // Hide navigation icon + .md-nav__icon { + display: none; + } + } + + // Adjust spacing for navigation list - same reason as below + .md-nav__list { + padding-inline-start: px2rem(12px); + padding-bottom: px2rem(8px); + } + + // Adjust spacing for navigation link - before this change, we set spacing + // on the left and right of a navigation item, but this led to the problem + // of cropped focus outlines, because we must set `overflow: hidden` on + // the navigation list for smooth expand and collapse transitions. + .md-nav__item > .md-nav__link { + margin-inline-end: px2rem(8px); + } + } + } + + // [screen +]: Tree-like navigation + @include break-from-device(screen) { + margin-bottom: px2rem(-8px); + transition: max-height 250ms cubic-bezier(0.86, 0, 0.07, 1); + + // Primary navigation + &--primary { + + // Navigation title + .md-nav__title { + position: sticky; + top: 0; + // Hack: because of the hack that we need to make .md-ellipsis work in + // Safari, we need to set `z-index` here as - see https://bit.ly/3s5M2jm + z-index: 1; + background: var(--md-default-bg-color); + box-shadow: 0 0 px2rem(8px) px2rem(8px) var(--md-default-bg-color); + + // Adjust snapping behavior + &[for="__drawer"] { + scroll-snap-align: start; + } + + // Hide navigation icon + .md-nav__icon { + display: none; + } + } + + // Adjust spacing for navigation list - same reason as below + .md-nav__list { + padding-inline-start: px2rem(12px); + padding-bottom: px2rem(8px); + } + + // Adjust spacing for navigation link - before this change, we set spacing + // on the left and right of a navigation item, but this led to the problem + // of cropped focus outlines, because we must set `overflow: hidden` on + // the navigation list for smooth expand and collapse transitions. + .md-nav__item > .md-nav__link { + margin-inline-end: px2rem(8px); + } + } + + // Hide nested navigation + &__toggle ~ & { + display: grid; + grid-template-rows: 0fr; + visibility: collapse; + opacity: 0; + transition: + grid-template-rows 250ms cubic-bezier(0.86, 0, 0.07, 1), + opacity 250ms, + visibility 0ms 250ms; + + // Navigation list + > .md-nav__list { + overflow: hidden; + } + } + + // Show nested navigation when toggle is active or indeterminate + &__toggle:is(:checked, :indeterminate) ~ & { + grid-template-rows: 1fr; + visibility: visible; + opacity: 1; + transition: + grid-template-rows 250ms cubic-bezier(0.86, 0, 0.07, 1), + opacity 150ms 100ms, + visibility 0ms; + } + + // Hide navigation title in nested navigation + &__item--nested > & > &__title { + display: none; + } + + // Navigation section + &__item--section { + display: block; + margin: 1.25em 0; + + // Adjust spacing on last child + &:last-child { + margin-bottom: 0; + } + + // Show navigation link as title + > .md-nav__link { + font-weight: 700; + + // Make labels discernable from links + &[for] { + color: var(--md-default-fg-color--light); + } + + // Omit clicks if not a section index page + &:not(.md-nav__container) { + pointer-events: none; + } + + // Hide navigation icon + > [for], + .md-icon { + display: none; + } + } + + // Navigation + > .md-nav { + display: block; + margin-inline-start: px2rem(-12px); + visibility: visible; + opacity: 1; + + // Adjust spacing on next level item + > .md-nav__list > .md-nav__item { + padding: 0; + } + } + } + + // Navigation icon + &__icon { + width: px2rem(18px); + height: px2rem(18px); + border-radius: 100%; + transition: background-color 250ms; + + // Navigation icon on hover + &:hover { + background-color: var(--md-accent-fg-color--transparent); + } + + // Navigation icon content + &::after { + display: inline-block; + width: 100%; + height: 100%; + vertical-align: px2rem(-2px); + content: ""; + background-color: currentcolor; + border-radius: 100%; + transition: transform 250ms; + mask-image: var(--md-nav-icon--next); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: rotate(180deg); + } + + // Navigation icon - rotate icon when toggle is active or indeterminate + .md-nav__item--nested .md-nav__toggle:checked ~ .md-nav__link &, + .md-nav__item--nested .md-nav__toggle:indeterminate ~ .md-nav__link & { + transform: rotate(90deg); + } + } + } + + // Modifier for when navigation tabs are rendered + &--lifted { + + // Hide site title + > .md-nav__title { + display: none; + } + + // Hide level 0 navigation items + > .md-nav__list > .md-nav__item { + display: none; + + // Active parent navigation item + &--active { + display: block; + + // Show navigation link as title + > .md-nav__link { + position: sticky; + top: 0; + z-index: 1; + margin-top: 0; + background: var(--md-default-bg-color); + box-shadow: 0 0 px2rem(8px) px2rem(8px) var(--md-default-bg-color); + + // Omit clicks if not a section index page + &:not(.md-nav__container) { + pointer-events: none; + } + } + + // Adjust spacing for navigation section + &.md-nav__item--section { + margin: 0; + } + } + + // Adjust spacing for nested navigation + > .md-nav { + margin-inline-start: px2rem(-12px); + } + + // Make labels discernable from links + > [for] { + color: var(--md-default-fg-color--light); + } + } + + // Hack: Always show active navigation tab on breakpoint screen, despite + // of checkbox being checked or not - see https://t.ly/Qc311 + .md-nav[data-md-level="1"] { + grid-template-rows: 1fr; + visibility: visible; + opacity: 1; + } + } + + // Modifier for when table of contents is rendered in primary navigation + &--integrated > .md-nav__list > .md-nav__item--active { + + // Add spacing to container for non-nested navigation items + &:not(.md-nav__item--nested) { + padding: 0 px2rem(12px); + + // Remove padding as it's given by container + > .md-nav__link { + padding: 0; + } + } + + // Show integrated table of contents + .md-nav--secondary { + display: block; + margin-bottom: 1.25em; + visibility: visible; + border-inline-start: px2rem(1px) solid var(--md-primary-fg-color); + opacity: 1; + + // Navigation list + > .md-nav__list { + padding-bottom: 0; + overflow: visible; + } + + // Hide table of contents title + > .md-nav__title { + display: none; + } + } + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_pagination.scss b/src/templates/assets/stylesheets/main/components/_pagination.scss new file mode 100644 index 00000000..a010bf43 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_pagination.scss @@ -0,0 +1,85 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Pagination +.md-pagination { + display: flex; + gap: px2rem(8px); + align-items: center; + justify-content: center; + font-size: px2rem(16px); + font-weight: 700; + + // Pagination item + > * { + display: flex; + align-items: center; + justify-content: center; + min-width: px2rem(36px); + height: px2rem(36px); + text-align: center; + border-radius: px2rem(4px); + } + + // Active pagination item + &__current { + color: var(--md-default-fg-color--light); + background-color: var(--md-default-fg-color--lightest); + } + + // Pagination link + &__link { + transition: + color 125ms, + background-color 125ms; + + // Pagination link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + background-color: var(--md-accent-fg-color--transparent); + + // Pagination icon + svg { + color: var(--md-accent-fg-color); + } + } + + // Show outline for keyboard devices + &.focus-visible { + outline-color: var(--md-accent-fg-color); + outline-offset: px2rem(4px); + } + + // Pagination icon + svg { + display: block; + width: px2rem(24px); + max-height: 100%; + color: var(--md-default-fg-color--lighter); + fill: currentcolor; + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_post.scss b/src/templates/assets/stylesheets/main/components/_post.scss new file mode 100644 index 00000000..cf6ce019 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_post.scss @@ -0,0 +1,196 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Post +.md-post { + + // Post backlink + &__back { + padding-bottom: px2rem(24px); + margin-bottom: px2rem(24px); + border-bottom: px2rem(1px) solid var(--md-default-fg-color--lightest); + + // [tablet -]: Hide post backlink + @include break-to-device(tablet) { + display: none; + } + + // Adjust for right-to-left languages + [dir="rtl"] & { + + // Flip icon vertically + svg { + transform: scaleX(-1); + } + } + } + + // Post authors + &__authors { + display: flex; + flex-direction: column; + gap: px2rem(12px); + margin: 0 px2rem(12px) px2rem(24px); + } + + // Post metadata + .md-post__meta { + + // Navigation link + a { + transition: color 125ms; + + // Navigation link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + } + } + + // Post navigation title @todo - generalize + &__title { + font-weight: 700; + color: var(--md-default-fg-color--light); + } + + // Post excerpt + &--excerpt { + margin-bottom: px2rem(64px); + + // Post excerpt header + .md-post__header { + display: flex; + gap: px2rem(12px); + align-items: center; + min-height: px2rem(32px); + } + + // Post excerpt authors + .md-post__authors { + display: inline-flex; + flex-direction: row; + gap: px2rem(4px); + align-items: center; + min-height: px2rem(48px); + margin: 0; + } + + // Post excerpt metadata + .md-post__meta .md-meta__list { + margin-inline-end: px2rem(8px); + } + + // Post excerpt content + .md-post__content > :first-child { + --md-scroll-margin: #{px2rem(120px)}; + + margin-top: 0; + } + } + + // Add margin to table of contents + > .md-nav--secondary { + margin: 1em 0; + } +} + +// ---------------------------------------------------------------------------- + +// Post author profile +.md-profile { + display: flex; + gap: px2rem(12px); + align-items: center; + width: 100%; + font-size: px2rem(14px); + line-height: 1.4; + + // Post author description + &__description { + flex-grow: 1; + } +} + +// ---------------------------------------------------------------------------- + +// Content area for post +.md-content--post { + display: flex; + + // [tablet -]: Switch to inverted column layout + @include break-to-device(tablet) { + flex-flow: column-reverse; + } + + // Content wrapper + > .md-content__inner { + min-width: 0; + + // [screen +]: Adjust spacing between content area and sidebars + @include break-from-device(screen) { + margin-inline-start: px2rem(24px); + } + } +} + +// Sidebar for post +.md-sidebar.md-sidebar--post { + + // [tablet -]: Adjust spacing + @include break-to-device(tablet) { + position: initial; + width: 100%; + padding: 0; + + .md-sidebar__inner { + padding: 0; + } + + .md-post__meta { + margin-inline: px2rem(12px); + } + + .md-nav__item { + display: inline; + border: none; + } + + .md-nav__list { + display: inline-flex; + flex-wrap: wrap; + gap: px2rem(12px); + padding-block: px2rem(12px); + } + + .md-nav__link { + padding: 0; + } + + .md-nav { + position: initial; + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_progress.scss b/src/templates/assets/stylesheets/main/components/_progress.scss new file mode 100644 index 00000000..7386ae33 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_progress.scss @@ -0,0 +1,53 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Progress variables +:root { + --md-progress-value: 0; + --md-progress-delay: 400ms; +} + +// ---------------------------------------------------------------------------- + +// Progress indicator +.md-progress { + position: fixed; + top: 0; + z-index: 4; + width: 100%; + height: px2rem(1.5px); + background: var(--md-primary-bg-color); + opacity: + min( + clamp(0, var(--md-progress-value), 1), + clamp(0, 100 - var(--md-progress-value), 1) + ); + transition: + transform 500ms cubic-bezier(0.19, 1, 0.22, 1), + opacity 250ms var(--md-progress-delay); + transform: scaleX(calc(var(--md-progress-value) * 1%)); + transform-origin: left; +} diff --git a/src/templates/assets/stylesheets/main/components/_search.scss b/src/templates/assets/stylesheets/main/components/_search.scss new file mode 100644 index 00000000..e0f36b0c --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_search.scss @@ -0,0 +1,707 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Search variables +:root { + --md-search-result-icon: svg-load("material/file-search-outline.svg"); +} + +// ---------------------------------------------------------------------------- + +// Search +.md-search { + position: relative; + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + padding: px2rem(4px) 0; + } + + // [no-js]: Hide search + .no-js & { + display: none; + } + + // Search overlay + &__overlay { + z-index: 1; + opacity: 0; + + // [tablet portrait -]: Search modal + @include break-to-device(tablet portrait) { + position: absolute; + top: px2rem(-20px); + width: px2rem(40px); + height: px2rem(40px); + overflow: hidden; + pointer-events: none; + background-color: var(--md-default-bg-color); + border-radius: px2rem(20px); + transition: + transform 300ms 100ms, + opacity 200ms 200ms; + transform-origin: center; + inset-inline-start: px2rem(-44px); + + // Show overlay when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + opacity: 1; + transition: + transform 400ms, + opacity 100ms; + } + } + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + position: fixed; + top: 0; + width: 0; + height: 0; + cursor: pointer; + background-color: hsla(0, 0%, 0%, 0.54); + transition: + width 0ms 250ms, + height 0ms 250ms, + opacity 250ms; + inset-inline-start: 0; + + // Show overlay when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + width: 100%; + // Hack: when the header is translated upon scrolling, a new layer is + // induced, which means that the height will now refer to the height of + // the header, albeit positioning is fixed. This should be mitigated + // in all cases when setting the height to 2x the viewport. + height: 200vh; + opacity: 1; + transition: + width 0ms, + height 0ms, + opacity 250ms; + } + } + + // Adjust appearance when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + + // [mobile portrait -]: Scale up 45 times + @include break-to-device(mobile portrait) { + transform: scale(45); + } + + // [mobile landscape]: Scale up 60 times + @include break-at-device(mobile landscape) { + transform: scale(60); + } + + // [tablet portrait]: Scale up 75 times + @include break-at-device(tablet portrait) { + transform: scale(75); + } + } + } + + // Search wrapper + &__inner { + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + + // [tablet portrait -]: Search modal + @include break-to-device(tablet portrait) { + position: fixed; + top: 0; + z-index: 2; + width: 0; + height: 0; + overflow: hidden; + opacity: 0; + transition: + width 0ms 300ms, + height 0ms 300ms, + transform 150ms 150ms cubic-bezier(0.4, 0, 0.2, 1), + opacity 150ms 150ms; + transform: translateX(5%); + inset-inline-start: 0; + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translateX(-5%); + } + + // Adjust appearance when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + width: 100%; + height: 100%; + opacity: 1; + transition: + width 0ms 0ms, + height 0ms 0ms, + transform 150ms 150ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 150ms 150ms; + transform: translateX(0); + } + } + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + position: relative; + float: inline-end; + width: px2rem(234px); + padding: px2rem(2px) 0; + transition: width 250ms cubic-bezier(0.1, 0.7, 0.1, 1); + } + + // Adjust appearance when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + + // [tablet landscape]: Omit overlaying header title + @include break-at-device(tablet landscape) { + width: px2rem(468px); + } + + // [screen +]: Match width of content area + @include break-from-device(screen) { + width: px2rem(688px); + } + } + } + + // Search form + &__form { + position: relative; + z-index: 2; + height: px2rem(48px); + background-color: var(--md-default-bg-color); + box-shadow: 0 0 px2rem(12px) transparent; + transition: + color 250ms, + background-color 250ms; + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + height: px2rem(36px); + background-color: hsla(0, 0%, 0%, 0.26); + border-radius: px2rem(2px); + + // Search form on hover + &:hover { + background-color: hsla(0, 0%, 100%, 0.12); + } + } + + // Adjust appearance when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + color: var(--md-default-fg-color); + background-color: var(--md-default-bg-color); + border-radius: px2rem(2px) px2rem(2px) 0 0; + box-shadow: 0 0 px2rem(12px) hsla(0, 0%, 0%, 0.07); + } + } + + // Search input + &__input { + position: relative; + z-index: 2; + width: 100%; + height: 100%; + padding-inline: px2rem(72px) px2rem(44px); + font-size: px2rem(18px); + text-overflow: ellipsis; + background: transparent; + + // Search placeholder + &::placeholder { + transition: color 250ms; + } + + // Search icon and placeholder + ~ .md-search__icon, + &::placeholder { + color: var(--md-default-fg-color--light); + } + + // Remove the "x" rendered by Internet Explorer + &::-ms-clear { + display: none; + } + + // [tablet portrait -]: Search modal + @include break-to-device(tablet portrait) { + width: 100%; + height: px2rem(48px); + font-size: px2rem(18px); + } + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + padding-inline-start: px2rem(44px); + font-size: px2rem(16px); + color: inherit; + + // Search placeholder + &::placeholder { + color: var(--md-primary-bg-color--light); + } + + // Search icon + + .md-search__icon { + color: var(--md-primary-bg-color); + } + + // Adjust appearance when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + text-overflow: clip; + + // Search icon and placeholder + + .md-search__icon { + color: var(--md-default-fg-color--light); + } + + // Search placeholder + &::placeholder { + color: transparent; + } + } + } + } + + // Search icon + &__icon { + display: inline-block; + width: px2rem(24px); + height: px2rem(24px); + cursor: pointer; + transition: + color 250ms, + opacity 250ms; + + // Search icon on hover + &:hover { + opacity: 0.7; + } + + // Search focus button + &[for="__search"] { + position: absolute; + top: px2rem(6px); + inset-inline-start: px2rem(10px); + z-index: 2; + + // Adjust for right-to-left languages + [dir="rtl"] & svg { + transform: scaleX(-1); + } + + // [tablet portrait -]: Search modal + @include break-to-device(tablet portrait) { + top: px2rem(12px); + inset-inline-start: px2rem(16px); + + // Hide the magnifying glass + svg:first-child { + display: none; + } + } + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + pointer-events: none; + + // Hide the back arrow + svg:last-child { + display: none; + } + } + } + } + + // Search options + &__options { + position: absolute; + top: px2rem(6px); + inset-inline-end: px2rem(10px); + z-index: 2; + pointer-events: none; + + // [tablet portrait -]: Search modal + @include break-to-device(tablet portrait) { + top: px2rem(12px); + inset-inline-end: px2rem(16px); + } + + // Search option buttons + > .md-icon { + margin-inline-start: px2rem(4px); + color: var(--md-default-fg-color--light); + opacity: 0; + transition: + transform 150ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 150ms; + transform: scale(0.75); + + // Hide outline for pointer devices + &:not(.focus-visible) { + outline: none; + -webkit-tap-highlight-color: transparent; + } + + // Show buttons when search is active and input non-empty + [data-md-toggle="search"]:checked ~ .md-header // stylelint-disable-line + .md-search__input:valid ~ & { + pointer-events: initial; + opacity: 1; + transform: scale(1); + + // Search focus icon + &:hover { + opacity: 0.7; + } + } + } + } + + // Search suggestions + &__suggest { + position: absolute; + top: 0; + display: flex; + align-items: center; + width: 100%; + height: 100%; + padding-inline: px2rem(72px) px2rem(44px); + font-size: px2rem(18px); + color: var(--md-default-fg-color--lighter); + white-space: nowrap; + opacity: 0; + transition: opacity 50ms; + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + padding-inline-start: px2rem(44px); + font-size: px2rem(16px); + } + + // Show suggestions when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + opacity: 1; + transition: opacity 300ms 100ms; + } + } + + // Search output + &__output { + position: absolute; + z-index: 1; + width: 100%; + overflow: hidden; + border-end-start-radius: px2rem(2px); + border-end-end-radius: px2rem(2px); + + // [tablet portrait -]: Search modal + @include break-to-device(tablet portrait) { + top: px2rem(48px); + bottom: 0; + } + + // [tablet landscape +]: Header-embedded search + @include break-from-device(tablet landscape) { + top: px2rem(38px); + opacity: 0; + transition: opacity 400ms; + + // Show output when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + box-shadow: var(--md-shadow-z3); + opacity: 1; + } + } + } + + // Search scroll wrapper + &__scrollwrap { + height: 100%; + overflow-y: auto; + // Hack: Chrome 88+ has weird overscroll behavior. Overall, scroll snapping + // seems to be something that is not ready for prime time on some browsers. + // scroll-snap-type: y mandatory; + touch-action: pan-y; + background-color: var(--md-default-bg-color); + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + + // Mitigiate excessive repaints on non-retina devices + @media (max-resolution: 1dppx) { + transform: translateZ(0); + } + + // [tablet landscape]: Set fixed width to omit unnecessary reflow + @include break-at-device(tablet landscape) { + width: px2rem(468px); + } + + // [screen +]: Set fixed width to omit unnecessary reflow + @include break-from-device(screen) { + width: px2rem(688px); + } + + // [tablet landscape +]: Limit height to viewport + @include break-from-device(tablet landscape) { + max-height: 0; + scrollbar-width: thin; + scrollbar-color: var(--md-default-fg-color--lighter) transparent; + + // Show scroll wrapper when search is active + [data-md-toggle="search"]:checked ~ .md-header & { + max-height: 75vh; + } + + // Search scroll wrapper on hover + &:hover { + scrollbar-color: var(--md-accent-fg-color) transparent; + } + + // Webkit scrollbar + &::-webkit-scrollbar { + width: px2rem(4px); + height: px2rem(4px); + } + + // Webkit scrollbar thumb + &::-webkit-scrollbar-thumb { + background-color: var(--md-default-fg-color--lighter); + + // Webkit scrollbar thumb on hover + &:hover { + background-color: var(--md-accent-fg-color); + } + } + } + } +} + +// Search result +.md-search-result { + color: var(--md-default-fg-color); + word-break: break-word; + + // Search result metadata + &__meta { + padding: 0 px2rem(16px); + font-size: px2rem(12.8px); + line-height: px2rem(36px); + color: var(--md-default-fg-color--light); + background-color: var(--md-default-fg-color--lightest); + scroll-snap-align: start; + + // [tablet landscape +]: Adjust spacing + @include break-from-device(tablet landscape) { + padding-inline-start: px2rem(44px); + } + } + + // Search result list + &__list { + padding: 0; + margin: 0; + list-style: none; + // Hack: omit accidental text selection on fast toggle of more button + user-select: none; + } + + // Search result item + &__item { + box-shadow: 0 px2rem(-1px) var(--md-default-fg-color--lightest); + + // Omit border on first child + &:first-child { + box-shadow: none; + } + } + + // Search result link + &__link { + display: block; + outline: none; + transition: background-color 250ms; + scroll-snap-align: start; + + // Search result link on focus/hover + &:is(:focus, :hover) { + background-color: var(--md-accent-fg-color--transparent); + } + + // Adjust spacing on last child of last link + &:last-child p:last-child { + margin-bottom: px2rem(12px); + } + } + + // Search result more container + &__more > summary { + position: sticky; + top: 0; + z-index: 1; + display: block; + cursor: pointer; + outline: none; + scroll-snap-align: start; + + // Hide native details marker + &::marker { + display: none; + } + + // Hide native details marker - legacy, must be split into a seprate rule, + // so older browsers don't consider the selector list as invalid + &::-webkit-details-marker { + display: none; + } + + // Search result more button + > div { + padding: px2em(12px) px2rem(16px); + font-size: px2rem(12.8px); + color: var(--md-typeset-a-color); + transition: + color 250ms, + background-color 250ms; + + // [tablet landscape +]: Adjust spacing + @include break-from-device(tablet landscape) { + padding-inline-start: px2rem(44px); + } + } + + // Search result more link on focus/hover + &:is(:focus, :hover) > div { + color: var(--md-accent-fg-color); + background-color: var(--md-accent-fg-color--transparent); + } + } + + // Adjust background for more container in open state + &__more[open] > summary { + background-color: var(--md-default-bg-color); + // box-shadow: 0 px2rem(-1px) hsla(0, 0%, 0%, 0.07) inset; + } + + // Search result article + &__article { + position: relative; + padding: 0 px2rem(16px); + overflow: hidden; + + // [tablet landscape +]: Adjust spacing + @include break-from-device(tablet landscape) { + padding-inline-start: px2rem(44px); + } + } + + // Search result icon + &__icon { + position: absolute; + inset-inline-start: 0; + width: px2rem(24px); + height: px2rem(24px); + margin: px2rem(10px); + color: var(--md-default-fg-color--light); + + // [tablet portrait -]: Hide icon + @include break-to-device(tablet portrait) { + display: none; + } + + // Search result icon content + &::after { + display: inline-block; + width: 100%; + height: 100%; + content: ""; + background-color: currentcolor; + mask-image: var(--md-search-result-icon); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: scaleX(-1); + } + } + } + + // Typesetted content + .md-typeset { + font-size: px2rem(12.8px); + line-height: 1.6; + color: var(--md-default-fg-color--light); + + // Search result article title + h1 { + margin: px2rem(11px) 0; + font-size: px2rem(16px); + font-weight: 400; + line-height: 1.4; + color: var(--md-default-fg-color); + + // Search term highlighting + mark { + text-decoration: none; + } + } + + // Search result section title + h2 { + margin: 0.5em 0; + font-size: px2rem(12.8px); + font-weight: 700; + line-height: 1.6; + color: var(--md-default-fg-color); + + // Search term highlighting + mark { + text-decoration: none; + } + } + } + + // Search result terms + &__terms { + display: block; + margin: 0.5em 0; + font-size: px2rem(12.8px); + font-style: italic; + color: var(--md-default-fg-color); + } + + // Search term highlighting + mark { + color: var(--md-accent-fg-color); + text-decoration: underline; + background-color: transparent; + } +} diff --git a/src/templates/assets/stylesheets/main/components/_select.scss b/src/templates/assets/stylesheets/main/components/_select.scss new file mode 100644 index 00000000..ed597a39 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_select.scss @@ -0,0 +1,115 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Selection +.md-select { + position: relative; + z-index: 1; + + // Selection tooltip + &__inner { + position: absolute; + top: calc(100% - #{px2rem(4px)}); + left: 50%; + max-height: 0; + margin-top: px2rem(4px); + color: var(--md-default-fg-color); + background-color: var(--md-default-bg-color); + border-radius: px2rem(2px); + box-shadow: var(--md-shadow-z2); + opacity: 0; + transition: + transform 250ms 375ms, + opacity 250ms 250ms, + max-height 0ms 500ms; + transform: translate3d(-50%, px2rem(6px), 0); + + // Selection bubble on parent focus/hover + .md-select:is(:focus-within, :hover) & { + max-height: px2rem(200px); + opacity: 1; + transition: + transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 250ms, + max-height 0ms; + transform: translate3d(-50%, 0, 0); + } + + // Selection bubble handle + &::after { + position: absolute; + top: 0; + left: 50%; + width: 0; + height: 0; + margin-top: px2rem(-4px); + margin-left: px2rem(-4px); + content: ""; + border: px2rem(4px) solid transparent; + border-top: 0; + border-bottom-color: var(--md-default-bg-color); + } + } + + // Selection list + &__list { + max-height: inherit; + padding: 0; + margin: 0; + overflow: auto; + font-size: px2rem(16px); + list-style-type: none; + border-radius: px2rem(2px); + } + + // Selection item + &__item { + line-height: px2rem(36px); + } + + // Selection link + &__link { + display: block; + width: 100%; + padding-inline: px2rem(12px) px2rem(24px); + cursor: pointer; + outline: none; + transition: + background-color 250ms, + color 250ms; + scroll-snap-align: start; + + // Link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + + // Link on focus + &:focus { + background-color: var(--md-default-fg-color--lightest); + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_sidebar.scss b/src/templates/assets/stylesheets/main/components/_sidebar.scss new file mode 100644 index 00000000..8a320c04 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_sidebar.scss @@ -0,0 +1,209 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Sidebar +.md-sidebar { + position: sticky; + top: px2rem(48px); + flex-shrink: 0; + align-self: flex-start; + width: px2rem(242px); + padding: px2rem(24px) 0; + + // [print]: Hide sidebar + @media print { + display: none; + } + + // Primary sidebar with navigation + &--primary { + + // [tablet -]: Show navigation as drawer + @include break-to-device(tablet) { + position: fixed; + top: 0; + z-index: 5; + display: block; + width: px2rem(242px); + height: 100%; + background-color: var(--md-default-bg-color); + transition: + transform 250ms cubic-bezier(0.4, 0, 0.2, 1), + box-shadow 250ms; + transform: translateX(0); + inset-inline-start: px2rem(-242px); + + // Show sidebar when drawer is active + [data-md-toggle="drawer"]:checked ~ .md-container & { + box-shadow: var(--md-shadow-z3); + transform: translateX(px2rem(242px)); + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translateX(px2rem(-242px)); + } + } + + // Stretch scroll wrapper for primary sidebar + .md-sidebar__scrollwrap { + position: absolute; + inset: 0; + margin: 0; + scroll-snap-type: none; + overflow: hidden; + } + } + } + + // [screen +]: Show navigation as sidebar + @include break-from-device(screen) { + height: 0; + + // [no-js]: Switch to native sticky behavior + .no-js & { + height: auto; + } + + // Adjust spacing for sticky navigation tabs + .md-header--lifted ~ .md-container & { + top: px2rem(96px); + } + } + + // Secondary sidebar with table of contents + &--secondary { + display: none; + order: 2; + + // [tablet landscape +]: Show table of contents as sidebar + @include break-from-device(tablet landscape) { + height: 0; + + // [no-js]: Switch to native sticky behavior + .no-js & { + height: auto; + } + + // Sidebar is visible + &:not([hidden]) { + display: block; + } + + // Ensure smooth scrolling on iOS + .md-sidebar__scrollwrap { + touch-action: pan-y; + } + } + } + + // Sidebar scroll wrapper + &__scrollwrap { + margin: 0 px2rem(4px); + overflow-y: auto; + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + // Hack: Chrome 81+ exhibits a strange bug, where it scrolls the container + // to the bottom if `scroll-snap-type` is set on the initial render. For + // this reason, we disable scroll snapping until this is resolved (#1667). + // scroll-snap-type: y mandatory; + scrollbar-width: thin; + scrollbar-gutter: stable; + scrollbar-color: var(--md-default-fg-color--lighter) transparent; + + // Webkit scrollbar + &::-webkit-scrollbar { + width: px2rem(4px); + height: px2rem(4px); + } + + // Sidebar scroll wrapper on focus/hover + &:is(:focus-within, :hover) { + scrollbar-color: var(--md-accent-fg-color) transparent; + + // Webkit scrollbar thumb + &::-webkit-scrollbar-thumb { + background-color: var(--md-default-fg-color--lighter); + + // Webkit scrollbar thumb on hover + &:hover { + background-color: var(--md-accent-fg-color); + } + } + } + } + + // Hack: the scrollbar is only visible when the sidebar's contents overflow, + // which is nice, but leads to the problem where the chevrons of expandable + // sections will jump by `4px` when the sidebar is shown. We wanted to fix + // this problem for so long, but haven't found a clean way of doing it. + // Until now. The following declaration is only applied to Webkit browsers + // (e.g. Chrome and Safari), which support styling of scrollbars. The trick + // is to add conditional padding on the side of the scrollbar only if the + // sidebar's content doesn't overflow. This hack is inspired and adapted + // from Ayke van Laëthem's year old trick – see https://bit.ly/3Sb1qql + @supports selector(::-webkit-scrollbar) { + + // Sidebar scroll wrapper + &__scrollwrap { + scrollbar-gutter: auto; + } + + // Sidebar wrapper + &__inner { + padding-inline-end: calc(100% - #{px2rem(230px)}); + } + } +} + +// [tablet -]: Show overlay on active drawer +@include break-to-device(tablet) { + + // Drawer overlay + .md-overlay { + position: fixed; + top: 0; + z-index: 5; + width: 0; + height: 0; + background-color: hsla(0, 0%, 0%, 0.54); + opacity: 0; + transition: + width 0ms 250ms, + height 0ms 250ms, + opacity 250ms; + + // Show overlay when drawer is active + [data-md-toggle="drawer"]:checked ~ & { + width: 100%; + height: 100%; + opacity: 1; + transition: + width 0ms, + height 0ms, + opacity 250ms; + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_source.scss b/src/templates/assets/stylesheets/main/components/_source.scss new file mode 100644 index 00000000..a2b72009 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_source.scss @@ -0,0 +1,182 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Keyframes +// ---------------------------------------------------------------------------- + +// Show repository facts +@keyframes facts { + 0% { + height: 0; + } + + 100% { + height: px2rem(13px); + } +} + +// Show repository fact +@keyframes fact { + 0% { + opacity: 0; + transform: translateY(100%); + } + + 50% { + opacity: 0; + } + + 100% { + opacity: 1; + transform: translateY(0%); + } +} + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Repository information variables +:root { + --md-source-forks-icon: svg-load("octicons/repo-forked-16.svg"); + --md-source-repositories-icon: svg-load("octicons/repo-16.svg"); + --md-source-stars-icon: svg-load("octicons/star-16.svg"); + --md-source-version-icon: svg-load("octicons/tag-16.svg"); +} + +// ---------------------------------------------------------------------------- + +// Repository information +.md-source { + display: block; + font-size: px2rem(13px); + line-height: 1.2; + white-space: nowrap; + outline-color: var(--md-accent-fg-color); + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + transition: opacity 250ms; + + // Repository information on hover + &:hover { + opacity: 0.7; + } + + // Repository icon + &__icon { + display: inline-block; + width: px2rem(40px); + height: px2rem(48px); + vertical-align: middle; + + // Align with margin only (as opposed to normal button alignment) + svg { + margin-inline-start: px2rem(12px); + margin-top: px2rem(12px); + } + + // Adjust spacing if icon is present + + .md-source__repository { + padding-inline-start: px2rem(40px); + margin-inline-start: px2rem(-40px); + } + } + + // Repository name + &__repository { + display: inline-block; + max-width: calc(100% - #{px2rem(24px)}); + margin-inline-start: px2rem(12px); + overflow: hidden; + text-overflow: ellipsis; + vertical-align: middle; + } + + // Repository facts + &__facts { + display: flex; + gap: px2rem(8px); + width: 100%; + padding: 0; + margin: px2rem(2px) 0 0; + overflow: hidden; + font-size: px2rem(11px); + list-style-type: none; + opacity: 0.75; + + // Show after the data was loaded + .md-source__repository--active & { + animation: facts 250ms ease-in; + } + } + + // Repository fact + &__fact { + overflow: hidden; + text-overflow: ellipsis; + + // Show after the data was loaded + .md-source__repository--active & { + animation: fact 400ms ease-out; + } + + // Repository fact icon + &::before { + display: inline-block; + width: px2rem(12px); + height: px2rem(12px); + margin-inline-end: px2rem(2px); + vertical-align: text-top; + content: ""; + background-color: currentcolor; + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + } + + // Adjust spacing for 2nd+ fact + &:nth-child(1n+2) { + flex-shrink: 0; + } + + // Repository fact: version + &--version::before { + mask-image: var(--md-source-version-icon); + } + + // Repository fact: stars + &--stars::before { + mask-image: var(--md-source-stars-icon); + } + + // Repository fact: forks + &--forks::before { + mask-image: var(--md-source-forks-icon); + } + + // Repository fact: repositories + &--repositories::before { + mask-image: var(--md-source-repositories-icon); + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_status.scss b/src/templates/assets/stylesheets/main/components/_status.scss new file mode 100644 index 00000000..9e096021 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_status.scss @@ -0,0 +1,73 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Status variables +:root { + --md-status: svg-load("material/information-outline.svg"); + --md-status--new: svg-load("material/alert-decagram.svg"); + --md-status--deprecated: svg-load("material/trash-can.svg"); + --md-status--encrypted: svg-load("material/shield-lock.svg"); +} + +// ---------------------------------------------------------------------------- + +// Status +.md-status { + + // Status icon + &::after { + display: inline-block; + width: px2em(18px); + height: px2em(18px); + vertical-align: text-bottom; + content: ""; + background-color: var(--md-default-fg-color--light); + mask-image: var(--md-status); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + } + + // Status icon on hover + &:hover::after { + background-color: currentcolor; + } + + // Status: new + &--new::after { + mask-image: var(--md-status--new); + } + + // Status: deprecated + &--deprecated::after { + mask-image: var(--md-status--deprecated); + } + + // Status: encrypted + &--encrypted::after { + mask-image: var(--md-status--encrypted); + } +} diff --git a/src/templates/assets/stylesheets/main/components/_tabs.scss b/src/templates/assets/stylesheets/main/components/_tabs.scss new file mode 100644 index 00000000..0da3384b --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_tabs.scss @@ -0,0 +1,133 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Navigation tabs +.md-tabs { + // Must be higher than the z-index of the back-to-top button, or the button + // will overlay the navigation tabs bar when scrolling up fast. + z-index: 3; + display: block; + width: 100%; + overflow: auto; + line-height: 1.3; + color: var(--md-primary-bg-color); + background-color: var(--md-primary-fg-color); + + // [print]: Hide tabs + @media print { + display: none; + } + + // [tablet -]: Hide tabs + @include break-to-device(tablet) { + display: none; + } + + // Navigation tabs are hidden + &[hidden] { + pointer-events: none; + } + + // Navigation tabs list + &__list { + display: flex; + padding: 0; + margin: 0; + margin-inline-start: px2rem(4px); + overflow: auto; + white-space: nowrap; + list-style: none; + contain: content; + // Hack: don't show scrollbar when navigation tabs overflow, which should + // only happen in rare occasions, as adding too many top level sections is + // discouraged, since hiding content on horitontal axis doesn't lead to a + // good user experience. It's just harder to discover. + scrollbar-width: none; + + // Hack: see above + &::-webkit-scrollbar { + display: none; + } + } + + // Navigation tabs item + &__item { + height: px2rem(48px); + padding-inline: px2rem(12px); + + // Navigation tabs link in active navigation + &--active .md-tabs__link { + color: inherit; + opacity: 1; + } + } + + // Navigation tabs link - could be defined as block elements and aligned via + // line height, but this would imply more repaints when scrolling + &__link { + display: flex; + margin-top: px2rem(16px); + font-size: px2rem(14px); + outline-color: var(--md-accent-fg-color); + outline-offset: px2rem(4px); + // Hack: save a repaint when tabs are appearing on scrolling up + backface-visibility: hidden; + opacity: 0.7; + transition: + transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 250ms; + + // Navigation tabs link on focus/hover + &:is(:focus, :hover) { + color: inherit; + opacity: 1; + } + + // Navigation tabs link icon + svg { + height: 1.3em; + margin-inline-end: px2rem(8px); + fill: currentcolor; + } + + // Delay transitions by a small amount + @for $i from 2 through 16 { + .md-tabs__item:nth-child(#{$i}) & { + transition-delay: 20ms * ($i - 1); + } + } + + // Hide tabs upon scrolling - disable transition to minimizes repaints + // while scrolling down, while scrolling up seems to be okay + .md-tabs[hidden] & { + opacity: 0; + transition: + transform 0ms 100ms, + opacity 100ms; + transform: translateY(50%); + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_tag.scss b/src/templates/assets/stylesheets/main/components/_tag.scss new file mode 100644 index 00000000..9f31829d --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_tag.scss @@ -0,0 +1,105 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Tag variables +:root { + --md-tag-icon: svg-load("material/pound.svg"); +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Tag list + .md-tags { + display: inline-flex; + flex-wrap: wrap; + gap: px2em(8px); + margin-top: px2em(-2px); + margin-bottom: px2em(12px); + } + + // Tag + .md-tag { + display: inline-flex; + gap: px2em(8px); + align-items: center; + padding: px2em(4px, 12.8px) px2em(10px, 12.8px); + font-size: px2rem(12.8px); // Fallback + font-size: min(px2em(12.8px), px2rem(12.8px)); + font-weight: 700; + line-height: 1.6; + letter-spacing: initial; + background: var(--md-default-fg-color--lightest); + border-radius: px2rem(48px); + + // Linked tag + &[href] { + color: inherit; + outline: none; + -webkit-tap-highlight-color: transparent; + transition: + color 125ms, + background-color 125ms; + + // Linked tag on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-bg-color); + background-color: var(--md-accent-fg-color); + } + } + + // Tag inside headline + [id] > & { + vertical-align: text-top; + } + } + + // Tag icon + .md-tag-icon { + + // Tag icon content + &::before { + display: inline-block; + width: 1.2em; + height: 1.2em; + vertical-align: text-bottom; + content: ""; + background-color: var(--md-default-fg-color--lighter); + transition: background-color 125ms; + mask-image: var(--md-tag-icon); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + } + + // Linked tag on focus/hover + &[href]:is(:focus, :hover)::before { + background-color: var(--md-accent-bg-color); + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_tooltip.scss b/src/templates/assets/stylesheets/main/components/_tooltip.scss new file mode 100644 index 00000000..421e5858 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_tooltip.scss @@ -0,0 +1,292 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Keyframes +// ---------------------------------------------------------------------------- + +// Continuous pulse animation +@keyframes pulse { + 0% { + transform: scale(0.95); + } + + 75% { + transform: scale(1); + } + + 100% { + transform: scale(0.95); + } +} + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Tooltip variables +:root { + --md-annotation-bg-icon: svg-load("material/circle.svg"); + --md-annotation-icon: svg-load("material/plus-circle.svg"); + --md-tooltip-width: #{px2rem(400px)}; +} + +// ---------------------------------------------------------------------------- + +// Tooltip +.md-tooltip { + position: absolute; + top: var(--md-tooltip-y); + left: + clamp( + var(--md-tooltip-0, #{px2rem(0px)}) + #{px2rem(16px)}, + var(--md-tooltip-x), + 100vw + + var(--md-tooltip-0, #{px2rem(0px)}) + #{px2rem(16px)} - + var(--md-tooltip-width) - + 2 * #{px2rem(16px)} + ); + // Hack: set an explicit `z-index` so we can transition it to ensure that any + // following elements are not overlaying the tooltip during the transition. + z-index: 0; + width: var(--md-tooltip-width); + max-width: calc(100vw - 2 * #{px2rem(16px)}); + font-family: var(--md-text-font-family); + color: var(--md-default-fg-color); + background-color: var(--md-default-bg-color); + border-radius: px2rem(2px); + box-shadow: var(--md-shadow-z2); + opacity: 0; + transition: + transform 0ms 250ms, + opacity 250ms, + z-index 250ms; + transform: translateY(px2rem(-8px)); + // Hack: promote to own layer to reduce jitter + backface-visibility: hidden; + + // Active tooltip + &--active { + z-index: 2; + opacity: 1; + transition: + transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1), + opacity 250ms, + z-index 0ms; + transform: translateY(0); + } + + // Show outline on target and for keyboard devices + :is(.focus-visible > &, &:target) { + outline: var(--md-accent-fg-color) auto; + } + + // Tooltip wrapper + &__inner { + padding: px2rem(16px); + font-size: px2rem(12.8px); + + // Adjust spacing on first child + &.md-typeset > :first-child { + margin-top: 0; + } + + // Adjust spacing on last child + &.md-typeset > :last-child { + margin-bottom: 0; + } + } +} + +// ---------------------------------------------------------------------------- + +// Annotation +.md-annotation { + font-weight: 400; + white-space: normal; + vertical-align: text-bottom; + outline: none; + + // Adjust for right-to-left languages + [dir="rtl"] & { + direction: rtl; + } + + // Annotation index in code block + code & { + font-family: var(--md-code-font-family); + font-size: inherit; + } + + // Annotation is not hidden (e.g. when copying) + &:not([hidden]) { + display: inline-block; + // Hack: ensure that the line height doesn't exceed the line height of the + // hosting line, because it will lead to dancing pixels. + line-height: 1.25; + } + + // Annotation index + &__index { + position: relative; + z-index: 0; + display: inline-block; + margin-inline: 0.4ch; + vertical-align: text-top; + cursor: pointer; + user-select: none; + outline: none; + + // Hack: increase specificity to override default for anchors in typesetted + // content, because transitions are defined on anchor elements + .md-annotation & { + transition: z-index 250ms; + } + + // Hack: Work around Firefox bug that renders a subpixel outline when + // rotating a mask image element. + // https://bugzilla.mozilla.org/show_bug.cgi?id=1671784 + overflow: hidden; // stylelint-disable-line order/properties-order + border-radius: 0.01px; + + // [screen]: Render annotation markers as icons + @media screen { + width: 2.2ch; + + // Annotation is visible + [data-md-visible] > & { + animation: pulse 2000ms infinite; + } + + // Annotation marker background + &::before { + position: absolute; + top: -0.1ch; + z-index: -1; + width: 2.2ch; + height: 2.2ch; + content: ""; + background: var(--md-default-bg-color); + mask-image: var(--md-annotation-bg-icon); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + } + + // Annotation marker – the marker must be positioned absolutely behind + // the index, because it shouldn't impact the rendering of a code block. + // Otherwise, small rounding differences in browsers can sometimes mess up + // alignment of text following an annotation. + &::after { + position: absolute; + top: -0.1ch; + z-index: -1; + width: 2.2ch; + height: 2.2ch; + content: ""; + background-color: var(--md-default-fg-color--lighter); + transition: + background-color 250ms, + transform 250ms; + // Hack: promote to own layer to reduce jitter + transform: scale(1.0001); + mask-image: var(--md-annotation-icon); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + + // Annotation marker for active tooltip + .md-tooltip--active + & { + transform: rotate(45deg); + } + + // Annotation marker for active tooltip or on hover + :is(.md-tooltip--active + &, :hover > &) { + background-color: var(--md-accent-fg-color); + } + } + } + + // Annotation index for active tooltip + .md-tooltip--active + & { + z-index: 2; + transition-duration: 0ms; + animation-play-state: paused; + } + + // Annotation marker + [data-md-annotation-id] { + display: inline-block; + + // [print]: Render annotation markers as numbers + @media print { + padding: 0 0.6ch; + font-weight: 700; + color: var(--md-default-bg-color); + white-space: nowrap; + background: var(--md-default-fg-color--lighter); + border-radius: 2ch; + + // Annotation marker content + &::after { + content: attr(data-md-annotation-id); + } + } + } + } +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Annotation list + .md-annotation-list { + list-style: none; + counter-reset: xxx; + + // Annotation list item + li { + position: relative; + + // Annotation list marker + &::before { + position: absolute; + top: px2em(4px); + inset-inline-start: px2em(-34px); + min-width: 2ch; + height: 2ch; + padding: 0 0.6ch; + font-size: px2em(14.2px); + font-weight: 700; + line-height: 1.25; + color: var(--md-default-bg-color); + text-align: center; + content: counter(xxx); + counter-increment: xxx; + background: var(--md-default-fg-color--lighter); + border-radius: 2ch; + } + } + } +} diff --git a/src/templates/assets/stylesheets/main/components/_top.scss b/src/templates/assets/stylesheets/main/components/_top.scss new file mode 100644 index 00000000..c24d44d1 --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_top.scss @@ -0,0 +1,83 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Back-to-top button +.md-top { + position: fixed; + top: px2rem(48px + 16px); + z-index: 2; + display: block; + padding: px2rem(8px) px2rem(16px); + margin-inline-start: 50%; + font-size: px2rem(14px); + color: var(--md-default-fg-color--light); + cursor: pointer; + background-color: var(--md-default-bg-color); + border-radius: px2rem(32px); + outline: none; + box-shadow: var(--md-shadow-z2); + transition: + color 125ms, + background-color 125ms, + transform 125ms cubic-bezier(0.4, 0, 0.2, 1), + opacity 125ms; + transform: translate(-50%, 0); + + // [print]: Hide back-to-top button + @media print { + display: none; + } + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translate(50%, 0); + } + + // Back-to-top button is hidden + &[hidden] { + pointer-events: none; + opacity: 0; + transition-duration: 0ms; + transform: translate(-50%, px2rem(4px)); + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translate(50%, px2rem(4px)); + } + } + + // Back-to-top button on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-bg-color); + background-color: var(--md-accent-fg-color); + } + + // Inline icon + svg { + display: inline-block; + vertical-align: -0.5em; + } +} diff --git a/src/templates/assets/stylesheets/main/components/_version.scss b/src/templates/assets/stylesheets/main/components/_version.scss new file mode 100644 index 00000000..3f85d6cd --- /dev/null +++ b/src/templates/assets/stylesheets/main/components/_version.scss @@ -0,0 +1,150 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Keyframes +// ---------------------------------------------------------------------------- + +// See https://github.com/squidfunk/mkdocs-material/issues/2429 +@keyframes hoverfix { + 0% { + pointer-events: none; + } +} + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Version selection variables +:root { + --md-version-icon: svg-load("fontawesome/solid/caret-down.svg"); +} + +// ---------------------------------------------------------------------------- + +// Version selection +.md-version { + flex-shrink: 0; + height: px2rem(48px); + font-size: px2rem(16px); + + // Current selection + &__current { + position: relative; + // Hack: in general, we would use `vertical-align` to align the version at + // the bottom with the title, but since the list uses absolute positioning, + // this won't work consistently. Furthermore, we would need to use inline + // positioning to align the links, which looks jagged. + top: px2rem(1px); + margin-inline: px2rem(28px) px2rem(8px); + color: inherit; + cursor: pointer; + outline: none; + + // Version selection icon + &::after { + display: inline-block; + width: px2rem(8px); + height: px2rem(12px); + margin-inline-start: px2rem(8px); + content: ""; + background-color: currentcolor; + mask-image: var(--md-version-icon); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + } + } + + // Version selection list + &__list { + position: absolute; + top: px2rem(3px); + z-index: 3; + max-height: 0; + padding: 0; + margin: px2rem(4px) px2rem(16px); + overflow: auto; + color: var(--md-default-fg-color); + list-style-type: none; + background-color: var(--md-default-bg-color); + border-radius: px2rem(2px); + box-shadow: var(--md-shadow-z2); + opacity: 0; + transition: + max-height 0ms 500ms, + opacity 250ms 250ms; + scroll-snap-type: y mandatory; + + // Version selection list on parent focus/hover + .md-version:is(:focus-within, :hover) & { + max-height: px2rem(200px); + opacity: 1; + transition: + max-height 0ms, + opacity 250ms; + } + + // Fix hover on touch devices + @media (pointer: coarse), (hover: none) { + // Switch off on hover + .md-version:hover & { + animation: hoverfix 250ms forwards; + } + + // Enable on focus + .md-version:focus-within & { + animation: none; + } + } + } + + // Version selection item + &__item { + line-height: px2rem(36px); + } + + // Version selection link + &__link { + display: block; + width: 100%; + padding-inline: px2rem(12px) px2rem(24px); + white-space: nowrap; + cursor: pointer; + outline: none; + transition: + color 250ms, + background-color 250ms; + scroll-snap-align: start; + + // Link on focus/hover + &:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + + // Link on focus + &:focus { + background-color: var(--md-default-fg-color--lightest); + } + } +} diff --git a/src/templates/assets/stylesheets/main/extensions/markdown/_admonition.scss b/src/templates/assets/stylesheets/main/extensions/markdown/_admonition.scss new file mode 100644 index 00000000..bf517989 --- /dev/null +++ b/src/templates/assets/stylesheets/main/extensions/markdown/_admonition.scss @@ -0,0 +1,195 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +@use "sass:color"; +@use "sass:list"; + +// ---------------------------------------------------------------------------- +// Variables +// ---------------------------------------------------------------------------- + +/// Admonition flavours +$admonitions: ( + "note": pencil-circle $clr-blue-a200, + "abstract": clipboard-text $clr-light-blue-a400, + "info": information $clr-cyan-a700, + "tip": fire $clr-teal-a700, + "success": check $clr-green-a700, + "question": help-circle $clr-light-green-a700, + "warning": alert $clr-orange-a400, + "failure": close $clr-red-a200, + "danger": lightning-bolt-circle $clr-red-a400, + "bug": shield-bug $clr-pink-a400, + "example": test-tube $clr-deep-purple-a200, + "quote": format-quote-close $clr-grey +) !default; + +// ---------------------------------------------------------------------------- +// Rules: layout +// ---------------------------------------------------------------------------- + +// Admonition variables +:root { + @each $name, $props in $admonitions { + --md-admonition-icon--#{$name}: + svg-load("material/#{list.nth($props, 1)}.svg"); + } +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Admonition - note that all styles also apply to details tags, which are + // rendered as collapsible admonitions with summary elements as titles. + .admonition { + display: flow-root; + padding: 0 px2rem(12px); + margin: px2em(20px, 12.8px) 0; + font-size: px2rem(12.8px); + color: var(--md-admonition-fg-color); + background-color: var(--md-admonition-bg-color); + border: px2rem(1.5px) solid $clr-blue-a200; + border-radius: px2rem(4px); + box-shadow: var(--md-shadow-z1); + transition: box-shadow 125ms; + page-break-inside: avoid; + + // [print]: Omit shadow as it may lead to rendering errors + @media print { + box-shadow: none; + } + + // Admonition on focus + &:focus-within { + box-shadow: 0 0 0 px2rem(4px) color.adjust($clr-blue-a200, $alpha: -0.9); + } + + // Hack: Chrome exhibits a weird issue where it will set nested elements to + // content-box. Doesn't happen in other browsers, so looks like a bug. + > * { + box-sizing: border-box; + } + + // Adjust vertical spacing for nested admonitions + .admonition { + margin-top: 1em; + margin-bottom: 1em; + } + + // Adjust spacing for contained table wrappers + .md-typeset__scrollwrap { + margin: 1em px2rem(-12px); + } + + // Adjust spacing for contained tables + .md-typeset__table { + padding: 0 px2rem(12px); + } + + // Adjust spacing for single-child tabbed block container + > .tabbed-set:only-child { + margin-top: 0; + } + + // Adjust spacing on last child + html & > :last-child { + margin-bottom: px2rem(12px); + } + } + + // Admonition title + .admonition-title { + position: relative; + padding-block: px2rem(8px); + padding-inline: px2rem(40px) px2rem(12px); + margin-block: 0; + margin-inline: px2rem(-12px); + font-weight: 700; + background-color: color.adjust($clr-blue-a200, $alpha: -0.9); + border: none; + border-inline-start-width: px2rem(4px); + border-start-start-radius: px2rem(2px); + border-start-end-radius: px2rem(2px); + + // Adjust spacing for title-only admonitions + html &:last-child { + margin-bottom: 0; + } + + // Admonition icon + &::before { + position: absolute; + top: px2em(10px); + width: px2rem(20px); + height: px2rem(20px); + content: ""; + background-color: $clr-blue-a200; + inset-inline-start: px2rem(12px); + mask-image: var(--md-admonition-icon--note); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + } + + // Inline code block + code { + box-shadow: 0 0 0 px2rem(1px) var(--md-default-fg-color--lightest); + } + } +} + +// ---------------------------------------------------------------------------- +// Rules: flavours +// ---------------------------------------------------------------------------- + +// Define admonition flavors +@each $name, $props in $admonitions { + $tint: list.nth($props, 2); + + // Admonition flavour + .md-typeset .admonition.#{$name} { + border-color: $tint; + + // Admonition on focus + &:focus-within { + box-shadow: 0 0 0 px2rem(4px) color.adjust($tint, $alpha: -0.9); + } + } + + // Admonition flavour title + .md-typeset .#{$name} > .admonition-title { + background-color: color.adjust($tint, $alpha: -0.9); + + // Admonition icon + &::before { + background-color: $tint; + mask-image: var(--md-admonition-icon--#{$name}); + } + + // Details marker + &::after { + color: $tint; + } + } +} diff --git a/src/templates/assets/stylesheets/main/extensions/markdown/_footnotes.scss b/src/templates/assets/stylesheets/main/extensions/markdown/_footnotes.scss new file mode 100644 index 00000000..59447d89 --- /dev/null +++ b/src/templates/assets/stylesheets/main/extensions/markdown/_footnotes.scss @@ -0,0 +1,146 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Footnotes variables +:root { + --md-footnotes-icon: svg-load("material/keyboard-return.svg"); +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Footnote container + .footnote { + font-size: px2rem(12.8px); + color: var(--md-default-fg-color--light); + + // Footnote list - omit left indentation + > ol { + margin-inline-start: 0; + + // Footnote item - footnote items can contain lists, so we need to scope + // the spacing adjustments to the top-level footnote item. + > li { + transition: color 125ms; + + // Darken color on target + &:target { + color: var(--md-default-fg-color); + } + + // Show backreferences on footnote focus without transition + &:focus-within .footnote-backref { + opacity: 1; + transition: none; + transform: translateX(0); + } + + // Show backreferences on footnote hover/target + &:is(:hover, :target) .footnote-backref { + opacity: 1; + transform: translateX(0); + } + + // Adjust spacing on first child + > :first-child { + margin-top: 0; + } + } + } + } + + // Footnote reference + .footnote-ref { + font-size: px2em(12px, 16px); + font-weight: 700; + + // Hack: increase specificity to override default + html & { + outline-offset: px2rem(2px); + } + } + + // Show outline for all devices + [id^="fnref:"]:target > .footnote-ref { + outline: auto; + } + + // Footnote backreference + .footnote-backref { + display: inline-block; + // Hack: omit Unicode arrow for replacement with icon + font-size: 0; + color: var(--md-typeset-a-color); + vertical-align: text-bottom; + opacity: 0; + transition: + color 250ms, + transform 250ms 250ms, + opacity 125ms 250ms; + transform: translateX(px2rem(5px)); + + // [print]: Show footnote backreferences + @media print { + color: var(--md-typeset-a-color); + opacity: 1; + transform: translateX(0); + } + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: translateX(px2rem(-5px)); + } + + // Adjust color on hover + &:hover { + color: var(--md-accent-fg-color); + } + + // Footnote backreference icon + &::before { + display: inline-block; + width: px2rem(16px); + height: px2rem(16px); + content: ""; + background-color: currentcolor; + mask-image: var(--md-footnotes-icon); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + + // Adjust for right-to-left languages + [dir="rtl"] & { + + // Flip icon vertically + svg { + transform: scaleX(-1); + } + } + } + } +} diff --git a/src/templates/assets/stylesheets/main/extensions/markdown/_toc.scss b/src/templates/assets/stylesheets/main/extensions/markdown/_toc.scss new file mode 100644 index 00000000..8284a5c0 --- /dev/null +++ b/src/templates/assets/stylesheets/main/extensions/markdown/_toc.scss @@ -0,0 +1,92 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Headerlink + .headerlink { + display: inline-block; + margin-inline-start: px2rem(10px); + color: var(--md-default-fg-color--lighter); + opacity: 0; + transition: + color 250ms, + opacity 125ms; + + // [print]: Hide headerlinks + @media print { + display: none; + } + } + + // Show headerlinks on parent hover + :is(:hover, :target) > .headerlink, + .headerlink:focus { + opacity: 1; + transition: + color 250ms, + opacity 125ms; + } + + // Adjust color on parent target or focus/hover + :target > .headerlink, + .headerlink:is(:focus, :hover) { + color: var(--md-accent-fg-color); + } + + // Adjust scroll margin for all elements with `id` attributes + :target { + --md-scroll-margin: #{px2rem(48px + 24px)}; + --md-scroll-offset: #{px2rem(0px)}; + // Scroll margin is finally ready for prime time - before, we used a hack + // for anchor correction based on pseudo elements but those times are gone. + scroll-margin-top: + calc( + var(--md-scroll-margin) - + var(--md-scroll-offset) + ); + + // [screen +]: Sticky navigation tabs + @include break-from-device(screen) { + + // Adjust scroll margin for sticky navigation tabs + .md-header--lifted ~ .md-container & { + --md-scroll-margin: #{px2rem(96px + 24px)}; + } + } + } + + // Adjust scroll offset for headlines of level 1-3 + :is(h1, h2, h3):target { + --md-scroll-offset: #{px2rem(4px)}; + } + + // Adjust scroll offset for headlines of level 4 + h4:target { + --md-scroll-offset: #{px2rem(3px)}; + } +} diff --git a/src/templates/assets/stylesheets/main/extensions/pymdownx/_arithmatex.scss b/src/templates/assets/stylesheets/main/extensions/pymdownx/_arithmatex.scss new file mode 100644 index 00000000..fe8ffd62 --- /dev/null +++ b/src/templates/assets/stylesheets/main/extensions/pymdownx/_arithmatex.scss @@ -0,0 +1,52 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Arithmatex container + div.arithmatex { + overflow: auto; + + // [mobile -]: Align with body copy + @include break-to-device(mobile) { + margin: 0 px2rem(-16px); + } + + // Arithmatex content + > * { + width: min-content; + padding: 0 px2rem(16px); + margin-inline: auto !important; // stylelint-disable-line + touch-action: auto; + + // MathJax container - see https://bit.ly/3HR8YJ5 + mjx-container { + margin: 0 !important; // stylelint-disable-line + } + } + } +} diff --git a/src/templates/assets/stylesheets/main/extensions/pymdownx/_critic.scss b/src/templates/assets/stylesheets/main/extensions/pymdownx/_critic.scss new file mode 100644 index 00000000..683705ce --- /dev/null +++ b/src/templates/assets/stylesheets/main/extensions/pymdownx/_critic.scss @@ -0,0 +1,76 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Deletion + del.critic { + background-color: var(--md-typeset-del-color); + box-decoration-break: clone; + } + + // Addition + ins.critic { + background-color: var(--md-typeset-ins-color); + box-decoration-break: clone; + } + + // Comment + .critic.comment { + color: var(--md-code-hl-comment-color); + box-decoration-break: clone; + + // Comment opening mark + &::before { + content: "/* "; + } + + // Comment closing mark + &::after { + content: " */"; + } + } + + // Critic block + .critic.block { + display: block; + padding-inline: px2rem(16px); + margin: 1em 0; + overflow: auto; + box-shadow: none; + + // Adjust spacing on first child + > :first-child { + margin-top: 0.5em; + } + + // Adjust spacing on last child + > :last-child { + margin-bottom: 0.5em; + } + } +} diff --git a/src/templates/assets/stylesheets/main/extensions/pymdownx/_details.scss b/src/templates/assets/stylesheets/main/extensions/pymdownx/_details.scss new file mode 100644 index 00000000..8eea678a --- /dev/null +++ b/src/templates/assets/stylesheets/main/extensions/pymdownx/_details.scss @@ -0,0 +1,121 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Details variables +:root { + --md-details-icon: svg-load("material/chevron-right.svg"); +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Details + details { + @extend .admonition; + + display: flow-root; + padding-top: 0; + overflow: visible; + + // Details title icon - rotate icon on transition to open state + &[open] > summary::after { + transform: rotate(90deg); + } + + // Adjust spacing for details in closed state + &:not([open]) { + padding-bottom: 0; + box-shadow: none; + + // Hack: we cannot set `overflow: hidden` on the `details` element (which + // is why we set it to `overflow: visible`, as the outline would not be + // visible when focusing. Therefore, we must set the border radius on the + // summary explicitly. + > summary { + border-radius: px2rem(2px); + } + } + } + + // Details title + summary { + @extend .admonition-title; + + display: block; + min-height: px2rem(20px); + padding-inline-end: px2rem(36px); + cursor: pointer; + border-start-start-radius: px2rem(2px); + border-start-end-radius: px2rem(2px); + + // Show outline for keyboard devices + &.focus-visible { + outline-color: var(--md-accent-fg-color); + outline-offset: px2rem(4px); + } + + // Hide outline for pointer devices + &:not(.focus-visible) { + outline: none; + -webkit-tap-highlight-color: transparent; + } + + // Details marker + &::after { + position: absolute; + top: px2em(10px); + width: px2rem(20px); + height: px2rem(20px); + content: ""; + background-color: currentcolor; + transition: transform 250ms; + transform: rotate(0deg); + inset-inline-end: px2rem(8px); + mask-image: var(--md-details-icon); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: rotate(180deg); + } + } + + // Hide native details marker - modern + &::marker { + display: none; + } + + // Hide native details marker - legacy, must be split into a seprate rule, + // so older browsers don't consider the selector list as invalid + &::-webkit-details-marker { + display: none; + } + } +} diff --git a/src/templates/assets/stylesheets/main/extensions/pymdownx/_emoji.scss b/src/templates/assets/stylesheets/main/extensions/pymdownx/_emoji.scss new file mode 100644 index 00000000..8b351013 --- /dev/null +++ b/src/templates/assets/stylesheets/main/extensions/pymdownx/_emoji.scss @@ -0,0 +1,43 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Emoji and icon container + :is(.emojione, .twemoji, .gemoji) { + display: inline-flex; + height: px2em(18px); + vertical-align: text-top; + + // Icon - inlined via mkdocs-material-extensions + svg { + width: px2em(18px); + max-height: 100%; + fill: currentcolor; + } + } +} diff --git a/src/templates/assets/stylesheets/main/extensions/pymdownx/_highlight.scss b/src/templates/assets/stylesheets/main/extensions/pymdownx/_highlight.scss new file mode 100644 index 00000000..7d297677 --- /dev/null +++ b/src/templates/assets/stylesheets/main/extensions/pymdownx/_highlight.scss @@ -0,0 +1,382 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules: syntax highlighting +// ---------------------------------------------------------------------------- + +// Code block +.highlight { + + // .o = Operator + // .ow = Operator, word + :is(.o, .ow) { + color: var(--md-code-hl-operator-color); + } + + .p { // Punctuation + color: var(--md-code-hl-punctuation-color); + } + + // .cpf = Comment, preprocessor file + // .l = Literal + // .s = Literal, string + // .sb = Literal, string backticks + // .sc = Literal, string char + // .s2 = Literal, string double + // .si = Literal, string interpol + // .s1 = Literal, string single + // .ss = Literal, string symbol + :is(.cpf, .l, .s, .sb, .sc, .s2, .si, .s1, .ss) { + color: var(--md-code-hl-string-color); + } + + // .cp = Comment, pre-processor + // .se = Literal, string escape + // .sh = Literal, string heredoc + // .sr = Literal, string regex + // .sx = Literal, string other + :is(.cp, .se, .sh, .sr, .sx) { + color: var(--md-code-hl-special-color); + } + + // .m = Number + // .mb = Number, binary + // .mf = Number, float + // .mh = Number, hex + // .mi = Number, integer + // .il = Number, integer long + // .mo = Number, octal + :is(.m, .mb, .mf, .mh, .mi, .il, .mo) { + color: var(--md-code-hl-number-color); + } + + // .k = Keyword, + // .kd = Keyword, declaration + // .kn = Keyword, namespace + // .kp = Keyword, pseudo + // .kr = Keyword, reserved + // .kt = Keyword, type + :is(.k, .kd, .kn, .kp, .kr, .kt) { + color: var(--md-code-hl-keyword-color); + } + + // .kc = Keyword, constant + // .n = Name + :is(.kc, .n) { + color: var(--md-code-hl-name-color); + } + + // .no = Name, constant + // .nb = Name, builtin + // .bp = Name, builtin pseudo + :is(.no, .nb, .bp) { + color: var(--md-code-hl-constant-color); + } + + // .nc = Name, class + // .ne = Name, exception + // .nf = Name, function + // .nn = Name, namespace + :is(.nc, .ne, .nf, .nn) { + color: var(--md-code-hl-function-color); + } + + // .nd = Name, decorator + // .ni = Name, entity + // .nl = Name, label + // .nt = Name, tag + :is(.nd, .ni, .nl, .nt) { + color: var(--md-code-hl-keyword-color); + } + + // .c = Comment + // .cm = Comment, multiline + // .c1 = Comment, single + // .ch = Comment, shebang + // .cs = Comment, special + // .sd = Literal, string doc + :is(.c, .cm, .c1, .ch, .cs, .sd) { + color: var(--md-code-hl-comment-color); + } + + // .na = Name, attribute + // .nv = Variable, + // .vc = Variable, class + // .vg = Variable, global + // .vi = Variable, instance + :is(.na, .nv, .vc, .vg, .vi) { + color: var(--md-code-hl-variable-color); + } + + // .ge = Generic, emph + // .gr = Generic, error + // .gh = Generic, heading + // .go = Generic, output + // .gp = Generic, prompt + // .gs = Generic, strong + // .gu = Generic, subheading + // .gt = Generic, traceback + :is(.ge, .gr, .gh, .go, .gp, .gs, .gu, .gt) { + color: var(--md-code-hl-generic-color); + } + + // .gd = Diff, delete + // .gi = Diff, insert + :is(.gd, .gi) { + padding: 0 px2em(2px); + margin: 0 px2em(-2px); + border-radius: px2rem(2px); + } + + .gd { // Diff, delete + background-color: var(--md-typeset-del-color); + } + + .gi { // Diff, insert + background-color: var(--md-typeset-ins-color); + } + + // Highlighted line + .hll { + display: block; + padding: 0 px2em(16px, 13.6px); + margin: 0 px2em(-16px, 13.6px); + background-color: var(--md-code-hl-color--light); + box-shadow: 2px 0 0 0 var(--md-code-hl-color) inset; + } + + // Code block title + span.filename { + position: relative; + display: flow-root; + padding: px2em(9px, 13.6px) px2em(16px, 13.6px); + margin-top: 1em; + font-size: px2em(13.6px); + font-weight: 700; + background-color: var(--md-code-bg-color); + border-bottom: px2rem(1px) solid var(--md-default-fg-color--lightest); + border-top-left-radius: px2rem(2px); + border-top-right-radius: px2rem(2px); + + // Adjust spacing for code block + + pre { + margin-top: 0; + + // Remove rounded border on top side + > code { + border-top-left-radius: 0; + border-top-right-radius: 0; + } + } + } + + // Code block line numbers (pymdownx-inline) + [data-linenos]::before { + position: sticky; + left: px2em(-16px, 13.6px); + // A `z-index` of 3 is necessary for ensuring that code block annotations + // don't overlay line numbers, as active annotations have a `z-index` of 2. + z-index: 3; + float: left; + padding-left: px2em(16px, 13.6px); + margin-right: px2em(16px, 13.6px); + margin-left: px2em(-16px, 13.6px); + color: var(--md-default-fg-color--light); + content: attr(data-linenos); + user-select: none; + background-color: var(--md-code-bg-color); + box-shadow: px2rem(-1px) 0 var(--md-default-fg-color--lightest) inset; + } + + // Code block line anchors - Chrome and Safari seem to have a strange bug + // where scroll margin is not applied to anchors inside code blocks. Setting + // positioning to absolute seems to fix the problem. Interestingly, this does + // not happen in Firefox. Furthermore we must set `visibility: hidden` or + // the copy to clipboard functionality will include an empty line between + // each set of lines. + code a[id] { + position: absolute; + visibility: hidden; + } + + // Copying in progress - this class is set before the content is copied and + // removed after copying is done to mitigate whitespace-related issues. + code[data-md-copying] { + + // Temporarily remove highlighted lines - see https://bit.ly/32iVGWh + .hll { + display: contents; + } + + // Temporarily remove annotations + .md-annotation { + display: none; + } + } +} + +// ---------------------------------------------------------------------------- +// Rules: layout +// ---------------------------------------------------------------------------- + +// Code block with line numbers +.highlighttable { + display: flow-root; + + // Set table elements to block layout, because otherwise the whole flexbox + // hacking won't work correctly + :is(tbody, td) { + display: block; + padding: 0; + } + + // We need to use flexbox layout, because otherwise it's not possible to + // make the code container scroll while keeping the line numbers static + tr { + display: flex; + } + + // The pre tags are nested inside a table, so we need to omit the margin + // because it collapses below all the overflows + pre { + margin: 0; + } + + // Code block title container + th.filename { + flex-grow: 1; + padding: 0; + text-align: left; + + // Adjust spacing + span.filename { + margin-top: 0; + } + } + + // Code block line numbers - disable user selection, so code can be easily + // copied without accidentally also copying the line numbers + .linenos { + padding: px2em(10.5px, 13.6px) px2em(16px, 13.6px); + padding-right: 0; + font-size: px2em(13.6px); + user-select: none; + background-color: var(--md-code-bg-color); + border-top-left-radius: px2rem(2px); + border-bottom-left-radius: px2rem(2px); + } + + // Code block line numbers container + .linenodiv { + padding-right: px2em(8px, 13.6px); + box-shadow: px2rem(-1px) 0 var(--md-default-fg-color--lightest) inset; + + // Adjust colors and alignment + pre { + color: var(--md-default-fg-color--light); + text-align: right; + } + } + + // Code block container - stretch to remaining space + .code { + flex: 1; + min-width: 0; + } +} + +// Code block line numbers container +.linenodiv a { + color: inherit; +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Code block with line numbers - unfortunately, these selectors need to be + // overly specific so they don't bleed into code blocks in annotations. + .highlighttable { + margin: 1em 0; + direction: ltr; + + // Remove rounded borders on code blocks + > tbody > tr > .code > div > pre > code { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + + // Code block result container + .highlight + .result { + padding: 0 px2em(16px); + margin-top: calc(-1em + #{px2em(-2px)}); + overflow: visible; + border: px2rem(1px) solid var(--md-code-bg-color); + border-top-width: px2rem(2px); + border-bottom-right-radius: px2rem(2px); + border-bottom-left-radius: px2rem(2px); + + // Clearfix, because we can't use overflow: auto + &::after { + display: block; + clear: both; + content: ""; + } + } +} + +// ---------------------------------------------------------------------------- +// Rules: top-level +// ---------------------------------------------------------------------------- + +// [mobile -]: Align with body copy +@include break-to-device(mobile) { + + // Top-level code block + .md-content__inner > .highlight { + margin: 1em px2rem(-16px); + + // Remove rounded borders + > .filename, + > pre > code { + border-radius: 0; + } + + // Code block with line numbers - unfortunately, these selectors need to be + // overly specific so they don't bleed into code blocks in annotations. + > .highlighttable > tbody > tr > .filename span.filename, + > .highlighttable > tbody > tr > .linenos, + > .highlighttable > tbody > tr > .code > div > pre > code { + border-radius: 0; + } + + // Code block result container + + .result { + margin-inline: px2rem(-16px); + border-inline-width: 0; + border-radius: 0; + } + } +} diff --git a/src/templates/assets/stylesheets/main/extensions/pymdownx/_keys.scss b/src/templates/assets/stylesheets/main/extensions/pymdownx/_keys.scss new file mode 100644 index 00000000..8749f08c --- /dev/null +++ b/src/templates/assets/stylesheets/main/extensions/pymdownx/_keys.scss @@ -0,0 +1,115 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Keyboard key + .keys { + + // Keyboard key icon + kbd:is(::before, ::after) { + position: relative; + margin: 0; + color: inherit; + -moz-osx-font-smoothing: initial; + -webkit-font-smoothing: initial; + } + + // Surrounding text + span { + padding: 0 px2em(3.2px); + color: var(--md-default-fg-color--light); + } + + // Define keyboard keys with left icon + @each $name, $code in ( + + // Modifiers + "alt": "\2387", + "left-alt": "\2387", + "right-alt": "\2387", + "command": "\2318", + "left-command": "\2318", + "right-command": "\2318", + "control": "\2303", + "left-control": "\2303", + "right-control": "\2303", + "meta": "\25C6", + "left-meta": "\25C6", + "right-meta": "\25C6", + "option": "\2325", + "left-option": "\2325", + "right-option": "\2325", + "shift": "\21E7", + "left-shift": "\21E7", + "right-shift": "\21E7", + "super": "\2756", + "left-super": "\2756", + "right-super": "\2756", + "windows": "\229E", + "left-windows": "\229E", + "right-windows": "\229E", + + // Other keys + "arrow-down": "\2193", + "arrow-left": "\2190", + "arrow-right": "\2192", + "arrow-up": "\2191", + "backspace": "\232B", + "backtab": "\21E4", + "caps-lock": "\21EA", + "clear": "\2327", + "context-menu": "\2630", + "delete": "\2326", + "eject": "\23CF", + "end": "\2913", + "escape": "\238B", + "home": "\2912", + "insert": "\2380", + "page-down": "\21DF", + "page-up": "\21DE", + "print-screen": "\2399" + ) { + .key-#{$name}::before { + padding-right: px2em(6.4px); + content: $code; + } + } + + // Define keyboard keys with right icon + @each $name, $code in ( + "tab": "\21E5", + "num-enter": "\2324", + "enter": "\23CE" + ) { + .key-#{$name}::after { + padding-left: px2em(6.4px); + content: $code; + } + } + } +} diff --git a/src/templates/assets/stylesheets/main/extensions/pymdownx/_tabbed.scss b/src/templates/assets/stylesheets/main/extensions/pymdownx/_tabbed.scss new file mode 100644 index 00000000..9df91bfc --- /dev/null +++ b/src/templates/assets/stylesheets/main/extensions/pymdownx/_tabbed.scss @@ -0,0 +1,400 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Tabbed variables +:root { + --md-tabbed-icon--prev: svg-load("material/chevron-left.svg"); + --md-tabbed-icon--next: svg-load("material/chevron-right.svg"); +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Tabbed container + .tabbed-set { + position: relative; + display: flex; + flex-flow: column wrap; + margin: 1em 0; + border-radius: px2rem(2px); + + // Tab radio button - the Tabbed extension will generate radio buttons with + // labels, so tabs can be triggered without the necessity for JavaScript. + // This is pretty cool, as it has great accessibility out-of-the box, so + // we just hide the radio button and toggle the label color for indication. + > input { + position: absolute; + width: 0; + height: 0; + opacity: 0; + + // Adjust scroll margin + &:target { + --md-scroll-offset: #{px2em(10px, 16px)}; + } + + // Tab label states + @for $i from 20 through 1 { + &:nth-child(#{$i}) { + + // Tab is active + &:checked { + + // Tab label + ~ .tabbed-labels > :nth-child(#{$i}) { + @extend %tabbed-label; + } + + // Tab content + ~ .tabbed-content > :nth-child(#{$i}) { + @extend %tabbed-content; + } + } + + // Tab label on keyboard focus + &.focus-visible ~ .tabbed-labels > :nth-child(#{$i}) { + @extend %tabbed-label-focus-visible; + } + } + } + + // Tab indicator on keyboard focus + &.focus-visible ~ .tabbed-labels::before { + background-color: var(--md-accent-fg-color); + } + } + } + + // Tabbed labels + .tabbed-labels { + display: flex; + max-width: 100%; + overflow: auto; + box-shadow: 0 px2rem(-1px) var(--md-default-fg-color--lightest) inset; + -ms-overflow-style: none; // IE, Edge + scrollbar-width: none; // Firefox + + // [print]: Move one layer up for ordering + @media print { + display: contents; + } + + // [screen and no reduced motion]: Disable animation + @media screen { + + // [js]: Show animated tab indicator + .js & { + position: relative; + + // Tab indicator + &::before { + position: absolute; + bottom: 0; + left: 0; + display: block; + width: var(--md-indicator-width); + height: 2px; + content: ""; + background: var(--md-default-fg-color); + transition: + width 225ms, + background-color 250ms, + transform 250ms; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transform: translateX(var(--md-indicator-x)); + } + } + } + + // Webkit scrollbar + &::-webkit-scrollbar { + display: none; // Chrome, Safari + } + + // Tab label + > label { + flex-shrink: 0; + width: auto; + padding: px2em(10px, 12.8px) 1.25em px2em(8px, 12.8px); + font-size: px2rem(12.8px); + font-weight: 700; + color: var(--md-default-fg-color--light); + white-space: nowrap; + cursor: pointer; + border-bottom: px2rem(2px) solid transparent; + border-radius: px2rem(2px) px2rem(2px) 0 0; + transition: + background-color 250ms, + color 250ms; + scroll-margin-inline-start: px2rem(20px); + + // [print]: Intersperse labels with containers + @media print { + + // Ensure correct order of labels + @for $i from 1 through 20 { + &:nth-child(#{$i}) { + order: $i; + } + } + } + + // Tab label on hover + &:hover { + color: var(--md-default-fg-color); + } + } + } + + // Tabbed content + .tabbed-content { + width: 100%; + + // [print]: Move one layer up for ordering + @media print { + display: contents; + } + } + + // Tabbed block + .tabbed-block { + display: none; + + // [print]: Intersperse labels with containers + @media print { + display: block; + + // Ensure correct order of containers + @for $i from 1 through 20 { + &:nth-child(#{$i}) { + order: $i; + } + } + } + + // Code block is the first child of a tab - remove margin and mirror + // previous (now deprecated) SuperFences code block grouping behavior + > pre:first-child, + > .highlight:first-child > pre { + margin: 0; + + // Remove rounded borders on code block + > code { + border-top-left-radius: 0; + border-top-right-radius: 0; + } + } + + // Code block is the first child of a tab - remove margin and mirror + // previous (now deprecated) SuperFences code block grouping behavior + > .highlight:first-child { + + // Code block title - remove spacing and rounded borders + > .filename { + margin: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; + } + + // Code block with line numbers - unfortunately, these selectors need to + // be overly specific so they don't bleed into code blocks in annotations. + > .highlighttable { + margin: 0; + + // Remove rounded borders on line numbers and titles + > tbody > tr > .filename span.filename, + > tbody > tr > .linenos { + margin: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; + } + + // Remove rounded borders on code blocks + > tbody > tr > .code > div > pre > code { + border-top-left-radius: 0; + border-top-right-radius: 0; + } + } + + // Code block result container - adjust spacing + + .result { + margin-top: px2em(-2px); + } + } + + // Adjust spacing for nested tabbed container + > .tabbed-set { + margin: 0; + } + } + + // Tabbed button + .tabbed-button { + display: block; + align-self: center; + width: px2rem(18px); + height: px2rem(18px); + margin-top: px2rem(2px); + color: var(--md-default-fg-color--light); + pointer-events: initial; + cursor: pointer; + border-radius: 100%; + transition: background-color 250ms; + + // Tabbed button on hover + &:hover { + color: var(--md-accent-fg-color); + background-color: var(--md-accent-fg-color--transparent); + } + + // Tabbed button icon + &::after { + display: block; + width: 100%; + height: 100%; + content: ""; + background-color: currentcolor; + transition: + background-color 250ms, + transform 250ms; + mask-image: var(--md-tabbed-icon--prev); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + } + } + + // Tabbed control + .tabbed-control { + position: absolute; + display: flex; + justify-content: start; + width: px2rem(24px); + height: px2rem(38px); + pointer-events: none; + background: + linear-gradient( + to right, + var(--md-default-bg-color) 60%, + transparent + ); + transition: opacity 125ms; + + // Adjust for right-to-left languages + [dir="rtl"] & { + transform: rotate(180deg); + } + + // Tabbed control is hidden + &[hidden] { + opacity: 0; + } + + // Tabbed control next + &--next { + right: 0; + justify-content: end; + background: + linear-gradient( + to left, + var(--md-default-bg-color) 60%, + transparent + ); + + // Tabbed button icon content + .tabbed-button::after { + mask-image: var(--md-tabbed-icon--next); + } + } + } +} + +// ---------------------------------------------------------------------------- +// Rules: top-level +// ---------------------------------------------------------------------------- + +// [mobile -]: Align with body copy +@include break-to-device(mobile) { + + // Top-level tabbed labels + .md-content__inner > .tabbed-set .tabbed-labels { + max-width: 100vw; + padding-inline-start: px2rem(16px); + margin: 0 px2rem(-16px); + scroll-padding-inline-start: px2rem(16px); + + // Hack: some browsers ignore the right padding on flex containers, + // see https://bit.ly/3lsPS3S + &::after { + padding-inline-end: px2rem(16px); + content: ""; + } + + // Tabbed control previous + ~ .tabbed-control--prev { + width: px2rem(40px); + padding-inline-start: px2rem(16px); + margin-inline-start: px2rem(-16px); + } + + // Tabbed control next + ~ .tabbed-control--next { + width: px2rem(40px); + padding-inline-end: px2rem(16px); + margin-inline-end: px2rem(-16px); + } + } +} + +// ---------------------------------------------------------------------------- +// Placeholders: improve colocation for better compression +// ---------------------------------------------------------------------------- + +// Tab label placeholder +%tabbed-label { + + // [screen]: Show active state + @media screen { + color: var(--md-default-fg-color); + + // [no-js]: Show border (indicator is animated with JavaScript) + .no-js & { + border-color: var(--md-default-fg-color); + } + } +} + +// Tab label on keyboard focus placeholder +%tabbed-label-focus-visible { + color: var(--md-accent-fg-color); +} + +// Tab content placeholder +%tabbed-content { + display: block; +} diff --git a/src/templates/assets/stylesheets/main/extensions/pymdownx/_tasklist.scss b/src/templates/assets/stylesheets/main/extensions/pymdownx/_tasklist.scss new file mode 100644 index 00000000..a1d1117c --- /dev/null +++ b/src/templates/assets/stylesheets/main/extensions/pymdownx/_tasklist.scss @@ -0,0 +1,78 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Tasklist variables +:root { + --md-tasklist-icon: svg-load("octicons/check-circle-fill-24.svg"); + --md-tasklist-icon--checked: svg-load("octicons/check-circle-fill-24.svg"); +} + +// ---------------------------------------------------------------------------- + +// Scoped in typesetted content to match specificity of regular content +.md-typeset { + + // Tasklist item + .task-list-item { + position: relative; + list-style-type: none; + + // Make checkbox items align with normal list items, but position + // everything in ems for correct layout at smaller font sizes + [type="checkbox"] { + position: absolute; + top: 0.45em; + inset-inline-start: -2em; + } + } + + // Hide native checkbox, when custom classes are enabled + .task-list-control [type="checkbox"] { + z-index: -1; + opacity: 0; + } + + // Tasklist indicator in unchecked state + .task-list-indicator::before { + position: absolute; + top: 0.15em; + width: px2em(20px); + height: px2em(20px); + content: ""; + background-color: var(--md-default-fg-color--lightest); + inset-inline-start: px2em(-24px); + mask-image: var(--md-tasklist-icon); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + } + + // Tasklist indicator in checked state + [type="checkbox"]:checked + .task-list-indicator::before { + background-color: $clr-green-a400; + mask-image: var(--md-tasklist-icon--checked); + } +} diff --git a/src/templates/assets/stylesheets/main/integrations/_mermaid.scss b/src/templates/assets/stylesheets/main/integrations/_mermaid.scss new file mode 100644 index 00000000..d0325f39 --- /dev/null +++ b/src/templates/assets/stylesheets/main/integrations/_mermaid.scss @@ -0,0 +1,67 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Mermaid variables +:root > * { + --md-mermaid-font-family: var(--md-text-font-family), sans-serif; + + // General colors + --md-mermaid-edge-color: var(--md-code-fg-color); + --md-mermaid-node-bg-color: var(--md-accent-fg-color--transparent); + --md-mermaid-node-fg-color: var(--md-accent-fg-color); + --md-mermaid-label-bg-color: var(--md-default-bg-color); + --md-mermaid-label-fg-color: var(--md-code-fg-color); + + // Sequence diagram colors + --md-mermaid-sequence-actor-bg-color: var(--md-mermaid-label-bg-color); + --md-mermaid-sequence-actor-fg-color: var(--md-mermaid-label-fg-color); + --md-mermaid-sequence-actor-border-color: var(--md-mermaid-node-fg-color); + --md-mermaid-sequence-actor-line-color: var(--md-default-fg-color--lighter); + --md-mermaid-sequence-actorman-bg-color: var(--md-mermaid-label-bg-color); + --md-mermaid-sequence-actorman-line-color: var(--md-mermaid-node-fg-color); + --md-mermaid-sequence-box-bg-color: var(--md-mermaid-node-bg-color); + --md-mermaid-sequence-box-fg-color: var(--md-mermaid-edge-color); + --md-mermaid-sequence-label-bg-color: var(--md-mermaid-node-bg-color); + --md-mermaid-sequence-label-fg-color: var(--md-mermaid-node-fg-color); + --md-mermaid-sequence-loop-bg-color: var(--md-mermaid-node-bg-color); + --md-mermaid-sequence-loop-fg-color: var(--md-mermaid-edge-color); + --md-mermaid-sequence-loop-border-color: var(--md-mermaid-node-fg-color); + --md-mermaid-sequence-message-fg-color: var(--md-mermaid-edge-color); + --md-mermaid-sequence-message-line-color: var(--md-mermaid-edge-color); + --md-mermaid-sequence-note-bg-color: var(--md-mermaid-label-bg-color); + --md-mermaid-sequence-note-fg-color: var(--md-mermaid-edge-color); + --md-mermaid-sequence-note-border-color: var(--md-mermaid-label-fg-color); + --md-mermaid-sequence-number-bg-color: var(--md-mermaid-node-fg-color); + --md-mermaid-sequence-number-fg-color: var(--md-accent-bg-color); +} + +// ---------------------------------------------------------------------------- + +// Mermaid container +.mermaid { + margin: 1em 0; + line-height: normal; +} diff --git a/src/templates/assets/stylesheets/palette.scss b/src/templates/assets/stylesheets/palette.scss new file mode 100644 index 00000000..ff73a982 --- /dev/null +++ b/src/templates/assets/stylesheets/palette.scss @@ -0,0 +1,40 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Dependencies +// ---------------------------------------------------------------------------- + +@import "material-color"; + +// ---------------------------------------------------------------------------- +// Local imports +// ---------------------------------------------------------------------------- + +@import "utilities/break"; +@import "utilities/convert"; + +@import "config"; + +@import "palette/scheme"; +@import "palette/accent"; +@import "palette/primary"; diff --git a/src/templates/assets/stylesheets/palette/_accent.scss b/src/templates/assets/stylesheets/palette/_accent.scss new file mode 100644 index 00000000..9f69b596 --- /dev/null +++ b/src/templates/assets/stylesheets/palette/_accent.scss @@ -0,0 +1,61 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Define accent colors +@each $name, $color in ( + "red": $clr-red-a400, + "pink": $clr-pink-a400, + "purple": $clr-purple-a200, + "deep-purple": $clr-deep-purple-a200, + "indigo": $clr-indigo-a200, + "blue": $clr-blue-a200, + "light-blue": $clr-light-blue-a700, + "cyan": $clr-cyan-a700, + "teal": $clr-teal-a700, + "green": $clr-green-a700, + "light-green": $clr-light-green-a700, + "lime": $clr-lime-a700, + "yellow": $clr-yellow-a700, + "amber": $clr-amber-a700, + "orange": $clr-orange-a400, + "deep-orange": $clr-deep-orange-a200 +) { + + // Color palette + [data-md-color-accent="#{$name}"] { + --md-accent-fg-color: hsla(#{hex2hsl($color)}, 1); + --md-accent-fg-color--transparent: hsla(#{hex2hsl($color)}, 0.1); + + // Inverted text for lighter shades + @if index("lime" "yellow" "amber" "orange", $name) { + --md-accent-bg-color: hsla(0, 0%, 0%, 0.87); + --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.54); + } @else { + --md-accent-bg-color: hsla(0, 0%, 100%, 1); + --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7); + } + } +} diff --git a/src/templates/assets/stylesheets/palette/_primary.scss b/src/templates/assets/stylesheets/palette/_primary.scss new file mode 100644 index 00000000..a8653f0f --- /dev/null +++ b/src/templates/assets/stylesheets/palette/_primary.scss @@ -0,0 +1,203 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +@use "sass:list"; + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Define primary colors +@each $name, $colors in ( + "red": $clr-red-400 $clr-red-300 $clr-red-600, + "pink": $clr-pink-500 $clr-pink-400 $clr-pink-700, + "purple": $clr-purple-400 $clr-purple-300 $clr-purple-600, + "deep-purple": $clr-deep-purple-400 $clr-deep-purple-300 $clr-deep-purple-500, + "indigo": $clr-indigo-500 $clr-indigo-400 $clr-indigo-700, + "blue": $clr-blue-500 $clr-blue-400 $clr-blue-700, + "light-blue": $clr-light-blue-500 $clr-light-blue-400 $clr-light-blue-700, + "cyan": $clr-cyan-500 $clr-cyan-400 $clr-cyan-700, + "teal": $clr-teal-500 $clr-teal-400 $clr-teal-700, + "green": $clr-green-500 $clr-green-400 $clr-green-700, + "light-green": $clr-light-green-500 $clr-light-green-400 $clr-light-green-700, + "lime": $clr-lime-500 $clr-lime-400 $clr-lime-700, + "yellow": $clr-yellow-500 $clr-yellow-400 $clr-yellow-700, + "amber": $clr-amber-500 $clr-amber-400 $clr-amber-700, + "orange": $clr-orange-400 $clr-orange-400 $clr-orange-600, + "deep-orange": $clr-deep-orange-400 $clr-deep-orange-300 $clr-deep-orange-600, + "brown": $clr-brown-500 $clr-brown-400 $clr-brown-700, + "grey": $clr-grey-600 $clr-grey-500 $clr-grey-700, + "blue-grey": $clr-blue-grey-600 $clr-blue-grey-500 $clr-blue-grey-700 +) { + + // Color palette + [data-md-color-primary="#{$name}"] { + --md-primary-fg-color: hsl(#{hex2hsl(list.nth($colors, 1))}); + --md-primary-fg-color--light: hsl(#{hex2hsl(list.nth($colors, 2))}); + --md-primary-fg-color--dark: hsl(#{hex2hsl(list.nth($colors, 3))}); + + // Inverted text for lighter shades + @if index("lime" "yellow" "amber" "orange", $name) { + --md-primary-bg-color: hsla(0, 0%, 0%, 0.87); + --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54); + } @else { + --md-primary-bg-color: hsla(0, 0%, 100%, 1); + --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7); + } + + // Typeset color shades + @if index("grey" "blue-grey", $name) { + --md-typeset-a-color: hsl(#{hex2hsl($clr-indigo-500)}); + } + } +} + +// ---------------------------------------------------------------------------- + +// Adjust link colors for light primary colors +@each $name, $color in ( + "light-green": hsl(88, 58%, 43%), + "lime": hsl(66, 88%, 32%), + "yellow": hsl(54, 100%, 36%), + "amber": hsl(45, 100%, 41%), + "orange": hsl(36, 100%, 45%) +) { + [data-md-color-primary="#{$name}"]:not([data-md-color-scheme="slate"]) { + --md-typeset-a-color: #{$color}; + } +} + +// ---------------------------------------------------------------------------- +// Rules: white +// ---------------------------------------------------------------------------- + +// Define primary colors for white +[data-md-color-primary="white"] { + --md-primary-fg-color: hsla(var(--md-hue), 0%, 100%, 1); + --md-primary-fg-color--light: hsla(var(--md-hue), 0%, 100%, 0.7); + --md-primary-fg-color--dark: hsla(var(--md-hue), 0%, 0%, 0.07); + --md-primary-bg-color: hsla(var(--md-hue), 0%, 0%, 0.87); + --md-primary-bg-color--light: hsla(var(--md-hue), 0%, 0%, 0.54); + + // Typeset `a` color shades + --md-typeset-a-color: hsl(#{hex2hsl($clr-indigo-500)}); + + // Form button + .md-button { + color: var(--md-typeset-a-color); + + // Primary button + &--primary { + color: hsla(var(--md-hue), 0%, 100%, 1); + background-color: var(--md-typeset-a-color); + border-color: var(--md-typeset-a-color); + } + } + + // [tablet portrait +]: Header-embedded search + @include break-from-device(tablet landscape) { + + // Search form + .md-search__form { + background-color: hsla(var(--md-hue), 0%, 0%, 0.07); + + // Search form on hover + &:hover { + background-color: hsla(var(--md-hue), 0%, 0%, 0.32); + } + } + + // Search icon + .md-search__input + .md-search__icon { + color: hsla(var(--md-hue), 0%, 0%, 0.87); + } + } + + // [screen +]: Add bottom border for tabs + @include break-from-device(screen) { + + // Navigation tabs + .md-tabs { + border-bottom: px2rem(1px) solid hsla(0, 0%, 0%, 0.07); + } + } +} + +// ---------------------------------------------------------------------------- +// Rules: black +// ---------------------------------------------------------------------------- + +// Define primary colors for black +[data-md-color-primary="black"] { + --md-primary-fg-color: hsla(var(--md-hue), 15%, 9%, 1); + --md-primary-fg-color--light: hsla(var(--md-hue), 15%, 9%, 0.54); + --md-primary-fg-color--dark: hsla(var(--md-hue), 15%, 9%, 1); + --md-primary-bg-color: hsla(var(--md-hue), 15%, 100%, 1); + --md-primary-bg-color--light: hsla(var(--md-hue), 15%, 100%, 0.7); + + // Typeset `a` color shades + --md-typeset-a-color: hsl(#{hex2hsl($clr-indigo-500)}); + + // Form button + .md-button { + color: var(--md-typeset-a-color); + + // Primary button + &--primary { + color: hsla(var(--md-hue), 0%, 100%, 1); + background-color: var(--md-typeset-a-color); + border-color: var(--md-typeset-a-color); + } + } + + // Header + .md-header { + background-color: hsla(var(--md-hue), 15%, 9%, 1); + } + + // [tablet portrait -]: Layered navigation + @include break-to-device(tablet portrait) { + + // Repository information container + .md-nav__source { + background-color: hsla(var(--md-hue), 15%, 11%, 0.87); + } + } + + // [tablet -]: Layered navigation + @include break-to-device(tablet) { + + // Site title in main navigation + html & .md-nav--primary .md-nav__title[for="__drawer"] { + background-color: hsla(var(--md-hue), 15%, 9%, 1); + } + } + + // [screen +]: Set background color for tabs + @include break-from-device(screen) { + + // Navigation tabs + .md-tabs { + background-color: hsla(var(--md-hue), 15%, 9%, 1); + } + } +} diff --git a/src/templates/assets/stylesheets/palette/_scheme.scss b/src/templates/assets/stylesheets/palette/_scheme.scss new file mode 100644 index 00000000..0a9f9823 --- /dev/null +++ b/src/templates/assets/stylesheets/palette/_scheme.scss @@ -0,0 +1,145 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +// ---------------------------------------------------------------------------- +// Rules +// ---------------------------------------------------------------------------- + +// Only use dark mode on screens +@media screen { + + // Slate theme, i.e. dark mode + [data-md-color-scheme="slate"] { + + // Indicate that the site is rendered with a dark color scheme + color-scheme: dark; + + // Default color shades + --md-default-fg-color: hsla(var(--md-hue), 15%, 90%, 0.82); + --md-default-fg-color--light: hsla(var(--md-hue), 15%, 90%, 0.56); + --md-default-fg-color--lighter: hsla(var(--md-hue), 15%, 90%, 0.32); + --md-default-fg-color--lightest: hsla(var(--md-hue), 15%, 90%, 0.12); + --md-default-bg-color: hsla(var(--md-hue), 15%, 14%, 1); + --md-default-bg-color--light: hsla(var(--md-hue), 15%, 14%, 0.54); + --md-default-bg-color--lighter: hsla(var(--md-hue), 15%, 14%, 0.26); + --md-default-bg-color--lightest: hsla(var(--md-hue), 15%, 14%, 0.07); + + // Code color shades + --md-code-fg-color: hsla(var(--md-hue), 18%, 86%, 0.82); + --md-code-bg-color: hsla(var(--md-hue), 15%, 18%, 1); + + // Code highlighting color shades + --md-code-hl-color--light: hsla(#{hex2hsl($clr-blue-a200)}, 0.15); + --md-code-hl-number-color: hsla(6, 74%, 63%, 1); + --md-code-hl-special-color: hsla(340, 83%, 66%, 1); + --md-code-hl-function-color: hsla(291, 57%, 65%, 1); + --md-code-hl-constant-color: hsla(250, 62%, 70%, 1); + --md-code-hl-keyword-color: hsla(219, 66%, 64%, 1); + --md-code-hl-string-color: hsla(150, 58%, 44%, 1); + --md-code-hl-name-color: var(--md-code-fg-color); + --md-code-hl-operator-color: var(--md-default-fg-color--light); + --md-code-hl-punctuation-color: var(--md-default-fg-color--light); + --md-code-hl-comment-color: var(--md-default-fg-color--light); + --md-code-hl-generic-color: var(--md-default-fg-color--light); + --md-code-hl-variable-color: var(--md-default-fg-color--light); + + // Typeset color shades + --md-typeset-color: var(--md-default-fg-color); + + // Typeset `a` color shades + --md-typeset-a-color: var(--md-primary-fg-color); + + // Typeset `kbd` color shades + --md-typeset-kbd-color: hsla(var(--md-hue), 15%, 90%, 0.12); + --md-typeset-kbd-accent-color: hsla(var(--md-hue), 15%, 90%, 0.2); + --md-typeset-kbd-border-color: hsla(var(--md-hue), 15%, 14%, 1); + + // Typeset `mark` color shades + --md-typeset-mark-color: hsla(#{hex2hsl($clr-blue-a200)}, 0.3); + + // Typeset `table` color shades + --md-typeset-table-color: hsla(var(--md-hue), 15%, 95%, 0.12); + --md-typeset-table-color--light: hsla(var(--md-hue), 15%, 95%, 0.035); + + // Admonition color shades + --md-admonition-fg-color: var(--md-default-fg-color); + --md-admonition-bg-color: var(--md-default-bg-color); + + // Footer color shades + --md-footer-bg-color: hsla(var(--md-hue), 15%, 10%, 0.87); + --md-footer-bg-color--dark: hsla(var(--md-hue), 15%, 8%, 1); + + // Shadow depth 1 + --md-shadow-z1: + 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.05), + 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.1); + + // Shadow depth 2 + --md-shadow-z2: + 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.25), + 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.25); + + // Shadow depth 3 + --md-shadow-z3: + 0 #{px2rem(4px)} #{px2rem(10px)} hsla(0, 0%, 0%, 0.4), + 0 0 #{px2rem(1px)} hsla(0, 0%, 0%, 0.35); + + // Hide images for light mode + img[src$="#only-light"], + img[src$="#gh-light-mode-only"] { + display: none; + } + } + + // -------------------------------------------------------------------------- + + // Adjust link colors for dark primary colors + @each $name, $color in ( + "pink": hsl(340, 81%, 63%), + "purple": hsl(291, 53%, 63%), + "deep-purple": hsl(262, 73%, 70%), + "indigo": hsl(219, 76%, 62%), + "teal": hsl(174, 100%, 40%), + "green": hsl(122, 39%, 60%), + "deep-orange": hsl(14, 100%, 65%), + "brown": hsl(16, 45%, 56%), + + // Set neutral colors to indigo + "grey": hsl(219, 66%, 62%), + "blue-grey": hsl(219, 66%, 62%), + "white": hsl(219, 66%, 62%), + "black": hsl(219, 66%, 62%) + ) { + [data-md-color-scheme="slate"][data-md-color-primary="#{$name}"] { + --md-typeset-a-color: #{$color}; + } + } + + // -------------------------------------------------------------------------- + + // Switching in progress - disable all transitions temporarily + [data-md-color-switching] *, + [data-md-color-switching] *::before, + [data-md-color-switching] *::after { + transition-duration: 0ms !important; // stylelint-disable-line + } +} diff --git a/src/templates/assets/stylesheets/utilities/_break.scss b/src/templates/assets/stylesheets/utilities/_break.scss new file mode 100644 index 00000000..7ccd8622 --- /dev/null +++ b/src/templates/assets/stylesheets/utilities/_break.scss @@ -0,0 +1,219 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +@use "sass:list"; +@use "sass:map"; +@use "sass:math"; + +// ---------------------------------------------------------------------------- +// Variables +// ---------------------------------------------------------------------------- + +/// +/// Device-specific breakpoints +/// +/// @example +/// $break-devices: ( +/// mobile: ( +/// portrait: 220px 479px, +/// landscape: 480px 719px +/// ), +/// tablet: ( +/// portrait: 720px 959px, +/// landscape: 960px 1219px +/// ), +/// screen: ( +/// small: 1220px 1599px, +/// medium: 1600px 1999px, +/// large: 2000px +/// ) +/// ); +/// +$break-devices: () !default; + +// ---------------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------------- + +/// +/// Choose minimum and maximum device widths +/// +@function break-select-min-max($devices) { + $min: 1000000; + $max: 0; + @each $key, $value in $devices { + @while type-of($value) == map { + $value: break-select-min-max($value); + } + @if type-of($value) == list { + @each $number in $value { + @if type-of($number) == number { + $min: math.min($number, $min); + @if $max { + $max: math.max($number, $max); + } + } @else { + @error "Invalid number: #{$number}"; + } + } + } @else if type-of($value) == number { + $min: math.min($value, $min); + $max: null; + } @else { + @error "Invalid value: #{$value}"; + } + } + @return $min, $max; +} + +/// +/// Select minimum and maximum widths for a device breakpoint +/// +@function break-select-device($device) { + $current: $break-devices; + @for $n from 1 through length($device) { + @if type-of($current) == map { + $current: map.get($current, list.nth($device, $n)); + } @else { + @error "Invalid device map: #{$devices}"; + } + } + @if type-of($current) == list or type-of($current) == number { + $current: (default: $current); + } + @return break-select-min-max($current); +} + +// ---------------------------------------------------------------------------- +// Mixins +// ---------------------------------------------------------------------------- + +/// +/// A minimum-maximum media query breakpoint +/// +@mixin break-at($breakpoint) { + @if type-of($breakpoint) == number { + @media screen and (min-width: $breakpoint) { + @content; + } + } @else if type-of($breakpoint) == list { + $min: list.nth($breakpoint, 1); + $max: list.nth($breakpoint, 2); + @if type-of($min) == number and type-of($max) == number { + @media screen and (min-width: $min) and (max-width: $max) { + @content; + } + } @else { + @error "Invalid breakpoint: #{$breakpoint}"; + } + } @else { + @error "Invalid breakpoint: #{$breakpoint}"; + } +} + +/// +/// An orientation media query breakpoint +/// +@mixin break-at-orientation($breakpoint) { + @if type-of($breakpoint) == string { + @media screen and (orientation: $breakpoint) { + @content; + } + } @else { + @error "Invalid breakpoint: #{$breakpoint}"; + } +} + +/// +/// A maximum-aspect-ratio media query breakpoint +/// +@mixin break-at-ratio($breakpoint) { + @if type-of($breakpoint) == number { + @media screen and (max-aspect-ratio: $breakpoint) { + @content; + } + } @else { + @error "Invalid breakpoint: #{$breakpoint}"; + } +} + +/// +/// A minimum-maximum media query device breakpoint +/// +@mixin break-at-device($device) { + @if type-of($device) == string { + $device: $device,; + } + @if type-of($device) == list { + $breakpoint: break-select-device($device); + @if list.nth($breakpoint, 2) { + $min: list.nth($breakpoint, 1); + $max: list.nth($breakpoint, 2); + + @media screen and (min-width: $min) and (max-width: $max) { + @content; + } + } @else { + @error "Invalid device: #{$device}"; + } + } @else { + @error "Invalid device: #{$device}"; + } +} + +/// +/// A minimum media query device breakpoint +/// +@mixin break-from-device($device) { + @if type-of($device) == string { + $device: $device,; + } + @if type-of($device) == list { + $breakpoint: break-select-device($device); + $min: list.nth($breakpoint, 1); + + @media screen and (min-width: $min) { + @content; + } + } @else { + @error "Invalid device: #{$device}"; + } +} + +/// +/// A maximum media query device breakpoint +/// +@mixin break-to-device($device) { + @if type-of($device) == string { + $device: $device,; + } + @if type-of($device) == list { + $breakpoint: break-select-device($device); + $max: list.nth($breakpoint, 2); + + @media screen and (max-width: $max) { + @content; + } + } @else { + @error "Invalid device: #{$device}"; + } +} diff --git a/src/templates/assets/stylesheets/utilities/_convert.scss b/src/templates/assets/stylesheets/utilities/_convert.scss new file mode 100644 index 00000000..8199c9c8 --- /dev/null +++ b/src/templates/assets/stylesheets/utilities/_convert.scss @@ -0,0 +1,79 @@ +//// +/// Copyright (c) 2016-2023 Martin Donath <martin.donath@squidfunk.com> +/// +/// Permission is hereby granted, free of charge, to any person obtaining a +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS +//// + +@use "sass:math"; + +// ---------------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------------- + +/// +/// Strip units from a number +/// +@function strip-units($number) { + @return math.div($number, ($number * 0 + 1)); +} + +/// +/// Convert color in HEX to HSL +/// +/// Note, that we need to strip the `deg` units from the `hue` value, as they +/// were added in Color Level 4, which not all browsers support. +/// +@function hex2hsl($color) { + @return + round(strip-units(hue($color))), + round(saturation($color)), + round(lightness($color)); +} + +// ---------------------------------------------------------------------------- + +/// +/// Convert font size in px to em +/// +@function px2em($size, $base: 16px) { + @if unit($size) == px { + @if unit($base) == px { + @return math.div($size, $base) * 1em; + } @else { + @error "Invalid base: #{$base} - unit must be 'px'"; + } + } @else { + @error "Invalid size: #{$size} - unit must be 'px'"; + } +} + +/// +/// Convert font size in px to rem +/// +@function px2rem($size, $base: 20px) { + @if unit($size) == px { + @if unit($base) == px { + @return math.div($size, $base) * 1rem; + } @else { + @error "Invalid base: #{$base} - unit must be 'px'"; + } + } @else { + @error "Invalid size: #{$size} - unit must be 'px'"; + } +} |
