From 6275672d3a078734b1cf66d96bb6015b8f62c2e1 Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Tue, 10 Sep 2024 16:30:56 +0200 Subject: [PATCH 01/16] feat: add layers for built-in styles --- packages/starlight/components/Page.astro | 13 +- packages/starlight/style/layers.css | 1 + packages/starlight/style/props.css | 358 ++++++++++++----------- packages/starlight/style/reset.css | 82 +++--- packages/starlight/style/shiki.css | 26 +- packages/starlight/style/util.css | 100 +++---- 6 files changed, 300 insertions(+), 280 deletions(-) create mode 100644 packages/starlight/style/layers.css diff --git a/packages/starlight/components/Page.astro b/packages/starlight/components/Page.astro index 0ab90d1bacb..09f0e280a40 100644 --- a/packages/starlight/components/Page.astro +++ b/packages/starlight/components/Page.astro @@ -1,6 +1,12 @@ --- import type { Props } from '../props'; +// TODO(HiDeoo) +import 'virtual:starlight/user-css'; + +// TODO(HiDeoo) +import '../style/layers.css'; + // Built-in CSS styles. import '../style/props.css'; import '../style/reset.css'; @@ -16,6 +22,8 @@ import Footer from 'virtual:starlight/components/Footer'; import Head from 'virtual:starlight/components/Head'; import Header from 'virtual:starlight/components/Header'; import Hero from 'virtual:starlight/components/Hero'; +// TODO(HiDeoo) +// TODO(HiDeoo) Maybe we can even move the definition to outside of the Markdown components import MarkdownContent from 'virtual:starlight/components/MarkdownContent'; import PageFrame from 'virtual:starlight/components/PageFrame'; import PageSidebar from 'virtual:starlight/components/PageSidebar'; @@ -25,11 +33,14 @@ import SkipLink from 'virtual:starlight/components/SkipLink'; import ThemeProvider from 'virtual:starlight/components/ThemeProvider'; import TwoColumnContent from 'virtual:starlight/components/TwoColumnContent'; +// TODO(HiDeoo) +// TODO(HiDeoo) Maybe we can move that too // Remark component CSS (needs to override `MarkdownContent.astro`) import '../style/asides.css'; +// FIXME(HiDeoo) // Important that this is the last import so it can override built-in styles. -import 'virtual:starlight/user-css'; +// import 'virtual:starlight/user-css'; const pagefindEnabled = Astro.props.entry.slug !== '404' && diff --git a/packages/starlight/style/layers.css b/packages/starlight/style/layers.css new file mode 100644 index 00000000000..4f547415b38 --- /dev/null +++ b/packages/starlight/style/layers.css @@ -0,0 +1 @@ +@layer starlight.base, starlight.reset, starlight.shiki, starlight.utils; diff --git a/packages/starlight/style/props.css b/packages/starlight/style/props.css index 09c0305d110..83eafa9b0e4 100644 --- a/packages/starlight/style/props.css +++ b/packages/starlight/style/props.css @@ -1,184 +1,186 @@ -:root, -::backdrop { - /* Colors (dark mode) */ - --sl-color-white: hsl(0, 0%, 100%); /* “white” */ - --sl-color-gray-1: hsl(224, 20%, 94%); - --sl-color-gray-2: hsl(224, 6%, 77%); - --sl-color-gray-3: hsl(224, 6%, 56%); - --sl-color-gray-4: hsl(224, 7%, 36%); - --sl-color-gray-5: hsl(224, 10%, 23%); - --sl-color-gray-6: hsl(224, 14%, 16%); - --sl-color-black: hsl(224, 10%, 10%); - - --sl-hue-orange: 41; - --sl-color-orange-low: hsl(var(--sl-hue-orange), 39%, 22%); - --sl-color-orange: hsl(var(--sl-hue-orange), 82%, 63%); - --sl-color-orange-high: hsl(var(--sl-hue-orange), 82%, 87%); - --sl-hue-green: 101; - --sl-color-green-low: hsl(var(--sl-hue-green), 39%, 22%); - --sl-color-green: hsl(var(--sl-hue-green), 82%, 63%); - --sl-color-green-high: hsl(var(--sl-hue-green), 82%, 80%); - --sl-hue-blue: 234; - --sl-color-blue-low: hsl(var(--sl-hue-blue), 54%, 20%); - --sl-color-blue: hsl(var(--sl-hue-blue), 100%, 60%); - --sl-color-blue-high: hsl(var(--sl-hue-blue), 100%, 87%); - --sl-hue-purple: 281; - --sl-color-purple-low: hsl(var(--sl-hue-purple), 39%, 22%); - --sl-color-purple: hsl(var(--sl-hue-purple), 82%, 63%); - --sl-color-purple-high: hsl(var(--sl-hue-purple), 82%, 89%); - --sl-hue-red: 339; - --sl-color-red-low: hsl(var(--sl-hue-red), 39%, 22%); - --sl-color-red: hsl(var(--sl-hue-red), 82%, 63%); - --sl-color-red-high: hsl(var(--sl-hue-red), 82%, 87%); - - --sl-color-accent-low: hsl(224, 54%, 20%); - --sl-color-accent: hsl(224, 100%, 60%); - --sl-color-accent-high: hsl(224, 100%, 85%); - - --sl-color-text: var(--sl-color-gray-2); - --sl-color-text-accent: var(--sl-color-accent-high); - --sl-color-text-invert: var(--sl-color-accent-low); - --sl-color-bg: var(--sl-color-black); - --sl-color-bg-nav: var(--sl-color-gray-6); - --sl-color-bg-sidebar: var(--sl-color-gray-6); - --sl-color-bg-inline-code: var(--sl-color-gray-5); - --sl-color-bg-accent: var(--sl-color-accent-high); - --sl-color-hairline-light: var(--sl-color-gray-5); - --sl-color-hairline: var(--sl-color-gray-6); - --sl-color-hairline-shade: var(--sl-color-black); - - --sl-color-backdrop-overlay: hsla(223, 13%, 10%, 0.66); - - /* Shadows (dark mode) */ - --sl-shadow-sm: 0px 1px 1px hsla(0, 0%, 0%, 0.12), 0px 2px 1px hsla(0, 0%, 0%, 0.24); - --sl-shadow-md: 0px 8px 4px hsla(0, 0%, 0%, 0.08), 0px 5px 2px hsla(0, 0%, 0%, 0.08), - 0px 3px 2px hsla(0, 0%, 0%, 0.12), 0px 1px 1px hsla(0, 0%, 0%, 0.15); - --sl-shadow-lg: 0px 25px 7px hsla(0, 0%, 0%, 0.03), 0px 16px 6px hsla(0, 0%, 0%, 0.1), - 0px 9px 5px hsla(223, 13%, 10%, 0.33), 0px 4px 4px hsla(0, 0%, 0%, 0.75), - 0px 4px 2px hsla(0, 0%, 0%, 0.25); - - /* Text size and line height */ - --sl-text-2xs: 0.75rem; /* 12px */ - --sl-text-xs: 0.8125rem; /* 13px */ - --sl-text-sm: 0.875rem; /* 14px */ - --sl-text-base: 1rem; /* 16px */ - --sl-text-lg: 1.125rem; /* 18px */ - --sl-text-xl: 1.25rem; /* 20px */ - --sl-text-2xl: 1.5rem; /* 24px */ - --sl-text-3xl: 1.8125rem; /* 29px */ - --sl-text-4xl: 2.1875rem; /* 35px */ - --sl-text-5xl: 2.625rem; /* 42px */ - --sl-text-6xl: 4rem; /* 64px */ - - --sl-text-body: var(--sl-text-base); - --sl-text-body-sm: var(--sl-text-xs); - --sl-text-code: var(--sl-text-sm); - --sl-text-code-sm: var(--sl-text-xs); - --sl-text-h1: var(--sl-text-4xl); - --sl-text-h2: var(--sl-text-3xl); - --sl-text-h3: var(--sl-text-2xl); - --sl-text-h4: var(--sl-text-xl); - --sl-text-h5: var(--sl-text-lg); - - --sl-line-height: 1.75; - --sl-line-height-headings: 1.2; - - --sl-font-system: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, - 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; - --sl-font-system-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', - 'Courier New', monospace; - --__sl-font: var(--sl-font, var(--sl-font-system)), var(--sl-font-system); - --__sl-font-mono: var(--sl-font-mono, var(--sl-font-system-mono)), var(--sl-font-system-mono); - - /** Key layout values */ - --sl-nav-height: 3.5rem; - --sl-nav-pad-x: 1rem; - --sl-nav-pad-y: 0.75rem; - --sl-mobile-toc-height: 3rem; - --sl-sidebar-width: 18.75rem; - --sl-sidebar-pad-x: 1rem; - --sl-content-width: 45rem; - --sl-content-pad-x: 1rem; - --sl-menu-button-size: 2rem; - --sl-nav-gap: var(--sl-content-pad-x); - /* Offset required to show outline inside an element instead of round the outside */ - --sl-outline-offset-inside: -0.1875rem; - - /* Global z-index values */ - --sl-z-index-toc: 4; - --sl-z-index-menu: 5; - --sl-z-index-navbar: 10; - --sl-z-index-skiplink: 20; -} +@layer starlight.base { + :root, + ::backdrop { + /* Colors (dark mode) */ + --sl-color-white: hsl(0, 0%, 100%); /* “white” */ + --sl-color-gray-1: hsl(224, 20%, 94%); + --sl-color-gray-2: hsl(224, 6%, 77%); + --sl-color-gray-3: hsl(224, 6%, 56%); + --sl-color-gray-4: hsl(224, 7%, 36%); + --sl-color-gray-5: hsl(224, 10%, 23%); + --sl-color-gray-6: hsl(224, 14%, 16%); + --sl-color-black: hsl(224, 10%, 10%); + + --sl-hue-orange: 41; + --sl-color-orange-low: hsl(var(--sl-hue-orange), 39%, 22%); + --sl-color-orange: hsl(var(--sl-hue-orange), 82%, 63%); + --sl-color-orange-high: hsl(var(--sl-hue-orange), 82%, 87%); + --sl-hue-green: 101; + --sl-color-green-low: hsl(var(--sl-hue-green), 39%, 22%); + --sl-color-green: hsl(var(--sl-hue-green), 82%, 63%); + --sl-color-green-high: hsl(var(--sl-hue-green), 82%, 80%); + --sl-hue-blue: 234; + --sl-color-blue-low: hsl(var(--sl-hue-blue), 54%, 20%); + --sl-color-blue: hsl(var(--sl-hue-blue), 100%, 60%); + --sl-color-blue-high: hsl(var(--sl-hue-blue), 100%, 87%); + --sl-hue-purple: 281; + --sl-color-purple-low: hsl(var(--sl-hue-purple), 39%, 22%); + --sl-color-purple: hsl(var(--sl-hue-purple), 82%, 63%); + --sl-color-purple-high: hsl(var(--sl-hue-purple), 82%, 89%); + --sl-hue-red: 339; + --sl-color-red-low: hsl(var(--sl-hue-red), 39%, 22%); + --sl-color-red: hsl(var(--sl-hue-red), 82%, 63%); + --sl-color-red-high: hsl(var(--sl-hue-red), 82%, 87%); + + --sl-color-accent-low: hsl(224, 54%, 20%); + --sl-color-accent: hsl(224, 100%, 60%); + --sl-color-accent-high: hsl(224, 100%, 85%); + + --sl-color-text: var(--sl-color-gray-2); + --sl-color-text-accent: var(--sl-color-accent-high); + --sl-color-text-invert: var(--sl-color-accent-low); + --sl-color-bg: var(--sl-color-black); + --sl-color-bg-nav: var(--sl-color-gray-6); + --sl-color-bg-sidebar: var(--sl-color-gray-6); + --sl-color-bg-inline-code: var(--sl-color-gray-5); + --sl-color-bg-accent: var(--sl-color-accent-high); + --sl-color-hairline-light: var(--sl-color-gray-5); + --sl-color-hairline: var(--sl-color-gray-6); + --sl-color-hairline-shade: var(--sl-color-black); + + --sl-color-backdrop-overlay: hsla(223, 13%, 10%, 0.66); + + /* Shadows (dark mode) */ + --sl-shadow-sm: 0px 1px 1px hsla(0, 0%, 0%, 0.12), 0px 2px 1px hsla(0, 0%, 0%, 0.24); + --sl-shadow-md: 0px 8px 4px hsla(0, 0%, 0%, 0.08), 0px 5px 2px hsla(0, 0%, 0%, 0.08), + 0px 3px 2px hsla(0, 0%, 0%, 0.12), 0px 1px 1px hsla(0, 0%, 0%, 0.15); + --sl-shadow-lg: 0px 25px 7px hsla(0, 0%, 0%, 0.03), 0px 16px 6px hsla(0, 0%, 0%, 0.1), + 0px 9px 5px hsla(223, 13%, 10%, 0.33), 0px 4px 4px hsla(0, 0%, 0%, 0.75), + 0px 4px 2px hsla(0, 0%, 0%, 0.25); + + /* Text size and line height */ + --sl-text-2xs: 0.75rem; /* 12px */ + --sl-text-xs: 0.8125rem; /* 13px */ + --sl-text-sm: 0.875rem; /* 14px */ + --sl-text-base: 1rem; /* 16px */ + --sl-text-lg: 1.125rem; /* 18px */ + --sl-text-xl: 1.25rem; /* 20px */ + --sl-text-2xl: 1.5rem; /* 24px */ + --sl-text-3xl: 1.8125rem; /* 29px */ + --sl-text-4xl: 2.1875rem; /* 35px */ + --sl-text-5xl: 2.625rem; /* 42px */ + --sl-text-6xl: 4rem; /* 64px */ + + --sl-text-body: var(--sl-text-base); + --sl-text-body-sm: var(--sl-text-xs); + --sl-text-code: var(--sl-text-sm); + --sl-text-code-sm: var(--sl-text-xs); + --sl-text-h1: var(--sl-text-4xl); + --sl-text-h2: var(--sl-text-3xl); + --sl-text-h3: var(--sl-text-2xl); + --sl-text-h4: var(--sl-text-xl); + --sl-text-h5: var(--sl-text-lg); + + --sl-line-height: 1.75; + --sl-line-height-headings: 1.2; + + --sl-font-system: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --sl-font-system-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', + 'Courier New', monospace; + --__sl-font: var(--sl-font, var(--sl-font-system)), var(--sl-font-system); + --__sl-font-mono: var(--sl-font-mono, var(--sl-font-system-mono)), var(--sl-font-system-mono); + + /** Key layout values */ + --sl-nav-height: 3.5rem; + --sl-nav-pad-x: 1rem; + --sl-nav-pad-y: 0.75rem; + --sl-mobile-toc-height: 3rem; + --sl-sidebar-width: 18.75rem; + --sl-sidebar-pad-x: 1rem; + --sl-content-width: 45rem; + --sl-content-pad-x: 1rem; + --sl-menu-button-size: 2rem; + --sl-nav-gap: var(--sl-content-pad-x); + /* Offset required to show outline inside an element instead of round the outside */ + --sl-outline-offset-inside: -0.1875rem; + + /* Global z-index values */ + --sl-z-index-toc: 4; + --sl-z-index-menu: 5; + --sl-z-index-navbar: 10; + --sl-z-index-skiplink: 20; + } -:root[data-theme='light'], -[data-theme='light'] ::backdrop { - /* Colours (light mode) */ - --sl-color-white: hsl(224, 10%, 10%); - --sl-color-gray-1: hsl(224, 14%, 16%); - --sl-color-gray-2: hsl(224, 10%, 23%); - --sl-color-gray-3: hsl(224, 7%, 36%); - --sl-color-gray-4: hsl(224, 6%, 56%); - --sl-color-gray-5: hsl(224, 6%, 77%); - --sl-color-gray-6: hsl(224, 20%, 94%); - --sl-color-gray-7: hsl(224, 19%, 97%); - --sl-color-black: hsl(0, 0%, 100%); - - --sl-color-orange-high: hsl(var(--sl-hue-orange), 80%, 25%); - --sl-color-orange: hsl(var(--sl-hue-orange), 90%, 60%); - --sl-color-orange-low: hsl(var(--sl-hue-orange), 90%, 88%); - --sl-color-green-high: hsl(var(--sl-hue-green), 80%, 22%); - --sl-color-green: hsl(var(--sl-hue-green), 90%, 46%); - --sl-color-green-low: hsl(var(--sl-hue-green), 85%, 90%); - --sl-color-blue-high: hsl(var(--sl-hue-blue), 80%, 30%); - --sl-color-blue: hsl(var(--sl-hue-blue), 90%, 60%); - --sl-color-blue-low: hsl(var(--sl-hue-blue), 88%, 90%); - --sl-color-purple-high: hsl(var(--sl-hue-purple), 90%, 30%); - --sl-color-purple: hsl(var(--sl-hue-purple), 90%, 60%); - --sl-color-purple-low: hsl(var(--sl-hue-purple), 80%, 90%); - --sl-color-red-high: hsl(var(--sl-hue-red), 80%, 30%); - --sl-color-red: hsl(var(--sl-hue-red), 90%, 60%); - --sl-color-red-low: hsl(var(--sl-hue-red), 80%, 90%); - - --sl-color-accent-high: hsl(234, 80%, 30%); - --sl-color-accent: hsl(234, 90%, 60%); - --sl-color-accent-low: hsl(234, 88%, 90%); - - --sl-color-text-accent: var(--sl-color-accent); - --sl-color-text-invert: var(--sl-color-black); - --sl-color-bg-nav: var(--sl-color-gray-7); - --sl-color-bg-sidebar: var(--sl-color-bg); - --sl-color-bg-inline-code: var(--sl-color-gray-6); - --sl-color-bg-accent: var(--sl-color-accent); - --sl-color-hairline-light: var(--sl-color-gray-6); - --sl-color-hairline-shade: var(--sl-color-gray-6); - - --sl-color-backdrop-overlay: hsla(225, 9%, 36%, 0.66); - - /* Shadows (light mode) */ - --sl-shadow-sm: 0px 1px 1px hsla(0, 0%, 0%, 0.06), 0px 2px 1px hsla(0, 0%, 0%, 0.06); - --sl-shadow-md: 0px 8px 4px hsla(0, 0%, 0%, 0.03), 0px 5px 2px hsla(0, 0%, 0%, 0.03), - 0px 3px 2px hsla(0, 0%, 0%, 0.06), 0px 1px 1px hsla(0, 0%, 0%, 0.06); - --sl-shadow-lg: 0px 25px 7px rgba(0, 0, 0, 0.01), 0px 16px 6px hsla(0, 0%, 0%, 0.03), - 0px 9px 5px hsla(223, 13%, 10%, 0.08), 0px 4px 4px hsla(0, 0%, 0%, 0.16), - 0px 4px 2px hsla(0, 0%, 0%, 0.04); -} + :root[data-theme='light'], + [data-theme='light'] ::backdrop { + /* Colours (light mode) */ + --sl-color-white: hsl(224, 10%, 10%); + --sl-color-gray-1: hsl(224, 14%, 16%); + --sl-color-gray-2: hsl(224, 10%, 23%); + --sl-color-gray-3: hsl(224, 7%, 36%); + --sl-color-gray-4: hsl(224, 6%, 56%); + --sl-color-gray-5: hsl(224, 6%, 77%); + --sl-color-gray-6: hsl(224, 20%, 94%); + --sl-color-gray-7: hsl(224, 19%, 97%); + --sl-color-black: hsl(0, 0%, 100%); + + --sl-color-orange-high: hsl(var(--sl-hue-orange), 80%, 25%); + --sl-color-orange: hsl(var(--sl-hue-orange), 90%, 60%); + --sl-color-orange-low: hsl(var(--sl-hue-orange), 90%, 88%); + --sl-color-green-high: hsl(var(--sl-hue-green), 80%, 22%); + --sl-color-green: hsl(var(--sl-hue-green), 90%, 46%); + --sl-color-green-low: hsl(var(--sl-hue-green), 85%, 90%); + --sl-color-blue-high: hsl(var(--sl-hue-blue), 80%, 30%); + --sl-color-blue: hsl(var(--sl-hue-blue), 90%, 60%); + --sl-color-blue-low: hsl(var(--sl-hue-blue), 88%, 90%); + --sl-color-purple-high: hsl(var(--sl-hue-purple), 90%, 30%); + --sl-color-purple: hsl(var(--sl-hue-purple), 90%, 60%); + --sl-color-purple-low: hsl(var(--sl-hue-purple), 80%, 90%); + --sl-color-red-high: hsl(var(--sl-hue-red), 80%, 30%); + --sl-color-red: hsl(var(--sl-hue-red), 90%, 60%); + --sl-color-red-low: hsl(var(--sl-hue-red), 80%, 90%); + + --sl-color-accent-high: hsl(234, 80%, 30%); + --sl-color-accent: hsl(234, 90%, 60%); + --sl-color-accent-low: hsl(234, 88%, 90%); + + --sl-color-text-accent: var(--sl-color-accent); + --sl-color-text-invert: var(--sl-color-black); + --sl-color-bg-nav: var(--sl-color-gray-7); + --sl-color-bg-sidebar: var(--sl-color-bg); + --sl-color-bg-inline-code: var(--sl-color-gray-6); + --sl-color-bg-accent: var(--sl-color-accent); + --sl-color-hairline-light: var(--sl-color-gray-6); + --sl-color-hairline-shade: var(--sl-color-gray-6); + + --sl-color-backdrop-overlay: hsla(225, 9%, 36%, 0.66); + + /* Shadows (light mode) */ + --sl-shadow-sm: 0px 1px 1px hsla(0, 0%, 0%, 0.06), 0px 2px 1px hsla(0, 0%, 0%, 0.06); + --sl-shadow-md: 0px 8px 4px hsla(0, 0%, 0%, 0.03), 0px 5px 2px hsla(0, 0%, 0%, 0.03), + 0px 3px 2px hsla(0, 0%, 0%, 0.06), 0px 1px 1px hsla(0, 0%, 0%, 0.06); + --sl-shadow-lg: 0px 25px 7px rgba(0, 0, 0, 0.01), 0px 16px 6px hsla(0, 0%, 0%, 0.03), + 0px 9px 5px hsla(223, 13%, 10%, 0.08), 0px 4px 4px hsla(0, 0%, 0%, 0.16), + 0px 4px 2px hsla(0, 0%, 0%, 0.04); + } -@media (min-width: 50em) { - :root { - --sl-nav-height: 4rem; - --sl-nav-pad-x: 1.5rem; - --sl-text-h1: var(--sl-text-5xl); - --sl-text-h2: var(--sl-text-4xl); - --sl-text-h3: var(--sl-text-3xl); - --sl-text-h4: var(--sl-text-2xl); + @media (min-width: 50em) { + :root { + --sl-nav-height: 4rem; + --sl-nav-pad-x: 1.5rem; + --sl-text-h1: var(--sl-text-5xl); + --sl-text-h2: var(--sl-text-4xl); + --sl-text-h3: var(--sl-text-3xl); + --sl-text-h4: var(--sl-text-2xl); + } } -} -@media (min-width: 72rem) { - :root { - --sl-content-pad-x: 1.5rem; - --sl-mobile-toc-height: 0rem; + @media (min-width: 72rem) { + :root { + --sl-content-pad-x: 1.5rem; + --sl-mobile-toc-height: 0rem; + } } } diff --git a/packages/starlight/style/reset.css b/packages/starlight/style/reset.css index 0867542a8c4..f2855a468e7 100644 --- a/packages/starlight/style/reset.css +++ b/packages/starlight/style/reset.css @@ -1,48 +1,50 @@ -*, -*::before, -*::after { - box-sizing: border-box; -} +@layer starlight.reset { + *, + *::before, + *::after { + box-sizing: border-box; + } -* { - margin: 0; -} + * { + margin: 0; + } -html { - color-scheme: dark; - accent-color: var(--sl-color-accent); -} + html { + color-scheme: dark; + accent-color: var(--sl-color-accent); + } -html[data-theme='light'] { - color-scheme: light; -} + html[data-theme='light'] { + color-scheme: light; + } -body { - font-family: var(--__sl-font); - line-height: var(--sl-line-height); - -webkit-font-smoothing: antialiased; - color: var(--sl-color-text); - background-color: var(--sl-color-bg); -} + body { + font-family: var(--__sl-font); + line-height: var(--sl-line-height); + -webkit-font-smoothing: antialiased; + color: var(--sl-color-text); + background-color: var(--sl-color-bg); + } -input, -button, -textarea, -select { - font: inherit; -} + input, + button, + textarea, + select { + font: inherit; + } -p, -h1, -h2, -h3, -h4, -h5, -h6, -code { - overflow-wrap: anywhere; -} + p, + h1, + h2, + h3, + h4, + h5, + h6, + code { + overflow-wrap: anywhere; + } -code { - font-family: var(--__sl-font-mono); + code { + font-family: var(--__sl-font-mono); + } } diff --git a/packages/starlight/style/shiki.css b/packages/starlight/style/shiki.css index b35288bdf8c..85bea575079 100644 --- a/packages/starlight/style/shiki.css +++ b/packages/starlight/style/shiki.css @@ -1,13 +1,15 @@ -:root { - --astro-code-color-text: var(--sl-color-white); - --astro-code-color-background: var(--sl-color-gray-6); - --astro-code-token-constant: var(--sl-color-blue-high); - --astro-code-token-string: var(--sl-color-green-high); - --astro-code-token-comment: var(--sl-color-gray-2); - --astro-code-token-keyword: var(--sl-color-purple-high); - --astro-code-token-parameter: var(--sl-color-red-high); - --astro-code-token-function: var(--sl-color-red-high); - --astro-code-token-string-expression: var(--sl-color-green-high); - --astro-code-token-punctuation: var(--sl-color-gray-2); - --astro-code-token-link: var(--sl-color-blue-high); +@layer starlight.shiki { + :root { + --astro-code-color-text: var(--sl-color-white); + --astro-code-color-background: var(--sl-color-gray-6); + --astro-code-token-constant: var(--sl-color-blue-high); + --astro-code-token-string: var(--sl-color-green-high); + --astro-code-token-comment: var(--sl-color-gray-2); + --astro-code-token-keyword: var(--sl-color-purple-high); + --astro-code-token-parameter: var(--sl-color-red-high); + --astro-code-token-function: var(--sl-color-red-high); + --astro-code-token-string-expression: var(--sl-color-green-high); + --astro-code-token-punctuation: var(--sl-color-gray-2); + --astro-code-token-link: var(--sl-color-blue-high); + } } diff --git a/packages/starlight/style/util.css b/packages/starlight/style/util.css index 74868532205..bb839538b33 100644 --- a/packages/starlight/style/util.css +++ b/packages/starlight/style/util.css @@ -1,61 +1,63 @@ -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; -} +@layer starlight.utils { + .sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; + } -.sl-hidden { - display: none; -} -.sl-flex { - display: flex; -} -.sl-block { - display: block; -} -@media (min-width: 50rem) { - .md\:sl-hidden { + .sl-hidden { display: none; } - .md\:sl-flex { + .sl-flex { display: flex; } - .md\:sl-block { + .sl-block { display: block; } -} -@media (min-width: 72rem) { - .lg\:sl-hidden { - display: none; + @media (min-width: 50rem) { + .md\:sl-hidden { + display: none; + } + .md\:sl-flex { + display: flex; + } + .md\:sl-block { + display: block; + } } - .lg\:sl-flex { - display: flex; + @media (min-width: 72rem) { + .lg\:sl-hidden { + display: none; + } + .lg\:sl-flex { + display: flex; + } + .lg\:sl-block { + display: block; + } } - .lg\:sl-block { - display: block; + [data-theme='light'] .light\:sl-hidden { + display: none; + } + [data-theme='dark'] .dark\:sl-hidden { + display: none; } -} -[data-theme='light'] .light\:sl-hidden { - display: none; -} -[data-theme='dark'] .dark\:sl-hidden { - display: none; -} - -/* -Flip an element around the y-axis when in an RTL context. -Primarily useful for things where we can’t rely on writing direction like icons. - - -In a LTR context: → In a RTL context: ← -*/ -[dir='rtl'] .rtl\:flip:not(:where([dir='rtl'] [dir='ltr'] *)) { - transform: matrix(-1, 0, 0, 1, 0, 0); + /** + * Flip an element around the y-axis when in an RTL context. + * Primarily useful for things where we can’t rely on writing direction like icons. + * + * + * + * In a LTR context: → In a RTL context: ← + */ + [dir='rtl'] .rtl\:flip:not(:where([dir='rtl'] [dir='ltr'] *)) { + transform: matrix(-1, 0, 0, 1, 0, 0); + } } From f2e6bf4d79219011ca35259b9608602667851bee Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:34:19 +0200 Subject: [PATCH 02/16] feat: add layer for components --- packages/starlight/components/Banner.astro | 26 +- .../starlight/components/ContentNotice.astro | 24 +- .../starlight/components/ContentPanel.astro | 32 +- packages/starlight/components/EditLink.astro | 18 +- packages/starlight/components/Footer.astro | 58 +- packages/starlight/components/Header.astro | 94 ++-- packages/starlight/components/Hero.astro | 118 ++-- .../components/MobileMenuFooter.astro | 32 +- .../components/MobileMenuToggle.astro | 66 +-- .../components/MobileTableOfContents.astro | 140 ++--- packages/starlight/components/Page.astro | 2 + packages/starlight/components/PageFrame.astro | 118 ++-- .../starlight/components/PageSidebar.astro | 64 +-- packages/starlight/components/PageTitle.astro | 14 +- .../starlight/components/Pagination.astro | 74 +-- packages/starlight/components/Search.astro | 518 +++++++++--------- packages/starlight/components/Select.astro | 96 ++-- .../components/SidebarPersister.astro | 6 +- .../starlight/components/SidebarSublist.astro | 154 +++--- packages/starlight/components/SiteTitle.astro | 32 +- packages/starlight/components/SkipLink.astro | 32 +- .../starlight/components/SocialIcons.astro | 16 +- .../TableOfContents/TableOfContentsList.astro | 96 ++-- .../components/TwoColumnContent.astro | 62 ++- packages/starlight/style/layers.css | 2 +- 25 files changed, 974 insertions(+), 920 deletions(-) diff --git a/packages/starlight/components/Banner.astro b/packages/starlight/components/Banner.astro index 107baa707de..e519f1f7043 100644 --- a/packages/starlight/components/Banner.astro +++ b/packages/starlight/components/Banner.astro @@ -7,17 +7,19 @@ const { banner } = Astro.props.entry.data; {banner &&
} diff --git a/packages/starlight/components/ContentNotice.astro b/packages/starlight/components/ContentNotice.astro index 9c354f9313b..7f27ec5dd0b 100644 --- a/packages/starlight/components/ContentNotice.astro +++ b/packages/starlight/components/ContentNotice.astro @@ -16,16 +16,18 @@ const { icon, label } = Astro.props;

