From dca9cc06c14de3896aed6b2fcabbad49363a5d12 Mon Sep 17 00:00:00 2001
From: "mcanouil-dev[bot]"
<211049963+mcanouil-dev[bot]@users.noreply.github.com>
Date: Sat, 1 Aug 2026 13:10:18 +0000
Subject: [PATCH] chore(deps): update 2 Quarto extensions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- mcanouil/atelier: 0.6.0 → 0.9.0
- mcanouil/gitlink: 1.8.0 → 1.9.0
---
.../mcanouil/atelier/_extension.yml | 86 +--
.../mcanouil/atelier/html/chrome.scss | 134 +++++
.../mcanouil/atelier/html/theme.scss | 494 +++++++++++++++---
.../mcanouil/atelier/social-metadata.lua | 31 +-
.../mcanouil/gitlink/_extension.yml | 7 +-
.../mcanouil/gitlink/_modules/widget.lua | 2 +-
docs/_extensions/mcanouil/gitlink/_schema.yml | 4 +-
docs/_extensions/mcanouil/gitlink/widget.css | 103 +++-
docs/_extensions/mcanouil/gitlink/widget.js | 106 ++--
9 files changed, 783 insertions(+), 184 deletions(-)
create mode 100644 docs/_extensions/mcanouil/atelier/html/chrome.scss
diff --git a/docs/_extensions/mcanouil/atelier/_extension.yml b/docs/_extensions/mcanouil/atelier/_extension.yml
index ea87ad8..f0cc22a 100644
--- a/docs/_extensions/mcanouil/atelier/_extension.yml
+++ b/docs/_extensions/mcanouil/atelier/_extension.yml
@@ -1,25 +1,66 @@
title: Atelier
author: Mickaël Canouil
-version: 0.6.0
-quarto-required: '>=1.9.36'
-source: mcanouil/quarto-atelier@0.6.0
-source-type: github
+version: 0.9.0
+quarto-required: ">=1.9.36"
contributes:
+ project:
+ project:
+ type: website
+ output-dir: _site
+ website:
+ repo-actions: [edit, issue]
+ repo-link-target: _blank
+ repo-link-rel: noopener noreferrer
+ # `locale` matches `lang: en-GB` below; override the two together.
+ # Naming `twitter-card` at all is what switches Quarto's Twitter
+ # provider on, after which it inherits title, description, image, and
+ # image alt from each page.
+ open-graph:
+ locale: en_GB
+ twitter-card:
+ card-style: summary_large_image
+ page-navigation: true
+ back-to-top-navigation: true
+ llms-txt: true
+ search:
+ location: navbar
+ type: overlay
+ # `background` and `foreground` are left to the theme on both bars: the
+ # chrome palette in `html/chrome.scss` sets `$navbar-bg`, `$navbar-fg`,
+ # `$footer-bg`, and `$footer-fg` from a layer Quarto evaluates first, so
+ # naming them here would be a configuration with no effect.
+ navbar:
+ search: true
+ page-footer:
+ border: true
+ left: |
+ Powered by [Quarto](https://quarto.org){target="_blank" rel="noopener noreferrer"}.
+ center: |
+ © []{#current-year} [Mickaël CANOUIL](https://mickael.canouil.fr){target="_blank" rel="noopener noreferrer"}.
+ format: atelier-html
formats:
common:
lang: en-GB
- date-format: dddd[, the] Do [of] MMMM, YYYY
+ date-format: "dddd[, the] Do [of] MMMM, YYYY"
code-copy: true
code-overflow: wrap
code-link: false
html:
respect-user-color-scheme: true
+ # Quarto builds the canonical link from `website.site-url`, giving a
+ # directory index the URL of its directory. Set `canonical-url: false`
+ # on a page served from more than one URL, such as `404.qmd`.
canonical-url: true
+ # `html/chrome.scss` comes before `brand` on purpose: Quarto evaluates
+ # user layer defaults in reverse list order, so a file placed first is
+ # evaluated last, after the brand palette it derives the chrome from.
theme:
light:
+ - html/chrome.scss
- brand
- html/theme.scss
dark:
+ - html/chrome.scss
- brand
- html/theme.scss
syntax-highlighting:
@@ -43,37 +84,4 @@ contributes:
- file: html/scripts/ordinal-dates.html
- file: html/scripts/a11y-fixes.html
- file: html/scripts/navbar-tooltips.html
- project:
- project:
- type: website
- output-dir: _site
- website:
- repo-actions:
- - edit
- - issue
- repo-link-target: _blank
- repo-link-rel: noopener noreferrer
- open-graph:
- locale: en_GB
- twitter-card:
- card-style: summary_large_image
- page-navigation: true
- back-to-top-navigation: true
- llms-txt: true
- search:
- location: navbar
- type: overlay
- navbar:
- background: dark
- foreground: light
- search: true
- page-footer:
- border: true
- background: dark
- foreground: light
- left: |
- Powered by [Quarto](https://quarto.org){target="_blank" rel="noopener noreferrer"}.
- center: >
- © []{#current-year} [Mickaël CANOUIL](https://mickael.canouil.fr){target="_blank" rel="noopener
- noreferrer"}.
- format: atelier-html
+source: mcanouil/quarto-atelier@0.9.0
diff --git a/docs/_extensions/mcanouil/atelier/html/chrome.scss b/docs/_extensions/mcanouil/atelier/html/chrome.scss
new file mode 100644
index 0000000..fe2aa86
--- /dev/null
+++ b/docs/_extensions/mcanouil/atelier/html/chrome.scss
@@ -0,0 +1,134 @@
+/*-- scss:defaults --*/
+
+// ===========================================================================
+// CHROME PALETTE
+// ===========================================================================
+// This file is listed before `brand` in the format's theme lists, which is
+// what lets it read the brand palette. Quarto emits user layer defaults in
+// reverse list order, so a file placed before brand has its defaults evaluated
+// after brand's, where $body-bg, $body-color, and $primary are all resolved,
+// and still ahead of every Quarto and Bootstrap `!default`. That is the only
+// point in the cascade where the chrome can be derived from the page and still
+// be handed to Quarto's own $navbar-*, $sidebar-*, and $footer-* variables.
+//
+// The chrome is the navbar, the page footer, and the sidebar: the bars that
+// frame the page rather than carry it.
+
+// How the chrome follows the colour scheme.
+//
+// auto Derived from the brand palette, so each bundle gets its own chrome
+// and the bars follow the colour-scheme toggle.
+// light Pinned to the light palette below in both schemes.
+// dark Pinned to the dark palette below in both schemes.
+$atelier-chrome: auto !default;
+
+@if not index((auto, light, dark), $atelier-chrome) {
+ @error "$atelier-chrome must be auto, light, or dark, but was #{$atelier-chrome}.";
+}
+
+// The pinned palettes, each a background, a foreground, and an accent that
+// every other chrome colour is derived from. Only the palette matching
+// $atelier-chrome is used, so pinning light leaves the dark values inert.
+$atelier-chrome-dark-bg: #1b242e !default;
+$atelier-chrome-dark-fg: #e8edf2 !default;
+$atelier-chrome-dark-accent: #7fa8c4 !default;
+
+$atelier-chrome-light-bg: #eef1f5 !default;
+$atelier-chrome-light-fg: #1b242e !default;
+$atelier-chrome-light-accent: #1f5f80 !default;
+
+// A project can drop `brand` from its theme list, in which case the page
+// variables are only defined in the Bootstrap layer that follows this one;
+// fall back to the Bootstrap defaults so `auto` still resolves.
+$atelier-chrome-page-bg: if(variable-exists(body-bg), $body-bg, #fff);
+$atelier-chrome-page-fg: if(variable-exists(body-color), $body-color, #212529);
+$atelier-chrome-page-accent: if(variable-exists(primary), $primary, #0d6efd);
+
+// In `auto` the bar is a light tint of the page rather than the page colour
+// itself, so it still reads as a bar without a hard colour break, and the
+// mix resolves per bundle: a paler paper in the light one, a lifted slate in
+// the dark one.
+$atelier-chrome-bg: if(
+ $atelier-chrome == dark,
+ $atelier-chrome-dark-bg,
+ if(
+ $atelier-chrome == light,
+ $atelier-chrome-light-bg,
+ mix($atelier-chrome-page-bg, $atelier-chrome-page-fg, 94%)
+ )
+) !default;
+
+// Both inks are run through Quarto's own `theme-contrast()`, which mixes a
+// colour towards black or white only until it clears the ratio asked of it and
+// returns it untouched otherwise. In `auto` that matters for the accent: a
+// brand primary is picked against the page, and the bar is a tint of the page,
+// so a primary sitting just above 4.5:1 on the page can fall under it here.
+// Setting either variable in a project skips the correction, since a `!default`
+// assignment is not evaluated at all once the variable is set.
+$atelier-chrome-fg: theme-contrast(
+ if(
+ $atelier-chrome == dark,
+ $atelier-chrome-dark-fg,
+ if(
+ $atelier-chrome == light,
+ $atelier-chrome-light-fg,
+ $atelier-chrome-page-fg
+ )
+ ),
+ $atelier-chrome-bg,
+ "AA"
+) !default;
+
+$atelier-chrome-accent: theme-contrast(
+ if(
+ $atelier-chrome == dark,
+ $atelier-chrome-dark-accent,
+ if(
+ $atelier-chrome == light,
+ $atelier-chrome-light-accent,
+ $atelier-chrome-page-accent
+ )
+ ),
+ $atelier-chrome-bg,
+ "AA"
+) !default;
+
+// Everything else follows from that triple, so a project re-points three
+// colours rather than eight.
+$atelier-chrome-surface: mix($atelier-chrome-bg, $atelier-chrome-fg, 90%) !default;
+$atelier-chrome-muted: mix($atelier-chrome-fg, $atelier-chrome-bg, 65%) !default;
+$atelier-chrome-accent-soft: rgba($atelier-chrome-accent, 0.16) !default;
+
+// A hairline between two surfaces, which is what the bar edges and the section
+// dividers want.
+$atelier-chrome-border: rgba($atelier-chrome-fg, 0.2) !default;
+
+// The boundary of a boxed control, which WCAG 1.4.11 asks 3:1 of. The weight
+// has to hold on a light bar as well as a dark one: at 0.4 it is 3.3:1 on the
+// dark palette but only 2.4:1 on the light one.
+$atelier-chrome-control-border: rgba($atelier-chrome-fg, 0.55) !default;
+
+// ===========================================================================
+// QUARTO CHROME VARIABLES
+// ===========================================================================
+// Handing the palette to Quarto's own variables is what makes the parts this
+// theme cannot reach from CSS come out right: the collapsed navbar's toggler
+// icon and the reader-mode toggle are SVGs with the foreground baked into the
+// markup, and the sidebar link, hover, and disabled colours are contrasted
+// against $sidebar-bg. These are plain assignments rather than defaults
+// because Quarto's own layer, which they have to beat, uses `!default`.
+$navbar-bg: $atelier-chrome-bg;
+$navbar-fg: $atelier-chrome-fg;
+$navbar-hl: $atelier-chrome-accent;
+
+// Quarto fades a hovered navbar link to `rgba($navbar-hl, 0.8)`, which mixes
+// the accent back into the bar and costs it about a third of its contrast;
+// hover at full strength instead, which is also what the sidebar does.
+$navbar-hover-color: $atelier-chrome-accent;
+
+$sidebar-bg: $atelier-chrome-bg;
+$sidebar-fg: $atelier-chrome-fg;
+
+$footer-bg: $atelier-chrome-bg;
+$footer-fg: $atelier-chrome-fg;
+$footer-border-color: $atelier-chrome-border;
diff --git a/docs/_extensions/mcanouil/atelier/html/theme.scss b/docs/_extensions/mcanouil/atelier/html/theme.scss
index aaa8f6a..98e9c7e 100644
--- a/docs/_extensions/mcanouil/atelier/html/theme.scss
+++ b/docs/_extensions/mcanouil/atelier/html/theme.scss
@@ -14,22 +14,62 @@ $enable-smooth-scroll: true !default;
@return mix($body-bg, $body-color, $weight);
}
+/*-- scss:mixins --*/
+
+// Dropdown menus render on both bars, each from its own tokens.
+@mixin atelier-dropdown($surface, $border, $fg, $accent, $accent-soft) {
+ .dropdown-menu {
+ background: $surface;
+ border: 1px solid $border;
+ border-radius: $border-radius-sm;
+ }
+
+ .dropdown-item {
+ color: $fg;
+ }
+
+ .dropdown-item:hover,
+ .dropdown-item:focus {
+ background: $accent-soft;
+ color: $accent;
+ }
+}
+
/*-- scss:rules --*/
// ===========================================================================
-// NAVBAR TOKENS (dark-pinned in both schemes)
+// CHROME TOKENS
// ===========================================================================
-// The navbar and footer are `background: dark` in both schemes, so their
-// surfaces must not follow the page scheme. These fixed tokens default to a
-// neutral slate; override them in a project stylesheet to match a site palette.
+// The chrome palette is resolved in `html/chrome.scss`, which follows the
+// colour scheme or pins to one of two fixed palettes depending on
+// `$atelier-chrome`. These tokens republish it as custom properties, which is
+// what the rules below read and what a project overrides for a single part of
+// a bar; re-point the Sass variables instead when the change should also reach
+// the colours Quarto bakes into its own markup.
:root {
- --atelier-navbar-bg: #1b242e;
- --atelier-navbar-surface: #223041;
- --atelier-navbar-fg: #e8edf2;
- --atelier-navbar-muted: #9db0c0;
- --atelier-navbar-accent: #7fa8c4;
- --atelier-navbar-accent-soft: rgba(127, 168, 196, 0.16);
- --atelier-navbar-border: rgba(232, 237, 242, 0.14);
+ --atelier-navbar-bg: #{$atelier-chrome-bg};
+ --atelier-navbar-surface: #{$atelier-chrome-surface};
+ --atelier-navbar-fg: #{$atelier-chrome-fg};
+ --atelier-navbar-muted: #{$atelier-chrome-muted};
+ --atelier-navbar-accent: #{$atelier-chrome-accent};
+ --atelier-navbar-accent-soft: #{$atelier-chrome-accent-soft};
+ --atelier-navbar-border: #{$atelier-chrome-border};
+
+ // A boxed control (a search field, a widget pill) needs a boundary that can
+ // be seen, where the hairline above only has to separate two surfaces.
+ --atelier-navbar-control-border: #{$atelier-chrome-control-border};
+
+ // A docked sidebar is the third bar, so its tokens default to the navbar
+ // ones: overriding the navbar palette carries the sidebar with it, and a
+ // project that wants the two to differ re-points these alone.
+ --atelier-sidebar-bg: var(--atelier-navbar-bg);
+ --atelier-sidebar-surface: var(--atelier-navbar-surface);
+ --atelier-sidebar-fg: var(--atelier-navbar-fg);
+ --atelier-sidebar-muted: var(--atelier-navbar-muted);
+ --atelier-sidebar-accent: var(--atelier-navbar-accent);
+ --atelier-sidebar-accent-soft: var(--atelier-navbar-accent-soft);
+ --atelier-sidebar-border: var(--atelier-navbar-border);
+ --atelier-sidebar-control-border: var(--atelier-navbar-control-border);
}
// ===========================================================================
@@ -181,20 +221,231 @@ html .panel-tabset > .tab-content {
}
// ===========================================================================
-// SIDEBAR + TOC
+// TOC
// ===========================================================================
-// Quarto marks the current page and section with .active but leaves them in
-// the sidebar body colour; surface them with the palette accent, and give the
-// margin TOC's active border the same accent instead of the baked grey.
-#quarto-sidebar .sidebar-item-container .active,
-#quarto-sidebar .sidebar-item-container .sidebar-link:hover,
-.sidebar-navigation .sidebar-item .active,
+// Quarto marks the current section with .active but leaves it in the body
+// colour, and gives its border the baked grey; the margin TOC sits on the page
+// surface, so both take the palette accent.
#TOC .active {
color: $primary;
+ border-left-color: $primary;
}
-#TOC .active {
- border-left-color: $primary;
+// ===========================================================================
+// SIDEBAR
+// ===========================================================================
+// `html/chrome.scss` hands the palette to `$sidebar-bg` and `$sidebar-fg`, so
+// the column and everything Quarto contrasts against it already match the
+// other two bars. What is left here is the treatment Quarto has no variable
+// for, plus the handful of colours it bakes past those two.
+//
+// Everything below is scoped to `body.docked`, the class Quarto adds when the
+// sidebar style is `docked`, which is also what raises these rules over the
+// Quarto rules they replace; only the sidebar edge, which Quarto draws with
+// `!important`, needs one of its own. A floating sidebar has no surface of its
+// own, and takes the chrome through Quarto's own rules alone.
+body.docked {
+ .sidebar.sidebar-navigation {
+ background-color: var(--atelier-sidebar-bg);
+ }
+
+ // `sidebar.border` defaults to true for a docked sidebar, and Quarto draws
+ // that edge from the baked $table-border-color with `!important`.
+ .sidebar.sidebar-navigation:not(.rollup) {
+ border-right: 1px solid var(--atelier-sidebar-border) !important;
+ }
+
+ #quarto-sidebar,
+ .sidebar-item-container {
+ color: var(--atelier-sidebar-fg);
+ }
+
+ .sidebar-item-container:hover,
+ .sidebar-item-container:focus-within,
+ .sidebar-item-container .active,
+ .sidebar-item-container .sidebar-link > code {
+ color: var(--atelier-sidebar-accent);
+ }
+
+ .sidebar-item-container.disabled {
+ color: var(--atelier-sidebar-muted);
+ }
+
+ // The current page reads as a pill rather than as a colour change alone,
+ // which matches the navbar dropdown treatment.
+ .sidebar-item-container .sidebar-link.active {
+ background: var(--atelier-sidebar-accent-soft);
+ border-radius: $border-radius-sm;
+ padding: 0.15rem 0.4rem;
+ margin: -0.15rem -0.4rem;
+ font-weight: 600;
+ }
+
+ // A sidebar entry with text and no href or contents is a group label; Quarto
+ // renders it as a bare span, in the same colour as a link.
+ .sidebar-item > .menu-text {
+ color: var(--atelier-sidebar-muted);
+ }
+
+ // Bootstrap draws an
from currentColor at 25% opacity, which on the dark
+ // column is all but invisible; use the border token at full strength.
+ .sidebar-navigation .sidebar-divider {
+ border-top-color: var(--atelier-sidebar-border);
+ opacity: 1;
+ }
+
+ .sidebar-item-toggle {
+ color: var(--atelier-sidebar-muted);
+ }
+
+ .sidebar-item-toggle:hover {
+ color: var(--atelier-sidebar-accent);
+ }
+
+ // The header (logo and title) only renders when the project has no navbar.
+ .sidebar-title {
+ color: var(--atelier-sidebar-fg);
+ }
+
+ .sidebar-title > a:hover,
+ .sidebar-title > a:focus-visible {
+ color: var(--atelier-sidebar-accent);
+ }
+
+ // Quarto renders the sidebar tools inside `.sidebar-title` whenever the
+ // sidebar has a title and the project has no navbar, as an inline-flex
+ // pulled up 6px, which lands the colour-scheme toggle on the title's line.
+ // A block-level flex row breaks it onto its own line, which the document
+ // order then places above the search field. Nothing here is forced: the
+ // gitlink extension stacks the same container into a column from an id
+ // selector when its widget is one of the tools.
+ .sidebar-title .sidebar-tools-main {
+ display: flex;
+ justify-content: flex-start;
+ margin-top: 0.5rem;
+ }
+
+ // `sidebar.align` reaches the header as a text class, which a flex row does
+ // not follow. Bootstrap has no `text-left`, so the rule above covers the
+ // left-aligned case on its own.
+ .sidebar-header.text-center .sidebar-title .sidebar-tools-main {
+ justify-content: center;
+ }
+
+ .sidebar-header.text-end .sidebar-title .sidebar-tools-main {
+ justify-content: flex-end;
+ }
+
+ // Quarto dims the sidebar tools to 0.7, which on the dark column drops the
+ // colour-scheme toggle and the repo links below the contrast floor.
+ .sidebar-navigation .quarto-navigation-tool {
+ color: var(--atelier-sidebar-fg);
+ opacity: 1;
+ }
+
+ .sidebar-navigation .quarto-navigation-tool:hover,
+ .sidebar-navigation .quarto-navigation-tool:focus-visible {
+ color: var(--atelier-sidebar-accent);
+ }
+
+ // A sidebar tool with a `menu` opens a Bootstrap dropdown on the dark column.
+ .sidebar-navigation {
+ @include atelier-dropdown(
+ var(--atelier-sidebar-surface),
+ var(--atelier-sidebar-border),
+ var(--atelier-sidebar-fg),
+ var(--atelier-sidebar-accent),
+ var(--atelier-sidebar-accent-soft)
+ );
+ }
+
+ // Inline sidebar search (`website.sidebar.search: true` with a textbox
+ // search). Quarto colours the input from $body-color through a four-class
+ // rule, which matches the sidebar surface in one of the two schemes and hides
+ // the text and the caret; the magnifier and the spinner come from
+ // $input-color at half opacity through another. Both chains have to be named
+ // here to be outranked.
+ .sidebar-search .aa-Form {
+ background-color: var(--atelier-sidebar-surface);
+ border-color: var(--atelier-sidebar-control-border);
+ color: var(--atelier-sidebar-fg);
+ }
+
+ .sidebar-search .aa-Form .aa-InputWrapper .aa-Input {
+ color: var(--atelier-sidebar-fg);
+ caret-color: var(--atelier-sidebar-fg);
+ }
+
+ .sidebar-search .aa-Form .aa-InputWrapper .aa-Input::placeholder {
+ color: var(--atelier-sidebar-muted);
+ opacity: 1;
+ }
+
+ .sidebar-search .aa-Form .aa-InputWrapperPrefix svg {
+ color: var(--atelier-sidebar-muted);
+ opacity: 1;
+ }
+
+ // Overlay search reaches the sidebar as a button rather than as a field.
+ // Quarto inks that button only inside `.sidebar-tools-*`, from a $sidebar-fg
+ // contrasted against the surface it painted rather than against ours, and
+ // through a selector carrying the search id; match the id to outrank it.
+ .sidebar-navigation #quarto-search .aa-DetachedSearchButton svg {
+ color: var(--atelier-sidebar-fg);
+ }
+
+ .sidebar-navigation #quarto-search .aa-DetachedSearchButton:hover svg {
+ color: var(--atelier-sidebar-accent);
+ }
+
+ // The mobile bar carrying the sidebar toggle, the page title, and the search
+ // button. Quarto paints it with $sidebar-bg, the surface this file replaces.
+ .quarto-secondary-nav {
+ background: var(--atelier-sidebar-bg);
+ border-bottom: 1px solid var(--atelier-sidebar-border);
+ }
+
+ .quarto-secondary-nav .quarto-btn-toggle,
+ .quarto-secondary-nav .quarto-search-button,
+ .quarto-secondary-nav-title,
+ .quarto-secondary-nav .quarto-page-breadcrumbs,
+ .quarto-secondary-nav .quarto-page-breadcrumbs a {
+ color: var(--atelier-sidebar-fg);
+ }
+
+ .quarto-secondary-nav .quarto-btn-toggle:hover,
+ .quarto-secondary-nav .quarto-search-button:hover,
+ .quarto-secondary-nav .quarto-page-breadcrumbs a:hover {
+ color: var(--atelier-sidebar-accent);
+ }
+
+ .quarto-secondary-nav .breadcrumb-item::before {
+ color: var(--atelier-sidebar-muted);
+ }
+
+ // The page focus ring is $primary, which on the dark column is far too dim;
+ // keep its geometry and swap the colour for the sidebar accent.
+ :is(#quarto-sidebar, .quarto-secondary-nav) :is(a, button):focus-visible {
+ outline-color: var(--atelier-sidebar-accent);
+ }
+
+ // The page scrollbar rules are unscoped, so without these the dark column
+ // would carry a page-coloured bar.
+ #quarto-sidebar {
+ scrollbar-color: var(--atelier-sidebar-muted) var(--atelier-sidebar-surface);
+
+ &::-webkit-scrollbar-track {
+ background: var(--atelier-sidebar-surface);
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: var(--atelier-sidebar-muted);
+ }
+
+ &::-webkit-scrollbar-thumb:hover {
+ background: var(--atelier-sidebar-accent);
+ }
+ }
}
// Quarto's floating back-to-top pill has no edge on tinted surfaces; give it
@@ -204,67 +455,150 @@ html .panel-tabset > .tab-content {
}
// ===========================================================================
-// NAVBAR (dark-pinned)
+// NAVBAR
// ===========================================================================
-// Uses the fixed --atelier-navbar-* tokens so the bar, dropdowns, and widgets
-// stay dark in both schemes; !important beats Quarto's `.navbar a` colour.
+// The bar itself, its links, and its tools are painted by Quarto from the
+// `$navbar-*` variables `html/chrome.scss` sets. Only the bottom edge, which
+// Quarto does not draw at all, and the dropdown menus are left.
.navbar {
- background: var(--atelier-navbar-bg) !important;
border-bottom: 1px solid var(--atelier-navbar-border);
-}
-
-.navbar-brand,
-.navbar .nav-link {
- color: var(--atelier-navbar-fg) !important;
-}
-
-.navbar .nav-link:hover,
-.navbar .nav-link.active {
- color: var(--atelier-navbar-accent) !important;
-}
-
-.navbar .dropdown-menu {
- background: var(--atelier-navbar-surface);
- border: 1px solid var(--atelier-navbar-border);
- border-radius: $border-radius-sm;
-}
-
-.navbar .dropdown-item {
- color: var(--atelier-navbar-fg);
-}
-.navbar .dropdown-item:hover,
-.navbar .dropdown-item:focus,
-.navbar .dropdown-item:focus-visible {
- background: var(--atelier-navbar-accent-soft);
- color: var(--atelier-navbar-accent);
+ @include atelier-dropdown(
+ var(--atelier-navbar-surface),
+ var(--atelier-navbar-border),
+ var(--atelier-navbar-fg),
+ var(--atelier-navbar-accent),
+ var(--atelier-navbar-accent-soft)
+ );
}
-// The search button and colour-scheme toggle pill styling ships with the
-// gitlink widget (widget.css and widget-navbar-tools.css via
-// `widget.style-navbar-tools`); bridge the fixed navbar tokens onto the
+// The pill visuals on the search button and the colour-scheme toggle, the
+// border and its hover fill, ship with the gitlink widget
+// (widget-navbar-tools.css via `widget.style-navbar-tools`); their geometry
+// comes from the control tokens below. Bridge the navbar tokens onto the
// widget's own custom properties so the pill, trigger, and dropdown match the
-// dark-pinned navbar. Inert when the gitlink extension is not installed.
+// bar they sit on. Inert when the gitlink extension is not installed.
.navbar {
- --gitlink-widget-border: var(--atelier-navbar-border);
+ --gitlink-widget-border: var(--atelier-navbar-control-border);
--gitlink-widget-accent: var(--atelier-navbar-accent);
--gitlink-widget-accent-soft: var(--atelier-navbar-accent-soft);
--gitlink-widget-menu-bg: var(--atelier-navbar-surface);
--gitlink-widget-menu-fg: var(--atelier-navbar-fg);
}
+// The same widget can render in the sidebar tools, where it takes the sidebar
+// tokens instead.
+body.docked .sidebar-navigation {
+ --gitlink-widget-border: var(--atelier-sidebar-control-border);
+ --gitlink-widget-accent: var(--atelier-sidebar-accent);
+ --gitlink-widget-accent-soft: var(--atelier-sidebar-accent-soft);
+ --gitlink-widget-menu-bg: var(--atelier-sidebar-surface);
+ --gitlink-widget-menu-fg: var(--atelier-sidebar-fg);
+}
+
// Structure ships with the extension's widget.css; match the radius of the
// navbar dropdown menus above.
body .navbar .gitlink-widget-dropdown {
border-radius: $border-radius-sm;
}
+// ===========================================================================
+// NAVBAR CONTROL SIZING
+// ===========================================================================
+// The search button, the colour-scheme toggle, and a `website.navbar.tools`
+// icon are three Quarto components with three box models: a 40px detached
+// button carrying a 26px glyph, an inline `` with no height of
+// its own, and a `bi` icon at the link font size. Pin all three to one control
+// box so they read as one set on the bar.
+//
+// The defaults are the numbers the gitlink widget applies (widget.css), so the
+// bar looks the same with and without that extension and neither stylesheet has
+// to win the cascade for the geometry to hold.
+:root {
+ --atelier-navbar-control-size: 2rem;
+ --atelier-navbar-control-icon-size: 1rem;
+ --atelier-navbar-control-gap: 0.4rem;
+
+ // The magnifier is the one glyph on the bar that does not fill its own box:
+ // Quarto's `aa-SubmitIcon` draws in 20 units of a 24-unit viewBox, where the
+ // colour-scheme glyph and the `bi` tool icons paint edge to edge. Scaling its
+ // box by 24/20 is what puts the ink at the icon size rather than the box.
+ --atelier-navbar-search-icon-size: calc(var(--atelier-navbar-control-icon-size) * 1.2);
+}
+
+.navbar {
+ // Quarto hands the search the whole free space with `margin-left: auto` below
+ // the expand breakpoint and 0.25rem above it; the control gap replaces both,
+ // so the search keeps the same distance from the tools at every width. Scoped
+ // to `.type-overlay`, the search this project type configures: a `textbox`
+ // search in the navbar is a field rather than a control box, and Quarto's own
+ // margins are what place it.
+ #quarto-search.type-overlay {
+ display: inline-flex;
+ align-items: center;
+ margin-left: var(--atelier-navbar-control-gap);
+ }
+
+ .quarto-navbar-tools {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--atelier-navbar-control-gap);
+ }
+
+ // Quarto pins the overlay autocomplete to a 40px box, wider than every other
+ // navbar control; let the button size it instead.
+ #quarto-search.type-overlay .aa-Autocomplete {
+ width: auto;
+ }
+
+ // `min-width` rather than `width`, so a tool with a `menu`, which keeps its
+ // dropdown caret in the navbar, can grow past the square rather than clip it.
+ #quarto-search .aa-DetachedSearchButton,
+ .quarto-navbar-tools .quarto-navigation-tool {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: var(--atelier-navbar-control-size);
+ height: var(--atelier-navbar-control-size);
+ // !important is required: Bootstrap's .px-1 utility on the toggle is itself
+ // !important. The inline padding only shows on a control wide enough to
+ // exceed the square, which is the caret case above.
+ padding: 0 0.25rem !important;
+ }
+
+ // Quarto leaves the glyph in a block wrapper whose height is a line box, so it
+ // is taller than the icon and splits the leftover unevenly around it, dropping
+ // the glyph off the button's centre; a flex wrapper hugs the icon instead.
+ #quarto-search .aa-DetachedSearchButtonIcon {
+ display: flex;
+ align-items: center;
+ }
+
+ // Quarto draws the overlay glyph at 26px, against the 1rem of the toggle glyph
+ // and the tool icons; `.aa-Autocomplete` is in the selector to match the
+ // specificity of that rule, which this then wins on order. `display: block`
+ // drops the inline baseline gap under the icon.
+ #quarto-search.type-overlay .aa-Autocomplete .aa-DetachedSearchButtonIcon svg {
+ display: block;
+ width: var(--atelier-navbar-search-icon-size);
+ height: var(--atelier-navbar-search-icon-size);
+ }
+
+ // Quarto gives the search button no hover colour at all, where it takes the
+ // colour-scheme toggle to the accent; match it.
+ #quarto-search .aa-DetachedSearchButton:hover .aa-DetachedSearchButtonIcon svg,
+ #quarto-search .aa-DetachedSearchButton:focus-visible .aa-DetachedSearchButtonIcon svg {
+ color: var(--atelier-navbar-accent);
+ }
+}
+
// ===========================================================================
// COLLAPSED NAVBAR (mobile)
// ===========================================================================
-// Below the expand breakpoint, keep the collapsed menu a wrapping row and stop
+// Below the expand breakpoint, keep the collapsed menu a wrapping row, stop
// Bootstrap's navbar-nav-scroll (max-height + overflow-y) from clipping an
-// absolutely-positioned dropdown; re-anchor navbar dropdowns to absolute.
+// absolutely-positioned dropdown by re-anchoring navbar dropdowns to absolute,
+// and regroup the bar as toggler, brand, then tools.
@media (max-width: 991.98px) {
.navbar .navbar-collapse .navbar-nav {
flex-direction: row;
@@ -285,22 +619,27 @@ body .navbar .gitlink-widget-dropdown {
top: 100%;
left: 0;
}
+
+ // Quarto orders the collapsed bar as toggler, brand, tools, search and pins
+ // the brand's inline margins to 0 !important; with the search margin cut back
+ // to the control gap above, the free space has nowhere to go and spreads the
+ // four controls across the bar. Give the brand the auto margins instead: the
+ // free space lands either side of it, leaving the toggler left, the brand
+ // centred, and the toggle and the search grouped right.
+ // !important is required to beat Quarto's own !important margins.
+ .navbar.navbar-expand-lg .navbar-container > .navbar-brand-container {
+ margin-inline: auto !important;
+ }
}
// ===========================================================================
-// FOOTER (dark-pinned)
+// FOOTER
// ===========================================================================
-// `page-footer.background: dark` paints the footer with Bootstrap's $dark,
-// which need not match the navbar tokens; repaint it so both dark-pinned bars
-// share one surface, and recolour links, which otherwise keep the page link
-// colour on the dark surface.
-.nav-footer {
- background: var(--atelier-navbar-bg) !important;
- border-top: 1px solid var(--atelier-navbar-border);
-}
-
+// Quarto paints the surface, the text, the links, and the top edge from the
+// chrome palette, the edge because `html/chrome.scss` sets
+// `$footer-border-color` alongside the rest. Only the link treatment is left:
+// Quarto underlines nothing and gives no hover colour of its own.
.nav-footer a {
- color: var(--atelier-navbar-fg);
text-decoration: none;
}
@@ -386,8 +725,8 @@ body .navbar .gitlink-widget-dropdown {
// TOOLTIPS
// ===========================================================================
// Bootstrap tooltips plus the tippy theme used by navbar-tooltips.html; both
-// pinned to the navbar tokens so they match the dark-pinned navbar in either
-// scheme.
+// take the navbar tokens, since every control they are bound to sits on the
+// navbar.
.tooltip {
--bs-tooltip-bg: var(--atelier-navbar-bg);
--bs-tooltip-color: var(--atelier-navbar-fg);
@@ -420,8 +759,9 @@ body .navbar .gitlink-widget-dropdown {
// THEME TOGGLE (sun in light scheme, moon in dark scheme)
// ===========================================================================
// Quarto renders an empty ; the glyph is a mask-image so it
-// follows currentColor and picks up the navbar-tool colour. The pill container
-// itself ships with the gitlink widget; this only draws the glyph.
+// follows currentColor and picks up the navbar-tool colour. The box around it
+// comes from the control tokens above, and its pill border, when there is one,
+// from the gitlink widget; this only draws the glyph.
$atelier-icon-sun: url('data:image/svg+xml,');
$atelier-icon-moon: url('data:image/svg+xml,');
@@ -463,14 +803,6 @@ $atelier-icon-moon: url('data:image/svg+xml,