From dc441858d48ab19cdb1ca1cae2326a5c28498112 Mon Sep 17 00:00:00 2001 From: Stefan van der Walt Date: Wed, 14 Aug 2024 14:43:42 -0700 Subject: [PATCH] Update PDST assets --- .../pst/abstracts/_accessibility.scss | 35 +-- assets/theme-css/pst/abstracts/_color.scss | 40 ++-- assets/theme-css/pst/abstracts/_links.scss | 210 +++++++----------- assets/theme-css/pst/abstracts/_mixins.scss | 47 ++++ assets/theme-css/pst/base/_base.scss | 44 ++-- .../pst/components/_breadcrumbs.scss | 15 +- .../theme-css/pst/components/_icon-links.scss | 72 ++++++ assets/theme-css/pst/components/_indices.scss | 34 +++ .../pst/components/_navbar-links.scss | 25 +++ .../theme-css/pst/components/_page-toc.scss | 28 +++ .../theme-css/pst/components/_prev-next.scss | 63 ++++++ .../pst/components/_readthedocs-switcher.scss | 70 ++++++ assets/theme-css/pst/components/_search.scss | 166 ++++++++++++++ .../theme-css/pst/components/_searchbox.scss | 45 ++++ .../pst/components/_switcher-theme.scss | 26 +++ .../pst/components/_switcher-version.scss | 82 +++++++ .../theme-css/pst/components/_toc-inpage.scss | 57 +++++ .../pst/components/_versionmodified.scss | 72 ++++++ .../pst/components/header/_header-logo.scss | 38 ++++ .../theme-css/pst/content/_admonitions.scss | 58 +++-- assets/theme-css/pst/content/_api.scss | 160 +++++++++++++ assets/theme-css/pst/content/_code.scss | 8 +- assets/theme-css/pst/content/_figures.scss | 16 ++ assets/theme-css/pst/content/_footnotes.scss | 33 +++ assets/theme-css/pst/content/_hacks.scss | 12 + assets/theme-css/pst/content/_lists.scss | 1 + assets/theme-css/pst/content/_math.scss | 49 ++++ assets/theme-css/pst/content/_quotes.scss | 16 +- assets/theme-css/pst/content/_spans.scss | 25 +++ assets/theme-css/pst/content/_tables.scss | 20 +- assets/theme-css/pst/content/_toctree.scss | 2 +- assets/theme-css/pst/extensions/_ablog.scss | 140 ++++++++++++ .../theme-css/pst/extensions/_bootstrap.scss | 19 ++ .../theme-css/pst/extensions/_copybutton.scss | 48 ++++ .../pst/extensions/_ethical-ads.scss | 23 ++ .../theme-css/pst/extensions/_execution.scss | 38 ++++ .../theme-css/pst/extensions/_graphviz.scss | 7 + assets/theme-css/pst/extensions/_leaflet.scss | 14 ++ .../theme-css/pst/extensions/_notebooks.scss | 130 +++++++++++ assets/theme-css/pst/extensions/_pydata.scss | 14 ++ .../pst/extensions/_sphinx_design.scss | 89 +++++--- .../pst/extensions/_togglebutton.scss | 7 +- assets/theme-css/pst/pydata-sphinx-theme.scss | 3 +- .../theme-css/pst/variables/_bootstrap.scss | 10 +- assets/theme-css/pst/variables/_color.scss | 56 ++++- assets/theme-css/pst/variables/_fonts.scss | 13 +- assets/theme-css/pst/variables/_layout.scss | 2 + .../pst/variables/_versionmodified.scss | 10 + 48 files changed, 1915 insertions(+), 277 deletions(-) create mode 100644 assets/theme-css/pst/components/_icon-links.scss create mode 100644 assets/theme-css/pst/components/_indices.scss create mode 100644 assets/theme-css/pst/components/_navbar-links.scss create mode 100644 assets/theme-css/pst/components/_page-toc.scss create mode 100644 assets/theme-css/pst/components/_prev-next.scss create mode 100644 assets/theme-css/pst/components/_readthedocs-switcher.scss create mode 100644 assets/theme-css/pst/components/_search.scss create mode 100644 assets/theme-css/pst/components/_searchbox.scss create mode 100644 assets/theme-css/pst/components/_switcher-theme.scss create mode 100644 assets/theme-css/pst/components/_switcher-version.scss create mode 100644 assets/theme-css/pst/components/_toc-inpage.scss create mode 100644 assets/theme-css/pst/components/_versionmodified.scss create mode 100644 assets/theme-css/pst/components/header/_header-logo.scss create mode 100644 assets/theme-css/pst/content/_api.scss create mode 100644 assets/theme-css/pst/content/_footnotes.scss create mode 100644 assets/theme-css/pst/content/_hacks.scss create mode 100644 assets/theme-css/pst/content/_math.scss create mode 100644 assets/theme-css/pst/content/_spans.scss create mode 100644 assets/theme-css/pst/extensions/_ablog.scss create mode 100644 assets/theme-css/pst/extensions/_bootstrap.scss create mode 100644 assets/theme-css/pst/extensions/_copybutton.scss create mode 100644 assets/theme-css/pst/extensions/_ethical-ads.scss create mode 100644 assets/theme-css/pst/extensions/_execution.scss create mode 100644 assets/theme-css/pst/extensions/_graphviz.scss create mode 100644 assets/theme-css/pst/extensions/_leaflet.scss create mode 100644 assets/theme-css/pst/extensions/_notebooks.scss create mode 100644 assets/theme-css/pst/extensions/_pydata.scss create mode 100644 assets/theme-css/pst/variables/_versionmodified.scss diff --git a/assets/theme-css/pst/abstracts/_accessibility.scss b/assets/theme-css/pst/abstracts/_accessibility.scss index 398dd731..bc5cf74b 100644 --- a/assets/theme-css/pst/abstracts/_accessibility.scss +++ b/assets/theme-css/pst/abstracts/_accessibility.scss @@ -1,14 +1,13 @@ -// loading the math module +@use "sass:color"; +@use "sass:map"; @use "sass:math"; -/** -* Get color combinations that meet a minimum contrast ratio as per WCAG 2 -*/ +// Get color combinations that meet a minimum contrast ratio as per WCAG 2 + // @param {color} $bg - Background color of the element // @param {color} optional $target-color-contrast-dark $target-color-contrast-light - Target text colors, defaul to our // $foundation-black and $foundation-white colors // @return {color} $max-ratio-color - The color that has the highest contrast ratio -// @function a11y-combination( $bg, $target-color-contrast-dark: $foundation-black, @@ -22,6 +21,7 @@ @each $fg in $foregrounds { $contrast-ratio: get-contrast-ratio($bg, $fg); + @if $contrast-ratio >= $min-contrast-ratio { @return $fg; } @else if $contrast-ratio > $max-ratio { @@ -29,8 +29,8 @@ $max-ratio-color: $fg; } } - @warn "Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$bg}..."; + @warn "Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$bg}..."; @return $max-ratio-color; } @@ -49,25 +49,25 @@ // Return WCAG2.1 relative luminance // See https://www.w3.org/TR/WCAG/#dfn-relative-luminance // See https://www.w3.org/TR/WCAG/#dfn-contrast-ratio -// @function luminance($target-color) { $rgb-col: ( - "r": red($target-color), - "g": green($target-color), - "b": blue($target-color), + "r": color.red($target-color), + "g": color.green($target-color), + "b": color.blue($target-color), ); @each $channel, $value in $rgb-col { // here we get RsRGB, GsRGB, and BsRGB - @if math.div($value, 255) <=0.03928 { - $rgb-col: map-merge( + // stylelint-disable-next-line number-max-precision + @if math.div($value, 255) <= 0.04045 { + $rgb-col: map.merge( $rgb-col, ( $channel: math.div(math.div($value, 255), 12.92), ) ); } @else { - $rgb-col: map-merge( + $rgb-col: map.merge( $rgb-col, ( $channel: @@ -77,8 +77,9 @@ } } - @return ( - 0.2126 * map-get($rgb-col, "r") + 0.7152 * map-get($rgb-col, "g") + 0.0722 * - map-get($rgb-col, "b") - ); + $r: map.get($rgb-col, "r"); + $g: map.get($rgb-col, "g"); + $b: map.get($rgb-col, "b"); + + @return (0.2126 * $r + 0.7152 * $g + 0.0722 * $b); } diff --git a/assets/theme-css/pst/abstracts/_color.scss b/assets/theme-css/pst/abstracts/_color.scss index bc4aa038..8898fc73 100644 --- a/assets/theme-css/pst/abstracts/_color.scss +++ b/assets/theme-css/pst/abstracts/_color.scss @@ -2,13 +2,16 @@ * Miscellaneous color functions and mixins **/ -// loading the math module +@use "sass:list"; +@use "sass:map"; +@use "sass:meta"; @use "sass:math"; +@use "sass:string"; // We must add ::before pseudo-element to some theme components (such as admonitions) // because users were instructed to customize the background color this way. @mixin legacy-backdrop-placeholder { - &:before { + &::before { content: ""; width: 100%; height: 100%; @@ -16,6 +19,7 @@ left: 0; top: 0; z-index: -1; + // So that hovering over the text within background is still possible. // Otherwise the background overlays the text and you cannot click or select easily. // ref: https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events @@ -31,8 +35,9 @@ // @return {*} @function map-deep-get($map, $keys...) { @each $key in $keys { - $map: map-get($map, $key); + $map: map.get($map, $key); } + @return $map; } @@ -44,9 +49,10 @@ // @param {String/Color} $color - Color definition from map // @return {Color} - Color type (in hex) @function check-color($color) { - @if type-of($color) == string { + @if meta.type-of($color) == string { $color: from-hex($color); } + @return $color; } @@ -55,12 +61,12 @@ */ // @param {String} $string - String representation of a color @function from-hex($string) { - $string-lower: to-lower-case($string); + $string-lower: string.to-lower-case($string); $r: ""; $g: ""; $b: ""; $hex: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f"; - $length: str-length($string); + $length: string.length($string); $max: if($length == 4, 1, 2); // Check for length accuracy @@ -70,18 +76,18 @@ // Loop from the second character (omitting #) @for $i from 2 through $length { - $c: str-slice($string-lower, $i, $i); + $c: string.slice($string-lower, $i, $i); // If wrong character, return - @if index($hex, $c) == null { + @if not list.index($hex, $c) { @return $string; } - @if str-length($r) < $max { + @if string.length($r) < $max { $r: $r + $c; - } @else if str-length($g) < $max { + } @else if string.length($g) < $max { $g: $g + $c; - } @else if str-length($b) < $max { + } @else if string.length($b) < $max { $b: $b + $c; } } @@ -92,18 +98,18 @@ $b: $b + $b; } - @return rgb(_hex-to-dec($r), _hex-to-dec($g), _hex-to-dec($b)); + @return rgb(hex-to-dec($r), hex-to-dec($g), hex-to-dec($b)); } -@function _hex-to-dec($string) { +@function hex-to-dec($string) { $hex: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f"; - $string: to-lower-case($string); - $length: str-length($string); - + $string: string.to-lower-case($string); + $length: string.length($string); $dec: 0; + @for $i from 1 through $length { $factor: 1 + (15 * ($length - $i)); - $index: index($hex, str-slice($string, $i, $i)); + $index: list.index($hex, string.slice($string, $i, $i)); $dec: $dec + $factor * ($index - 1); } diff --git a/assets/theme-css/pst/abstracts/_links.scss b/assets/theme-css/pst/abstracts/_links.scss index 82f6e48e..c3e9d31c 100644 --- a/assets/theme-css/pst/abstracts/_links.scss +++ b/assets/theme-css/pst/abstracts/_links.scss @@ -1,28 +1,32 @@ -/** - * Consistent styling for links - **/ +// Consistent styling for links +// ============================ + +@use "sass:string"; // Define some useful variables for links styling consistency -// -// Thickness of the underline for links -// the default will be either: + +// The default thickness of the underline for links will be either: // - 1px -// - 0.0625rem if it's thicker than 1px because the user has changed the text -// size in their browser -$link-underline-thickness: unquote("max(1px, .0625rem)") !default; +// - 0.0625rem if it's thicker than 1px because the user has changed the text +// size in their browser +$link-underline-thickness: string.unquote("max(1px, .0625rem)") !default; + // Offset of link underlines from text baseline // The default is 3px expressed as ems, as calculated against the default body // font size (on desktop). $link-underline-offset: 0.1578em !default; + // Thickness of link underlines in hover state // The default for each link will be the thickest of the following: // - 3px // - 0.1875rem, if it's thicker than 3px because the user has changed the text // size in their browser // - 0.12em (relative to the link's text size) -$link-hover-decoration-thickness: unquote("max(3px, .1875rem, .12em)") !default; +$link-hover-decoration-thickness: string.unquote( + "max(3px, .1875rem, .12em)" +) !default; -// Ensures links have an underline decoration by default - needed to meet +// Ensures links have an underline decoration by default - needed to meet // WCAG SC 1.4.1 @mixin link-decoration { text-decoration: underline; @@ -41,36 +45,36 @@ $link-hover-decoration-thickness: unquote("max(3px, .1875rem, .12em)") !default; @mixin link-decoration-hover { @if $link-hover-decoration-thickness { text-decoration-thickness: $link-hover-decoration-thickness; - // Disable ink skipping on underlines on hover. Browsers haven't - // standardised on this part of the spec yet, so set both properties - text-decoration-skip-ink: none; // Chromium, Firefox - text-decoration-skip: none; // Safari + + // Disable ink skipping on underlines on hover. + text-decoration-skip-ink: none; } } // Simple hover style - can be used alone or in conjunction with other mixins -// Add the text underline and change in thickness on hover +// Add the text underline and change in thickness on hover. +// Intended for use with the `:hover` pseudo-class. @mixin link-style-hover { - &:hover { - @include link-decoration; - @include link-decoration-hover; - color: var(--pst-color-link-hover); - } + @include link-decoration; + @include link-decoration-hover; + + color: var(--pst-color-link-hover); } // Default link styles -// +// ------------------- // Defines: default unvisited, visited, hover, and active. // TODO: @trallard to improve focus styles in subsequent PR @mixin link-style-default { // So that really long links don't spill out of their container word-wrap: break-word; - color: var(--pst-color-link); + @include link-decoration; &:hover { color: var(--pst-color-link-hover); + @include link-decoration-hover; } @@ -82,6 +86,7 @@ $link-hover-decoration-thickness: unquote("max(3px, .1875rem, .12em)") !default; // Visited should still be hoverable &:visited { color: var(--pst-color-link); + &:hover { color: var(--pst-color-link-hover); } @@ -89,7 +94,7 @@ $link-hover-decoration-thickness: unquote("max(3px, .1875rem, .12em)") !default; } // Text link styles -// +// ---------------- // Makes links use the muted text colour and removes the underline. // Use this mixin for navigation bar links. @mixin link-style-text { @@ -98,13 +103,14 @@ $link-hover-decoration-thickness: unquote("max(3px, .1875rem, .12em)") !default; &:hover { color: var(--pst-color-link-hover); + @include link-decoration; @include link-decoration-hover; } } // Sidebar and TOC links -// +// --------------------- // Makes links use the muted text colour and removes the underline. // Use this mixin for navigation the primary sidebar and table of contents. // Active and hover should work together rather than one overriding the other. @@ -116,6 +122,7 @@ $link-hover-decoration-thickness: unquote("max(3px, .1875rem, .12em)") !default; text-decoration: underline; background-color: transparent; color: var(--pst-color-link-hover); + @include link-decoration-hover; } @@ -132,7 +139,7 @@ $link-hover-decoration-thickness: unquote("max(3px, .1875rem, .12em)") !default; } // Sidebar current page link styles -// +// -------------------------------- // Adds a vertical line on the left hand side of the link to indicate that // it's the current page. Note this is distinct from an active state. // Used on the primary sidebar and the TOC. @@ -140,13 +147,16 @@ $link-hover-decoration-thickness: unquote("max(3px, .1875rem, .12em)") !default; @mixin link-sidebar-current { font-weight: 600; color: var(--pst-color-primary); + @if $link-hover-decoration-thickness { $notch-shadow: inset $link-hover-decoration-thickness - 0px - 0px + 0 + 0 var(--pst-color-primary); + box-shadow: $notch-shadow; + &:focus-visible { box-shadow: $notch-shadow, $focus-ring-box-shadow; outline: none; @@ -154,115 +164,59 @@ $link-hover-decoration-thickness: unquote("max(3px, .1875rem, .12em)") !default; } } -// Navigation bar current page link styles -// -// Adds a bottom underline, this leaves enough space for the hover state without -// cluttering the navbar. -// We want the side box shadow to have the same thickness as the hover underline -@mixin link-navbar-current { - font-weight: 600; - color: var(--pst-color-primary); - @if $link-hover-decoration-thickness { - border-bottom: $link-hover-decoration-thickness - solid - var(--pst-color-primary); - } -} +// Header navbar text and icon links +// --------------------------------- +// (includes light/dark mode button) + +// This mixin makes it possible to show hover/underline and focus/ring styles at +// the same time. The trick is to use: +// - a pseudo-element with bottom border for the hover underline +// - a CSS outline for the focus ring. + +// Normally we use box-shadow for underline and outline for focus ring. But we +// cannot apply box-shadow and outline together on the same element because the +// border-radius value that we use to round the outline will also round the +// box-shadow used for the underline. We also cannot use text-underline because +// it does not work on non-text links, nor do we want to use it on text links +// that we want to treat as blocks, such as the header nav links because the +// underline will wrap across two lines if the link text also wraps across two +// lines. +@mixin link-style-block { + color: var(--pst-color-text-muted); + + // Set position relative so that the child ::before pseudo-element's absolute + // position is relative to this element. + position: relative; + + // Set up pseudo-element used for hover underline styles + &::before { + content: ""; + display: block; + position: absolute; + inset: 0; + background-color: transparent; -// Navigation bar icon links hover styles -// -// Adds a bottom box-shadow - since there is no text we cannot use text-decoration -// We want the side box shadow to have the same thickness as the hover underline -@mixin icon-navbar-hover { - &:hover { - color: var(--pst-color-link-hover); @if $link-hover-decoration-thickness { - box-shadow: 0px - $link-hover-decoration-thickness - 0px - var(--pst-color-link-hover); + bottom: calc(-1 * $link-hover-decoration-thickness); + margin: $link-hover-decoration-thickness 0; } } -} - -/* -Mixin for links in the header (and the More dropdown toggle). - -The mixin assumes it will be applied to some element X with a markup structure -like: X > .nav-link, or X > .dropdown-toggle. - -It also assumes X.current is how the app annotates which item in the header nav -corresponds to the section in the docs that the user is currently reading. -*/ -@mixin header-link { - // Target the child and not the parent because we want the underline in the - // mobile sidebar to only span the width of the text not the entire row/line. - > .nav-link, - > .dropdown-toggle { - border-radius: 2px; - color: var(--pst-color-text-muted); - } - > .nav-link { - // Set up pseudo-element for hover and current states below. - position: relative; + &:hover { + color: var(--pst-color-secondary); + text-decoration: none; // override the link-style-hover mixin &::before { - content: ""; - display: block; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: transparent; - } - - // Underline on hover. - // - Don't use text-decoration because it will wrap across two lines if - // the link text also wraps across two lines. - // - Use pseudo-element in order to avoid the border-radius values - // rounding the edges of the underline. (And since a header link can be - // both focused and hovered at the same time and we want the focus ring - // but not the underline to be rounded, we cannot use a box shadow or - // bottom border link element to create the underline, or else it will - // be rounded and if we apply border-radius 0 then the hovered focus - // ring would go from rounded to sharp. So we have to use the - // pseudo-element.) - &:hover { - color: var(--pst-color-secondary); - text-decoration: none; // override the link-style-hover mixin - &::before { - border-bottom: 3px solid var(--pst-color-secondary); + @if $link-hover-decoration-thickness { + border-bottom: $link-hover-decoration-thickness + solid + var(--pst-color-secondary); } } - - &:focus-visible { - box-shadow: none; // override Bootstrap - outline: 3px solid var(--pst-color-accent); - outline-offset: 3px; - } - } - - > .dropdown-toggle { - &:focus-visible { - box-shadow: $focus-ring-box-shadow; - } - &:hover { - text-decoration: none; - box-shadow: 0 0 0 $focus-ring-width var(--pst-color-link-hover); // purple focus ring - // Brighten the text on hover (muted -> base) - color: var(--pst-color-text-base); - } } - &.current { - > .nav-link { - color: var(--pst-color-primary); - - // Underline the current navbar item - &::before { - border-bottom: 3px solid var(--pst-color-primary); - } - } + &:focus-visible { + box-shadow: none; // override Bootstrap + outline: 3px solid var(--pst-color-accent); + outline-offset: 3px; } } diff --git a/assets/theme-css/pst/abstracts/_mixins.scss b/assets/theme-css/pst/abstracts/_mixins.scss index 9aa9873f..f72992a4 100644 --- a/assets/theme-css/pst/abstracts/_mixins.scss +++ b/assets/theme-css/pst/abstracts/_mixins.scss @@ -21,3 +21,50 @@ border-radius: 0.25rem; padding: 0.5rem; } + +@mixin table-colors { + color: var(--pst-color-table); + border: 1px solid var(--pst-color-table-outer-border); + + th, + td { + ~ th, + ~ td { + border-left: 1px solid var(--pst-color-table-inner-border); + } + } + + thead { + tr { + background-color: var(--pst-color-table-heading-bg); + border-bottom: 2px solid var(--pst-color-primary); + } + } + + tbody { + tr { + &:nth-child(odd) { + background-color: var(--pst-color-table-row-zebra-low-bg); + } + + &:nth-child(even) { + background-color: var(--pst-color-table-row-zebra-high-bg); + } + + &:hover { + background-color: var(--pst-color-table-row-hover-bg); + } + } + } +} + +// Minimum mouse hit area +// ---------------------- +// Ensures that the element has a minimum hit area that conforms to +// accessibility guidelines. For WCAG AA, we need 24px x 24px, see: +// https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html +@mixin min-hit-area() { + box-sizing: border-box; + min-width: 24px; + min-height: 24px; +} diff --git a/assets/theme-css/pst/base/_base.scss b/assets/theme-css/pst/base/_base.scss index f660a4c0..f48bc20b 100644 --- a/assets/theme-css/pst/base/_base.scss +++ b/assets/theme-css/pst/base/_base.scss @@ -7,7 +7,7 @@ body { background-color: var(--pst-color-background); font-family: var(--pst-font-family-base); font-weight: 400; - line-height: 1.65; + line-height: $line-height-body; color: var(--pst-color-text-base); min-height: 100vh; display: flex; @@ -22,7 +22,6 @@ body { p { margin-bottom: 1.15rem; font-size: 1em; - color: var(--pst-color-text-base); /* section header in docstring pages */ &.rubric { @@ -40,17 +39,11 @@ a { // The # anchor that appears on hover over headings &.headerlink { color: var(--pst-color-secondary); - opacity: 0.7; font-size: 0.8em; - padding: 0 4px 0 4px; + padding: 0 4px; margin-left: 0.2em; text-decoration: none; - transition: all 0.2s ease-out; user-select: none; - - &:hover { - opacity: 1; - } } // set up a icon next to the shorten links from github and gitlab @@ -72,7 +65,7 @@ a { } } -.heading-style { +%heading-style { margin: 2.75rem 0 1.05rem; font-family: var(--pst-font-family-heading); font-weight: var(--pst-font-weight-heading); @@ -80,38 +73,44 @@ a { } h1 { - @extend .heading-style; + @extend %heading-style; + margin-top: 0; font-size: var(--pst-font-size-h1); color: var(--pst-heading-color); } h2 { - @extend .heading-style; + @extend %heading-style; + font-size: var(--pst-font-size-h2); color: var(--pst-heading-color); } h3 { - @extend .heading-style; + @extend %heading-style; + font-size: var(--pst-font-size-h3); color: var(--pst-heading-color); } h4 { - @extend .heading-style; + @extend %heading-style; + font-size: var(--pst-font-size-h4); color: var(--pst-heading-color); } h5 { - @extend .heading-style; + @extend %heading-style; + font-size: var(--pst-font-size-h5); color: var(--pst-color-text-base); } h6 { - @extend .heading-style; + @extend %heading-style; + font-size: var(--pst-font-size-h6); color: var(--pst-color-text-base); } @@ -152,7 +151,7 @@ code { } pre { - margin: 1.5em 0 1.5em 0; + margin: 1.5em 0; padding: 1rem; background-color: var(--pst-color-surface); color: var(--pst-color-text-base); @@ -169,7 +168,7 @@ pre { // the back to top btn #pst-back-to-top { - // z-index: $zindex-tooltip; + z-index: $zindex-tooltip; position: fixed; display: none; top: 90vh; @@ -185,11 +184,12 @@ pre { margin-inline-end: 0.5em; } - @include link-style-hover; &:hover { + @include link-style-hover; + text-decoration-thickness: 1px; - background-color: var(--pst-violet-600); - color: var(--pst-color-secondary-text); + background-color: var(--pst-color-secondary-highlight); + color: var(--pst-color-secondary-highlight-text); } &:focus-visible { @@ -201,7 +201,7 @@ pre { } // Focus ring -// +// ---------- // Note: The Bootstrap stylesheet provides the focus ring (customized by this // theme via Sass variables in _bootstrap.scss) in some cases. This rule covers // all other cases. diff --git a/assets/theme-css/pst/components/_breadcrumbs.scss b/assets/theme-css/pst/components/_breadcrumbs.scss index 6c94056f..d2e511b1 100644 --- a/assets/theme-css/pst/components/_breadcrumbs.scss +++ b/assets/theme-css/pst/components/_breadcrumbs.scss @@ -13,16 +13,29 @@ ul.bd-breadcrumbs { li.breadcrumb-item { display: flex; align-items: center; + white-space: nowrap; + overflow-x: hidden; + + a, + .ellipsis { + overflow-x: hidden; + text-overflow: ellipsis; + + // Need to add margin, otherwise the overflow: hidden rule on the parent + // will hide the focus ring + margin: $focus-ring-width; + } // Style should look like heavier in-page links // keeping visited in the default link colour font-weight: bold; + a { @include link-style-text; } // Items that aren't the home have a caret to the left - &:not(.breadcrumb-home):before { + &:not(.breadcrumb-home)::before { font: var(--fa-font-solid); font-size: 0.8rem; content: var(--pst-breadcrumb-divider); diff --git a/assets/theme-css/pst/components/_icon-links.scss b/assets/theme-css/pst/components/_icon-links.scss new file mode 100644 index 00000000..8edba3fd --- /dev/null +++ b/assets/theme-css/pst/components/_icon-links.scss @@ -0,0 +1,72 @@ +/** + * Icon links in the navbar + */ + +.pst-navbar-icon { + // Extra specificity needed for overrides + html & { + @include min-hit-area; + @include link-style-block; + + display: flex; + align-items: center; + justify-content: center; + + // Bootstrap overrides + border-radius: 0; + border: none; + font-size: 1rem; + line-height: $line-height-body; // Override Boostrap, which defines a separate line-height for buttons + padding: $navbar-link-padding-y 0; // Horizontal white space in nav bar between items is controlled via column gap rule on the container. + + // Make the navbar icon links have the same size as the navbar text links + height: calc(2 * $navbar-link-padding-y + $line-height-body * 1rem); + } +} + +ul.navbar-icon-links { + display: flex; + flex-flow: row wrap; + column-gap: 1rem; + justify-content: space-evenly; + align-items: center; + padding-left: 0; + margin-bottom: 0; + list-style: none; + + // Icons styling + i { + &.fa-brands, + &.fa-regular, + &.fa-solid { + vertical-align: middle; + font-style: normal; + font-size: var(--pst-font-size-icon); + } + + /* Social media buttons hard-code the brand color */ + &.fa-square-twitter::before { + color: #55acee; + } + + &.fa-square-gitlab::before { + color: #548; + } + + &.fa-bitbucket::before { + color: #0052cc; + } + } + + // Force images to be icon-sized + img.icon-link-image { + height: 1.5em; + border-radius: 0.2rem; + } + + .fa-pydata { + stroke: var(--pst-color-background); + stroke-linejoin: round; + stroke-width: 0.35; + } +} diff --git a/assets/theme-css/pst/components/_indices.scss b/assets/theme-css/pst/components/_indices.scss new file mode 100644 index 00000000..d55aa563 --- /dev/null +++ b/assets/theme-css/pst/components/_indices.scss @@ -0,0 +1,34 @@ +.sidebar-indices-items { + display: flex; + flex-direction: column; + border-top: 1px solid var(--pst-color-border); + + @include media-breakpoint-up($breakpoint-sidebar-primary) { + border-top: none; + } + + .sidebar-indices-items__title { + font-weight: var(--pst-sidebar-header-font-weight); + font-size: var(--pst-sidebar-header-font-size); + color: var(--pst-color-text-base); + margin-bottom: 0.5rem; + } + + ul.indices-link { + margin-right: -1rem; + list-style: none; + padding: 0; + + li > a { + display: block; + padding: 0.25rem 0; + color: var(--pst-color-text-muted); + + &:hover { + color: var(--pst-color-primary); + text-decoration: none; + background-color: transparent; + } + } + } +} diff --git a/assets/theme-css/pst/components/_navbar-links.scss b/assets/theme-css/pst/components/_navbar-links.scss new file mode 100644 index 00000000..ea853971 --- /dev/null +++ b/assets/theme-css/pst/components/_navbar-links.scss @@ -0,0 +1,25 @@ +/** + * Navigation links in the navbar and icon links + */ +ul.navbar-nav { + // Reduce padding of nested `ul` items a bit + ul { + padding: 0 0 0 1rem; + } + + // Navbar links - do not have an underline by default + li { + display: flex; + flex-direction: column; + + a { + display: flex; + align-items: center; + height: 100%; + padding-top: $navbar-link-padding-y; + padding-bottom: $navbar-link-padding-y; + + @include link-style-text; + } + } +} diff --git a/assets/theme-css/pst/components/_page-toc.scss b/assets/theme-css/pst/components/_page-toc.scss new file mode 100644 index 00000000..5a6dcf08 --- /dev/null +++ b/assets/theme-css/pst/components/_page-toc.scss @@ -0,0 +1,28 @@ +/** + * The list of in-page TOC links + */ +.page-toc { + .section-nav { + padding-left: 0; + border-bottom: none; + + ul { + padding-left: 1rem; + } + } + + // override bootstrap settings + .nav-link { + font-size: var(--pst-sidebar-font-size-mobile); + + @include media-breakpoint-up($breakpoint-sidebar-secondary) { + font-size: var(--pst-sidebar-font-size); + } + } + + .onthispage { + color: var(--pst-color-text-base); + font-weight: var(--pst-sidebar-header-font-weight); + margin-bottom: 0.5rem; + } +} diff --git a/assets/theme-css/pst/components/_prev-next.scss b/assets/theme-css/pst/components/_prev-next.scss new file mode 100644 index 00000000..f94b3395 --- /dev/null +++ b/assets/theme-css/pst/components/_prev-next.scss @@ -0,0 +1,63 @@ +/** +* Previous / Next navigation buttons +**/ +.prev-next-area { + width: 100%; + + p { + color: var(--pst-color-text-muted); + margin: 0 0.3em; + line-height: 1.3em; + } + + i { + font-size: 1.2em; + } + + a { + // So that buttons align with icons + display: flex; + align-items: center; + border: none; + padding: 10px; + max-width: 45%; + overflow-x: hidden; + color: var(--pst-color-text-muted); + text-decoration: none; + + p.prev-next-title { + @include link-style-default; + + font-weight: var(--pst-admonition-font-weight-heading); + font-size: 1.1em; + } + + &:hover, + &:visited:hover { + p.prev-next-title { + @include link-style-hover; + } + } + + .prev-next-info { + flex-direction: column; + margin: 0 0.5em; + + .prev-next-subtitle { + text-transform: capitalize; + } + } + + &.left-prev { + float: left; + } + + &.right-next { + float: right; + + div.prev-next-info { + text-align: right; + } + } + } +} diff --git a/assets/theme-css/pst/components/_readthedocs-switcher.scss b/assets/theme-css/pst/components/_readthedocs-switcher.scss new file mode 100644 index 00000000..3e038bf4 --- /dev/null +++ b/assets/theme-css/pst/components/_readthedocs-switcher.scss @@ -0,0 +1,70 @@ +.bd-sidebar-primary div#rtd-footer-container { + position: sticky; + bottom: -1rem; + margin: -1rem; // ignore sidebar padding + + .rst-versions.rst-badge { + position: unset; + font-size: 0.9em; + font-family: var(--pst-font-family-base); + max-width: unset; + + .rst-current-version { + display: flex; + align-items: center; + gap: 0.2rem; + height: 2.5rem; + transition: background-color 0.2s ease-out; + background-color: var(--pst-color-background); + color: var(--pst-color-success); + border-top: 1px solid var(--pst-color-border); + } + + .fa.fa-book { + color: var(--pst-color-text-muted); + margin-right: auto; + + &::after { + color: var(--pst-color-text-base); + content: "Read The Docs"; + font-family: var(--pst-font-family-base); + font-weight: var(--pst-admonition-font-weight-heading); + } + } + + .fa.fa-caret-down { + color: var(--pst-color-text-muted); + } + } + + .rst-versions.rst-badge.shift-up { + .rst-current-version { + border-bottom: 1px solid var(--pst-color-border); + } + } + + .rst-other-versions { + background-color: var(--pst-color-surface); + color: var(--pst-color-text-base); + + dl { + dd a { + color: var(--pst-color-text-muted); + } + } + + hr { + background-color: var(--pst-color-border); + } + + small a { + color: var(--pst-color-link); + } + + input { + padding-left: 0.5rem; + border: 1px solid var(--pst-color-border); + background-color: var(--pst-color-surface); + } + } +} diff --git a/assets/theme-css/pst/components/_search.scss b/assets/theme-css/pst/components/_search.scss new file mode 100644 index 00000000..e75b08d7 --- /dev/null +++ b/assets/theme-css/pst/components/_search.scss @@ -0,0 +1,166 @@ +/** + * Search field + **/ +.bd-search { + position: relative; + padding-left: 0.5rem; + gap: 0.5rem; + background-color: var(--pst-color-background); + border-radius: $admonition-border-radius; + border: 1px solid var(--pst-color-border); + color: var(--pst-color-text-base); + + // Background should always be same color regardless of active or not + &:active { + background-color: var(--pst-color-background); + color: var(--pst-color-text-muted); + } + + // Hoist the focus ring from the input field to its parent + &:focus-within { + box-shadow: $focus-ring-box-shadow; + + input:focus { + box-shadow: none; + } + } + + .icon { + position: absolute; + color: var(--pst-color-border); + left: 25px; + } + + .fa-solid.fa-magnifying-glass { + position: absolute; + left: calc((2.5rem - 0.7em) / 2); + color: var(--pst-color-text-muted); + } + + input.form-control { + background-color: var(--pst-color-background); + color: var(--pst-color-text-base); + border: none; + + // Inner-text of the search bar + &::placeholder { + color: var(--pst-color-text-muted); + } + + // Remove the little "x" that pops up when you start typing + &::-webkit-search-cancel-button, + &::-webkit-search-decoration { + appearance: none; + } + + &:focus, + &:focus-visible { + color: var(--pst-color-text-muted); + } + } + + // Shows off the keyboard shortcuts for the button + .search-button__kbd-shortcut { + display: flex; + margin-inline-end: 0.5rem; + color: var(--pst-color-border); + } +} + +/** + * Search button - located in the navbar + */ +.search-button i { + // Search link icon should be a bit bigger since it is separate from icon links + font-size: 1.3rem; +} + +/** + * The search modal + */ +#pst-search-dialog { + display: none; + + &[open] { + display: flex; + + // Center in middle of screen just underneath header + position: fixed; + z-index: $zindex-modal; + top: 30%; + left: 50%; + transform: translate(-50%, -50%); + right: 1rem; + margin-top: 0.5rem; + width: 90%; + max-width: 800px; + background-color: transparent; + padding: $focus-ring-width; + border: none; + + &::backdrop { + background-color: black; + opacity: 0.5; + } + + form.bd-search { + flex-grow: 1; + + // Font and input text a bit bigger + svg, + input { + font-size: var(--pst-font-size-icon); + } + } + } +} + +/** + * The search button component that looks like a field. + * Lives at components/search-button-field.html + */ +.search-button-field { + $search-button-border-radius: 1.5em; + + display: inline-flex; + align-items: center; + border: var(--pst-color-border) solid 1px; + border-radius: $search-button-border-radius; + color: var(--pst-color-text-muted); + padding: 0.5em; + background-color: var(--pst-color-surface); + + &:hover { + box-shadow: 0 0 0 $focus-ring-width var(--pst-color-link-hover); + } + + &:focus-visible { + border-radius: $search-button-border-radius; + } + + // The keyboard shortcut text + .search-button__default-text { + font-size: var(--bs-nav-link-font-size); + font-weight: var(--bs-nav-link-font-weight); + margin-right: 0.5em; + margin-left: 0.5em; + } + + .kbd-shortcut__modifier { + font-size: 0.75em; + } + + // Ensures that all the text lines up in the middle + > * { + align-items: center; + } + + // Only the icon should be visible on narrow screens + > :not(svg) { + display: none; + + @include media-breakpoint-up(lg) { + display: flex; + } + } +} diff --git a/assets/theme-css/pst/components/_searchbox.scss b/assets/theme-css/pst/components/_searchbox.scss new file mode 100644 index 00000000..948ea60a --- /dev/null +++ b/assets/theme-css/pst/components/_searchbox.scss @@ -0,0 +1,45 @@ +/** + * The 'Hide Search Matches' button. + * This only shows up when a person lands on a page after clicking a search result. + * Clicking it removes the highlighting of the search term from the page. + * We want it to behave like a button. + */ +div#searchbox { + // Leave `#searchbox` rules empty so that it doesn't show at all when it is empty + p.highlight-link { + margin: 1rem 0; + width: fit-content; + + // A bit more margin on wide screens to mimic article behavior + @include media-breakpoint-up($breakpoint-sidebar-secondary) { + margin-left: 2rem; + } + + // Put outer shadow on this one so that we can darken the link w/ an inner shadow + @include box-shadow; + + // Style the button to look like a Sphinx Design button + a { + border-radius: 0.25rem; + font-size: 1.25rem; + padding: 0.75rem; + background-color: var(--pst-color-primary); + color: var(--pst-color-primary-text); + text-decoration: none; + + // The box shadow is inset so that it darkens the button on hover + transition: box-shadow 0.25s ease-out; + + &:hover { + box-shadow: inset 0 0 50px 50px rgb(0 0 0 / 25%); + } + + &::before { + content: var(--pst-icon-search-minus); + color: unset; + font: var(--fa-font-solid); + margin-right: 0.5rem; + } + } + } +} diff --git a/assets/theme-css/pst/components/_switcher-theme.scss b/assets/theme-css/pst/components/_switcher-theme.scss new file mode 100644 index 00000000..8fe5d519 --- /dev/null +++ b/assets/theme-css/pst/components/_switcher-theme.scss @@ -0,0 +1,26 @@ +/** + * Light/dark theme switcher + */ + +.theme-switch-button { + .theme-switch { + display: none; + + &:active { + text-decoration: none; + color: var(--pst-color-link-hover); + } + + .fa-lg { + aspect-ratio: 1 / 1; + } + } +} + +@each $mode in auto, light, dark { + html[data-mode="#{$mode}"] + .theme-switch-button + .theme-switch[data-mode="#{$mode}"] { + display: inline; // inline needed for span height to be calculated using inherited font size and line height + } +} diff --git a/assets/theme-css/pst/components/_switcher-version.scss b/assets/theme-css/pst/components/_switcher-version.scss new file mode 100644 index 00000000..a5dd6140 --- /dev/null +++ b/assets/theme-css/pst/components/_switcher-version.scss @@ -0,0 +1,82 @@ +button.btn.version-switcher__button { + border-color: var(--pst-color-border); + color: var(--pst-color-text-base); + + // Add a margin on narrow screens to avoid feeling cramped + margin-bottom: 1em; + + @include media-breakpoint-up($breakpoint-sidebar-primary) { + margin-bottom: unset; + } + + &:hover { + box-shadow: 0 0 0 $focus-ring-width var(--pst-color-secondary); + border-color: transparent; + } + + &:active { + color: var(--pst-color-text-base); + border-color: var(--pst-color-border); + } + + &:focus-visible { + border-color: transparent; + } +} + +.version-switcher__menu { + border-color: var(--pst-color-border); + border-radius: var(--bs-dropdown-border-radius); + + a.list-group-item { + background-color: var(--pst-color-on-background); + color: var(--pst-color-text-base); + padding: 0.75rem 1.25rem; + + &:not(:last-child) { + border-bottom: 1px solid var(--pst-color-border); + } + + &:hover { + @include link-style-hover; + + background-color: var(--pst-color-surface); + } + + &.active { + @include link-sidebar-current; + + position: relative; + z-index: 1; + + span::before { + content: ""; + width: 100%; + height: 100%; + position: absolute; + z-index: -1; + left: 0; + top: 0; + } + } + + &:focus-visible { + z-index: 10; // keep focus ring on top (prevent the hover background of the next dropdown item from covering the ring) + } + } +} + +// Font behavior on mobile +button.version-switcher__button, +.version-switcher__menu { + font-size: 1.1em; // A bit smaller than other menu font + z-index: $zindex-modal; // higher than the sidebars + + // Make sure it meets WCAG target size requirement no matter the version + // string displayed in the button + @include min-hit-area; + + @include media-breakpoint-up($breakpoint-sidebar-primary) { + font-size: unset; + } +} diff --git a/assets/theme-css/pst/components/_toc-inpage.scss b/assets/theme-css/pst/components/_toc-inpage.scss new file mode 100644 index 00000000..af98dc4c --- /dev/null +++ b/assets/theme-css/pst/components/_toc-inpage.scss @@ -0,0 +1,57 @@ +/* Collapsing of the TOC sidebar while scrolling */ + +/* Nav: hide second level (shown on .active) */ + +nav.page-toc { + // A little extra space before the buttons + margin-bottom: 1rem; +} + +.bd-toc .nav { + .nav { + display: none; + + // So we can manually specify a level as visible in the config + &.visible { + display: block; + } + } + + > .active > ul { + display: block; + } +} + +// Each entry of the in-page TOC +.toc-entry { + display: block; + + a > code { + color: var(--pst-color-text-muted); + } + + a.nav-link { + display: block; + padding: 0.125rem 0; + + // Padding w/ negative margin so the top TOC item highlight overlaps w/ the TOC border + padding-left: 1rem; + margin-left: -1rem; + + @include link-sidebar; + + &.active { + @include link-sidebar-current; + + background-color: transparent; + + &:hover { + color: var(--pst-color-link-hover); + } + } + + &:focus-visible { + border-radius: $focus-ring-radius; + } + } +} diff --git a/assets/theme-css/pst/components/_versionmodified.scss b/assets/theme-css/pst/components/_versionmodified.scss new file mode 100644 index 00000000..4151482b --- /dev/null +++ b/assets/theme-css/pst/components/_versionmodified.scss @@ -0,0 +1,72 @@ +div.versionadded, +div.versionchanged, +div.deprecated { + vertical-align: middle; + margin: 1.5625em auto; + padding: 0 0.6rem; + overflow: hidden; + + /* break-inside has replaced page-break-inside and is widely usable since 2019 */ + page-break-inside: avoid; + break-inside: avoid; + border-left: 0.2rem solid; + border-color: var(--pst-color-info); + border-radius: $admonition-border-radius; + background-color: var(--pst-color-on-background); + + @include box-shadow; + + position: relative; + + > p { + margin-bottom: 0.6rem; + margin-top: 0.6rem; + } +} + +div.versionadded { + border-color: var(--pst-color-success); + background-color: var(--pst-color-success-bg); +} + +div.versionchanged { + border-color: var(--pst-color-warning); + background-color: var(--pst-color-warning-bg); +} + +div.deprecated { + border-color: var(--pst-color-danger); + background-color: var(--pst-color-danger-bg); +} + +span.versionmodified { + font-weight: 600; + + &::before { + margin-right: 0.6rem; + color: var(--pst-color-info); + font: var(--fa-font-solid); + content: var(--pst-icon-versionmodified-default); + } +} + +span.versionmodified.added { + &::before { + color: var(--pst-color-success); + content: var(--pst-icon-versionmodified-added); + } +} + +span.versionmodified.changed { + &::before { + color: var(--pst-color-warning); + content: var(--pst-icon-versionmodified-changed); + } +} + +span.versionmodified.deprecated { + &::before { + color: var(--pst-color-danger); + content: var(--pst-icon-versionmodified-deprecated); + } +} diff --git a/assets/theme-css/pst/components/header/_header-logo.scss b/assets/theme-css/pst/components/header/_header-logo.scss new file mode 100644 index 00000000..5e96d66f --- /dev/null +++ b/assets/theme-css/pst/components/header/_header-logo.scss @@ -0,0 +1,38 @@ +/** + * Logo in the navbar + */ + +.navbar-brand { + position: relative; + height: var(--pst-header-height); + max-height: var(--pst-header-height); + padding: 0.5rem 0; + width: auto; + margin: 0; + display: flex; + + // Ensure that the logo stays the same length while other content shrinks + flex-shrink: 0; + align-items: center; + gap: 0.5rem; + + // If there's no logo image, we use a p element w/ the site title + p { + color: var(--pst-color-text-base); + margin-bottom: 0; + } + + // If there's a logo, it'll be in an img block + img { + max-width: 100%; + height: 100%; + width: auto; + } + + &:hover, + &:visited:hover { + @include link-style-hover; + + color: var(--pst-color-text-base); + } +} diff --git a/assets/theme-css/pst/content/_admonitions.scss b/assets/theme-css/pst/content/_admonitions.scss index 9a316c7d..ea74e5d3 100644 --- a/assets/theme-css/pst/content/_admonitions.scss +++ b/assets/theme-css/pst/content/_admonitions.scss @@ -4,17 +4,22 @@ */ $admonition-border-radius: 0.25rem; $admonition-left-border-width: 0.2rem; + div.admonition, .admonition { margin: 1.5625em auto; - padding: 0 0.6rem 0.8rem 0.6rem; + padding: 0 0.6rem 0.8rem; overflow: hidden; + + /* break-inside has replaced page-break-inside and is widely usable since 2019 */ page-break-inside: avoid; + break-inside: avoid; border-left: $admonition-left-border-width solid; border-color: var(--pst-color-info); border-radius: $admonition-border-radius; background-color: var(--pst-color-on-background); - @include box-shadow(); + + @include box-shadow; // Last item should have no spacing since we'll control that w/ padding *:last-child { @@ -39,12 +44,15 @@ div.admonition, padding: 0.4rem 0.6rem 0.4rem 2rem; font-weight: var(--pst-admonition-font-weight-heading); position: relative; + @include legacy-backdrop-placeholder; + background-color: var(--pst-color-info-bg); + // now that we use solid colors we want the title on top z-index: 1; - &:after { + &::after { position: absolute; left: 0.5rem; width: 1rem; @@ -64,10 +72,11 @@ div.admonition, &.attention { border-color: var(--pst-color-attention); + > .admonition-title { background-color: var(--pst-color-attention-bg); - &:after { + &::after { color: var(--pst-color-attention); content: var(--pst-icon-admonition-attention); } @@ -76,10 +85,11 @@ div.admonition, &.caution { border-color: var(--pst-color-warning); + > .admonition-title { background-color: var(--pst-color-warning-bg); - &:after { + &::after { color: var(--pst-color-warning); content: var(--pst-icon-admonition-caution); } @@ -88,10 +98,11 @@ div.admonition, &.warning { border-color: var(--pst-color-warning); + > .admonition-title { background-color: var(--pst-color-warning-bg); - &:after { + &::after { color: var(--pst-color-warning); content: var(--pst-icon-admonition-warning); } @@ -100,10 +111,11 @@ div.admonition, &.danger { border-color: var(--pst-color-danger); + > .admonition-title { background-color: var(--pst-color-danger-bg); - &:after { + &::after { color: var(--pst-color-danger); content: var(--pst-icon-admonition-danger); } @@ -112,10 +124,11 @@ div.admonition, &.error { border-color: var(--pst-color-danger); + > .admonition-title { background-color: var(--pst-color-danger-bg); - &:after { + &::after { color: var(--pst-color-danger); content: var(--pst-icon-admonition-error); } @@ -124,10 +137,11 @@ div.admonition, &.hint { border-color: var(--pst-color-success); + > .admonition-title { background-color: var(--pst-color-success-bg); - &:after { + &::after { color: var(--pst-color-success); content: var(--pst-icon-admonition-hint); } @@ -136,10 +150,11 @@ div.admonition, &.tip { border-color: var(--pst-color-success); + > .admonition-title { background-color: var(--pst-color-success-bg); - &:after { + &::after { color: var(--pst-color-success); content: var(--pst-icon-admonition-tip); } @@ -148,10 +163,11 @@ div.admonition, &.important { border-color: var(--pst-color-attention); + > .admonition-title { background-color: var(--pst-color-attention-bg); - &:after { + &::after { color: var(--pst-color-attention); content: var(--pst-icon-admonition-important); } @@ -160,10 +176,11 @@ div.admonition, &.note { border-color: var(--pst-color-info); + > .admonition-title { background-color: var(--pst-color-info-bg); - &:after { + &::after { color: var(--pst-color-info); content: var(--pst-icon-admonition-note); } @@ -172,10 +189,11 @@ div.admonition, &.seealso { border-color: var(--pst-color-success); + > .admonition-title { background-color: var(--pst-color-success-bg); - &:after { + &::after { color: var(--pst-color-success); content: var(--pst-icon-admonition-seealso); } @@ -184,10 +202,11 @@ div.admonition, &.admonition-todo { border-color: var(--pst-color-secondary); + > .admonition-title { background-color: var(--pst-color-secondary-bg); - &:after { + &::after { color: var(--pst-color-secondary); content: var(--pst-icon-admonition-todo); } @@ -238,8 +257,8 @@ div.admonition, // No inner margin since we have less horizontal space w/ the sidebar p.admonition-title ~ * { - margin-left: 0rem; - margin-right: 0rem; + margin-left: 0; + margin-right: 0; } } } @@ -263,10 +282,11 @@ aside.topic { border-color: var(--pst-color-border); border-radius: $admonition-border-radius; padding: 1rem 1.25rem; - @include box-shadow(); + + @include box-shadow; .topic-title { - margin: 0 0 0.5rem 0; + margin: 0 0 0.5rem; } // Over-ride text color to ensure enough contrast @@ -292,9 +312,11 @@ aside.sidebar { border: 1px solid var(--pst-color-border); background-color: var(--pst-color-surface); border-radius: $admonition-border-radius; + // to match the admonition-styled sidebars: margin-left: 0.5rem; padding: 0; + > *:last-child { padding-bottom: 1rem; } diff --git a/assets/theme-css/pst/content/_api.scss b/assets/theme-css/pst/content/_api.scss new file mode 100644 index 00000000..b6b92c9a --- /dev/null +++ b/assets/theme-css/pst/content/_api.scss @@ -0,0 +1,160 @@ +// Style API docs from sphinx' autodoc / autosummary + +/******************************************************************************* +* Styling for field lists +*/ + +/* grey highlighting of 'parameter' and 'returns' field */ +table.field-list { + border-collapse: separate; + border-spacing: 10px; + margin-left: 1px; + + th.field-name { + padding: 1px 8px 1px 5px; + white-space: nowrap; + background-color: var(--pst-color-surface); + } + + /* italic font for parameter types */ + td.field-body { + p { + font-style: italic; + + > strong { + font-style: normal; + } + } + + /* reduced space around parameter description */ + blockquote { + border-left: none; + margin: 0 0 0.3em; + padding-left: 30px; + } + } +} + +/******************************************************************************* +* Styling for autosummary tables +*/ + +.table.autosummary { + // The first column (with the signature) should not wrap + td:first-child { + white-space: nowrap; + } +} + +/* overriding basic.css to use our own monospace font */ +.sig { + font-family: var(--pst-font-family-monospace); +} + +/* C++ specific styling - overriding the basic.css to avoid custom colors */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, +.sig.c .kt, +.sig.cpp .k, +.sig.cpp .kt { + color: var(--pst-color-text-base); +} + +.sig.c .m, +.sig.cpp .m { + color: var(--pst-color-text-base); +} + +.sig.c .s, +.sig.c .sc, +.sig.cpp .s, +.sig.cpp .sc { + color: var(--pst-color-text-base); +} + +// addition + +// .sig.c .sig-name .n, +// .sig.cpp .sig-name .n { +// color: var(--pst-color-inline-code); +// } + +.sig-name { + color: var(--pst-color-inline-code); +} + +.sig-param .o, +.sig-param .default_value { + color: var(--pst-color-text-muted); + font-weight: normal; +} + +// change target color for dark theme +dt:target, +span.highlighted { + background-color: var(--pst-color-target); +} + +.viewcode-back { + font-family: var(--pst-font-family-base); +} + +.viewcode-block:target { + border-top: 1px solid var(--pst-color-border); + border-bottom: 1px solid var(--pst-color-border); + position: relative; + background-color: var(--pst-color-target); +} + +dl > dt > a:has(.viewcode-link) { + // Sphinx applies a `float:right` rule to the .viewcode-line span, which + // exposes a browser glitch in the focus ring. It seems the browser creates + // two separate boxes, an empty box where the anchor element gets laid out and + // then another box around the anchor's contents that have been floated right. + // Firefox draws the focus ring around the empty anchor element box. Chrome + // draws two focus rings: one around the empty anchor and one around the + // floated-right element. To fix the glitch, we apply the float rule on the + // parent rather than the child. + float: right; + + .viewcode-link { + float: none; + } +} + +/******************************************************************************* +* Styling for autosummary titles like "parameters" and "returns" +*/ + +// the API selector +// from https://github.com/pradyunsg/furo/blob/main/src/furo/assets/styles/content/_api.sass#L6) +dl[class]:not(.option-list, .field-list, .footnote, .glossary, .simple) { + // increase margin bottom after the dl elements + margin-bottom: 3rem; + + dd { + margin-left: 2rem; + + // Fix until this will be solved to Sphinx https://github.com/sphinx-doc/sphinx/issues/10815 + & > dl.simple > dt { + display: flex; + } + } + + dl.field-list { + display: grid; + grid-template-columns: unset; + } + + dt.field-odd, + dt.field-even { + margin-top: 0.2rem; + margin-bottom: 0.1rem; + background-color: var(--pst-color-surface); + } +} diff --git a/assets/theme-css/pst/content/_code.scss b/assets/theme-css/pst/content/_code.scss index 8f4a264d..6371097e 100644 --- a/assets/theme-css/pst/content/_code.scss +++ b/assets/theme-css/pst/content/_code.scss @@ -12,6 +12,7 @@ div.literal-block-wrapper { flex-direction: column; width: unset; border-radius: $admonition-border-radius; + break-inside: avoid; } // Code blocks with captions @@ -38,6 +39,7 @@ div.literal-block-wrapper { div[class*="highlight-"] { margin: 0; border-radius: 0; + pre { border: none; box-shadow: none; @@ -59,12 +61,6 @@ a > code { color: var(--pst-color-inline-code-links); } -// Fix for Sphinx's "highlight" directive - this is an issue with our accessible pygments theme -// and the colour we are using for the background of the code blocks. -html[data-theme="light"] .highlight .nf { - color: #0078a1 !important; -} - // Minimum opacity needed for linenos to be WCAG AA conformant span.linenos { opacity: 0.8 !important; diff --git a/assets/theme-css/pst/content/_figures.scss b/assets/theme-css/pst/content/_figures.scss index 05a3fbe0..f5e89f1c 100644 --- a/assets/theme-css/pst/content/_figures.scss +++ b/assets/theme-css/pst/content/_figures.scss @@ -1,9 +1,19 @@ +figure > a, +figure > a > img, +figure > img, +figure > video { + display: block; + margin-left: auto; + margin-right: auto; +} + figure { a.headerlink { // So that header link doesn't push caption to be off-center. position: absolute; font-size: inherit; } + // Default headerlink hover doesn't trigger on figures &:hover a.headerlink { visibility: visible; @@ -16,12 +26,18 @@ figure { margin-left: auto; margin-right: auto; margin-top: 0.3rem; + text-align: center; & > p:last-child { // Don't add extra margin to already existing figure bottom margin margin-bottom: 0; } + p { + text-align: start; + display: inline-block; + } + table.table { width: fit-content; margin-left: auto; diff --git a/assets/theme-css/pst/content/_footnotes.scss b/assets/theme-css/pst/content/_footnotes.scss new file mode 100644 index 00000000..5d82f3a1 --- /dev/null +++ b/assets/theme-css/pst/content/_footnotes.scss @@ -0,0 +1,33 @@ +// For consistency, add bracket around footnotes/citations which are +// cited more than once. E.g. [Newton](1,2) instead of Newton(1,2) +dt.label > span.brackets:not(:only-child)::before { + content: "["; +} + +dt.label > span.brackets:not(:only-child)::after { + content: "]"; +} + +// Make footnote as a superscript +a.footnote-reference { + vertical-align: super; + font-size: small; +} + +// Docutils 0.18 uses an `aside.footnote` container with different internal structure +aside.footnote { + margin-bottom: 0.5rem; + + &:last-child { + margin-bottom: 1rem; + } + + span.label, + span.backrefs { + font-weight: bold; + } + + &:target { + background-color: var(--pst-color-target); + } +} diff --git a/assets/theme-css/pst/content/_hacks.scss b/assets/theme-css/pst/content/_hacks.scss new file mode 100644 index 00000000..0d389b85 --- /dev/null +++ b/assets/theme-css/pst/content/_hacks.scss @@ -0,0 +1,12 @@ +/** + * Hacky fixes that don't fit cleanly into other sections + */ + +// Ensure user highlighting/selecting behaves properly +// From https://stackoverflow.com/a/34372191 +table.highlighttable td.linenos, +span.linenos, +div.doctest > div.highlight span.gp { + /* gp: Generic.Prompt */ + user-select: none; +} diff --git a/assets/theme-css/pst/content/_lists.scss b/assets/theme-css/pst/content/_lists.scss index ae40a315..957b549e 100644 --- a/assets/theme-css/pst/content/_lists.scss +++ b/assets/theme-css/pst/content/_lists.scss @@ -8,6 +8,7 @@ dd { ol, ul { padding-inline-start: 2rem; + li > p:first-child { margin-bottom: 0.25rem; margin-top: 0.25rem; diff --git a/assets/theme-css/pst/content/_math.scss b/assets/theme-css/pst/content/_math.scss new file mode 100644 index 00000000..fad65a00 --- /dev/null +++ b/assets/theme-css/pst/content/_math.scss @@ -0,0 +1,49 @@ +/** + * Mathematics via MathJax. + * + * This is designed for MathJax v3 + * ref: https://www.sphinx-doc.org/en/master/usage/extensions/math.html#module-sphinx.ext.mathjax + */ + +// Applies to all math elements +span.math, +div.math { + align-items: center; + display: flex; + max-width: 100%; + + // This will be over-ridden for the y-direction and divs + overflow: hidden; +} + +// Inline-only +span.math { + display: inline-flex; +} + +// Block-level only +div.math { + gap: 0.5em; + + // So that the eqno shows up after the equation + flex-direction: row-reverse; + + // The equation number / link + span.eqno a.headerlink { + position: relative; + font-size: 1em; + } + + // The math container + mjx-container { + flex-grow: 1; + padding-bottom: 0.2rem; + overflow: auto; + + // Set height to 0 so that it does not cause scrollbars to appear + // ref: https://github.com/mathjax/MathJax/issues/2521 + mjx-assistive-mml { + height: 0; + } + } +} diff --git a/assets/theme-css/pst/content/_quotes.scss b/assets/theme-css/pst/content/_quotes.scss index 0387c103..b01bed94 100644 --- a/assets/theme-css/pst/content/_quotes.scss +++ b/assets/theme-css/pst/content/_quotes.scss @@ -1,8 +1,8 @@ // GitHub blockquote style blockquote { - padding: 1em 1em; + padding: 1em; color: var(--pst-color-text-muted); - border-left: 0.25em solid var(--pst-color-border); + border-left: 0.25em solid var(--pst-color-blockquote-notch); border-radius: $admonition-border-radius; position: relative; @@ -12,7 +12,7 @@ blockquote { // remove padding from included line-block to avoid duplication .line-block { - margin: 0 0; + margin: 0; } // remove margin bottom for the last p @@ -21,10 +21,16 @@ blockquote { } @include legacy-backdrop-placeholder; + background-color: var(--pst-color-surface); - //hack to make the text in the blockquote selectable - &:before { + // Ensure there is enough contrast against the background + a { + color: var(--pst-color-inline-code-links); + } + + // hack to make the text in the blockquote selectable + &::before { z-index: -1; } } diff --git a/assets/theme-css/pst/content/_spans.scss b/assets/theme-css/pst/content/_spans.scss new file mode 100644 index 00000000..5f2ae156 --- /dev/null +++ b/assets/theme-css/pst/content/_spans.scss @@ -0,0 +1,25 @@ +/** + * Span-level styling within content + */ + +span.guilabel { + border: 1px solid var(--pst-color-info); + font-size: 80%; + font-weight: 700; + border-radius: 4px; + padding: 2.4px 6px; + margin: auto 2px; + position: relative; + + @include legacy-backdrop-placeholder; + + background-color: var(--pst-color-info-bg); +} + +a.reference.download::before { + content: var(--pst-icon-download); + font: var(--fa-font-solid); + font-size: 0.8em; + padding: 0 0.25em; + color: var(--pst-color-text-muted); +} diff --git a/assets/theme-css/pst/content/_tables.scss b/assets/theme-css/pst/content/_tables.scss index c476269c..3d261d75 100644 --- a/assets/theme-css/pst/content/_tables.scss +++ b/assets/theme-css/pst/content/_tables.scss @@ -2,11 +2,7 @@ * Tables */ -// ensure table will fit in the article width and make them y-scrollable table { - display: table; - overflow: auto; - // default to table-center margin-left: auto; margin-right: auto; @@ -31,23 +27,31 @@ table caption { // MyST Markdown tables use these classes to control alignment th, td { - &.text-align\:left { + &.text-left { text-align: left; } - &.text-align\:right { + &.text-right { text-align: right; } - &.text-align\:center { + &.text-center { text-align: center; } } // override bootstrap table colors .table { - --bs-table-bg: transparent; //background + @include table-colors; + + --bs-table-bg: transparent; // background --bs-table-color: var( --pst-color-text-base ); // ensure text and bullets are visible } + +.pst-scrollable-table-container { + // Put a horizontal scrollbar just below tables that are too wide to fit + // within the main column + overflow-x: auto; +} diff --git a/assets/theme-css/pst/content/_toctree.scss b/assets/theme-css/pst/content/_toctree.scss index d216ab74..ddc6cb12 100644 --- a/assets/theme-css/pst/content/_toctree.scss +++ b/assets/theme-css/pst/content/_toctree.scss @@ -4,7 +4,7 @@ .toctree-wrapper { p.caption { font-size: 1.5em; - margin-bottom: 0em; + margin-bottom: 0; } & > ul { diff --git a/assets/theme-css/pst/extensions/_ablog.scss b/assets/theme-css/pst/extensions/_ablog.scss new file mode 100644 index 00000000..49c3b1a1 --- /dev/null +++ b/assets/theme-css/pst/extensions/_ablog.scss @@ -0,0 +1,140 @@ +/** + * ABlog + * ref: https://ablog.readthedocs.io/ + */ + +/** + * Sidebar template components + */ +.ablog-sidebar-item { + h2, + h3 { + font-size: var(--pst-sidebar-header-font-size); + + // Remove unnecessary vertical whitespace + margin-top: 0.5rem; + + // The headers are all links, but this makes them hard to parse + // So we change the colors to make them look like headers + a { + color: var(--pst-color-text-base); + } + } + + ul { + // No bullet points for the primary sidebar items + list-style: none; + padding-left: 0; + + // Otherwise a scrollbar randomly shows up + overflow-y: hidden; + + // List of recent post items + display: flex; + flex-direction: column; + gap: 0.5em; + margin-bottom: 0; + + // The ablog cloud should move horizontally + &.ablog-cloud { + flex-flow: row wrap; + gap: 0.5rem; + + // Vertical-align tag clouds + li { + // Center the tag cloud items + display: flex; + align-items: center; + } + } + } +} + +/** + * Previous / next buttons at the bottom + */ +.ablog__prev-next { + font-size: 1.2em; + display: flex; + padding: 1rem 0; + + // The bottom previous / next arrows + > span { + // To ensure that the whole thing fits on one line even if there are long titles + display: flex; + max-width: 45%; + + // Links within each span have the collection of icon + text + a { + display: flex; + align-items: center; + margin-left: auto; + gap: 1rem; + line-height: 1.5rem; + + i::before { + color: var(--pst-color-text-base); + } + } + } + + // The first span is for the previous page and aligns to the left + span.ablog__prev { + i.fa-arrow-circle-left::before { + content: var(--pst-icon-angle-left); + } + } + + // The second span is just an empty space so we remove it because we're + // positioning with flex + span.ablog__spacer { + display: none; + } + + // The third span is aligned to the right + span.ablog__next { + margin-left: auto; + text-align: right; + + i.fa-arrow-circle-right::before { + content: var(--pst-icon-angle-right); + } + } +} + +/** + * {postlist} directive and posts page + */ +.ablog__collection, +.postlist { + padding-left: 0; + + .ablog-post { + list-style: none; + + // Post metadata tags (author, links ,etc) should be a bit smaller + .ablog-archive { + display: flex; + flex-flow: row wrap; + gap: 1rem; + list-style: none; + font-size: 0.75rem; + padding-left: 0; + } + + // Title line should be a bit bigger and bold to stand out + .ablog-post-title { + margin-top: 0; + font-size: 1.25rem; + + a { + font-weight: bold; + } + } + + // Read more button should be a bit bigger + .ablog-post-expand { + margin-bottom: 0.5rem; + } + } +} diff --git a/assets/theme-css/pst/extensions/_bootstrap.scss b/assets/theme-css/pst/extensions/_bootstrap.scss new file mode 100644 index 00000000..9198bad0 --- /dev/null +++ b/assets/theme-css/pst/extensions/_bootstrap.scss @@ -0,0 +1,19 @@ +/** + * Special cases for Bootstrap functionality + */ + +// Bootstrap adds margin to their general container class. However, sphinx/docutils +// can also generate output with the container class, but in those cases we should +// not add the margin from bootstrap. Same for max-width. +.docutils.container { + padding-left: unset; + padding-right: unset; + margin-left: unset; + margin-right: unset; + max-width: unset; + width: unset; +} + +.btn { + --bs-btn-focus-box-shadow: #{$btn-focus-box-shadow}; +} diff --git a/assets/theme-css/pst/extensions/_copybutton.scss b/assets/theme-css/pst/extensions/_copybutton.scss new file mode 100644 index 00000000..10540067 --- /dev/null +++ b/assets/theme-css/pst/extensions/_copybutton.scss @@ -0,0 +1,48 @@ +/** + * Sphinx Copybutton + * ref: https://sphinx-copybutton.readthedocs.io/ + */ + +div.highlight button.copybtn { + // Nicer spacing + display: flex; + align-items: center; + justify-content: center; + + // Don't over-ride the success color + &:not(.success) { + color: var(--pst-color-muted); + } + + border: none; + background-color: var(--pst-color-surface); + + &:hover { + &:not(.success) { + color: var(--pst-color-text); + background-color: var(--pst-color-shadow); + } + } + + // Tooltip styling + &.o-tooltip--left::after { + color: var(--pst-color-text); + background-color: var(--pst-color-surface); + } + + &:focus { + // For keyboard users, make the copy button visible when focussed. + opacity: 1; + } + + &:focus-visible { + outline: $focus-ring-outline; + } +} + +div.highlight:has(button.copybtn) { + // Make sure the code block has enough height for the copy button. + // Sphinx-copybutton sets 0.3em top offset plus 1.7em height: + // https://github.com/executablebooks/sphinx-copybutton/blob/master/sphinx_copybutton/_static/copybutton.css + min-height: 2em; +} diff --git a/assets/theme-css/pst/extensions/_ethical-ads.scss b/assets/theme-css/pst/extensions/_ethical-ads.scss new file mode 100644 index 00000000..3e9bf0cc --- /dev/null +++ b/assets/theme-css/pst/extensions/_ethical-ads.scss @@ -0,0 +1,23 @@ +// adapt ethical ad to the theme +#ethical-ad-placement { + .ethical-sidebar a, + .ethical-sidebar a:visited, + .ethical-sidebar a:hover, + .ethical-sidebar a:active, + .ethical-footer a, + .ethical-footer a:visited, + .ethical-footer a:hover, + .ethical-footer a:active { + color: var(--pst-color-text-base); + } + + .ethical-sidebar, + .ethical-footer { + background-color: var(--pst-color-background); + border: 1px solid var(--pst-color-border); + border-radius: 5px; + color: var(--pst-color-text-base); + font-size: 14px; + line-height: 20px; + } +} diff --git a/assets/theme-css/pst/extensions/_execution.scss b/assets/theme-css/pst/extensions/_execution.scss new file mode 100644 index 00000000..42505e3b --- /dev/null +++ b/assets/theme-css/pst/extensions/_execution.scss @@ -0,0 +1,38 @@ +/** + * Styles for various Sphinx execution libraries. + * For now, where these define output sections, we simply revert their background + * to be a "light theme" background. This ensures that inputs/outputs behave similarly, + * because the CSS is often controlled by each package. + * In the future, we might add dark theme support for specific packages. + */ + +/****************************************************************************** + * Jupyter Sphinx + */ + +.bd-content div.jupyter_container { + // We don't want borders around the whole container, just around code cells + border: none; + background-color: unset; + box-shadow: none; + + // Code cells should have the same style as our other code objects + div.output, + div.highlight { + border-radius: 0.25rem; + } + + div.highlight { + background-color: var(--pst-color-surface); + } + + // Ensure the style is the same as our code cells. Jupyter Sphinx makes it tiny. + .cell_input, + .cell_output { + border-radius: 0.25rem; + + pre { + padding: 1rem; + } + } +} diff --git a/assets/theme-css/pst/extensions/_graphviz.scss b/assets/theme-css/pst/extensions/_graphviz.scss new file mode 100644 index 00000000..3b0bb509 --- /dev/null +++ b/assets/theme-css/pst/extensions/_graphviz.scss @@ -0,0 +1,7 @@ +/* Styles for graphviz generated output from Sphinx */ + +/* Style the inheritance diagram such that it has a dark mode */ +html[data-theme="dark"] div.graphviz > object.inheritance { + filter: brightness(0.8) invert(0.82) contrast(1.2); + color-scheme: normal; +} diff --git a/assets/theme-css/pst/extensions/_leaflet.scss b/assets/theme-css/pst/extensions/_leaflet.scss new file mode 100644 index 00000000..a349a49c --- /dev/null +++ b/assets/theme-css/pst/extensions/_leaflet.scss @@ -0,0 +1,14 @@ +/** + * style for the various mapping libs based on leaflet (folium, geemap, ipyleaflet) + * mainly ensure the good display of the maps in both themes and avoid the customization + * of the tiles + */ + +/** + * avoid border override from pydata-sphinx-theme + * minimal selctor to get the priority + */ +html[data-theme="dark"] .bd-content img.leaflet-tile.leaflet-tile-loaded { + border-radius: 0; + padding: 0; +} diff --git a/assets/theme-css/pst/extensions/_notebooks.scss b/assets/theme-css/pst/extensions/_notebooks.scss new file mode 100644 index 00000000..c1994550 --- /dev/null +++ b/assets/theme-css/pst/extensions/_notebooks.scss @@ -0,0 +1,130 @@ +/** + * Styles for various Sphinx execution libraries to display pre-executed notebooks. + * For now, where these define output sections, we simply revert their background + * to be a "light theme" background. This ensures that inputs/outputs behave similarly, + * because the CSS is often controlled by each package. + * In the future, we might add dark theme support for specific packages. + */ + +/******************************************************************************* + * nbsphinx + */ +html div.rendered_html, +// NBsphinx ipywidgets output selector +html .jp-RenderedHTMLCommon { + // Add some margin around the element box for the focus ring. Otherwise the + // focus ring gets clipped because the containing elements have `overflow: + // hidden` applied to them (via the `.lm-Widget` selector) + margin: $focus-ring-width; + + table { + table-layout: auto; + } +} + +.bd-content .nboutput { + .output_area { + &.rendered_html, + .jp-RenderedHTMLCommon { + // pandas + table.dataframe { + @include table-colors; + } + } + + // Dark theme special-cases + html[data-theme="dark"] & { + &.rendered_html:not(:has(table.dataframe)), + // ipywidgets + .widget-subarea { + @include cell-output-background; + } + + &.stderr { + background-color: var(--pst-color-danger); + } + } + } +} + +// Add extra padding to the final item in an nbsphinx container +div.nblast.container { + margin-bottom: 1rem; +} + +// Override nbsphinx's colors for notebook cell prompts because they do not have +// sufficient contrast. Colors chosen from accessible-pygments +// a11y-high-contrast-{light,dark} themes. + +// Notebook cell input line number. Replace nbsphinx's low contrast blue with +// higher contrast blues. +.nbinput.container .prompt pre { + html[data-theme="light"] & { + // Copied from accessible-pygments [a11y-high-contrast-light](https://github.com/Quansight-Labs/accessible-pygments/tree/main/a11y_pygments/a11y_high_contrast_light) + color: #005b82; + } + + html[data-theme="dark"] & { + // Copied from accessible-pygments [a11y-high-contrast-dark](https://github.com/Quansight-Labs/accessible-pygments/tree/main/a11y_pygments/a11y_high_contrast_dark) + color: #00e0e0; + } +} + +// Notebook cell output line number. Replace nbsphinx's low contrast red with +// higher contrast red / orange. +.nboutput.container .prompt pre { + html[data-theme="light"] & { + // Copied from accessible-pygments [a11y-high-contrast-light](https://github.com/Quansight-Labs/accessible-pygments/tree/main/a11y_pygments/a11y_high_contrast_light) + color: #a12236; + } + + html[data-theme="dark"] & { + // Copied from accessible-pygments [a11y-high-contrast-dark](https://github.com/Quansight-Labs/accessible-pygments/tree/main/a11y_pygments/a11y_high_contrast_dark) + color: #ffa07a; + } +} + +/******************************************************************************* + * myst NB + */ + +div.cell_output .output { + max-width: 100%; + overflow-x: auto; +} + +.bd-content div.cell_output { + // pandas + table.dataframe { + @include table-colors; + } + + html[data-theme="dark"] & { + img, + .text_html:not(:has(table.dataframe)), + // ipywidgets + .widget-subarea { + @include cell-output-background; + } + } +} + +// Prevent tables from scrunching together +.bd-content { + div.cell_input { + display: flex; + flex-direction: column; + justify-content: stretch; + } + + div.cell_input, + div.output { + border-radius: $admonition-border-radius; + } + + div.output { + table { + table-layout: auto; + } + } +} diff --git a/assets/theme-css/pst/extensions/_pydata.scss b/assets/theme-css/pst/extensions/_pydata.scss new file mode 100644 index 00000000..56ee5fbf --- /dev/null +++ b/assets/theme-css/pst/extensions/_pydata.scss @@ -0,0 +1,14 @@ +/** + * Special-cases for packages in the PyData ecosystem + */ + +// xarray output display in bootstrap +.xr-wrap[hidden] { + display: block !important; +} + +// ipywidgets +.jp-OutputArea-output.lm-Widget { + // override overflow:hidden rule from Lumino (.lm-Widget) to allow scrolling + overflow: auto; +} diff --git a/assets/theme-css/pst/extensions/_sphinx_design.scss b/assets/theme-css/pst/extensions/_sphinx_design.scss index 66bdfdbf..46d7bb8b 100644 --- a/assets/theme-css/pst/extensions/_sphinx_design.scss +++ b/assets/theme-css/pst/extensions/_sphinx_design.scss @@ -6,8 +6,10 @@ * same for our overrides to have any effect. */ @use "../variables/color" as pst-color; -@use "sass:meta"; @use "sass:color"; +@use "sass:map"; +@use "sass:meta"; +@use "sass:string"; /******************************************************************************* * Color and variables @@ -60,50 +62,65 @@ $extra-semantic-colors: ( "dark": $foundation-dark-gray, "black": $foundation-black, ); - -$all-colors: map-merge($pst-semantic-colors, $extra-semantic-colors); +$all-colors: map.merge($pst-semantic-colors, $extra-semantic-colors); @mixin create-sd-colors($value, $name) { // define the pst variables, so that downstream user overrides will work + @debug "Creating color variables for semantic color: #{$name}"; + --pst-color-#{$name}: #{$value}; + // we are now using a11y-combination to calculate the text color - this is based // on the WCAG color contrast guidelines --pst-color-#{$name}-text: #{a11y-combination($value)}; - //TODO: highlight seems to be used for buttons @trallard to fix on a11y follow-up work - --pst-color-#{$name}-highlight: #{darken($value, 15%)}; + + // highlight is used for hover effects on buttons, here we make some fluid scaling + // to avoid jarring effects -- we create a local variable that we can access + // later to calculate the text color + $highlight-color: color.scale($value, $lightness: -15%, $saturation: 5%); + + --pst-color-#{$name}-highlight: #{$highlight-color}; + // override the sphinx-design variables --sd-color-#{$name}: var(--pst-color-#{$name}); --sd-color-#{$name}-text: var(--pst-color-#{$name}-text); - //TODO: highlight seems to be used for buttons @trallard to fix on a11y follow-up work --sd-color-#{$name}-highlight: var(--pst-color-#{$name}-highlight); + + // calculate the text color for the highlight color + --pst-color-#{$name}-highlight-text: #{a11y-combination($highlight-color)}; } // Now we override the --sd-color-* variables. @each $mode in (light, dark) { + @debug "Creating color variables for mode: #{$mode}"; html[data-theme="#{$mode}"] { // check if this color is defined differently for light/dark @each $name in $sd-semantic-color-names { - $definition: map-get($all-colors, $name); - @if type-of($definition) == map { + $definition: map.get($all-colors, $name); + + @if meta.type-of($definition) == map { @each $key, $value in $definition { - @if str-index($key, $mode) != null { + @if string.index($key, $mode) { // since now we define the bg colours in the semantic colours and not // by changing opacity, we need to check if the key contains bg and the // correct mode (light/dark) - @if str-index($key, "bg") != null { + @if string.index($key, "bg") { --sd-color-#{$name}-bg: #{$value}; - // create local variable - $bg-var: --sd-color-#{$name}-bg; + + // create local variable -- needed to calculate the text color $value: check-color($value); + --sd-color-#{$name}-bg-text: #{a11y-combination($value)}; } @else { $value: check-color($value); + @include create-sd-colors($value, $name); } } } } @else { - $value: map-get($all-colors, $name); + $value: map.get($all-colors, $name); + @include create-sd-colors($value, $name); } } @@ -125,7 +142,7 @@ html[data-theme="light"] { .sd-shadow-sm, .sd-shadow-md, .sd-shadow-lg { - @include box-shadow(); + @include box-shadow; } } @@ -141,6 +158,7 @@ html[data-theme="light"] { background-color: var(--pst-color-panel-background); border-bottom: 1px solid var(--pst-color-border); } + .sd-card-footer { background-color: var(--pst-color-panel-background); border-top: 1px solid var(--pst-color-border); @@ -156,7 +174,7 @@ html[data-theme="light"] { outline: none; // Put the focus ring on the element's ::after pseudo-element - &:after { + &::after { outline: $focus-ring-outline; border-radius: 0.25rem; // copied from Sphinx Design CSS for .sd-card } @@ -166,6 +184,7 @@ html[data-theme="light"] { border-color: var(--pst-color-link-hover); } } + /******************************************************************************* * tabs */ @@ -177,6 +196,7 @@ html[data-theme="light"] { border-style: solid solid none; border-color: var(--pst-color-primary) var(--pst-color-primary) transparent; // top LR bottom + border-width: 0.125rem 0.125rem 0; border-radius: 0.125rem 0.125rem 0 0; background-color: var(--pst-color-on-background); @@ -192,9 +212,11 @@ html[data-theme="light"] { } // Hover label - &:not(:checked):not(:focus-visible) + label:hover { + &:not(:checked, :focus-visible) + label:hover { border-color: transparent; color: var(--pst-color-secondary); + text-decoration-line: underline; + text-decoration-thickness: $link-hover-decoration-thickness; } } @@ -202,7 +224,7 @@ html[data-theme="light"] { > label { color: var(--pst-color-on-surface); border: 0.125rem solid transparent; - border-radius: 0.125rem 0.125rem 0px 0px; + border-radius: 0.125rem 0.125rem 0 0; background-color: var(--pst-color-surface); padding: 0 0.75em; margin-inline-end: 0.25rem; @@ -229,18 +251,14 @@ html[data-theme="light"] { details.sd-dropdown { // Remove all borders to over-ride SD behavior, and we'll add our own later - border: 0px !important; - summary.sd-card-header { - border: 0 !important; - & + div.sd-summary-content { - border: 0; - } - } + border: 0 !important; + // Drop shadow should behave same as admonitions - @include box-shadow(); + @include box-shadow; // Header is where the "clickable" box goes summary.sd-card-header { + border: 0 !important; display: flex; align-items: center; position: relative; // So background color works @@ -253,13 +271,18 @@ details.sd-dropdown { // so that it is defined in both places --pst-sd-dropdown-color: var(--pst-gray-500); --pst-sd-dropdown-bg-color: var(--pst-color-surface); + & + div.sd-summary-content { + border: 0; + --pst-sd-dropdown-color: var(--sd-color-card-border); } + @each $name in $sd-semantic-color-names { &.sd-bg-#{$name} { --pst-sd-dropdown-color: var(--sd-color-#{$name}); --pst-sd-dropdown-bg-color: var(--sd-color-#{$name}-bg); + // Otherwise it won't be defined in the sibling element & + div.sd-summary-content { --pst-sd-dropdown-color: var(--sd-color-#{$name}); @@ -273,19 +296,24 @@ details.sd-dropdown { } @include legacy-backdrop-placeholder; + background-color: var(--pst-sd-dropdown-bg-color) !important; // Add a left border with the same structure as our admonitions border-left: 0.2rem solid var(--pst-sd-dropdown-color) !important; + + // stylelint-disable-next-line no-duplicate-selectors & + div.sd-summary-content { border-left: 0.2rem solid var(--pst-sd-dropdown-color) !important; border-bottom-left-radius: calc(0.25rem - 1px); background-color: var(--pst-color-on-background); } + span.sd-summary-icon { display: inline-flex; align-items: center; color: var(--pst-sd-dropdown-color) !important; + svg { opacity: 1; } @@ -314,12 +342,21 @@ html { min-width: 2.25rem; padding: 0.3125rem 0.75rem 0.4375rem; // 5px 12px 7px - @include link-style-hover; // override Sphinx Design &:hover { + @include link-style-hover; // override Sphinx Design + text-decoration-thickness: 1px; } } + @each $name in $sd-semantic-color-names { + .sd-btn-#{$name} { + &:hover { + color: var(--pst-color-#{$name}-highlight-text) !important; + } + } + } + @each $name in $sd-semantic-color-names { .sd-btn-#{$name}, .sd-btn-outline-#{$name} { diff --git a/assets/theme-css/pst/extensions/_togglebutton.scss b/assets/theme-css/pst/extensions/_togglebutton.scss index 5013c056..1d0f87cc 100644 --- a/assets/theme-css/pst/extensions/_togglebutton.scss +++ b/assets/theme-css/pst/extensions/_togglebutton.scss @@ -32,7 +32,7 @@ } // Focus ring - // + // ---------- // Sphinx-togglebutton makes the entire admonition header clickable, but // only the button within the header is focusable. We want the entire // clickable area to be surrounded with a focus ring, so that's why we use @@ -50,11 +50,12 @@ // the left border on the container's children). This makes it complicated // to get the focus ring to simultaneously cover the left border in the // header and align perfectly on the right with the body. - .admonition-title:focus-within:before { + .admonition-title:focus-within::before { content: ""; transform: translateX( -$admonition-left-border-width ); // align left edges of admonition and ring + width: calc(100% + $admonition-left-border-width); // align right edges height: 100%; border: $focus-ring-outline; @@ -62,7 +63,7 @@ } // When expanded, sharpen the bottom left and right corners of the focus ring - &:not(.toggle-hidden) .admonition-title:focus-within:before { + &:not(.toggle-hidden) .admonition-title:focus-within::before { border-bottom-left-radius: 0; border-bottom-right-radius: 0; } diff --git a/assets/theme-css/pst/pydata-sphinx-theme.scss b/assets/theme-css/pst/pydata-sphinx-theme.scss index 86711ed3..1b5cb5fc 100644 --- a/assets/theme-css/pst/pydata-sphinx-theme.scss +++ b/assets/theme-css/pst/pydata-sphinx-theme.scss @@ -2,7 +2,7 @@ //@import "~bootstrap/scss/functions"; @import "variables/bootstrap"; //@import "~bootstrap/scss/variables"; -//@import "~bootstrap/scss/xins"; +//@import "~bootstrap/scss/mixins"; // Variables @import "variables/layout"; @@ -68,6 +68,7 @@ //@import "./extensions/copybutton"; //@import "./extensions/ethical-ads"; //@import "./extensions/execution"; +//@import "./extensions/graphviz"; //@import "./extensions/pydata"; @import "./extensions/sphinx_design"; @import "./extensions/togglebutton"; diff --git a/assets/theme-css/pst/variables/_bootstrap.scss b/assets/theme-css/pst/variables/_bootstrap.scss index ded36710..b848eceb 100644 --- a/assets/theme-css/pst/variables/_bootstrap.scss +++ b/assets/theme-css/pst/variables/_bootstrap.scss @@ -1,13 +1,11 @@ // Override bootstrap variables $spacer: 1rem; - $container-max-widths: ( sm: 540px, md: 720px, lg: 960px, xl: 1400px, ); - $grid-breakpoints: ( xs: 0, sm: 540px, @@ -15,23 +13,19 @@ $grid-breakpoints: ( lg: 960px, xl: 1200px, ); - $dropdown-link-hover-bg: var(--pst-color-surface); + // --pst-color-surface can also be assigned to the dark variant because it is // scoped to different values depending on light/dark theme $dropdown-dark-link-hover-bg: var(--pst-color-surface); $dropdown-link-active-bg: var(--pst-color-surface); $dropdown-dark-link-active-bg: var(--pst-color-surface); - $focus-ring-width: 0.1875rem; // 3px at 100% zoom (0.1875 * 16px base font = 3px) $focus-ring-opacity: 1; $focus-ring-color: var(--pst-color-accent); $focus-ring-blur: 0; $focus-ring-box-shadow: 0 0 $focus-ring-blur $focus-ring-width $focus-ring-color; + // outline creates the same style of focus ring, it just uses CSS outline instead of box shadow $focus-ring-outline: $focus-ring-color solid $focus-ring-width; $btn-focus-box-shadow: $focus-ring-box-shadow; - -.btn { - --bs-btn-focus-box-shadow: #{$btn-focus-box-shadow}; -} diff --git a/assets/theme-css/pst/variables/_color.scss b/assets/theme-css/pst/variables/_color.scss index 7318cc40..bd5e767c 100644 --- a/assets/theme-css/pst/variables/_color.scss +++ b/assets/theme-css/pst/variables/_color.scss @@ -5,6 +5,10 @@ * To see the full list of colors see https://www.figma.com/file/rUrrHGhUBBIAAjQ82x6pz9/PyData-Design-system---proposal-for-implementation-(2)?node-id=1234%3A765&t=ifcFT1JtnrSshGfi-1 */ +@use "sass:map"; +@use "sass:meta"; +@use "sass:string"; + /** * Function to get items from nested maps */ @@ -13,8 +17,9 @@ // @return {*} @function map-deep-get($map, $keys...) { @each $key in $keys { - $map: map-get($map, $key); + $map: map.get($map, $key); } + @return $map; } @@ -98,22 +103,26 @@ $color-palette: ( // See https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast // 4.5 - is for text that is 14pt or less $min-contrast-ratio-4: 4.5; + // 3 is for text that is 18pt or bold, or for non-text elements $min-contrast-ratio-3: 3; // Customize the light and dark text colors for use in our color contrast function. $foundation-black: #14181e; -$foundation-white: #ffffff; +$foundation-white: #fff; + // This is a custom - calculated color between gray 100 and 200 - to reduce // the contrast ratio (avoid a jarring effect) $base-light-text: #ced6dd; + // used in sphinx_design - gray 100 $foundation-light-gray: #f3f4f5; + // used in sphinx_design - gray 700 $foundation-muted-gray: #29313d; + // used in sphinx_design - gray 800 $foundation-dark-gray: #222832; - $pst-semantic-colors: ( "primary": ( "light": #{map-deep-get($color-palette, "teal", "500")}, @@ -151,7 +160,7 @@ $pst-semantic-colors: ( "dark": #5fb488, "bg-dark": #002f17, ), - // This is is based on the warning color + // This is based on the warning color "attention": ( "light": var(--pst-color-warning), @@ -189,6 +198,12 @@ $pst-semantic-colors: ( "light": rgba(23, 23, 26, 0.2), "dark": #{map-deep-get($color-palette, "gray", "700")}, ), + "blockquote-notch": ( + // These colors have a contrast ratio > 3.0 against both the background and + // surface colors that the notch is sandwiched between + "light": #{map-deep-get($color-palette, "gray", "500")}, + "dark": #{map-deep-get($color-palette, "gray", "400")}, + ), "inline-code": ( "light": #{map-deep-get($color-palette, "pink", "600")}, "dark": #{map-deep-get($color-palette, "pink", "300")}, @@ -203,6 +218,18 @@ $pst-semantic-colors: ( "light": #f3cf95, "dark": #675c04, ), + "table": ( + "light": #{map-deep-get($color-palette, "foundation", "black")}, + "dark": #{map-deep-get($color-palette, "foundation", "white")}, + ), + "table-row-hover": ( + "bg-light": #{map-deep-get($color-palette, "violet", "300")}, + "bg-dark": #{map-deep-get($color-palette, "violet", "600")}, + ), + "table-inner-border": ( + "light": #{map-deep-get($color-palette, "gray", "200")}, + "dark": #364150, + ), // DEPTH COLORS - you can see the elevation colours and shades // in the Figma file https://www.figma.com/file/rUrrHGhUBBIAAjQ82x6pz9/PyData-Design-system---proposal-for-implementation-(2)?node-id=1492%3A922&t=sQeQZehkOzposYEg-1 // background: color of the canvas / the furthest back layer @@ -243,13 +270,13 @@ $pst-semantic-colors: ( @mixin theme-colors($mode) { // check if this color is defined differently for light/dark @each $col-name, $definition in $pst-semantic-colors { - @if type-of($definition) == map { + @if meta.type-of($definition) == map { @each $key, $val in $definition { - @if str-index($key, $mode) != null { + @if string.index($key, $mode) { // since now we define the bg colours in the semantic colours and not // by changing opacity, we need to check if the key contains bg and the // correct mode (light/dark) - @if str-index($key, "bg") != null { + @if string.index($key, "bg") { --pst-color-#{$col-name}-bg: #{$val}; } @else { --pst-color-#{$col-name}: #{$val}; @@ -265,7 +292,12 @@ $pst-semantic-colors: ( & { --pst-color-link: var(--pst-color-primary); --pst-color-link-hover: var(--pst-color-secondary); + --pst-color-table-outer-border: var(--pst-color-surface); + --pst-color-table-heading-bg: var(--pst-color-surface); + --pst-color-table-row-zebra-high-bg: var(--pst-color-on-background); + --pst-color-table-row-zebra-low-bg: var(--pst-color-surface); } + // adapt to light/dark-specific content @if $mode == "light" { .only-dark, @@ -277,21 +309,24 @@ $pst-semantic-colors: ( .only-light ~ figcaption { display: none !important; } + /* Adjust images in dark mode (unless they have class .only-dark or * .dark-light, in which case assume they're already optimized for dark * mode). */ - img:not(.only-dark):not(.dark-light) { + img:not(.only-dark, .dark-light) { filter: brightness(0.8) contrast(1.2); } + /* Give images a light background in dark mode in case they have * transparency and black text (unless they have class .only-dark or .dark-light, in * which case assume they're already optimized for dark mode). */ - .bd-content img:not(.only-dark):not(.dark-light) { - background-color: rgb(255, 255, 255); + .bd-content img:not(.only-dark, .dark-light) { + background-color: rgb(255 255 255); border-radius: 0.25rem; } + // MathJax SVG outputs should be filled to same color as text. .MathJax_SVG * { fill: var(--pst-color-text-base); @@ -310,6 +345,7 @@ html:not([data-theme]) { @each $mode in (light, dark) { html[data-theme="#{$mode}"] { @include theme-colors($mode); + color-scheme: $mode; } } diff --git a/assets/theme-css/pst/variables/_fonts.scss b/assets/theme-css/pst/variables/_fonts.scss index 3c435e69..19219c3d 100644 --- a/assets/theme-css/pst/variables/_fonts.scss +++ b/assets/theme-css/pst/variables/_fonts.scss @@ -32,13 +32,14 @@ html { // Font family // These are adapted from https://systemfontstack.com/ */ - --pst-font-family-base-system: -apple-system, BlinkMacSystemFont, Segoe UI, - "Helvetica Neue", Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, - Segoe UI Symbol; - --pst-font-family-monospace-system: "SFMono-Regular", Menlo, Consolas, Monaco, - Liberation Mono, Lucida Console, monospace; - + --pst-font-family-base-system: -apple-system, "BlinkMacSystemFont", "Segoe UI", + "Helvetica Neue", "Arial", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", + "Segoe UI Symbol"; + --pst-font-family-monospace-system: "SFMono-Regular", "Menlo", "Consolas", + "Monaco", "Liberation Mono", "Lucida Console", monospace; --pst-font-family-base: var(--pst-font-family-base-system); --pst-font-family-heading: var(--pst-font-family-base-system); --pst-font-family-monospace: var(--pst-font-family-monospace-system); } + +$line-height-body: 1.65; diff --git a/assets/theme-css/pst/variables/_layout.scss b/assets/theme-css/pst/variables/_layout.scss index 1fbd63d8..eaae298a 100644 --- a/assets/theme-css/pst/variables/_layout.scss +++ b/assets/theme-css/pst/variables/_layout.scss @@ -35,3 +35,5 @@ $admonition-border-radius: 0.25rem; // In this theme, some focus rings have rounded corners while others do not. // This variable sets the border radius for the rounded focus rings. $focus-ring-radius: 0.125rem; // 2px at 100% zoom and 16px base font. + +$navbar-link-padding-y: 0.25rem; diff --git a/assets/theme-css/pst/variables/_versionmodified.scss b/assets/theme-css/pst/variables/_versionmodified.scss new file mode 100644 index 00000000..20432fbd --- /dev/null +++ b/assets/theme-css/pst/variables/_versionmodified.scss @@ -0,0 +1,10 @@ +html { + /***************************************************************************** + * versionmodified + **/ + + --pst-icon-versionmodified-default: var(--pst-icon-exclamation-circle); + --pst-icon-versionmodified-added: var(--pst-icon-exclamation-circle); + --pst-icon-versionmodified-changed: var(--pst-icon-exclamation-circle); + --pst-icon-versionmodified-deprecated: var(--pst-icon-exclamation-circle); +}