diff --git a/packages/starlight/components/ContentPanel.astro b/packages/starlight/components/ContentPanel.astro index 3f23fcd0537..6d461322ac4 100644 --- a/packages/starlight/components/ContentPanel.astro +++ b/packages/starlight/components/ContentPanel.astro @@ -7,23 +7,25 @@ import type { Props } from '../props';
diff --git a/packages/starlight/components/EditLink.astro b/packages/starlight/components/EditLink.astro index 74be4c8f79d..a0f73d59f52 100644 --- a/packages/starlight/components/EditLink.astro +++ b/packages/starlight/components/EditLink.astro @@ -15,13 +15,15 @@ const { editUrl, labels } = Astro.props; } diff --git a/packages/starlight/components/Footer.astro b/packages/starlight/components/Footer.astro index f75b5e40703..c96f16f3a80 100644 --- a/packages/starlight/components/Footer.astro +++ b/packages/starlight/components/Footer.astro @@ -25,34 +25,36 @@ import { Icon } from '../components'; diff --git a/packages/starlight/components/Header.astro b/packages/starlight/components/Header.astro index 87b97fb1c6f..6752b9e2ebd 100644 --- a/packages/starlight/components/Header.astro +++ b/packages/starlight/components/Header.astro @@ -32,57 +32,59 @@ const shouldRenderSearch = diff --git a/packages/starlight/components/Hero.astro b/packages/starlight/components/Hero.astro index 0d184d40383..6e784d63f35 100644 --- a/packages/starlight/components/Hero.astro +++ b/packages/starlight/components/Hero.astro @@ -65,78 +65,80 @@ if (image) { diff --git a/packages/starlight/components/MobileMenuFooter.astro b/packages/starlight/components/MobileMenuFooter.astro index 62eb23e62d4..f45851fb818 100644 --- a/packages/starlight/components/MobileMenuFooter.astro +++ b/packages/starlight/components/MobileMenuFooter.astro @@ -14,20 +14,22 @@ import type { Props } from '../props'; diff --git a/packages/starlight/components/MobileMenuToggle.astro b/packages/starlight/components/MobileMenuToggle.astro index b48e12300f7..8328fd87f29 100644 --- a/packages/starlight/components/MobileMenuToggle.astro +++ b/packages/starlight/components/MobileMenuToggle.astro @@ -53,45 +53,49 @@ const { labels } = Astro.props; diff --git a/packages/starlight/components/MobileTableOfContents.astro b/packages/starlight/components/MobileTableOfContents.astro index 74342e3c5c3..691e404d8fe 100644 --- a/packages/starlight/components/MobileTableOfContents.astro +++ b/packages/starlight/components/MobileTableOfContents.astro @@ -28,82 +28,84 @@ const { labels, toc } = Astro.props; } diff --git a/packages/starlight/components/Page.astro b/packages/starlight/components/Page.astro index 09f0e280a40..c262ae2b431 100644 --- a/packages/starlight/components/Page.astro +++ b/packages/starlight/components/Page.astro @@ -7,12 +7,14 @@ import 'virtual:starlight/user-css'; // TODO(HiDeoo) import '../style/layers.css'; +// TODO(HiDeoo) // Built-in CSS styles. import '../style/props.css'; import '../style/reset.css'; import '../style/shiki.css'; import '../style/util.css'; +// TODO(HiDeoo) // Components — can override built-in CSS, but not user CSS. import Banner from 'virtual:starlight/components/Banner'; import ContentPanel from 'virtual:starlight/components/ContentPanel'; diff --git a/packages/starlight/components/PageFrame.astro b/packages/starlight/components/PageFrame.astro index 3398034369c..4111c97c0dd 100644 --- a/packages/starlight/components/PageFrame.astro +++ b/packages/starlight/components/PageFrame.astro @@ -23,72 +23,76 @@ const { hasSidebar, labels } = Astro.props; diff --git a/packages/starlight/components/PageSidebar.astro b/packages/starlight/components/PageSidebar.astro index 97caff9fab9..c177f967a3a 100644 --- a/packages/starlight/components/PageSidebar.astro +++ b/packages/starlight/components/PageSidebar.astro @@ -21,39 +21,41 @@ import TableOfContents from 'virtual:starlight/components/TableOfContents'; } diff --git a/packages/starlight/components/PageTitle.astro b/packages/starlight/components/PageTitle.astro index 8c6d932b871..0a4bfd7c1fd 100644 --- a/packages/starlight/components/PageTitle.astro +++ b/packages/starlight/components/PageTitle.astro @@ -6,11 +6,13 @@ import type { Props } from '../props';

{Astro.props.entry.data.title}

diff --git a/packages/starlight/components/Pagination.astro b/packages/starlight/components/Pagination.astro index 0c92c31e0c8..a766cdbf47b 100644 --- a/packages/starlight/components/Pagination.astro +++ b/packages/starlight/components/Pagination.astro @@ -35,44 +35,46 @@ const isRtl = dir === 'rtl'; diff --git a/packages/starlight/components/Search.astro b/packages/starlight/components/Search.astro index 713e9415136..6b4680f044e 100644 --- a/packages/starlight/components/Search.astro +++ b/packages/starlight/components/Search.astro @@ -163,304 +163,308 @@ const pagefindTranslations = { diff --git a/packages/starlight/components/Select.astro b/packages/starlight/components/Select.astro index 8be1685985c..1221d558332 100644 --- a/packages/starlight/components/Select.astro +++ b/packages/starlight/components/Select.astro @@ -28,60 +28,62 @@ interface Props { diff --git a/packages/starlight/components/SidebarPersister.astro b/packages/starlight/components/SidebarPersister.astro index ae485c97b9f..c3cab33547b 100644 --- a/packages/starlight/components/SidebarPersister.astro +++ b/packages/starlight/components/SidebarPersister.astro @@ -66,7 +66,9 @@ declare global { diff --git a/packages/starlight/components/SidebarSublist.astro b/packages/starlight/components/SidebarSublist.astro index b521ba13ef5..64754e3858e 100644 --- a/packages/starlight/components/SidebarSublist.astro +++ b/packages/starlight/components/SidebarSublist.astro @@ -59,93 +59,95 @@ const { sublist, nested } = Astro.props; diff --git a/packages/starlight/components/SiteTitle.astro b/packages/starlight/components/SiteTitle.astro index 2f4b829943e..5e64b4d2087 100644 --- a/packages/starlight/components/SiteTitle.astro +++ b/packages/starlight/components/SiteTitle.astro @@ -35,20 +35,22 @@ const { siteTitle, siteTitleHref } = Astro.props; diff --git a/packages/starlight/components/SkipLink.astro b/packages/starlight/components/SkipLink.astro index 307c1ef9a6e..42fdce057b0 100644 --- a/packages/starlight/components/SkipLink.astro +++ b/packages/starlight/components/SkipLink.astro @@ -8,20 +8,22 @@ const { labels } = Astro.props; {labels['skipLink.label']} diff --git a/packages/starlight/components/SocialIcons.astro b/packages/starlight/components/SocialIcons.astro index 59557068f80..b82d29e851f 100644 --- a/packages/starlight/components/SocialIcons.astro +++ b/packages/starlight/components/SocialIcons.astro @@ -22,12 +22,14 @@ const links = Object.entries(config.social || {}) as [Platform, SocialConfig][]; } diff --git a/packages/starlight/components/TableOfContents/TableOfContentsList.astro b/packages/starlight/components/TableOfContents/TableOfContentsList.astro index 8ea9eb84280..21f37c9e689 100644 --- a/packages/starlight/components/TableOfContents/TableOfContentsList.astro +++ b/packages/starlight/components/TableOfContents/TableOfContentsList.astro @@ -26,52 +26,54 @@ const { toc, isMobile = false, depth = 0 } = Astro.props; diff --git a/packages/starlight/components/TwoColumnContent.astro b/packages/starlight/components/TwoColumnContent.astro index 5eefb3e79ac..e26ee22267f 100644 --- a/packages/starlight/components/TwoColumnContent.astro +++ b/packages/starlight/components/TwoColumnContent.astro @@ -16,41 +16,43 @@ import type { Props } from '../props'; diff --git a/packages/starlight/style/layers.css b/packages/starlight/style/layers.css index 4f547415b38..0ce2b3a0a9a 100644 --- a/packages/starlight/style/layers.css +++ b/packages/starlight/style/layers.css @@ -1 +1 @@ -@layer starlight.base, starlight.reset, starlight.shiki, starlight.utils; +@layer starlight.base, starlight.reset, starlight.shiki, starlight.utils, starlight.components; From db9e3504c5cb6759926dd93c6bec9c0c4f52977c Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:43:56 +0200 Subject: [PATCH 03/16] feat: add layer for content --- packages/starlight/components/Page.astro | 2 - packages/starlight/style/layers.css | 2 +- packages/starlight/style/markdown.css | 388 ++++++++++++----------- 3 files changed, 198 insertions(+), 194 deletions(-) diff --git a/packages/starlight/components/Page.astro b/packages/starlight/components/Page.astro index c262ae2b431..64423609f9e 100644 --- a/packages/starlight/components/Page.astro +++ b/packages/starlight/components/Page.astro @@ -24,8 +24,6 @@ import Footer from 'virtual:starlight/components/Footer'; import Head from 'virtual:starlight/components/Head'; import Header from 'virtual:starlight/components/Header'; import Hero from 'virtual:starlight/components/Hero'; -// TODO(HiDeoo) -// TODO(HiDeoo) Maybe we can even move the definition to outside of the Markdown components import MarkdownContent from 'virtual:starlight/components/MarkdownContent'; import PageFrame from 'virtual:starlight/components/PageFrame'; import PageSidebar from 'virtual:starlight/components/PageSidebar'; diff --git a/packages/starlight/style/layers.css b/packages/starlight/style/layers.css index 0ce2b3a0a9a..9bc19c50653 100644 --- a/packages/starlight/style/layers.css +++ b/packages/starlight/style/layers.css @@ -1 +1 @@ -@layer starlight.base, starlight.reset, starlight.shiki, starlight.utils, starlight.components; +@layer starlight.base, starlight.reset, starlight.shiki, starlight.utils, starlight.components, starlight.content; diff --git a/packages/starlight/style/markdown.css b/packages/starlight/style/markdown.css index 596ae6120a9..ef92a02f449 100644 --- a/packages/starlight/style/markdown.css +++ b/packages/starlight/style/markdown.css @@ -1,217 +1,223 @@ -.sl-markdown-content - :not(a, strong, em, del, span, input, code) - + :not(a, strong, em, del, span, input, code, :where(.not-content *)) { - margin-top: 1rem; -} +@layer starlight.content { + .sl-markdown-content + :not(a, strong, em, del, span, input, code) + + :not(a, strong, em, del, span, input, code, :where(.not-content *)) { + margin-top: 1rem; + } -/* Headings after non-headings have more spacing. */ -.sl-markdown-content - :not(h1, h2, h3, h4, h5, h6) - + :is(h1, h2, h3, h4, h5, h6):not(:where(.not-content *)) { - margin-top: 1.5em; -} + /* Headings after non-headings have more spacing. */ + .sl-markdown-content + :not(h1, h2, h3, h4, h5, h6) + + :is(h1, h2, h3, h4, h5, h6):not(:where(.not-content *)) { + margin-top: 1.5em; + } -.sl-markdown-content li + li:not(:where(.not-content *)), -.sl-markdown-content dt + dt:not(:where(.not-content *)), -.sl-markdown-content dt + dd:not(:where(.not-content *)), -.sl-markdown-content dd + dd:not(:where(.not-content *)) { - margin-top: 0.25rem; -} + .sl-markdown-content li + li:not(:where(.not-content *)), + .sl-markdown-content dt + dt:not(:where(.not-content *)), + .sl-markdown-content dt + dd:not(:where(.not-content *)), + .sl-markdown-content dd + dd:not(:where(.not-content *)) { + margin-top: 0.25rem; + } -.sl-markdown-content li:not(:where(.not-content *)) { - overflow-wrap: anywhere; -} + .sl-markdown-content li:not(:where(.not-content *)) { + overflow-wrap: anywhere; + } -.sl-markdown-content - li - > :last-child:not(li, ul, ol):not(a, strong, em, del, span, input, :where(.not-content *)) { - margin-bottom: 1.25rem; -} + .sl-markdown-content + li + > :last-child:not(li, ul, ol):not(a, strong, em, del, span, input, :where(.not-content *)) { + margin-bottom: 1.25rem; + } -.sl-markdown-content dt:not(:where(.not-content *)) { - font-weight: 700; -} -.sl-markdown-content dd:not(:where(.not-content *)) { - padding-inline-start: 1rem; -} + .sl-markdown-content dt:not(:where(.not-content *)) { + font-weight: 700; + } + .sl-markdown-content dd:not(:where(.not-content *)) { + padding-inline-start: 1rem; + } -.sl-markdown-content :is(h1, h2, h3, h4, h5, h6):not(:where(.not-content *)) { - color: var(--sl-color-white); - line-height: var(--sl-line-height-headings); - font-weight: 600; -} + .sl-markdown-content :is(h1, h2, h3, h4, h5, h6):not(:where(.not-content *)) { + color: var(--sl-color-white); + line-height: var(--sl-line-height-headings); + font-weight: 600; + } -.sl-markdown-content :is(img, picture, video, canvas, svg, iframe):not(:where(.not-content *)) { - display: block; - max-width: 100%; - height: auto; -} + .sl-markdown-content :is(img, picture, video, canvas, svg, iframe):not(:where(.not-content *)) { + display: block; + max-width: 100%; + height: auto; + } -.sl-markdown-content h1:not(:where(.not-content *)) { - font-size: var(--sl-text-h1); -} -.sl-markdown-content h2:not(:where(.not-content *)) { - font-size: var(--sl-text-h2); -} -.sl-markdown-content h3:not(:where(.not-content *)) { - font-size: var(--sl-text-h3); -} -.sl-markdown-content h4:not(:where(.not-content *)) { - font-size: var(--sl-text-h4); -} -.sl-markdown-content h5:not(:where(.not-content *)) { - font-size: var(--sl-text-h5); -} -.sl-markdown-content h6:not(:where(.not-content *)) { - font-size: var(--sl-text-h6); -} + .sl-markdown-content h1:not(:where(.not-content *)) { + font-size: var(--sl-text-h1); + } + .sl-markdown-content h2:not(:where(.not-content *)) { + font-size: var(--sl-text-h2); + } + .sl-markdown-content h3:not(:where(.not-content *)) { + font-size: var(--sl-text-h3); + } + .sl-markdown-content h4:not(:where(.not-content *)) { + font-size: var(--sl-text-h4); + } + .sl-markdown-content h5:not(:where(.not-content *)) { + font-size: var(--sl-text-h5); + } + .sl-markdown-content h6:not(:where(.not-content *)) { + font-size: var(--sl-text-h6); + } -.sl-markdown-content a:not(:where(.not-content *)) { - color: var(--sl-color-text-accent); -} -.sl-markdown-content a:hover:not(:where(.not-content *)) { - color: var(--sl-color-white); -} + .sl-markdown-content a:not(:where(.not-content *)) { + color: var(--sl-color-text-accent); + } + .sl-markdown-content a:hover:not(:where(.not-content *)) { + color: var(--sl-color-white); + } -.sl-markdown-content code:not(:where(.not-content *)) { - background-color: var(--sl-color-bg-inline-code); - margin-block: -0.125rem; - padding: 0.125rem 0.375rem; - font-size: var(--sl-text-code-sm); -} -.sl-markdown-content :is(h1, h2, h3, h4, h5, h6) code { - font-size: inherit; -} + .sl-markdown-content code:not(:where(.not-content *)) { + background-color: var(--sl-color-bg-inline-code); + margin-block: -0.125rem; + padding: 0.125rem 0.375rem; + font-size: var(--sl-text-code-sm); + } + .sl-markdown-content :is(h1, h2, h3, h4, h5, h6) code { + font-size: inherit; + } -.sl-markdown-content pre:not(:where(.not-content *)) { - border: 1px solid var(--sl-color-gray-5); - padding: 0.75rem 1rem; - font-size: var(--sl-text-code); - tab-size: 2; -} + .sl-markdown-content pre:not(:where(.not-content *)) { + border: 1px solid var(--sl-color-gray-5); + padding: 0.75rem 1rem; + font-size: var(--sl-text-code); + tab-size: 2; + } -.sl-markdown-content pre code:not(:where(.not-content *)) { - all: unset; - font-family: var(--__sl-font-mono); -} + .sl-markdown-content pre code:not(:where(.not-content *)) { + all: unset; + font-family: var(--__sl-font-mono); + } -.sl-markdown-content blockquote:not(:where(.not-content *)) { - border-inline-start: 1px solid var(--sl-color-gray-5); - padding-inline-start: 1rem; -} + .sl-markdown-content blockquote:not(:where(.not-content *)) { + border-inline-start: 1px solid var(--sl-color-gray-5); + padding-inline-start: 1rem; + } -/* Table styling */ -.sl-markdown-content table:not(:where(.not-content *)) { - display: block; - overflow: auto; - border-spacing: 0; -} -.sl-markdown-content :is(th, td):not(:where(.not-content *)) { - border-bottom: 1px solid var(--sl-color-gray-5); - padding: 0.5rem 1rem; - /* Align text to the top of the row in multiline tables. */ - vertical-align: baseline; -} -.sl-markdown-content :is(th:first-child, td:first-child):not(:where(.not-content *)) { - padding-inline-start: 0; -} -.sl-markdown-content :is(th:last-child, td:last-child):not(:where(.not-content *)) { - padding-inline-end: 0; -} -.sl-markdown-content th:not(:where(.not-content *)) { - color: var(--sl-color-white); - font-weight: 600; -} -/* Align headings to the start of the line unless set by the `align` attribute. */ -.sl-markdown-content th:not([align]):not(:where(.not-content *)) { - text-align: start; -} -/* s,
s, and
s inside asides */ -.sl-markdown-content .starlight-aside :is(th, td, hr, blockquote):not(:where(.not-content *)) { - border-color: var(--sl-color-gray-4); -} -@supports (border-color: color-mix(in srgb, var(--sl-color-asides-text-accent) 30%, transparent)) { + /* Table styling */ + .sl-markdown-content table:not(:where(.not-content *)) { + display: block; + overflow: auto; + border-spacing: 0; + } + .sl-markdown-content :is(th, td):not(:where(.not-content *)) { + border-bottom: 1px solid var(--sl-color-gray-5); + padding: 0.5rem 1rem; + /* Align text to the top of the row in multiline tables. */ + vertical-align: baseline; + } + .sl-markdown-content :is(th:first-child, td:first-child):not(:where(.not-content *)) { + padding-inline-start: 0; + } + .sl-markdown-content :is(th:last-child, td:last-child):not(:where(.not-content *)) { + padding-inline-end: 0; + } + .sl-markdown-content th:not(:where(.not-content *)) { + color: var(--sl-color-white); + font-weight: 600; + } + /* Align headings to the start of the line unless set by the `align` attribute. */ + .sl-markdown-content th:not([align]):not(:where(.not-content *)) { + text-align: start; + } + /*
s,
s, and
s inside asides */ .sl-markdown-content .starlight-aside :is(th, td, hr, blockquote):not(:where(.not-content *)) { - border-color: color-mix(in srgb, var(--sl-color-asides-text-accent) 30%, transparent); + border-color: var(--sl-color-gray-4); + } + @supports ( + border-color: color-mix(in srgb, var(--sl-color-asides-text-accent) 30%, transparent) + ) { + .sl-markdown-content .starlight-aside :is(th, td, hr, blockquote):not(:where(.not-content *)) { + border-color: color-mix(in srgb, var(--sl-color-asides-text-accent) 30%, transparent); + } } -} -/* inside asides */ -@supports (border-color: color-mix(in srgb, var(--sl-color-asides-text-accent) 12%, transparent)) { - .sl-markdown-content .starlight-aside code:not(:where(.not-content *)) { - background-color: color-mix(in srgb, var(--sl-color-asides-text-accent) 12%, transparent); + /* inside asides */ + @supports ( + border-color: color-mix(in srgb, var(--sl-color-asides-text-accent) 12%, transparent) + ) { + .sl-markdown-content .starlight-aside code:not(:where(.not-content *)) { + background-color: color-mix(in srgb, var(--sl-color-asides-text-accent) 12%, transparent); + } } -} -.sl-markdown-content hr:not(:where(.not-content *)) { - border: 0; - border-bottom: 1px solid var(--sl-color-hairline); -} + .sl-markdown-content hr:not(:where(.not-content *)) { + border: 0; + border-bottom: 1px solid var(--sl-color-hairline); + } -/*
and styles */ -.sl-markdown-content details:not(:where(.not-content *)) { - --sl-details-border-color: var(--sl-color-gray-5); - --sl-details-border-color--hover: var(--sl-color-text-accent); + /*
and styles */ + .sl-markdown-content details:not(:where(.not-content *)) { + --sl-details-border-color: var(--sl-color-gray-5); + --sl-details-border-color--hover: var(--sl-color-text-accent); - border-inline-start: 2px solid var(--sl-details-border-color); - padding-inline-start: 1rem; -} -.sl-markdown-content details:not([open]):hover:not(:where(.not-content *)), -.sl-markdown-content details:has(> summary:hover):not(:where(.not-content *)) { - border-color: var(--sl-details-border-color--hover); -} -.sl-markdown-content summary:not(:where(.not-content *)) { - color: var(--sl-color-white); - cursor: pointer; - display: block; /* Needed to hide the default marker in some browsers. */ - font-weight: 600; - /* Expand the outline so that the marker cannot distort it. */ - margin-inline-start: -0.5rem; - padding-inline-start: 0.5rem; -} -.sl-markdown-content details[open] > summary:not(:where(.not-content *)) { - margin-bottom: 1rem; -} + border-inline-start: 2px solid var(--sl-details-border-color); + padding-inline-start: 1rem; + } + .sl-markdown-content details:not([open]):hover:not(:where(.not-content *)), + .sl-markdown-content details:has(> summary:hover):not(:where(.not-content *)) { + border-color: var(--sl-details-border-color--hover); + } + .sl-markdown-content summary:not(:where(.not-content *)) { + color: var(--sl-color-white); + cursor: pointer; + display: block; /* Needed to hide the default marker in some browsers. */ + font-weight: 600; + /* Expand the outline so that the marker cannot distort it. */ + margin-inline-start: -0.5rem; + padding-inline-start: 0.5rem; + } + .sl-markdown-content details[open] > summary:not(:where(.not-content *)) { + margin-bottom: 1rem; + } -/* marker styles */ -.sl-markdown-content summary:not(:where(.not-content *))::marker, -.sl-markdown-content summary:not(:where(.not-content *))::-webkit-details-marker { - display: none; -} -.sl-markdown-content summary:not(:where(.not-content *))::before { - --sl-details-marker-size: 1.25rem; - - background-color: currentColor; - content: ''; - display: inline-block; - height: var(--sl-details-marker-size); - width: var(--sl-details-marker-size); - margin-inline: calc((var(--sl-details-marker-size) / 4) * -1) 0.25rem; - vertical-align: middle; - -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M14.8 11.3 10.6 7a1 1 0 1 0-1.4 1.5l3.5 3.5-3.5 3.5a1 1 0 0 0 0 1.4 1 1 0 0 0 .7.3 1 1 0 0 0 .7-.3l4.2-4.2a1 1 0 0 0 0-1.4Z'/%3E%3C/svg%3E%0A"); - mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M14.8 11.3 10.6 7a1 1 0 1 0-1.4 1.5l3.5 3.5-3.5 3.5a1 1 0 0 0 0 1.4 1 1 0 0 0 .7.3 1 1 0 0 0 .7-.3l4.2-4.2a1 1 0 0 0 0-1.4Z'/%3E%3C/svg%3E%0A"); - -webkit-mask-repeat: no-repeat; - mask-repeat: no-repeat; -} -@media (prefers-reduced-motion: no-preference) { + /* marker styles */ + .sl-markdown-content summary:not(:where(.not-content *))::marker, + .sl-markdown-content summary:not(:where(.not-content *))::-webkit-details-marker { + display: none; + } .sl-markdown-content summary:not(:where(.not-content *))::before { - transition: transform 0.2s ease-in-out; + --sl-details-marker-size: 1.25rem; + + background-color: currentColor; + content: ''; + display: inline-block; + height: var(--sl-details-marker-size); + width: var(--sl-details-marker-size); + margin-inline: calc((var(--sl-details-marker-size) / 4) * -1) 0.25rem; + vertical-align: middle; + -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M14.8 11.3 10.6 7a1 1 0 1 0-1.4 1.5l3.5 3.5-3.5 3.5a1 1 0 0 0 0 1.4 1 1 0 0 0 .7.3 1 1 0 0 0 .7-.3l4.2-4.2a1 1 0 0 0 0-1.4Z'/%3E%3C/svg%3E%0A"); + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M14.8 11.3 10.6 7a1 1 0 1 0-1.4 1.5l3.5 3.5-3.5 3.5a1 1 0 0 0 0 1.4 1 1 0 0 0 .7.3 1 1 0 0 0 .7-.3l4.2-4.2a1 1 0 0 0 0-1.4Z'/%3E%3C/svg%3E%0A"); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + } + @media (prefers-reduced-motion: no-preference) { + .sl-markdown-content summary:not(:where(.not-content *))::before { + transition: transform 0.2s ease-in-out; + } + } + .sl-markdown-content details[open] > summary:not(:where(.not-content *))::before { + transform: rotateZ(90deg); + } + [dir='rtl'] .sl-markdown-content summary:not(:where(.not-content *))::before, + .sl-markdown-content [dir='rtl'] summary:not(:where(.not-content *))::before { + transform: rotateZ(180deg); + } + /* with only a paragraph automatically added when using MDX */ + .sl-markdown-content summary:not(:where(.not-content *)) p:only-child { + display: inline; } -} -.sl-markdown-content details[open] > summary:not(:where(.not-content *))::before { - transform: rotateZ(90deg); -} -[dir='rtl'] .sl-markdown-content summary:not(:where(.not-content *))::before, -.sl-markdown-content [dir='rtl'] summary:not(:where(.not-content *))::before { - transform: rotateZ(180deg); -} -/* with only a paragraph automatically added when using MDX */ -.sl-markdown-content summary:not(:where(.not-content *)) p:only-child { - display: inline; -} -/*
styles inside asides */ -.sl-markdown-content .starlight-aside details:not(:where(.not-content *)) { - --sl-details-border-color: var(--sl-color-asides-border); - --sl-details-border-color--hover: var(--sl-color-asides-text-accent); + /*
styles inside asides */ + .sl-markdown-content .starlight-aside details:not(:where(.not-content *)) { + --sl-details-border-color: var(--sl-color-asides-border); + --sl-details-border-color--hover: var(--sl-color-asides-text-accent); + } } From dedea00caa34e471c890c42a0ffa0e6e6605d6ab Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:51:06 +0200 Subject: [PATCH 04/16] feat: add layer for asides --- packages/starlight/components/Page.astro | 6 +- packages/starlight/style/asides.css | 90 ++++++++++++------------ packages/starlight/style/layers.css | 2 +- 3 files changed, 48 insertions(+), 50 deletions(-) diff --git a/packages/starlight/components/Page.astro b/packages/starlight/components/Page.astro index 64423609f9e..5fca0d142ba 100644 --- a/packages/starlight/components/Page.astro +++ b/packages/starlight/components/Page.astro @@ -13,6 +13,7 @@ import '../style/props.css'; import '../style/reset.css'; import '../style/shiki.css'; import '../style/util.css'; +import '../style/asides.css'; // TODO(HiDeoo) // Components — can override built-in CSS, but not user CSS. @@ -33,11 +34,6 @@ import SkipLink from 'virtual:starlight/components/SkipLink'; import ThemeProvider from 'virtual:starlight/components/ThemeProvider'; import TwoColumnContent from 'virtual:starlight/components/TwoColumnContent'; -// TODO(HiDeoo) -// TODO(HiDeoo) Maybe we can move that too -// Remark component CSS (needs to override `MarkdownContent.astro`) -import '../style/asides.css'; - // FIXME(HiDeoo) // Important that this is the last import so it can override built-in styles. // import 'virtual:starlight/user-css'; diff --git a/packages/starlight/style/asides.css b/packages/starlight/style/asides.css index adbb0558f48..10459cf46ee 100644 --- a/packages/starlight/style/asides.css +++ b/packages/starlight/style/asides.css @@ -1,49 +1,51 @@ -.starlight-aside { - padding: 1rem; - border-inline-start: 0.25rem solid var(--sl-color-asides-border); - color: var(--sl-color-white); -} -.starlight-aside--note { - --sl-color-asides-text-accent: var(--sl-color-blue-high); - --sl-color-asides-border: var(--sl-color-blue); - background-color: var(--sl-color-blue-low); -} -.starlight-aside--tip { - --sl-color-asides-text-accent: var(--sl-color-purple-high); - --sl-color-asides-border: var(--sl-color-purple); - background-color: var(--sl-color-purple-low); -} -.starlight-aside--caution { - --sl-color-asides-text-accent: var(--sl-color-orange-high); - --sl-color-asides-border: var(--sl-color-orange); - background-color: var(--sl-color-orange-low); -} -.starlight-aside--danger { - --sl-color-asides-text-accent: var(--sl-color-red-high); - --sl-color-asides-border: var(--sl-color-red); - background-color: var(--sl-color-red-low); -} +@layer starlight.asides { + .starlight-aside { + padding: 1rem; + border-inline-start: 0.25rem solid var(--sl-color-asides-border); + color: var(--sl-color-white); + } + .starlight-aside--note { + --sl-color-asides-text-accent: var(--sl-color-blue-high); + --sl-color-asides-border: var(--sl-color-blue); + background-color: var(--sl-color-blue-low); + } + .starlight-aside--tip { + --sl-color-asides-text-accent: var(--sl-color-purple-high); + --sl-color-asides-border: var(--sl-color-purple); + background-color: var(--sl-color-purple-low); + } + .starlight-aside--caution { + --sl-color-asides-text-accent: var(--sl-color-orange-high); + --sl-color-asides-border: var(--sl-color-orange); + background-color: var(--sl-color-orange-low); + } + .starlight-aside--danger { + --sl-color-asides-text-accent: var(--sl-color-red-high); + --sl-color-asides-border: var(--sl-color-red); + background-color: var(--sl-color-red-low); + } -.starlight-aside__title { - display: flex; - gap: 0.5rem; - align-items: center; - font-size: var(--sl-text-h5); - font-weight: 600; - line-height: var(--sl-line-height-headings); - color: var(--sl-color-asides-text-accent); -} + .starlight-aside__title { + display: flex; + gap: 0.5rem; + align-items: center; + font-size: var(--sl-text-h5); + font-weight: 600; + line-height: var(--sl-line-height-headings); + color: var(--sl-color-asides-text-accent); + } -.starlight-aside__icon { - font-size: 1.333em; - width: 1em; - height: 1em; -} + .starlight-aside__icon { + font-size: 1.333em; + width: 1em; + height: 1em; + } -.starlight-aside__title + .starlight-aside__content { - margin-top: 0.5rem; -} + .starlight-aside__title + .starlight-aside__content { + margin-top: 0.5rem; + } -.starlight-aside__content a { - color: var(--sl-color-asides-text-accent); + .starlight-aside__content a { + color: var(--sl-color-asides-text-accent); + } } diff --git a/packages/starlight/style/layers.css b/packages/starlight/style/layers.css index 9bc19c50653..246e483f719 100644 --- a/packages/starlight/style/layers.css +++ b/packages/starlight/style/layers.css @@ -1 +1 @@ -@layer starlight.base, starlight.reset, starlight.shiki, starlight.utils, starlight.components, starlight.content; +@layer starlight.base, starlight.reset, starlight.shiki, starlight.utils, starlight.components, starlight.content, starlight.asides; From ee9ca478ae30f2625807fa7ae9e96d22f5461762 Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Tue, 10 Sep 2024 18:14:17 +0200 Subject: [PATCH 05/16] refactor: increase utils layer precedence order --- packages/starlight/components/Header.astro | 3 ++- packages/starlight/components/MobileMenuFooter.astro | 5 ++--- packages/starlight/components/Page.astro | 2 +- packages/starlight/style/layers.css | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/starlight/components/Header.astro b/packages/starlight/components/Header.astro index 6752b9e2ebd..f494087a989 100644 --- a/packages/starlight/components/Header.astro +++ b/packages/starlight/components/Header.astro @@ -15,7 +15,7 @@ const shouldRenderSearch = config.pagefind || config.components.Search !== '@astrojs/starlight/components/Search.astro'; --- -
+
@@ -34,6 +34,7 @@ const shouldRenderSearch = diff --git a/packages/starlight/user-components/Card.astro b/packages/starlight/user-components/Card.astro index 6b95e5bf88d..7ad33a9aa9d 100644 --- a/packages/starlight/user-components/Card.astro +++ b/packages/starlight/user-components/Card.astro @@ -19,47 +19,49 @@ const { icon, title } = Astro.props; diff --git a/packages/starlight/user-components/CardGrid.astro b/packages/starlight/user-components/CardGrid.astro index df05287e49c..7a21e8e7320 100644 --- a/packages/starlight/user-components/CardGrid.astro +++ b/packages/starlight/user-components/CardGrid.astro @@ -9,27 +9,29 @@ const { stagger = false } = Astro.props;
diff --git a/packages/starlight/user-components/FileTree.astro b/packages/starlight/user-components/FileTree.astro index 1e079cf2cda..b2893aa4c54 100644 --- a/packages/starlight/user-components/FileTree.astro +++ b/packages/starlight/user-components/FileTree.astro @@ -14,127 +14,129 @@ const html = processFileTree(fileTreeHtml, t('fileTree.directory')); diff --git a/packages/starlight/user-components/Icon.astro b/packages/starlight/user-components/Icon.astro index 7575cc78702..5937f4b8f1d 100644 --- a/packages/starlight/user-components/Icon.astro +++ b/packages/starlight/user-components/Icon.astro @@ -24,10 +24,12 @@ const a11yAttrs = label ? ({ 'aria-label': label } as const) : ({ 'aria-hidden': /> diff --git a/packages/starlight/user-components/LinkButton.astro b/packages/starlight/user-components/LinkButton.astro index 3bf68f073d7..015ae30ba82 100644 --- a/packages/starlight/user-components/LinkButton.astro +++ b/packages/starlight/user-components/LinkButton.astro @@ -26,51 +26,53 @@ const { diff --git a/packages/starlight/user-components/LinkCard.astro b/packages/starlight/user-components/LinkCard.astro index 8cf6fbd90fd..d78d0e5ca68 100644 --- a/packages/starlight/user-components/LinkCard.astro +++ b/packages/starlight/user-components/LinkCard.astro @@ -21,56 +21,58 @@ const { title, description, ...attributes } = Astro.props;
diff --git a/packages/starlight/user-components/Steps.astro b/packages/starlight/user-components/Steps.astro index c66dffb1f43..a1b62c85068 100644 --- a/packages/starlight/user-components/Steps.astro +++ b/packages/starlight/user-components/Steps.astro @@ -8,79 +8,81 @@ const { html } = processSteps(content); diff --git a/packages/starlight/user-components/Tabs.astro b/packages/starlight/user-components/Tabs.astro index f3108806686..3e2ece5fc5c 100644 --- a/packages/starlight/user-components/Tabs.astro +++ b/packages/starlight/user-components/Tabs.astro @@ -98,43 +98,45 @@ if (isSynced) { From af7e55aafb1c133ee90593e17109069e80ffcdee Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Tue, 10 Sep 2024 19:23:16 +0200 Subject: [PATCH 07/16] feat: add layer to expressive-code --- packages/starlight/integrations/expressive-code/index.ts | 2 ++ packages/starlight/style/layers.css | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/starlight/integrations/expressive-code/index.ts b/packages/starlight/integrations/expressive-code/index.ts index c3fd38546b7..68a0a85c942 100644 --- a/packages/starlight/integrations/expressive-code/index.ts +++ b/packages/starlight/integrations/expressive-code/index.ts @@ -80,6 +80,7 @@ export function getStarlightEcConfigPreprocessor({ const { themes: themesInput, + cascadeLayer, customizeTheme, styleOverrides: { textMarkers: textMarkersStyleOverrides, ...otherStyleOverrides } = {}, useStarlightDarkModeSwitch, @@ -135,6 +136,7 @@ export function getStarlightEcConfigPreprocessor({ // Return the default selector return `[data-theme='${theme.name}']`; }, + cascadeLayer: cascadeLayer ?? 'starlight.expressive-code', styleOverrides: { borderRadius: '0px', borderWidth: '1px', diff --git a/packages/starlight/style/layers.css b/packages/starlight/style/layers.css index b28a5af6348..981025769b3 100644 --- a/packages/starlight/style/layers.css +++ b/packages/starlight/style/layers.css @@ -1 +1 @@ -@layer starlight.base, starlight.reset, starlight.shiki, starlight.components, starlight.content, starlight.asides, starlight.user-components, starlight.utils; +@layer starlight.base, starlight.reset, starlight.shiki, starlight.components, starlight.content, starlight.expressive-code, starlight.asides, starlight.user-components, starlight.utils; From 37c2255d27925d6a201394e42a23994dd087b40c Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Tue, 10 Sep 2024 19:44:46 +0200 Subject: [PATCH 08/16] fix: aside component icon size --- packages/starlight/style/layers.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/starlight/style/layers.css b/packages/starlight/style/layers.css index 981025769b3..c6d9e50d613 100644 --- a/packages/starlight/style/layers.css +++ b/packages/starlight/style/layers.css @@ -1 +1 @@ -@layer starlight.base, starlight.reset, starlight.shiki, starlight.components, starlight.content, starlight.expressive-code, starlight.asides, starlight.user-components, starlight.utils; +@layer starlight.base, starlight.reset, starlight.shiki, starlight.components, starlight.content, starlight.expressive-code, starlight.user-components, starlight.asides, starlight.utils; From 81c6b133123a9792ccf5aaec54d9b49f3b67571d Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Wed, 11 Sep 2024 12:12:39 +0200 Subject: [PATCH 09/16] test: add `local-prod-visual-diff` module --- docs/astro.config.mjs | 2 + packages/local-prod-visual-diff/.gitignore | 1 + packages/local-prod-visual-diff/diff.setup.ts | 9 ++ packages/local-prod-visual-diff/diff.test.ts | 146 ++++++++++++++++++ packages/local-prod-visual-diff/package.json | 18 +++ .../playwright.config.ts | 33 ++++ pnpm-lock.yaml | 46 +++++- 7 files changed, 251 insertions(+), 4 deletions(-) create mode 100644 packages/local-prod-visual-diff/.gitignore create mode 100644 packages/local-prod-visual-diff/diff.setup.ts create mode 100644 packages/local-prod-visual-diff/diff.test.ts create mode 100644 packages/local-prod-visual-diff/package.json create mode 100644 packages/local-prod-visual-diff/playwright.config.ts diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 08eb61e6a98..c9adcccacc7 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -29,6 +29,8 @@ const ogUrl = new URL('og.jpg?v=1', site).href; const ogImageAlt = 'Make your docs shine with Starlight'; export default defineConfig({ + // TODO(HiDeoo) Remove this, only used to avoid screenshoting the dev toolbar. + devToolbar: { enabled: false }, site, trailingSlash: 'always', integrations: [ diff --git a/packages/local-prod-visual-diff/.gitignore b/packages/local-prod-visual-diff/.gitignore new file mode 100644 index 00000000000..750e145aa20 --- /dev/null +++ b/packages/local-prod-visual-diff/.gitignore @@ -0,0 +1 @@ +screenshots/ diff --git a/packages/local-prod-visual-diff/diff.setup.ts b/packages/local-prod-visual-diff/diff.setup.ts new file mode 100644 index 00000000000..2d57c072c2c --- /dev/null +++ b/packages/local-prod-visual-diff/diff.setup.ts @@ -0,0 +1,9 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; + +// Delete the dev and diff screenshots directories before running the tests. +await fs.rm(path.join('screenshots', 'dev'), { force: true, recursive: true }); +await fs.rm(path.join('screenshots', 'diff'), { force: true, recursive: true }); + +// Ensure the diff screenshots directory exists. +await fs.mkdir(path.join('screenshots', 'diff'), { recursive: true }); diff --git a/packages/local-prod-visual-diff/diff.test.ts b/packages/local-prod-visual-diff/diff.test.ts new file mode 100644 index 00000000000..f9624cc054a --- /dev/null +++ b/packages/local-prod-visual-diff/diff.test.ts @@ -0,0 +1,146 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { expect, test, type Page } from '@playwright/test'; +import pixelmatch from 'pixelmatch'; +import { PNG } from 'pngjs'; + +const prodUrl = new URL('https://starlight.astro.build'); + +// A list of all the routes to visually compare between the production and development environments. +// This could be based on the sitemap but it was not worth the effort for this PR. +const routePaths = [ + '/', + '/getting-started/', + '/manual-setup/', + '/environmental-impact/', + '/guides/pages/', + '/guides/authoring-content/', + '/guides/components/', + '/guides/css-and-tailwind/', + '/guides/customization/', + '/guides/i18n/', + '/guides/overriding-components/', + '/guides/sidebar/', + '/guides/site-search/', + '/reference/configuration/', + '/resources/plugins/', + '/resources/community-content/', + '/resources/showcase/', +]; + +// The maximum number of mismatched pixels between the production and development screenshots. +const maxDiffPixels = 10; + +for (const routePath of routePaths) { + test.only(`CSS Layers: ${routePath}`, async ({ page }) => { + const prodScreenshotPath = getScreenshotPath(routePath, 'prod'); + + // Take a screenshot of the production route if it doesn't exist. + if (!(await exists(prodScreenshotPath))) { + await page.goto(new URL(routePath, prodUrl).toString()); + await takeScreenshot(page, prodScreenshotPath); + } + + const devScreenshotPath = getScreenshotPath(routePath, 'dev'); + + // Take a screenshot of the development route. + await page.goto(routePath); + await takeScreenshot(page, devScreenshotPath); + + // Compare the screenshots between the production and development routes. + const { diffPixels, diffImage } = await compareScreenshots( + prodScreenshotPath, + devScreenshotPath + ); + + // Save the diff image if the number of mismatched pixels is greater than the maximum allowed. + if (diffPixels > maxDiffPixels) { + await fs.writeFile(getScreenshotPath(routePath, 'diff'), PNG.sync.write(diffImage)); + } + + // Assert the number of mismatched pixels is less than the maximum allowed. + expect(diffPixels).toBeLessThan(maxDiffPixels); + }); +} + +async function compareScreenshots(screenshotPath1: string, screenshotPath2: string) { + let screenshot1: PNG = await getScreenshot(screenshotPath1); + let screenshot2: PNG = await getScreenshot(screenshotPath2); + + let diffSize: ScreenshotSize; + + // If the screenshots have different dimensions, resize them to the largest dimensions so we can + // see where the differences start to appear. + if (screenshot1.width !== screenshot2.width || screenshot1.height !== screenshot2.height) { + diffSize = { + width: Math.max(screenshot1.width, screenshot2.width), + height: Math.max(screenshot1.height, screenshot2.height), + }; + + screenshot1 = resizeScreenshot(screenshot1, diffSize); + screenshot2 = resizeScreenshot(screenshot2, diffSize); + } else { + diffSize = { width: screenshot1.width, height: screenshot1.height }; + } + + const diffImage = new PNG(diffSize); + + const diffPixels = pixelmatch( + screenshot1.data, + screenshot2.data, + diffImage.data, + diffSize.width, + diffSize.height, + { threshold: 0.2 } + ); + + return { diffPixels, diffImage }; +} + +function resizeScreenshot(screenshot: PNG, size: ScreenshotSize) { + const resized = new PNG(size); + PNG.bitblt(screenshot, resized, 0, 0, screenshot.width, screenshot.height); + return resized; +} + +async function getScreenshot(screenshotPath: string) { + const data = await fs.readFile(screenshotPath); + return PNG.sync.read(data); +} + +async function takeScreenshot(page: Page, screenshotPath: string) { + // Ensure all images are loaded before taking the screenshot. + for (const lazyImage of await page.locator('img[loading="lazy"]:visible').all()) { + await lazyImage.scrollIntoViewIfNeeded(); + } + + // Scroll to the top of the page to ensure the screenshot is consistent. + await page.evaluate(() => window.scrollTo(0, 0)); + + await page.screenshot({ path: screenshotPath, fullPage: true }); +} + +function getScreenshotPath(routePath: string, type: ScreenshotType) { + return path.join( + 'screenshots', + type, + routePath.replace(/\//g, '-').replace(/^-/, '').replace(/-$/, '').replace(/^$/, 'index') + + '.png' + ); +} + +async function exists(filePath: string) { + try { + await fs.access(filePath, fs.constants.F_OK); + return true; + } catch { + return false; + } +} + +type ScreenshotType = 'dev' | 'prod' | 'diff'; + +interface ScreenshotSize { + width: number; + height: number; +} diff --git a/packages/local-prod-visual-diff/package.json b/packages/local-prod-visual-diff/package.json new file mode 100644 index 00000000000..cdaa53bc2bd --- /dev/null +++ b/packages/local-prod-visual-diff/package.json @@ -0,0 +1,18 @@ +{ + "name": "starlight-local-prod-visual-diff", + "version": "0.1.0", + "description": "Visual diffing between local and production builds of Starlight", + "private": true, + "scripts": { + "test": "playwright install --with-deps chromium && playwright test" + }, + "license": "MIT", + "dependencies": { + "@playwright/test": "^1.45.0", + "@types/pixelmatch": "^5.2.6", + "@types/pngjs": "^6.0.5", + "pixelmatch": "^6.0.0", + "pngjs": "^7.0.0" + }, + "type": "module" +} diff --git a/packages/local-prod-visual-diff/playwright.config.ts b/packages/local-prod-visual-diff/playwright.config.ts new file mode 100644 index 00000000000..7336800d896 --- /dev/null +++ b/packages/local-prod-visual-diff/playwright.config.ts @@ -0,0 +1,33 @@ +import { defineConfig, devices } from '@playwright/test'; + +const baseURL = 'http://localhost:4321'; + +export default defineConfig({ + forbidOnly: !!process.env['CI'], + projects: [ + { + name: 'setup diff', + testMatch: /diff\.setup\.ts/, + }, + { + name: 'Chrome Stable', + use: { + ...devices['Desktop Chrome'], + headless: true, + }, + dependencies: ['setup diff'], + }, + ], + testMatch: '*.test.ts', + use: { + baseURL, + }, + webServer: [ + { + command: 'pnpm run dev', + cwd: '../../docs', + reuseExistingServer: !process.env['CI'], + url: baseURL, + }, + ], +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ac9b53a9b93..d5701437bd7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -121,6 +121,24 @@ importers: specifier: ^3.4.4 version: 3.4.4 + packages/dev-prod-visual-diff: + dependencies: + '@playwright/test': + specifier: ^1.45.0 + version: 1.45.0 + '@types/pixelmatch': + specifier: ^5.2.6 + version: 5.2.6 + '@types/pngjs': + specifier: ^6.0.5 + version: 6.0.5 + pixelmatch: + specifier: ^6.0.0 + version: 6.0.0 + pngjs: + specifier: ^7.0.0 + version: 7.0.0 + packages/docsearch: dependencies: '@astrojs/starlight': @@ -1767,7 +1785,6 @@ packages: hasBin: true dependencies: playwright: 1.45.0 - dev: true /@rollup/pluginutils@5.1.0: resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} @@ -2054,6 +2071,18 @@ packages: resolution: {integrity: sha512-H6qeTp03jrknklSn4bpT1/9+1xCAEIU2CnjcWPkicJy8A1SKuthanbvoHYMiv79/2W3Xn1XE4gfSJFzt2U3JSw==} dev: true + /@types/pixelmatch@5.2.6: + resolution: {integrity: sha512-wC83uexE5KGuUODn6zkm9gMzTwdY5L0chiK+VrKcDfEjzxh1uadlWTvOmAbCpnM9zx/Ww3f8uKlYQVnO/TrqVg==} + dependencies: + '@types/node': 18.16.19 + dev: false + + /@types/pngjs@6.0.5: + resolution: {integrity: sha512-0k5eKfrA83JOZPppLtS2C7OUtyNAl2wKNxfyYl9Q5g9lPkgBl/9hNyAu6HuEH2J4XmIv2znEpkDd0SaZVxW6iQ==} + dependencies: + '@types/node': 18.16.19 + dev: false + /@types/sax@1.2.4: resolution: {integrity: sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==} dependencies: @@ -3651,7 +3680,6 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true - dev: true optional: true /fsevents@2.3.3: @@ -5874,6 +5902,13 @@ packages: engines: {node: '>= 6'} dev: false + /pixelmatch@6.0.0: + resolution: {integrity: sha512-FYpL4XiIWakTnIqLqvt3uN4L9B3TsuHIvhLILzTiJZMJUsGvmKNeL4H3b6I99LRyerK9W4IuOXw+N28AtRgK2g==} + hasBin: true + dependencies: + pngjs: 7.0.0 + dev: false + /pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -5892,7 +5927,6 @@ packages: resolution: {integrity: sha512-lZmHlFQ0VYSpAs43dRq1/nJ9G/6SiTI7VPqidld9TDefL9tX87bTKExWZZUF5PeRyqtXqd8fQi2qmfIedkwsNQ==} engines: {node: '>=18'} hasBin: true - dev: true /playwright@1.45.0: resolution: {integrity: sha512-4z3ac3plDfYzGB6r0Q3LF8POPR20Z8D0aXcxbJvmfMgSSq1hkcgvFRXJk9rUq5H/MJ0Ktal869hhOdI/zUTeLA==} @@ -5902,7 +5936,11 @@ packages: playwright-core: 1.45.0 optionalDependencies: fsevents: 2.3.2 - dev: true + + /pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + dev: false /postcss-import@15.1.0(postcss@8.4.45): resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} From 475c26dae90a52b9c8922f537fc4e59cee58afdd Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:26:12 +0200 Subject: [PATCH 10/16] fix: select icons --- packages/local-prod-visual-diff/diff.test.ts | 14 ++++++++++--- packages/starlight/components/Select.astro | 22 +++++++++++--------- packages/starlight/style/layers.css | 2 +- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/packages/local-prod-visual-diff/diff.test.ts b/packages/local-prod-visual-diff/diff.test.ts index f9624cc054a..3c25e688e07 100644 --- a/packages/local-prod-visual-diff/diff.test.ts +++ b/packages/local-prod-visual-diff/diff.test.ts @@ -54,7 +54,7 @@ for (const routePath of routePaths) { ); // Save the diff image if the number of mismatched pixels is greater than the maximum allowed. - if (diffPixels > maxDiffPixels) { + if (diffPixels >= maxDiffPixels) { await fs.writeFile(getScreenshotPath(routePath, 'diff'), PNG.sync.write(diffImage)); } @@ -91,7 +91,7 @@ async function compareScreenshots(screenshotPath1: string, screenshotPath2: stri diffImage.data, diffSize.width, diffSize.height, - { threshold: 0.2 } + { threshold: 0.1 } ); return { diffPixels, diffImage }; @@ -114,8 +114,16 @@ async function takeScreenshot(page: Page, screenshotPath: string) { await lazyImage.scrollIntoViewIfNeeded(); } + const overviewLink = page.getByRole('link', { name: 'Overview', exact: true }); + // Scroll to the top of the page to ensure the screenshot is consistent. - await page.evaluate(() => window.scrollTo(0, 0)); + if (await overviewLink.isVisible()) { + // Use the Overview link when possible to avoid mismatched pixels due to ToC highlighting. + overviewLink.click(); + } else { + await page.evaluate(() => window.scrollTo(0, 0)); + } + await page.waitForTimeout(500); await page.screenshot({ path: screenshotPath, fullPage: true }); } diff --git a/packages/starlight/components/Select.astro b/packages/starlight/components/Select.astro index 1221d558332..97982797b34 100644 --- a/packages/starlight/components/Select.astro +++ b/packages/starlight/components/Select.astro @@ -51,16 +51,6 @@ interface Props { pointer-events: none; } - .label-icon { - font-size: var(--sl-label-icon-size); - inset-inline-start: 0; - } - - .caret { - font-size: var(--sl-caret-size); - inset-inline-end: 0; - } - select { border: 0; padding-block: 0.625rem; @@ -86,4 +76,16 @@ interface Props { } } } + + @layer starlight.user-components { + .label-icon { + font-size: var(--sl-label-icon-size); + inset-inline-start: 0; + } + + .caret { + font-size: var(--sl-caret-size); + inset-inline-end: 0; + } + } diff --git a/packages/starlight/style/layers.css b/packages/starlight/style/layers.css index c6d9e50d613..5c418a3f4fb 100644 --- a/packages/starlight/style/layers.css +++ b/packages/starlight/style/layers.css @@ -1 +1 @@ -@layer starlight.base, starlight.reset, starlight.shiki, starlight.components, starlight.content, starlight.expressive-code, starlight.user-components, starlight.asides, starlight.utils; +@layer starlight.base, starlight.reset, starlight.shiki, starlight.components, starlight.content, starlight.user-components, starlight.asides, starlight.expressive-code, starlight.utils; From 8070d70dcb1036e0cf57dd2adb3ce30eb1cf3a50 Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:34:52 +0200 Subject: [PATCH 11/16] fix: steps content styles --- packages/local-prod-visual-diff/diff.test.ts | 2 +- packages/starlight/user-components/Steps.astro | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/local-prod-visual-diff/diff.test.ts b/packages/local-prod-visual-diff/diff.test.ts index 3c25e688e07..c2ccdfa6c5d 100644 --- a/packages/local-prod-visual-diff/diff.test.ts +++ b/packages/local-prod-visual-diff/diff.test.ts @@ -91,7 +91,7 @@ async function compareScreenshots(screenshotPath1: string, screenshotPath2: stri diffImage.data, diffSize.width, diffSize.height, - { threshold: 0.1 } + { threshold: 0.2 } ); return { diffPixels, diffImage }; diff --git a/packages/starlight/user-components/Steps.astro b/packages/starlight/user-components/Steps.astro index a1b62c85068..99c0815a375 100644 --- a/packages/starlight/user-components/Steps.astro +++ b/packages/starlight/user-components/Steps.astro @@ -62,7 +62,9 @@ const { html } = processSteps(content); width: var(--guide-width); background-color: var(--sl-color-hairline-light); } + } + @layer starlight.content { /* Adjust first item inside a step so that it aligns vertically with the number even if using a larger font size (e.g. a heading) */ .sl-steps > li > :first-child { From ec587be1161b03bca6df453173ac41605980f52c Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:41:47 +0200 Subject: [PATCH 12/16] docs: update browserslist query --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6fedacf1e0e..d4f2bd96cac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -275,7 +275,7 @@ To add a language, you will need its BCP-47 tag and a label. See [“Adding a ne - Components that require client-side JavaScript or CSS should use JavaScript/CSS features that are well-supported by browsers. - You can find a list of supported browsers and their versions using this [browserslist query](https://browsersl.ist/#q=%3E+0.5%25%2C+not+dead%2C+Chrome+%3E%3D+88%2C+Edge+%3E%3D+88%2C+Firefox+%3E%3D+98%2C+Safari+%3E%3D+15.4%2C+iOS+%3E%3D+15.4%2C+not+op_mini+all). To check whether or not a feature is supported, you can visit the [Can I use](https://caniuse.com) website and search for the feature. + You can find a list of supported browsers and their versions using this [browserslist query](https://browsersl.ist/#q=%3E+0.5%25%2C+not+dead%2C+Chrome+%3E%3D+99%2C+Edge+%3E%3D+99%2C+Firefox+%3E%3D+98%2C+Safari+%3E%3D+15.4%2C+iOS+%3E%3D+15.4%2C+not+op_mini+all). To check whether or not a feature is supported, you can visit the [Can I use](https://caniuse.com) website and search for the feature. [discord]: https://astro.build/chat [issues]: https://github.com/withastro/starlight/issues From cc2fccda24dc01eef4de00462f32e27498714644 Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:45:02 +0200 Subject: [PATCH 13/16] test: add local prod command --- packages/local-prod-visual-diff/playwright.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/local-prod-visual-diff/playwright.config.ts b/packages/local-prod-visual-diff/playwright.config.ts index 7336800d896..27fb0e622d7 100644 --- a/packages/local-prod-visual-diff/playwright.config.ts +++ b/packages/local-prod-visual-diff/playwright.config.ts @@ -25,6 +25,7 @@ export default defineConfig({ webServer: [ { command: 'pnpm run dev', + // command: 'pnpm run build && pnpm run preview', cwd: '../../docs', reuseExistingServer: !process.env['CI'], url: baseURL, From 94e7df42794e2f504e19198f1004b05e0984e2c6 Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:11:01 +0200 Subject: [PATCH 14/16] refactor: clean css import comments --- packages/starlight/components/Page.astro | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/starlight/components/Page.astro b/packages/starlight/components/Page.astro index f1e859e3d60..f5e9bcb3794 100644 --- a/packages/starlight/components/Page.astro +++ b/packages/starlight/components/Page.astro @@ -1,13 +1,12 @@ --- import type { Props } from '../props'; -// TODO(HiDeoo) +// Important that this is the first import so it can override cascade layers order. import 'virtual:starlight/user-css'; -// TODO(HiDeoo) +// Starlight nested cascade layers definitions which specify the default order of internal layers. import '../style/layers.css'; -// TODO(HiDeoo) // Built-in CSS styles. import '../style/props.css'; import '../style/reset.css'; @@ -15,8 +14,6 @@ import '../style/shiki.css'; import '../style/asides.css'; import '../style/util.css'; -// TODO(HiDeoo) -// Components — can override built-in CSS, but not user CSS. import Banner from 'virtual:starlight/components/Banner'; import ContentPanel from 'virtual:starlight/components/ContentPanel'; import FallbackContentNotice from 'virtual:starlight/components/FallbackContentNotice'; @@ -34,10 +31,6 @@ import SkipLink from 'virtual:starlight/components/SkipLink'; import ThemeProvider from 'virtual:starlight/components/ThemeProvider'; import TwoColumnContent from 'virtual:starlight/components/TwoColumnContent'; -// FIXME(HiDeoo) -// Important that this is the last import so it can override built-in styles. -// import 'virtual:starlight/user-css'; - const pagefindEnabled = Astro.props.entry.slug !== '404' && !Astro.props.entry.slug.endsWith('/404') && From cee7cbd0d868a772c74c5117e06a4c69cadf3dc4 Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:11:23 +0200 Subject: [PATCH 15/16] docs: cascade layers --- docs/src/content/docs/guides/css-and-tailwind.mdx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/src/content/docs/guides/css-and-tailwind.mdx b/docs/src/content/docs/guides/css-and-tailwind.mdx index 405b8e27c34..55f33f0b921 100644 --- a/docs/src/content/docs/guides/css-and-tailwind.mdx +++ b/docs/src/content/docs/guides/css-and-tailwind.mdx @@ -48,6 +48,13 @@ Customize the styles applied to your Starlight site by providing additional CSS You can see all the CSS custom properties used by Starlight that you can set to customize your site in the [`props.css` file on GitHub](https://github.com/withastro/starlight/blob/main/packages/starlight/style/props.css). +Starlight uses [cascade layers](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_layers) internally so that any custom unlayered CSS will override the default styles. +If you are using cascade layers in your custom CSS, you can use the [`@layer`](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer) CSS at-rule to define the order of precedence for different layers including the ones used by Starlight: + +```css +@layer my-reset, starlight, my-layer; +``` + ## Tailwind CSS Tailwind CSS support in Astro projects is provided by the [Astro Tailwind integration](https://docs.astro.build/en/guides/integrations-guide/tailwind/). From 8b39634a244ae563d5e49d40be399e6fdc182b4a Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:53:13 +0200 Subject: [PATCH 16/16] fix: update lockfile --- pnpm-lock.yaml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d5701437bd7..74c1bd3ba28 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -121,24 +121,6 @@ importers: specifier: ^3.4.4 version: 3.4.4 - packages/dev-prod-visual-diff: - dependencies: - '@playwright/test': - specifier: ^1.45.0 - version: 1.45.0 - '@types/pixelmatch': - specifier: ^5.2.6 - version: 5.2.6 - '@types/pngjs': - specifier: ^6.0.5 - version: 6.0.5 - pixelmatch: - specifier: ^6.0.0 - version: 6.0.0 - pngjs: - specifier: ^7.0.0 - version: 7.0.0 - packages/docsearch: dependencies: '@astrojs/starlight': @@ -164,6 +146,24 @@ importers: specifier: ^1.3.8 version: 1.3.8 + packages/local-prod-visual-diff: + dependencies: + '@playwright/test': + specifier: ^1.45.0 + version: 1.45.0 + '@types/pixelmatch': + specifier: ^5.2.6 + version: 5.2.6 + '@types/pngjs': + specifier: ^6.0.5 + version: 6.0.5 + pixelmatch: + specifier: ^6.0.0 + version: 6.0.0 + pngjs: + specifier: ^7.0.0 + version: 7.0.0 + packages/markdoc: dependencies: '@astrojs/markdoc':