Use accessible indentation (#2253)

This commit is contained in:
Jonathan Neal 2021-12-22 16:11:05 -05:00 committed by GitHub
parent 305ce4182f
commit 6ddd7678ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
440 changed files with 21261 additions and 20879 deletions

View file

@ -4,9 +4,12 @@
root = true root = true
[*] [*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8 charset = utf-8
trim_trailing_whitespace = false end_of_line = lf
indent_size = 2
indent_style = tab
insert_final_newline = true insert_final_newline = true
trim_trailing_whitespace = false
[{.*,*.md,*.json,*.toml,*.yml,}]
indent_style = space

View file

@ -3,5 +3,14 @@
"semi": true, "semi": true,
"singleQuote": true, "singleQuote": true,
"tabWidth": 2, "tabWidth": 2,
"trailingComma": "es5" "trailingComma": "es5",
"useTabs": true,
"overrides": [
{
"files": [".*", "*.json", "*.md", "*.toml", "*.yml"],
"options": {
"useTabs": false
}
}
]
} }

View file

@ -1,12 +1,12 @@
// @ts-check // @ts-check
export default /** @type {import('astro').AstroUserConfig} */ ({ export default /** @type {import('astro').AstroUserConfig} */ ({
buildOptions: { buildOptions: {
site: 'https://docs.astro.build/', site: 'https://docs.astro.build/',
}, },
renderers: [ renderers: [
// Our main renderer for frontend components // Our main renderer for frontend components
'@astrojs/renderer-preact', '@astrojs/renderer-preact',
// Needed for Algolia search component // Needed for Algolia search component
'@astrojs/renderer-react', '@astrojs/renderer-react',
], ],
}); });

View file

@ -1,34 +1,34 @@
.language-css > code, .language-css > code,
.language-sass > code, .language-sass > code,
.language-scss > code { .language-scss > code {
color: #fd9170; color: #fd9170;
} }
.language-diff .token.prefix.deleted, .language-diff .token.prefix.deleted,
.language-diff .token.prefix.inserted { .language-diff .token.prefix.inserted {
user-select: none; user-select: none;
} }
[class*='language-'] .namespace { [class*='language-'] .namespace {
opacity: 0.7; opacity: 0.7;
} }
.token.plain-text, .token.plain-text,
[class*='language-bash'] span.token, [class*='language-bash'] span.token,
[class*='language-shell'] span.token { [class*='language-shell'] span.token {
color: hsla(var(--color-gray-90), 1); color: hsla(var(--color-gray-90), 1);
} }
[class*='language-bash'] span.token, [class*='language-bash'] span.token,
[class*='language-shell'] span.token { [class*='language-shell'] span.token {
font-style: bold; font-style: bold;
} }
.token.prolog, .token.prolog,
.token.comment, .token.comment,
[class*='language-bash'] span.token.comment, [class*='language-bash'] span.token.comment,
[class*='language-shell'] span.token.comment { [class*='language-shell'] span.token.comment {
color: hsla(var(--color-gray-70), 1); color: hsla(var(--color-gray-70), 1);
} }
.token.selector, .token.selector,
@ -38,7 +38,7 @@
.token.variable, .token.variable,
.token.entity, .token.entity,
.token.deleted { .token.deleted {
color: #fa5e5b; color: #fa5e5b;
} }
.token.boolean, .token.boolean,
@ -51,7 +51,7 @@
.token.hexcode, .token.hexcode,
.token.class-name, .token.class-name,
.token.attr-name { .token.attr-name {
color: hsla(var(--color-yellow), 1); color: hsla(var(--color-yellow), 1);
} }
.token.atrule, .token.atrule,
@ -61,41 +61,41 @@
.token.pseudo-class, .token.pseudo-class,
.token.pseudo-element, .token.pseudo-element,
.token.string { .token.string {
color: hsla(var(--color-green), 1); color: hsla(var(--color-green), 1);
} }
.token.symbol, .token.symbol,
.token.function, .token.function,
.token.id, .token.id,
.token.important { .token.important {
color: hsla(var(--color-blue), 1); color: hsla(var(--color-blue), 1);
} }
.token.important, .token.important,
.token.id { .token.id {
font-weight: bold; font-weight: bold;
} }
.token.cdata, .token.cdata,
.token.char, .token.char,
.token.property { .token.property {
color: #23b1af; color: #23b1af;
} }
.token.inserted { .token.inserted {
color: hsla(var(--color-green), 1); color: hsla(var(--color-green), 1);
} }
.token.keyword { .token.keyword {
color: #ff657c; color: #ff657c;
font-style: italic; font-style: italic;
} }
.token.operator { .token.operator {
color: hsla(var(--color-gray-70), 1); color: hsla(var(--color-gray-70), 1);
} }
.token.attr-value .token.attr-equals, .token.attr-value .token.attr-equals,
.token.punctuation { .token.punctuation {
color: hsla(var(--color-gray-80), 1); color: hsla(var(--color-gray-80), 1);
} }

View file

@ -1,46 +1,46 @@
* { * {
box-sizing: border-box; box-sizing: border-box;
margin: 0; margin: 0;
} }
/* Global focus outline reset */ /* Global focus outline reset */
*:focus:not(:focus-visible) { *:focus:not(:focus-visible) {
outline: none; outline: none;
} }
:root { :root {
--user-font-scale: 1rem - 16px; --user-font-scale: 1rem - 16px;
--max-width: calc(100% - 1rem); --max-width: calc(100% - 1rem);
} }
@media (min-width: 50em) { @media (min-width: 50em) {
:root { :root {
--max-width: 46em; --max-width: 46em;
} }
} }
body { body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 100vh; min-height: 100vh;
font-family: var(--font-body); font-family: var(--font-body);
font-size: 1rem; font-size: 1rem;
font-size: clamp(0.9rem, 0.75rem + 0.375vw + var(--user-font-scale), 1rem); font-size: clamp(0.9rem, 0.75rem + 0.375vw + var(--user-font-scale), 1rem);
line-height: 1.5; line-height: 1.5;
max-width: 100vw; max-width: 100vw;
} }
nav ul { nav ul {
list-style: none; list-style: none;
padding: 0; padding: 0;
} }
.content > section > * + * { .content > section > * + * {
margin-top: 1.25rem; margin-top: 1.25rem;
} }
.content > section > :first-child { .content > section > :first-child {
margin-top: 0; margin-top: 0;
} }
/* Typography */ /* Typography */
@ -50,335 +50,335 @@ h3,
h4, h4,
h5, h5,
h6 { h6 {
margin-bottom: 1rem; margin-bottom: 1rem;
font-weight: bold; font-weight: bold;
line-height: 1; line-height: 1;
} }
h1, h1,
h2 { h2 {
max-width: 40ch; max-width: 40ch;
} }
:is(h2, h3):not(:first-child) { :is(h2, h3):not(:first-child) {
margin-top: 3rem; margin-top: 3rem;
} }
:is(h4, h5, h6):not(:first-child) { :is(h4, h5, h6):not(:first-child) {
margin-top: 2rem; margin-top: 2rem;
} }
h1 { h1 {
font-size: 3.25rem; font-size: 3.25rem;
font-weight: 800; font-weight: 800;
} }
h2 { h2 {
font-size: 2.5rem; font-size: 2.5rem;
} }
h3 { h3 {
font-size: 1.75rem; font-size: 1.75rem;
} }
h4 { h4 {
font-size: 1.3rem; font-size: 1.3rem;
} }
h5 { h5 {
font-size: 1rem; font-size: 1rem;
} }
p, p,
.content ul { .content ul {
line-height: 1.65em; line-height: 1.65em;
} }
p, p,
.content ul { .content ul {
color: var(--theme-text-light); color: var(--theme-text-light);
} }
small, small,
.text_small { .text_small {
font-size: 0.833rem; font-size: 0.833rem;
} }
a { a {
color: var(--theme-text-accent); color: var(--theme-text-accent);
text-underline-offset: 0.08em; text-underline-offset: 0.08em;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
} }
article > section :is(ul, ol) > * + * { article > section :is(ul, ol) > * + * {
margin-top: 0.25rem; margin-top: 0.25rem;
} }
article > section nav :is(ul, ol) > * + * { article > section nav :is(ul, ol) > * + * {
margin-top: inherit; margin-top: inherit;
} }
article > section li > :is(p, pre, blockquote):not(:first-child) { article > section li > :is(p, pre, blockquote):not(:first-child) {
margin-top: 1rem; margin-top: 1rem;
} }
article > section :is(ul, ol) { article > section :is(ul, ol) {
padding-left: 1em; padding-left: 1em;
} }
article > section nav :is(ul, ol) { article > section nav :is(ul, ol) {
padding-left: inherit; padding-left: inherit;
} }
article > section nav { article > section nav {
margin-top: 1rem; margin-top: 1rem;
margin-bottom: 2rem; margin-bottom: 2rem;
} }
article > section ::marker { article > section ::marker {
font-weight: bold; font-weight: bold;
color: var(--theme-text-light); color: var(--theme-text-light);
} }
article > section iframe { article > section iframe {
width: 100%; width: 100%;
height: auto; height: auto;
aspect-ratio: 16 / 9; aspect-ratio: 16 / 9;
} }
a > code:not([class*='language']) { a > code:not([class*='language']) {
position: relative; position: relative;
color: var(--theme-text-accent); color: var(--theme-text-accent);
background: transparent; background: transparent;
text-underline-offset: var(--padding-block); text-underline-offset: var(--padding-block);
} }
a > code:not([class*='language'])::before { a > code:not([class*='language'])::before {
content: ''; content: '';
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
display: block; display: block;
background: var(--theme-accent); background: var(--theme-accent);
opacity: var(--theme-accent-opacity); opacity: var(--theme-accent-opacity);
border-radius: var(--border-radius); border-radius: var(--border-radius);
} }
a:hover, a:hover,
a:focus { a:focus {
text-decoration: underline; text-decoration: underline;
} }
a:focus { a:focus {
outline: 2px solid currentColor; outline: 2px solid currentColor;
outline-offset: 0.25em; outline-offset: 0.25em;
} }
strong { strong {
font-weight: 600; font-weight: 600;
color: inherit; color: inherit;
} }
/* Supporting Content */ /* Supporting Content */
code { code {
font-family: var(--font-mono); font-family: var(--font-mono);
font-size: 0.85em; font-size: 0.85em;
} }
code:not([class*='language']) { code:not([class*='language']) {
--border-radius: 3px; --border-radius: 3px;
--padding-block: 0.2rem; --padding-block: 0.2rem;
--padding-inline: 0.4rem; --padding-inline: 0.4rem;
color: var(--theme-code-inline-text); color: var(--theme-code-inline-text);
background-color: var(--theme-code-inline-bg); background-color: var(--theme-code-inline-bg);
padding: var(--padding-block) var(--padding-inline); padding: var(--padding-block) var(--padding-inline);
margin: calc(var(--padding-block) * -1) -0.125em; margin: calc(var(--padding-block) * -1) -0.125em;
border-radius: var(--border-radius); border-radius: var(--border-radius);
box-shadow: 0 2px 1px 0 rgba(0, 0, 0, 0.08); box-shadow: 0 2px 1px 0 rgba(0, 0, 0, 0.08);
word-break: break-word; word-break: break-word;
} }
pre > code:not([class*='language']) { pre > code:not([class*='language']) {
background-color: transparent; background-color: transparent;
padding: 0; padding: 0;
margin: 0; margin: 0;
border-radius: 0; border-radius: 0;
color: inherit; color: inherit;
} }
pre > code { pre > code {
font-size: 1em; font-size: 1em;
} }
table, table,
pre { pre {
position: relative; position: relative;
--padding-block: 1rem; --padding-block: 1rem;
--padding-inline: 2rem; --padding-inline: 2rem;
padding: var(--padding-block) var(--padding-inline); padding: var(--padding-block) var(--padding-inline);
padding-right: calc(var(--padding-inline) * 2); padding-right: calc(var(--padding-inline) * 2);
margin-left: calc(var(--padding-inline) * -1); margin-left: calc(var(--padding-inline) * -1);
margin-right: calc(var(--padding-inline) * -1); margin-right: calc(var(--padding-inline) * -1);
font-family: var(--font-mono); font-family: var(--font-mono);
line-height: 1.5; line-height: 1.5;
font-size: 0.85em; font-size: 0.85em;
overflow-y: hidden; overflow-y: hidden;
overflow-x: auto; overflow-x: auto;
} }
table { table {
width: 100%; width: 100%;
padding: var(--padding-block) 0; padding: var(--padding-block) 0;
margin: 0; margin: 0;
border-collapse: collapse; border-collapse: collapse;
} }
/* Zebra striping */ /* Zebra striping */
tr:nth-of-type(odd) { tr:nth-of-type(odd) {
background: var(--theme-bg-hover); background: var(--theme-bg-hover);
} }
th { th {
background: var(--color-black); background: var(--color-black);
color: var(--theme-color); color: var(--theme-color);
font-weight: bold; font-weight: bold;
} }
td, td,
th { th {
padding: 6px; padding: 6px;
text-align: left; text-align: left;
} }
pre { pre {
background-color: var(--theme-code-bg); background-color: var(--theme-code-bg);
color: var(--theme-code-text); color: var(--theme-code-text);
} }
blockquote code:not([class*='language']) { blockquote code:not([class*='language']) {
background-color: var(--theme-bg); background-color: var(--theme-bg);
} }
@media (min-width: 37.75em) { @media (min-width: 37.75em) {
pre { pre {
--padding-inline: 1.25rem; --padding-inline: 1.25rem;
border-radius: 8px; border-radius: 8px;
margin-left: 0; margin-left: 0;
margin-right: 0; margin-right: 0;
} }
} }
blockquote { blockquote {
margin: 2rem 0; margin: 2rem 0;
padding: 1.25em 1.5rem; padding: 1.25em 1.5rem;
border-left: 3px solid var(--theme-text-light); border-left: 3px solid var(--theme-text-light);
background-color: var(--theme-bg-offset); background-color: var(--theme-bg-offset);
border-radius: 0 0.25rem 0.25rem 0; border-radius: 0 0.25rem 0.25rem 0;
line-height: 1.7; line-height: 1.7;
} }
img { img {
max-width: 100%; max-width: 100%;
} }
.flex { .flex {
display: flex; display: flex;
align-items: center; align-items: center;
} }
button { button {
display: flex; display: flex;
align-items: center; align-items: center;
justify-items: center; justify-items: center;
gap: 0.25em; gap: 0.25em;
padding: 0.33em 0.67em; padding: 0.33em 0.67em;
border: 0; border: 0;
background: var(--theme-bg); background: var(--theme-bg);
display: flex; display: flex;
font-size: 1rem; font-size: 1rem;
align-items: center; align-items: center;
gap: 0.25em; gap: 0.25em;
border-radius: 99em; border-radius: 99em;
color: var(--theme-text); color: var(--theme-text);
background-color: var(--theme-bg); background-color: var(--theme-bg);
} }
h2.heading { h2.heading {
font-size: 1rem; font-size: 1rem;
font-weight: 700; font-weight: 700;
padding: 0.1rem 1rem; padding: 0.1rem 1rem;
text-transform: uppercase; text-transform: uppercase;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.header-link { .header-link {
font-size: 1rem; font-size: 1rem;
padding: 0.1rem 0 0.1rem 1rem; padding: 0.1rem 0 0.1rem 1rem;
border-left: 4px solid var(--theme-divider); border-left: 4px solid var(--theme-divider);
} }
.header-link:hover, .header-link:hover,
.header-link:focus { .header-link:focus {
border-left-color: var(--theme-accent); border-left-color: var(--theme-accent);
color: var(--theme-accent); color: var(--theme-accent);
} }
.header-link:focus-within { .header-link:focus-within {
color: var(--theme-text-light); color: var(--theme-text-light);
border-left-color: hsla(var(--color-gray-40), 1); border-left-color: hsla(var(--color-gray-40), 1);
} }
.header-link svg { .header-link svg {
opacity: 0.6; opacity: 0.6;
} }
.header-link:hover svg { .header-link:hover svg {
opacity: 0.8; opacity: 0.8;
} }
.header-link a { .header-link a {
display: inline-flex; display: inline-flex;
gap: 0.5em; gap: 0.5em;
width: 100%; width: 100%;
padding: 0.15em 0 0.15em 0; padding: 0.15em 0 0.15em 0;
} }
.header-link.depth-3 { .header-link.depth-3 {
padding-left: 2rem; padding-left: 2rem;
} }
.header-link.depth-4 { .header-link.depth-4 {
padding-left: 3rem; padding-left: 3rem;
} }
.header-link a { .header-link a {
font: inherit; font: inherit;
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
} }
/* Screenreader Only Text */ /* Screenreader Only Text */
.sr-only { .sr-only {
position: absolute; position: absolute;
width: 1px; width: 1px;
height: 1px; height: 1px;
padding: 0; padding: 0;
margin: -1px; margin: -1px;
overflow: hidden; overflow: hidden;
clip: rect(0, 0, 0, 0); clip: rect(0, 0, 0, 0);
white-space: nowrap; white-space: nowrap;
border-width: 0; border-width: 0;
} }
.focus\:not-sr-only:focus, .focus\:not-sr-only:focus,
.focus\:not-sr-only:focus-visible { .focus\:not-sr-only:focus-visible {
position: static; position: static;
width: auto; width: auto;
height: auto; height: auto;
padding: 0; padding: 0;
margin: 0; margin: 0;
overflow: visible; overflow: visible;
clip: auto; clip: auto;
white-space: normal; white-space: normal;
} }
:target { :target {
scroll-margin: calc(var(--theme-sidebar-offset, 5rem) + 2rem) 0 2rem; scroll-margin: calc(var(--theme-sidebar-offset, 5rem) + 2rem) 0 2rem;
} }

View file

@ -1,3 +1,3 @@
Array.from(document.getElementsByTagName('pre')).forEach((element) => { Array.from(document.getElementsByTagName('pre')).forEach((element) => {
element.setAttribute('tabindex', '0'); element.setAttribute('tabindex', '0');
}); });

View file

@ -1,13 +1,13 @@
:root { :root {
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, --font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
sans-serif, Apple Color Emoji, Segoe UI Emoji; sans-serif, Apple Color Emoji, Segoe UI Emoji;
--font-body: system-ui, var(--font-fallback); --font-body: system-ui, var(--font-fallback);
--font-mono: 'IBM Plex Mono', Consolas, 'Andale Mono WT', 'Andale Mono', --font-mono: 'IBM Plex Mono', Consolas, 'Andale Mono WT', 'Andale Mono',
'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono',
'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco,
'Courier New', Courier, monospace; 'Courier New', Courier, monospace;
/* /*
* Variables with --color-base prefix define * Variables with --color-base prefix define
* the hue, and saturation values to be used for * the hue, and saturation values to be used for
* hsla colors. * hsla colors.
@ -18,109 +18,109 @@
* *
*/ */
--color-base-white: 0, 0%; --color-base-white: 0, 0%;
--color-base-black: 240, 100%; --color-base-black: 240, 100%;
--color-base-gray: 215, 14%; --color-base-gray: 215, 14%;
--color-base-blue: 212, 100%; --color-base-blue: 212, 100%;
--color-base-blue-dark: 212, 72%; --color-base-blue-dark: 212, 72%;
--color-base-green: 158, 79%; --color-base-green: 158, 79%;
--color-base-orange: 22, 100%; --color-base-orange: 22, 100%;
--color-base-purple: 269, 79%; --color-base-purple: 269, 79%;
--color-base-red: 351, 100%; --color-base-red: 351, 100%;
--color-base-yellow: 41, 100%; --color-base-yellow: 41, 100%;
/* /*
* Color palettes are made using --color-base * Color palettes are made using --color-base
* variables, along with a lightness value to * variables, along with a lightness value to
* define different variants. * define different variants.
* *
*/ */
--color-gray-5: var(--color-base-gray), 5%; --color-gray-5: var(--color-base-gray), 5%;
--color-gray-10: var(--color-base-gray), 10%; --color-gray-10: var(--color-base-gray), 10%;
--color-gray-20: var(--color-base-gray), 20%; --color-gray-20: var(--color-base-gray), 20%;
--color-gray-30: var(--color-base-gray), 30%; --color-gray-30: var(--color-base-gray), 30%;
--color-gray-40: var(--color-base-gray), 40%; --color-gray-40: var(--color-base-gray), 40%;
--color-gray-50: var(--color-base-gray), 50%; --color-gray-50: var(--color-base-gray), 50%;
--color-gray-60: var(--color-base-gray), 60%; --color-gray-60: var(--color-base-gray), 60%;
--color-gray-70: var(--color-base-gray), 70%; --color-gray-70: var(--color-base-gray), 70%;
--color-gray-80: var(--color-base-gray), 80%; --color-gray-80: var(--color-base-gray), 80%;
--color-gray-90: var(--color-base-gray), 90%; --color-gray-90: var(--color-base-gray), 90%;
--color-gray-95: var(--color-base-gray), 95%; --color-gray-95: var(--color-base-gray), 95%;
--color-blue: var(--color-base-blue), 61%; --color-blue: var(--color-base-blue), 61%;
--color-blue-dark: var(--color-base-blue-dark), 39%; --color-blue-dark: var(--color-base-blue-dark), 39%;
--color-green: var(--color-base-green), 42%; --color-green: var(--color-base-green), 42%;
--color-orange: var(--color-base-orange), 50%; --color-orange: var(--color-base-orange), 50%;
--color-purple: var(--color-base-purple), 54%; --color-purple: var(--color-base-purple), 54%;
--color-red: var(--color-base-red), 54%; --color-red: var(--color-base-red), 54%;
--color-yellow: var(--color-base-yellow), 59%; --color-yellow: var(--color-base-yellow), 59%;
} }
:root { :root {
color-scheme: light; color-scheme: light;
--theme-accent: hsla(var(--color-orange), 1); --theme-accent: hsla(var(--color-orange), 1);
--theme-text-accent: hsla(var(--color-orange), 1); --theme-text-accent: hsla(var(--color-orange), 1);
--theme-accent-opacity: 0.1; --theme-accent-opacity: 0.1;
--theme-divider: hsla(var(--color-gray-95), 1); --theme-divider: hsla(var(--color-gray-95), 1);
--theme-text: hsla(var(--color-gray-10), 1); --theme-text: hsla(var(--color-gray-10), 1);
--theme-text-light: hsla(var(--color-gray-40), 1); --theme-text-light: hsla(var(--color-gray-40), 1);
/* @@@: not used anywhere */ /* @@@: not used anywhere */
--theme-text-lighter: hsla(var(--color-gray-80), 1); --theme-text-lighter: hsla(var(--color-gray-80), 1);
--theme-bg: hsla(var(--color-base-white), 100%, 1); --theme-bg: hsla(var(--color-base-white), 100%, 1);
--theme-bg-hover: hsla(var(--color-gray-95), 1); --theme-bg-hover: hsla(var(--color-gray-95), 1);
--theme-bg-offset: hsla(var(--color-gray-90), 1); --theme-bg-offset: hsla(var(--color-gray-90), 1);
--theme-bg-accent: hsla(var(--color-orange), var(--theme-accent-opacity)); --theme-bg-accent: hsla(var(--color-orange), var(--theme-accent-opacity));
--theme-code-inline-bg: hsla(var(--color-gray-95), 1); --theme-code-inline-bg: hsla(var(--color-gray-95), 1);
--theme-code-inline-text: var(--theme-text); --theme-code-inline-text: var(--theme-text);
--theme-code-bg: hsla(217, 19%, 27%, 1); --theme-code-bg: hsla(217, 19%, 27%, 1);
--theme-code-text: hsla(var(--color-gray-95), 1); --theme-code-text: hsla(var(--color-gray-95), 1);
--theme-navbar-bg: hsla(var(--color-base-white), 100%, 1); --theme-navbar-bg: hsla(var(--color-base-white), 100%, 1);
--theme-navbar-height: 6rem; --theme-navbar-height: 6rem;
--theme-selection-color: hsla(var(--color-orange), 1); --theme-selection-color: hsla(var(--color-orange), 1);
--theme-selection-bg: hsla(var(--color-orange), var(--theme-accent-opacity)); --theme-selection-bg: hsla(var(--color-orange), var(--theme-accent-opacity));
} }
body { body {
background: var(--theme-bg); background: var(--theme-bg);
color: var(--theme-text); color: var(--theme-text);
} }
:root.theme-dark { :root.theme-dark {
color-scheme: dark; color-scheme: dark;
--theme-accent-opacity: 0.4; --theme-accent-opacity: 0.4;
--theme-accent: hsla(var(--color-orange), 1); --theme-accent: hsla(var(--color-orange), 1);
--theme-text-accent: hsla(var(--color-orange), 1); --theme-text-accent: hsla(var(--color-orange), 1);
--theme-divider: hsla(var(--color-gray-10), 1); --theme-divider: hsla(var(--color-gray-10), 1);
--theme-text: hsla(var(--color-gray-90), 1); --theme-text: hsla(var(--color-gray-90), 1);
--theme-text-light: hsla(var(--color-gray-80), 1); --theme-text-light: hsla(var(--color-gray-80), 1);
/* @@@: not used anywhere */ /* @@@: not used anywhere */
--theme-text-lighter: hsla(var(--color-gray-40), 1); --theme-text-lighter: hsla(var(--color-gray-40), 1);
--theme-bg: hsla(215, 28%, 17%, 1); --theme-bg: hsla(215, 28%, 17%, 1);
--theme-bg-hover: hsla(var(--color-gray-40), 1); --theme-bg-hover: hsla(var(--color-gray-40), 1);
--theme-bg-offset: hsla(var(--color-gray-5), 1); --theme-bg-offset: hsla(var(--color-gray-5), 1);
--theme-code-inline-bg: hsla(var(--color-gray-10), 1); --theme-code-inline-bg: hsla(var(--color-gray-10), 1);
--theme-code-inline-text: hsla(var(--color-base-white), 100%, 1); --theme-code-inline-text: hsla(var(--color-base-white), 100%, 1);
--theme-code-bg: hsla(var(--color-gray-5), 1); --theme-code-bg: hsla(var(--color-gray-5), 1);
--theme-code-text: hsla(var(--color-base-white), 100%, 1); --theme-code-text: hsla(var(--color-base-white), 100%, 1);
--theme-navbar-bg: hsla(215, 28%, 17%, 1); --theme-navbar-bg: hsla(215, 28%, 17%, 1);
--theme-selection-color: hsla(var(--color-base-white), 100%, 1); --theme-selection-color: hsla(var(--color-base-white), 100%, 1);
--theme-selection-bg: hsla(var(--color-purple), var(--theme-accent-opacity)); --theme-selection-bg: hsla(var(--color-purple), var(--theme-accent-opacity));
/* DocSearch [Algolia] */ /* DocSearch [Algolia] */
--docsearch-modal-background: var(--theme-bg); --docsearch-modal-background: var(--theme-bg);
--docsearch-searchbox-focus-background: var(--theme-divider); --docsearch-searchbox-focus-background: var(--theme-divider);
--docsearch-footer-background: var(--theme-divider); --docsearch-footer-background: var(--theme-divider);
--docsearch-text-color: var(--theme-text); --docsearch-text-color: var(--theme-text);
--docsearch-hit-background: var(--theme-divider); --docsearch-hit-background: var(--theme-divider);
--docsearch-hit-shadow: none; --docsearch-hit-shadow: none;
--docsearch-hit-color: var(--theme-text); --docsearch-hit-color: var(--theme-text);
--docsearch-footer-shadow: inset 0 2px 10px #000; --docsearch-footer-shadow: inset 0 2px 10px #000;
--docsearch-modal-shadow: inset 0 0 8px #000; --docsearch-modal-shadow: inset 0 0 8px #000;
} }
::selection { ::selection {
color: var(--theme-selection-color); color: var(--theme-selection-color);
background-color: var(--theme-selection-bg); background-color: var(--theme-selection-bg);
} }

View file

@ -1,52 +1,62 @@
--- ---
const {data, index} = Astro.props; const { data, index } = Astro.props;
const hasScreenshot = !!data.demo; const hasScreenshot = !!data.demo;
const backgroundStyle = hasScreenshot ? `url('https://v1.screenshot.11ty.dev/${encodeURIComponent(data.demo)}/medium/9:16/')` : `linear-gradient(60deg, var(--theme-bg-accent), var(--theme-accent))` const backgroundStyle = hasScreenshot
? `url('https://v1.screenshot.11ty.dev/${encodeURIComponent(
data.demo
)}/medium/9:16/')`
: `linear-gradient(60deg, var(--theme-bg-accent), var(--theme-accent))`;
--- ---
<article
class={`card ${hasScreenshot ? 'has-screenshot' : ''}`}
style={`background: ${backgroundStyle}; background-size: cover;`}
>
{hasScreenshot && <div class="background-dimmer"></div>}
<div class="card-body">
<a href={data.github} class="card-header" target="_blank">
{data.name}
<span>{` →`}</span>
</a>
</div>
</article>
<style> <style>
.card { .card {
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
grid-column: span 1; grid-column: span 1;
flex-grow: 1; flex-grow: 1;
height: 200px; height: 200px;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
padding: 1rem; padding: 1rem;
text-align: center; text-align: center;
} }
.card-header { .card-header {
flex-grow: 1; flex-grow: 1;
font-weight: bold; font-weight: bold;
font-size: 1.8rem; font-size: 1.8rem;
} }
.background-dimmer { .background-dimmer {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
height: 100%; height: 100%;
width: 100%; width: 100%;
background: linear-gradient(45deg, #0004, #000B); background: linear-gradient(45deg, #0004, #000b);
z-index: 2; z-index: 2;
} }
.card-body, .card-header { .card-body,
color: var(--text-color); .card-header {
} color: var(--text-color);
.card-body { }
z-index: 3; .card-body {
} z-index: 3;
.card.has-screenshot .card-header, }
.card.has-screenshot .card-body { .card.has-screenshot .card-header,
color: white; .card.has-screenshot .card-body {
} color: white;
}
</style> </style>
<article class={`card ${hasScreenshot ? 'has-screenshot' : ''}`} style={`background: ${backgroundStyle}; background-size: cover;`}>
{hasScreenshot && <div class="background-dimmer"></div>}
<div class="card-body">
<a href={data.github} class="card-header" target="_blank">
{data.name}
<span>{` →`}</span>
</a>
</div>
</article>

View file

@ -2,7 +2,7 @@
// fetch all commits for just this page's path // fetch all commits for just this page's path
export interface Props { export interface Props {
path: string; path: string;
} }
const { path } = Astro.props as Props; const { path } = Astro.props as Props;
@ -11,147 +11,166 @@ const url = `https://api.github.com/repos/withastro/astro/commits?path=${commitP
const commitsURL = `https://github.com/withastro/astro/commits/main/${commitPath}`; const commitsURL = `https://github.com/withastro/astro/commits/main/${commitPath}`;
async function getCommits(url) { async function getCommits(url) {
try { try {
const token = import.meta.env.SNOWPACK_PUBLIC_GITHUB_TOKEN; const token = import.meta.env.SNOWPACK_PUBLIC_GITHUB_TOKEN;
if (!token) { if (!token) {
throw new Error( throw new Error(
'Cannot find "SNOWPACK_PUBLIC_GITHUB_TOKEN" used for escaping rate-limiting.' 'Cannot find "SNOWPACK_PUBLIC_GITHUB_TOKEN" used for escaping rate-limiting.'
); );
} }
const auth = `Basic ${Buffer.from(token, "binary").toString("base64")}`; const auth = `Basic ${Buffer.from(token, 'binary').toString('base64')}`;
const res = await fetch(url, { const res = await fetch(url, {
method: "GET", method: 'GET',
headers: { headers: {
Authorization: auth, Authorization: auth,
"User-Agent": "astro-docs/1.0", 'User-Agent': 'astro-docs/1.0',
}, },
}); });
const data = await res.json(); const data = await res.json();
if (!res.ok) { if (!res.ok) {
throw new Error( throw new Error(
`Request to fetch commits failed. Reason: ${res.statusText} `Request to fetch commits failed. Reason: ${res.statusText}
Message: ${data.message}` Message: ${data.message}`
); );
} }
return data; return data;
} catch (e) { } catch (e) {
console.warn(`[error] /src/components/AvatarList.astro console.warn(`[error] /src/components/AvatarList.astro
${e?.message ?? e}`); ${e?.message ?? e}`);
return new Array(); return new Array();
} }
} }
function removeDups(arr) { function removeDups(arr) {
if (!arr) { if (!arr) {
return new Array(); return new Array();
} }
let map = new Map(); let map = new Map();
for (let item of arr) { for (let item of arr) {
let author = item.author; let author = item.author;
// Deduplicate based on author.id // Deduplicate based on author.id
map.set(author.id, { login: author.login, id: author.id }); map.set(author.id, { login: author.login, id: author.id });
} }
return Array.from(map.values()); return Array.from(map.values());
} }
const data = await getCommits(url); const data = await getCommits(url);
const unique = removeDups(data); const unique = removeDups(data);
const recentContributors = unique.slice(0, 3); // only show avatars for the 3 most recent contributors const recentContributors = unique.slice(0, 3); // only show avatars for the 3 most recent contributors
const additionalContributors = unique.length - recentContributors.length; // list the rest of them as # of extra contributors const additionalContributors = unique.length - recentContributors.length; // list the rest of them as # of extra contributors
--- ---
<!-- Thanks to @5t3ph for https://smolcss.dev/#smol-avatar-list! --> <!-- Thanks to @5t3ph for https://smolcss.dev/#smol-avatar-list! -->
<div class="contributors"> <div class="contributors">
<ul class="avatar-list" style={`--avatar-count: ${recentContributors.length}`}> <ul
class="avatar-list"
{recentContributors.map((item) => ( style={`--avatar-count: ${recentContributors.length}`}
<li><a href={`https://github.com/${item.login}`}><img alt={`Contributor ${item.login}`} title={`Contributor ${item.login}`} width="64" height="64" src={`https://avatars.githubusercontent.com/u/${item.id}`}/></a></li> >
{recentContributors.map((item) => (
))} <li>
</ul> <a href={`https://github.com/${item.login}`}>
{additionalContributors > 0 && <span><a href={commitsURL}>{`and ${additionalContributors} additional contributor${additionalContributors > 1 ? 's' : ''}.`}</a></span>} <img
{unique.length === 0 && <a href={commitsURL}>Contributors</a>} alt={`Contributor ${item.login}`}
title={`Contributor ${item.login}`}
width="64"
height="64"
src={`https://avatars.githubusercontent.com/u/${item.id}`}
/>
</a>
</li>
))}
</ul>
{additionalContributors > 0 && (
<span>
<a
href={commitsURL}
>{`and ${additionalContributors} additional contributor${
additionalContributors > 1 ? 's' : ''
}.`}</a>
</span>
)}
{unique.length === 0 && <a href={commitsURL}>Contributors</a>}
</div> </div>
<style> <style>
.avatar-list { .avatar-list {
--avatar-size: 2.5rem; --avatar-size: 2.5rem;
--avatar-count: 3; --avatar-count: 3;
display: grid; display: grid;
list-style: none; list-style: none;
/* Default to displaying most of the avatar to /* Default to displaying most of the avatar to
enable easier access on touch devices, ensuring enable easier access on touch devices, ensuring
the WCAG touch target size is met or exceeded */ the WCAG touch target size is met or exceeded */
grid-template-columns: repeat( grid-template-columns: repeat(
var(--avatar-count), var(--avatar-count),
max(44px, calc(var(--avatar-size) / 1.15)) max(44px, calc(var(--avatar-size) / 1.15))
); );
/* `padding` matches added visual dimensions of /* `padding` matches added visual dimensions of
the `box-shadow` to help create a more accurate the `box-shadow` to help create a more accurate
computed component size */ computed component size */
padding: 0.08em; padding: 0.08em;
font-size: var(--avatar-size); font-size: var(--avatar-size);
} }
@media (any-hover: hover) and (any-pointer: fine) { @media (any-hover: hover) and (any-pointer: fine) {
.avatar-list { .avatar-list {
/* We create 1 extra cell to enable the computed /* We create 1 extra cell to enable the computed
width to match the final visual width */ width to match the final visual width */
grid-template-columns: repeat( grid-template-columns: repeat(
calc(var(--avatar-count) + 1), calc(var(--avatar-count) + 1),
calc(var(--avatar-size) / 1.75) calc(var(--avatar-size) / 1.75)
); );
} }
} }
.avatar-list li { .avatar-list li {
width: var(--avatar-size); width: var(--avatar-size);
height: var(--avatar-size); height: var(--avatar-size);
} }
.avatar-list li:hover ~ li a, .avatar-list li:hover ~ li a,
.avatar-list li:focus-within ~ li a { .avatar-list li:focus-within ~ li a {
transform: translateX(33%); transform: translateX(33%);
} }
.avatar-list img, .avatar-list img,
.avatar-list a { .avatar-list a {
display: block; display: block;
border-radius: 50%; border-radius: 50%;
} }
.avatar-list a { .avatar-list a {
transition: transform 180ms ease-in-out; transition: transform 180ms ease-in-out;
} }
.avatar-list img { .avatar-list img {
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: cover; object-fit: cover;
background-color: #fff; background-color: #fff;
box-shadow: 0 0 0 0.05em #fff, 0 0 0 0.08em rgba(0, 0, 0, 0.15); box-shadow: 0 0 0 0.05em #fff, 0 0 0 0.08em rgba(0, 0, 0, 0.15);
} }
.avatar-list a:focus { .avatar-list a:focus {
outline: 2px solid transparent; outline: 2px solid transparent;
/* Double-layer trick to work for dark and light backgrounds */ /* Double-layer trick to work for dark and light backgrounds */
box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white; box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white;
} }
.contributors { .contributors {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.contributors > * + * { .contributors > * + * {
margin-left: .75rem; margin-left: 0.75rem;
} }
</style> </style>

View file

@ -4,13 +4,13 @@ const { path } = Astro.props;
--- ---
<footer> <footer>
<AvatarList path={path} /> <AvatarList {path} />
</footer> </footer>
<style> <style>
footer { footer {
margin-top: auto; margin-top: auto;
padding: 2rem 0; padding: 2rem 0;
border-top: 3px solid var(--theme-divider); border-top: 3px solid var(--theme-divider);
} }
</style> </style>

View file

@ -1,10 +1,10 @@
<!-- Global Metadata --> <!-- Global Metadata -->
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width" />
<meta name="theme-color" content="#ff5e00"/> <meta name="theme-color" content="#ff5e00" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg"/> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="alternate icon" type="image/x-icon" href="/favicon.ico" /> <link rel="alternate icon" type="image/x-icon" href="/favicon.ico" />
<link rel="sitemap" href="/sitemap.xml"/> <link rel="sitemap" href="/sitemap.xml" />
<!-- Global CSS --> <!-- Global CSS -->
<link rel="stylesheet" href="/theme.css" /> <link rel="stylesheet" href="/theme.css" />
@ -12,29 +12,38 @@
<link rel="stylesheet" href="/index.css" /> <link rel="stylesheet" href="/index.css" />
<!-- Preload Fonts --> <!-- Preload Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital@0;1&display=swap" rel="stylesheet"> <link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital@0;1&display=swap"
rel="stylesheet"
/>
<!-- Scrollable a11y code helper --> <!-- Scrollable a11y code helper -->
<script type="module" src="/make-scrollable-code-focusable.js" /> <script type="module" src="/make-scrollable-code-focusable.js"></script>
<!-- This is intentionally inlined to avoid FOUC --> <!-- This is intentionally inlined to avoid FOUC -->
<script> <script>
const root = document.documentElement; const root = document.documentElement;
const theme = localStorage.getItem('theme'); const theme = localStorage.getItem('theme');
if (theme === 'dark' || (!theme) && window.matchMedia('(prefers-color-scheme: dark)').matches) { if (
root.classList.add('theme-dark'); theme === 'dark' ||
} else { (!theme && window.matchMedia('(prefers-color-scheme: dark)').matches)
root.classList.remove('theme-dark'); ) {
} root.classList.add('theme-dark');
} else {
root.classList.remove('theme-dark');
}
</script> </script>
<!-- Global site tag (gtag.js) - Google Analytics --> <!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-130280175-15"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=UA-130280175-15"
></script>
<script> <script>
window.dataLayer = window.dataLayer || []; window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);} function gtag() {
gtag('js', new Date()); dataLayer.push(arguments);
gtag('config', 'UA-130280175-15'); }
gtag('js', new Date());
gtag('config', 'UA-130280175-15');
</script> </script>

View file

@ -1,43 +1,48 @@
--- ---
import {SITE, OPEN_GRAPH} from '../config.ts'; import { SITE, OPEN_GRAPH } from '../config.ts';
import { getLanguageFromURL } from '../util.ts'; import { getLanguageFromURL } from '../util.ts';
export interface Props { export interface Props {
content: any, content: any;
site: any, site: any;
canonicalURL: URL, canonicalURL: URL;
}; }
const { const { content = {}, canonicalURL } = Astro.props;
content = {},
canonicalURL,
} = Astro.props;
const imageSrc = content?.image?.src ?? OPEN_GRAPH.image.src; const imageSrc = content?.image?.src ?? OPEN_GRAPH.image.src;
const canonicalImageSrc = new URL(imageSrc, Astro.site); const canonicalImageSrc = new URL(imageSrc, Astro.site);
const imageAlt = content?.image?.alt ?? OPEN_GRAPH.image.alt; const imageAlt = content?.image?.alt ?? OPEN_GRAPH.image.alt;
const lang = canonicalURL && getLanguageFromURL(canonicalURL.pathname); const lang = canonicalURL && getLanguageFromURL(canonicalURL.pathname);
--- ---
<!-- Page Metadata --> <!-- Page Metadata -->
<link rel="canonical" href={canonicalURL}/> <link rel="canonical" href={canonicalURL} />
<!-- Algolia docsearch language facet --> <!-- Algolia docsearch language facet -->
<meta name="docsearch:language" content={lang} /> <meta name="docsearch:language" content={lang} />
<!-- OpenGraph Tags --> <!-- OpenGraph Tags -->
<meta property="og:title" content={content.title ?? SITE.title}/> <meta property="og:title" content={content.title ?? SITE.title} />
<meta property="og:type" content="article"/> <meta property="og:type" content="article" />
<meta property="og:url" content={canonicalURL}/> <meta property="og:url" content={canonicalURL} />
<meta property="og:locale" content={content.ogLocale ?? OPEN_GRAPH.locale}/> <meta property="og:locale" content={content.ogLocale ?? OPEN_GRAPH.locale} />
<meta property="og:image" content={canonicalImageSrc}/> <meta property="og:image" content={canonicalImageSrc} />
<meta property="og:image:alt" content={imageAlt}/> <meta property="og:image:alt" content={imageAlt} />
<meta name="description" property="og:description" content={content.description ? content.description : SITE.description}/> <meta
<meta property="og:site_name" content={SITE.title}/> name="description"
property="og:description"
content={content.description ? content.description : SITE.description}
/>
<meta property="og:site_name" content={SITE.title} />
<!-- Twitter Tags --> <!-- Twitter Tags -->
<meta name="twitter:card" content="summary_large_image"/> <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content={OPEN_GRAPH.twitter}/> <meta name="twitter:site" content={OPEN_GRAPH.twitter} />
<meta name="twitter:title" content={content.title ?? SITE.title}/> <meta name="twitter:title" content={content.title ?? SITE.title} />
<meta name="twitter:description" content={content.description ? content.description : SITE.description}/> <meta
<meta name="twitter:image" content={canonicalImageSrc}/> name="twitter:description"
<meta name="twitter:image:alt" content={imageAlt}/> content={content.description ? content.description : SITE.description}
/>
<meta name="twitter:image" content={canonicalImageSrc} />
<meta name="twitter:image:alt" content={imageAlt} />
<!-- <!--
TODO: Add json+ld data, maybe https://schema.org/APIReference makes sense? TODO: Add json+ld data, maybe https://schema.org/APIReference makes sense?

View file

@ -1,20 +1,36 @@
--- ---
const {size} = Astro.props; const { size } = Astro.props;
--- ---
<svg class="logo" width={size} height={size} viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg">
<style> <svg
#flame { class="logo"
/* fill: #ff5d01; */ width={size}
fill: #3894ff; height={size}
} viewBox="0 0 256 256"
#a { fill="none"
/* fill: #000014; */ xmlns="http://www.w3.org/2000/svg"
fill: #3894ff; >
} <style>
</style> #flame {
<title>Logo</title> /* fill: #ff5d01; */
<path id="a" fill-rule="evenodd" clip-rule="evenodd" fill: #3894ff;
d="M163.008 18.929c1.944 2.413 2.935 5.67 4.917 12.181l43.309 142.27a180.277 180.277 0 00-51.778-17.53l-28.198-95.29a3.67 3.67 0 00-7.042.01l-27.857 95.232a180.225 180.225 0 00-52.01 17.557l43.52-142.281c1.99-6.502 2.983-9.752 4.927-12.16a15.999 15.999 0 016.484-4.798c2.872-1.154 6.271-1.154 13.07-1.154h31.085c6.807 0 10.211 0 13.086 1.157a16.004 16.004 0 016.487 4.806z" /> }
<path id="flame" fill-rule="evenodd" clip-rule="evenodd" #a {
d="M168.19 180.151c-7.139 6.105-21.39 10.268-37.804 10.268-20.147 0-37.033-6.272-41.513-14.707-1.602 4.835-1.961 10.367-1.961 13.902 0 0-1.056 17.355 11.015 29.426 0-6.268 5.081-11.349 11.349-11.349 10.743 0 10.731 9.373 10.721 16.977v.679c0 11.542 7.054 21.436 17.086 25.606a23.27 23.27 0 01-2.339-10.2c0-11.008 6.463-15.107 13.974-19.87 5.976-3.79 12.616-8.001 17.192-16.449a31.024 31.024 0 003.743-14.82c0-3.299-.513-6.479-1.463-9.463z" /> /* fill: #000014; */
</svg> fill: #3894ff;
}
</style>
<title>Logo</title>
<path
id="a"
fill-rule="evenodd"
clip-rule="evenodd"
d="M163.008 18.929c1.944 2.413 2.935 5.67 4.917 12.181l43.309 142.27a180.277 180.277 0 00-51.778-17.53l-28.198-95.29a3.67 3.67 0 00-7.042.01l-27.857 95.232a180.225 180.225 0 00-52.01 17.557l43.52-142.281c1.99-6.502 2.983-9.752 4.927-12.16a15.999 15.999 0 016.484-4.798c2.872-1.154 6.271-1.154 13.07-1.154h31.085c6.807 0 10.211 0 13.086 1.157a16.004 16.004 0 016.487 4.806z"
></path>
<path
id="flame"
fill-rule="evenodd"
clip-rule="evenodd"
d="M168.19 180.151c-7.139 6.105-21.39 10.268-37.804 10.268-20.147 0-37.033-6.272-41.513-14.707-1.602 4.835-1.961 10.367-1.961 13.902 0 0-1.056 17.355 11.015 29.426 0-6.268 5.081-11.349 11.349-11.349 10.743 0 10.731 9.373 10.721 16.977v.679c0 11.542 7.054 21.436 17.086 25.606a23.27 23.27 0 01-2.339-10.2c0-11.008 6.463-15.107 13.974-19.87 5.976-3.79 12.616-8.001 17.192-16.449a31.024 31.024 0 003.743-14.82c0-3.299-.513-6.479-1.463-9.463z"
></path>
</svg>

View file

@ -2,158 +2,183 @@
import SkipToContent from './SkipToContent.astro'; import SkipToContent from './SkipToContent.astro';
import SidebarToggle from './SidebarToggle.tsx'; import SidebarToggle from './SidebarToggle.tsx';
import LanguageSelect from './LanguageSelect.tsx'; import LanguageSelect from './LanguageSelect.tsx';
import Search from "./Search.tsx"; import Search from './Search.tsx';
import { getLanguageFromURL } from '../../util.ts'; import { getLanguageFromURL } from '../../util.ts';
const {currentPage} = Astro.props; const { currentPage } = Astro.props;
const lang = currentPage && getLanguageFromURL(currentPage); const lang = currentPage && getLanguageFromURL(currentPage);
--- ---
<style>
header {
z-index: 11;
height: var(--theme-navbar-height);
width: 100%;
background-color: var(--theme-navbar-bg);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
position: sticky;
top: 0;
}
.logo {
direction: ltr;
display: flex;
overflow: hidden;
width: 30px;
font-size: 1rem;
flex-shrink: 0;
font-weight: 600;
line-height: 1;
color: hsla(var(--color-base-white), 100%, 1);
text-decoration: none;
gap: 0.5em;
z-index: -1;
}
.logo a {
padding: 0.5em 0.25em;
margin: -0.5em -0.25em;
}
.logo svg {
height: 40px;
width: auto;
display: block;
color: var(--theme-accent);
}
.logo .hover {
opacity: 0.0;
}
.logo a {
transition: transform 180ms ease-out;
}
.logo a:hover,
.logo a:focus {
outline: none;
opacity: 1.0;
transform: translateY(-2px);
}
.logo h1 {
font: inherit;
color: inherit;
margin: 0;
}
.nav-wrapper {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 1em;
width: 100%;
max-width: 82em;
padding: 0 1rem;
}
@media (min-width: 50em) {
header {
position: static;
padding: 2rem 0rem 0 2rem;
}
.logo {
width: auto;
margin: 0;
z-index: 0;
}
.menu-toggle {
display: none;
}
.logo {
width: auto;
}
}
/** Style Algolia */
:root {
--docsearch-primary-color: var(--theme-accent);
--docsearch-logo-color: var(--theme-text);
}
.search-item {
display: none;
position: relative;
z-index: 10;
flex-grow: 1;
padding-right: 0.7rem;
display: flex;
max-width: 200px;
}
:global(.search-item > *) {
flex-grow: 1;
}
@media (min-width: 50em) {
.search-item {
max-width: 400px;
}
}
</style>
<header> <header>
<SkipToContent /> <SkipToContent />
<nav class="nav-wrapper" title="Top Navigation"> <nav class="nav-wrapper" title="Top Navigation">
<div class="menu-toggle"> <div class="menu-toggle">
<SidebarToggle client:idle/> <SidebarToggle client:idle />
</div> </div>
<div class="logo flex"> <div class="logo flex">
<a href="https://astro.build/"> <a href="https://astro.build/">
<h1 class="sr-only">Astro</h1> <h1 class="sr-only">Astro</h1>
<svg xmlns="http://www.w3.org/2000/svg" width="363" height="102" viewBox="0 0 363 102" fill="none"> <svg
<style> xmlns="http://www.w3.org/2000/svg"
.text { width="363"
fill: var(--theme-text); height="102"
} viewBox="0 0 363 102"
.hover { fill="none"
fill: var(--theme-accent); >
} <style>
</style> .text {
<path class="text" fill-rule="evenodd" d="M55.07 14.216l16.81 54.865a72.6 72.6 0 00-20.765-6.984L39.808 24.135a1.475 1.475 0 00-2.827.005L25.81 62.078a72.598 72.598 0 00-20.859 6.995L21.847 14.2c.998-3.243 1.497-4.865 2.47-6.066a8 8 0 013.239-2.392c1.434-.576 3.13-.576 6.524-.576h8.751c3.398 0 5.097 0 6.532.577a8 8 0 013.241 2.397c.972 1.203 1.47 2.827 2.465 6.076z" clip-rule="evenodd"/> fill: var(--theme-text);
<path fill="#FF5D01" fill-rule="evenodd" d="M54.618 71.779c-2.863 2.432-8.578 4.091-15.161 4.091-8.08 0-14.852-2.499-16.649-5.86-.642 1.926-.786 4.13-.786 5.539 0 0-.423 6.915 4.418 11.725 0-2.498 2.037-4.522 4.551-4.522 4.309 0 4.304 3.734 4.3 6.764v.27c0 4.6 2.829 8.541 6.852 10.203a9.22 9.22 0 01-.938-4.064c0-4.386 2.592-6.02 5.604-7.917 2.396-1.51 5.06-3.188 6.894-6.554a12.297 12.297 0 001.502-5.905c0-1.314-.206-2.581-.587-3.77z" clip-rule="evenodd"/> }
<path class="text" d="M126.554 69c13.115 0 21.047-3.14 25.68-9.654 0 2.904.157 5.651.55 8.163h7.774c-.706-4.082-.863-6.75-.863-14.128V43.334c0-10.831-8.403-16.56-24.424-16.56-15.47 0-25.522 5.964-26.779 14.598h8.246c1.256-5.808 7.774-8.87 18.533-8.87 10.602 0 16.885 3.69 16.885 9.969v.785l-24.502 1.413c-9.974.549-13.665 1.962-16.492 4.003-2.67 1.962-4.162 5.023-4.162 8.555C107 64.683 114.696 69 126.554 69zm2.513-5.573c-9.109 0-14.135-2.119-14.135-6.357 0-4.553 3.141-6.593 14.214-7.3l23.01-1.412v1.805c0 8.241-9.66 13.264-23.089 13.264zM196.086 69c16.256 0 22.775-5.337 22.775-13.108 0-6.436-4.006-9.732-14.215-10.596l-19.083-1.49c-5.183-.393-8.088-1.884-8.088-5.102 0-4.082 4.476-6.201 14.135-6.201 10.995 0 16.727 2.198 20.497 7.064l6.361-3.061c-3.927-6.122-12.644-9.733-26.151-9.733-13.9 0-22.224 4.631-22.224 12.244 0 6.829 4.947 10.125 14.292 10.91l18.926 1.492c6.204.47 8.089 1.726 8.089 4.944 0 4.631-4.79 6.829-14.293 6.829-11.544 0-18.847-3.14-22.381-8.87l-6.204 3.376C173.312 64.918 181.715 69 196.086 69zM234.929 34.151v18.916c0 7.77 2.67 15.54 17.198 15.54 3.691 0 8.167-.706 10.131-1.57V60.68c-2.749.628-6.047 1.1-9.267 1.1-6.832 0-10.523-2.67-10.523-9.42V34.151h19.633v-5.887h-19.633V15l-7.539 3.061v10.204h-12.33v5.886h12.33zM280.823 28.265h-6.911v39.244h7.461V52.83c0-5.65 1.099-10.439 4.24-13.735 2.749-3.061 6.283-4.788 12.487-4.788 2.12 0 3.455.157 5.262.471v-7.22c-1.65-.393-3.063-.472-5.184-.472-8.402 0-15.078 4.945-17.355 12.558v-11.38zM334.807 69C351.534 69 363 60.523 363 47.887c0-12.637-11.466-21.114-28.193-21.114-16.727 0-28.193 8.477-28.193 21.114C306.614 60.523 318.08 69 334.807 69zm0-6.2c-12.329 0-20.261-5.809-20.261-14.913 0-9.105 7.932-14.913 20.261-14.913 12.251 0 20.261 5.808 20.261 14.913 0 9.104-8.01 14.912-20.261 14.912z"/> .hover {
</svg> fill: var(--theme-accent);
</a> }
<a href="https://docs.astro.build/"> </style>
<h1 class="sr-only">Docs</h1> <path
<svg xmlns="http://www.w3.org/2000/svg" width="226" height="102" viewBox="0 0 226 102" fill="none"> class="text"
<path fill="currentColor" d="M25.805 68c14.688 0 24.883-8.41 24.883-21.14 0-12.786-9.62-19.756-24.653-19.756H0V68h25.805zm-14.17-33.005H24.25c8.352 0 14.17 4.09 14.17 12.039 0 8.236-5.3 13.075-14.113 13.075H11.635V34.995zM82.673 69.382c16.704 0 27.418-8.582 27.418-21.83 0-13.248-10.771-21.83-27.418-21.83-16.589 0-27.418 8.582-27.418 21.83 0 13.19 10.83 21.83 27.418 21.83zm0-8.64c-9.1 0-15.149-5.299-15.149-13.19 0-7.891 6.048-13.19 15.15-13.19 9.1 0 15.205 5.299 15.205 13.19 0 7.891-6.105 13.19-15.206 13.19zM141.497 69.382c13.306 0 22.637-5.299 25.978-14.572l-11.866-2.535c-1.67 5.415-6.393 8.295-13.709 8.295-9.216 0-15.033-5.127-15.033-13.018 0-8.006 5.702-13.018 14.918-13.018 7.43 0 12.154 3.053 13.709 8.64l12.038-2.13c-2.707-9.562-12.268-15.322-25.574-15.322-16.128 0-27.302 9.043-27.302 22.003 0 13.133 10.425 21.657 26.841 21.657zM194.94 69.382c14.745 0 23.212-5.01 23.212-14.054 0-7.603-4.665-10.944-15.955-12.096l-11.289-1.094c-5.242-.576-6.97-1.556-6.97-4.09 0-2.765 3.456-4.262 9.792-4.262 7.834 0 13.709 2.476 16.762 6.508l7.315-6.163c-5.069-5.702-13.133-8.41-23.501-8.41-13.997 0-21.888 4.781-21.888 12.903 0 7.546 4.781 11.232 14.803 12.326l12.557 1.383c4.896.518 6.624 1.555 6.624 4.09 0 3.225-3.456 4.723-10.886 4.723-8.352 0-14.688-3.226-18.087-8.007l-8.294 5.818c4.205 6.451 13.709 10.425 25.805 10.425z"/> fill-rule="evenodd"
</svg> d="M55.07 14.216l16.81 54.865a72.6 72.6 0 00-20.765-6.984L39.808 24.135a1.475 1.475 0 00-2.827.005L25.81 62.078a72.598 72.598 0 00-20.859 6.995L21.847 14.2c.998-3.243 1.497-4.865 2.47-6.066a8 8 0 013.239-2.392c1.434-.576 3.13-.576 6.524-.576h8.751c3.398 0 5.097 0 6.532.577a8 8 0 013.241 2.397c.972 1.203 1.47 2.827 2.465 6.076z"
</a> clip-rule="evenodd"></path>
</div> <path
<div style="flex-grow: 1;"></div> fill="#FF5D01"
{lang && <LanguageSelect lang={lang} client:idle />} fill-rule="evenodd"
<div class="search-item"><Search lang={lang} client:idle /></div> d="M54.618 71.779c-2.863 2.432-8.578 4.091-15.161 4.091-8.08 0-14.852-2.499-16.649-5.86-.642 1.926-.786 4.13-.786 5.539 0 0-.423 6.915 4.418 11.725 0-2.498 2.037-4.522 4.551-4.522 4.309 0 4.304 3.734 4.3 6.764v.27c0 4.6 2.829 8.541 6.852 10.203a9.22 9.22 0 01-.938-4.064c0-4.386 2.592-6.02 5.604-7.917 2.396-1.51 5.06-3.188 6.894-6.554a12.297 12.297 0 001.502-5.905c0-1.314-.206-2.581-.587-3.77z"
</nav> clip-rule="evenodd"></path>
<path
class="text"
d="M126.554 69c13.115 0 21.047-3.14 25.68-9.654 0 2.904.157 5.651.55 8.163h7.774c-.706-4.082-.863-6.75-.863-14.128V43.334c0-10.831-8.403-16.56-24.424-16.56-15.47 0-25.522 5.964-26.779 14.598h8.246c1.256-5.808 7.774-8.87 18.533-8.87 10.602 0 16.885 3.69 16.885 9.969v.785l-24.502 1.413c-9.974.549-13.665 1.962-16.492 4.003-2.67 1.962-4.162 5.023-4.162 8.555C107 64.683 114.696 69 126.554 69zm2.513-5.573c-9.109 0-14.135-2.119-14.135-6.357 0-4.553 3.141-6.593 14.214-7.3l23.01-1.412v1.805c0 8.241-9.66 13.264-23.089 13.264zM196.086 69c16.256 0 22.775-5.337 22.775-13.108 0-6.436-4.006-9.732-14.215-10.596l-19.083-1.49c-5.183-.393-8.088-1.884-8.088-5.102 0-4.082 4.476-6.201 14.135-6.201 10.995 0 16.727 2.198 20.497 7.064l6.361-3.061c-3.927-6.122-12.644-9.733-26.151-9.733-13.9 0-22.224 4.631-22.224 12.244 0 6.829 4.947 10.125 14.292 10.91l18.926 1.492c6.204.47 8.089 1.726 8.089 4.944 0 4.631-4.79 6.829-14.293 6.829-11.544 0-18.847-3.14-22.381-8.87l-6.204 3.376C173.312 64.918 181.715 69 196.086 69zM234.929 34.151v18.916c0 7.77 2.67 15.54 17.198 15.54 3.691 0 8.167-.706 10.131-1.57V60.68c-2.749.628-6.047 1.1-9.267 1.1-6.832 0-10.523-2.67-10.523-9.42V34.151h19.633v-5.887h-19.633V15l-7.539 3.061v10.204h-12.33v5.886h12.33zM280.823 28.265h-6.911v39.244h7.461V52.83c0-5.65 1.099-10.439 4.24-13.735 2.749-3.061 6.283-4.788 12.487-4.788 2.12 0 3.455.157 5.262.471v-7.22c-1.65-.393-3.063-.472-5.184-.472-8.402 0-15.078 4.945-17.355 12.558v-11.38zM334.807 69C351.534 69 363 60.523 363 47.887c0-12.637-11.466-21.114-28.193-21.114-16.727 0-28.193 8.477-28.193 21.114C306.614 60.523 318.08 69 334.807 69zm0-6.2c-12.329 0-20.261-5.809-20.261-14.913 0-9.105 7.932-14.913 20.261-14.913 12.251 0 20.261 5.808 20.261 14.913 0 9.104-8.01 14.912-20.261 14.912z"
></path>
</svg>
</a>
<a href="https://docs.astro.build/">
<h1 class="sr-only">Docs</h1>
<svg
xmlns="http://www.w3.org/2000/svg"
width="226"
height="102"
viewBox="0 0 226 102"
fill="none"
>
<path
fill="currentColor"
d="M25.805 68c14.688 0 24.883-8.41 24.883-21.14 0-12.786-9.62-19.756-24.653-19.756H0V68h25.805zm-14.17-33.005H24.25c8.352 0 14.17 4.09 14.17 12.039 0 8.236-5.3 13.075-14.113 13.075H11.635V34.995zM82.673 69.382c16.704 0 27.418-8.582 27.418-21.83 0-13.248-10.771-21.83-27.418-21.83-16.589 0-27.418 8.582-27.418 21.83 0 13.19 10.83 21.83 27.418 21.83zm0-8.64c-9.1 0-15.149-5.299-15.149-13.19 0-7.891 6.048-13.19 15.15-13.19 9.1 0 15.205 5.299 15.205 13.19 0 7.891-6.105 13.19-15.206 13.19zM141.497 69.382c13.306 0 22.637-5.299 25.978-14.572l-11.866-2.535c-1.67 5.415-6.393 8.295-13.709 8.295-9.216 0-15.033-5.127-15.033-13.018 0-8.006 5.702-13.018 14.918-13.018 7.43 0 12.154 3.053 13.709 8.64l12.038-2.13c-2.707-9.562-12.268-15.322-25.574-15.322-16.128 0-27.302 9.043-27.302 22.003 0 13.133 10.425 21.657 26.841 21.657zM194.94 69.382c14.745 0 23.212-5.01 23.212-14.054 0-7.603-4.665-10.944-15.955-12.096l-11.289-1.094c-5.242-.576-6.97-1.556-6.97-4.09 0-2.765 3.456-4.262 9.792-4.262 7.834 0 13.709 2.476 16.762 6.508l7.315-6.163c-5.069-5.702-13.133-8.41-23.501-8.41-13.997 0-21.888 4.781-21.888 12.903 0 7.546 4.781 11.232 14.803 12.326l12.557 1.383c4.896.518 6.624 1.555 6.624 4.09 0 3.225-3.456 4.723-10.886 4.723-8.352 0-14.688-3.226-18.087-8.007l-8.294 5.818c4.205 6.451 13.709 10.425 25.805 10.425z"
></path>
</svg>
</a>
</div>
<div style="flex-grow: 1;"></div>
{lang && <LanguageSelect lang={lang} client:idle />}
<div class="search-item"><Search {lang} client:idle /></div>
</nav>
</header> </header>
<style>
header {
z-index: 11;
height: var(--theme-navbar-height);
width: 100%;
background-color: var(--theme-navbar-bg);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
position: sticky;
top: 0;
}
.logo {
direction: ltr;
display: flex;
overflow: hidden;
width: 30px;
font-size: 1rem;
flex-shrink: 0;
font-weight: 600;
line-height: 1;
color: hsla(var(--color-base-white), 100%, 1);
text-decoration: none;
gap: 0.5em;
z-index: -1;
}
.logo a {
padding: 0.5em 0.25em;
margin: -0.5em -0.25em;
}
.logo svg {
height: 40px;
width: auto;
display: block;
color: var(--theme-accent);
}
.logo .hover {
opacity: 0;
}
.logo a {
transition: transform 180ms ease-out;
}
.logo a:hover,
.logo a:focus {
outline: none;
opacity: 1;
transform: translateY(-2px);
}
.logo h1 {
font: inherit;
color: inherit;
margin: 0;
}
.nav-wrapper {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 1em;
width: 100%;
max-width: 82em;
padding: 0 1rem;
}
@media (min-width: 50em) {
header {
position: static;
padding: 2rem 0rem 0 2rem;
}
.logo {
width: auto;
margin: 0;
z-index: 0;
}
.menu-toggle {
display: none;
}
.logo {
width: auto;
}
}
/** Style Algolia */
:root {
--docsearch-primary-color: var(--theme-accent);
--docsearch-logo-color: var(--theme-text);
}
.search-item {
display: none;
position: relative;
z-index: 10;
flex-grow: 1;
padding-right: 0.7rem;
display: flex;
max-width: 200px;
}
:global(.search-item > *) {
flex-grow: 1;
}
@media (min-width: 50em) {
.search-item {
max-width: 400px;
}
}
</style>

View file

@ -1,50 +1,50 @@
.language-select { .language-select {
flex-grow: 1; flex-grow: 1;
width: 48px; width: 48px;
box-sizing: border-box; box-sizing: border-box;
margin: 0; margin: 0;
padding: 0.33em 2rem; padding: 0.33em 2rem;
overflow: visible; overflow: visible;
font-weight: 500; font-weight: 500;
font-size: 1rem; font-size: 1rem;
font-family: inherit; font-family: inherit;
line-height: inherit; line-height: inherit;
background-color: var(--theme-bg); background-color: var(--theme-bg);
border-color: var(--theme-text-lighter); border-color: var(--theme-text-lighter);
color: var(--theme-text-light); color: var(--theme-text-light);
border-style: solid; border-style: solid;
border-width: 1px; border-width: 1px;
border-radius: 0.25rem; border-radius: 0.25rem;
outline: 0; outline: 0;
cursor: pointer; cursor: pointer;
transition-timing-function: ease-out; transition-timing-function: ease-out;
transition-duration: 0.2s; transition-duration: 0.2s;
transition-property: border-color, color; transition-property: border-color, color;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
background-position: 97%; background-position: 97%;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 1.5em 1.5em; background-size: 1.5em 1.5em;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-webkit-appearance: none; -webkit-appearance: none;
} }
.language-select-wrapper .language-select:hover, .language-select-wrapper .language-select:hover,
.language-select-wrapper .language-select:focus { .language-select-wrapper .language-select:focus {
color: var(--theme-text); color: var(--theme-text);
border-color: var(--theme-text-light); border-color: var(--theme-text-light);
} }
.language-select-wrapper { .language-select-wrapper {
color: var(--theme-text-light); color: var(--theme-text-light);
position: relative; position: relative;
} }
.language-select-wrapper > svg { .language-select-wrapper > svg {
position: absolute; position: absolute;
top: 8px; top: 8px;
left: 8px; left: 8px;
pointer-events: none; pointer-events: none;
} }
@media (min-width: 50em) { @media (min-width: 50em) {
.language-select { .language-select {
width: 100%; width: 100%;
} }
} }

View file

@ -3,104 +3,104 @@ import { h } from 'preact';
import './LanguageSelect.css'; import './LanguageSelect.css';
const LanguageSelect: FunctionalComponent<{ lang: string }> = ({ lang }) => { const LanguageSelect: FunctionalComponent<{ lang: string }> = ({ lang }) => {
return ( return (
<div class="language-select-wrapper"> <div class="language-select-wrapper">
<svg <svg
aria-hidden="true" aria-hidden="true"
focusable="false" focusable="false"
role="img" role="img"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 88.6 77.3" viewBox="0 0 88.6 77.3"
height="1.2em" height="1.2em"
width="1.2em" width="1.2em"
> >
<path <path
fill="currentColor" fill="currentColor"
d="M61,24.6h7.9l18.7,51.6h-7.7l-5.4-15.5H54.3l-5.6,15.5h-7.2L61,24.6z M72.6,55l-8-22.8L56.3,55H72.6z" d="M61,24.6h7.9l18.7,51.6h-7.7l-5.4-15.5H54.3l-5.6,15.5h-7.2L61,24.6z M72.6,55l-8-22.8L56.3,55H72.6z"
/> />
<path <path
fill="currentColor" fill="currentColor"
d="M53.6,60.6c-10-4-16-9-22-14c0,0,1.3,1.3,0,0c-6,5-20,13-20,13l-4-6c8-5,10-6,19-13c-2.1-1.9-12-13-13-19h8 c4,9,10,14,10,14c10-8,10-19,10-19h8c0,0-1,13-12,24l0,0c5,5,10,9,19,13L53.6,60.6z M1.6,16.6h56v-8h-23v-7h-9v7h-24V16.6z" d="M53.6,60.6c-10-4-16-9-22-14c0,0,1.3,1.3,0,0c-6,5-20,13-20,13l-4-6c8-5,10-6,19-13c-2.1-1.9-12-13-13-19h8 c4,9,10,14,10,14c10-8,10-19,10-19h8c0,0-1,13-12,24l0,0c5,5,10,9,19,13L53.6,60.6z M1.6,16.6h56v-8h-23v-7h-9v7h-24V16.6z"
/> />
</svg> </svg>
<select <select
class="language-select" class="language-select"
value={lang} value={lang}
aria-label="Select language" aria-label="Select language"
onChange={(e) => { onChange={(e) => {
const newLang = e.target.value; const newLang = e.target.value;
if (newLang === 'en') { if (newLang === 'en') {
window.location.pathname = `/getting-started`; window.location.pathname = `/getting-started`;
} else { } else {
window.location.pathname = `/${newLang}/getting-started`; window.location.pathname = `/${newLang}/getting-started`;
} }
// TODO: Preserve the current page, if it exists: // TODO: Preserve the current page, if it exists:
// const oldPathname = window.location.pathname; // const oldPathname = window.location.pathname;
// const oldPathnameParts = oldPathname.split('/'); // const oldPathnameParts = oldPathname.split('/');
// oldPathnameParts.shift(); // oldPathnameParts.shift();
// if (/^[a-z]{2}$/.test(oldPathnameParts[0])) { // if (/^[a-z]{2}$/.test(oldPathnameParts[0])) {
// oldPathnameParts.shift(); // oldPathnameParts.shift();
// } // }
// if (newLang !== 'en') { // if (newLang !== 'en') {
// oldPathnameParts.unshift(newLang); // oldPathnameParts.unshift(newLang);
// } // }
// window.location.pathname = '/' + oldPathnameParts.join('/'); // window.location.pathname = '/' + oldPathnameParts.join('/');
}} }}
> >
<option value="en"> <option value="en">
<span>English</span> <span>English</span>
</option> </option>
<option value="de"> <option value="de">
<span>Deutsch</span> <span>Deutsch</span>
</option> </option>
<option value="nl"> <option value="nl">
<span>Nederlands</span> <span>Nederlands</span>
</option> </option>
<option value="pt-br"> <option value="pt-br">
<span>Português do Brasil</span> <span>Português do Brasil</span>
</option> </option>
<option value="fi"> <option value="fi">
<span>Suomi</span> <span>Suomi</span>
</option> </option>
<option value="es"> <option value="es">
<span>Español</span> <span>Español</span>
</option> </option>
<option value="zh-CN"> <option value="zh-CN">
<span></span> <span></span>
</option> </option>
<option value="zh-TW"> <option value="zh-TW">
<span></span> <span></span>
</option> </option>
<option value="bg"> <option value="bg">
<span>Български</span> <span>Български</span>
</option> </option>
<option value="fr"> <option value="fr">
<span>Français</span> <span>Français</span>
</option> </option>
<option value="bn"> <option value="bn">
<span></span> <span></span>
</option> </option>
<option value="kr"> <option value="kr">
<span></span> <span></span>
</option> </option>
<option value="ar"> <option value="ar">
<span>العربية</span> <span>العربية</span>
</option> </option>
<option value="da"> <option value="da">
<span>Dansk</span> <span>Dansk</span>
</option> </option>
<option value="ja"> <option value="ja">
<span></span> <span></span>
</option> </option>
<option value="ru"> <option value="ru">
<span>Русский</span> <span>Русский</span>
</option> </option>
<option value="it"> <option value="it">
<span>Italiano</span> <span>Italiano</span>
</option> </option>
</select> </select>
</div> </div>
); );
}; };
export default LanguageSelect; export default LanguageSelect;

View file

@ -1,75 +1,75 @@
/** Style Algolia */ /** Style Algolia */
:root { :root {
--docsearch-primary-color: var(--theme-accent); --docsearch-primary-color: var(--theme-accent);
--docsearch-logo-color: var(--theme-text); --docsearch-logo-color: var(--theme-text);
} }
.DocSearch-Modal .DocSearch-Hit a { .DocSearch-Modal .DocSearch-Hit a {
box-shadow: none; box-shadow: none;
border: 1px solid var(--theme-accent); border: 1px solid var(--theme-accent);
} }
/** Style Search Bar */ /** Style Search Bar */
.search-placeholder { .search-placeholder {
flex-grow: 1; flex-grow: 1;
text-align: initial; text-align: initial;
} }
.search-input { .search-input {
flex-grow: 1; flex-grow: 1;
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
margin: 0; margin: 0;
padding: 0.33em 0.5em; padding: 0.33em 0.5em;
overflow: visible; overflow: visible;
font-weight: 500; font-weight: 500;
font-size: 1rem; font-size: 1rem;
font-family: inherit; font-family: inherit;
line-height: inherit; line-height: inherit;
background-color: var(--theme-divider); background-color: var(--theme-divider);
border-color: var(--theme-divider); border-color: var(--theme-divider);
color: var(--theme-text-light); color: var(--theme-text-light);
border-style: solid; border-style: solid;
border-width: 1px; border-width: 1px;
border-radius: 0.25rem; border-radius: 0.25rem;
outline: 0; outline: 0;
cursor: pointer; cursor: pointer;
transition-timing-function: ease-out; transition-timing-function: ease-out;
transition-duration: 0.2s; transition-duration: 0.2s;
transition-property: border-color, color; transition-property: border-color, color;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
} }
.search-input:hover, .search-input:hover,
.search-input:focus { .search-input:focus {
color: var(--theme-text); color: var(--theme-text);
border-color: var(--theme-text-light); border-color: var(--theme-text-light);
} }
.search-input:hover::placeholder, .search-input:hover::placeholder,
.search-input:focus::placeholder { .search-input:focus::placeholder {
color: var(--theme-text-light); color: var(--theme-text-light);
} }
.search-input::placeholder { .search-input::placeholder {
color: var(--theme-text-light); color: var(--theme-text-light);
} }
.search-hint { .search-hint {
padding: 3px 5px; padding: 3px 5px;
display: none; display: none;
display: none; display: none;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
letter-spacing: 0.125em; letter-spacing: 0.125em;
font-size: 13px; font-size: 13px;
font-family: var(--font-mono); font-family: var(--font-mono);
pointer-events: none; pointer-events: none;
border-color: var(--theme-text-lighter); border-color: var(--theme-text-lighter);
color: var(--theme-text-light); color: var(--theme-text-light);
border-style: solid; border-style: solid;
border-width: 1px; border-width: 1px;
border-radius: 0.25rem; border-radius: 0.25rem;
line-height: 14px; line-height: 14px;
} }
@media (min-width: 50em) { @media (min-width: 50em) {
.search-hint { .search-hint {
display: flex; display: flex;
} }
} }

View file

@ -6,88 +6,88 @@ import '@docsearch/css/dist/style.css';
import './Search.css'; import './Search.css';
const { DocSearchModal, useDocSearchKeyboardEvents } = const { DocSearchModal, useDocSearchKeyboardEvents } =
(docsearch as unknown as { default: typeof docsearch }).default || docsearch; (docsearch as unknown as { default: typeof docsearch }).default || docsearch;
export default function Search(props) { export default function Search(props) {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const searchButtonRef = useRef(); const searchButtonRef = useRef();
const [initialQuery, setInitialQuery] = useState(null); const [initialQuery, setInitialQuery] = useState(null);
const { lang = 'en' } = props; const { lang = 'en' } = props;
const onOpen = useCallback(() => { const onOpen = useCallback(() => {
setIsOpen(true); setIsOpen(true);
}, [setIsOpen]); }, [setIsOpen]);
const onClose = useCallback(() => { const onClose = useCallback(() => {
setIsOpen(false); setIsOpen(false);
}, [setIsOpen]); }, [setIsOpen]);
const onInput = useCallback( const onInput = useCallback(
(e) => { (e) => {
setIsOpen(true); setIsOpen(true);
setInitialQuery(e.key); setInitialQuery(e.key);
}, },
[setIsOpen, setInitialQuery] [setIsOpen, setInitialQuery]
); );
useDocSearchKeyboardEvents({ useDocSearchKeyboardEvents({
isOpen, isOpen,
onOpen, onOpen,
onClose, onClose,
onInput, onInput,
searchButtonRef, searchButtonRef,
}); });
return ( return (
<> <>
<button <button
type="button" type="button"
ref={searchButtonRef} ref={searchButtonRef}
onClick={onOpen} onClick={onOpen}
className="search-input" className="search-input"
> >
<svg width="24" height="24" fill="none"> <svg width="24" height="24" fill="none">
<path <path
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
stroke="currentColor" stroke="currentColor"
strokeWidth="2" strokeWidth="2"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> />
</svg> </svg>
<span className="search-placeholder">Search</span> <span className="search-placeholder">Search</span>
<span className="search-hint"> <span className="search-hint">
<span className="sr-only">Press </span> <span className="sr-only">Press </span>
<kbd>/</kbd> <kbd>/</kbd>
<span className="sr-only"> to search</span> <span className="sr-only"> to search</span>
</span> </span>
</button> </button>
{isOpen && {isOpen &&
createPortal( createPortal(
<DocSearchModal <DocSearchModal
initialQuery={initialQuery} initialQuery={initialQuery}
initialScrollY={window.scrollY} initialScrollY={window.scrollY}
onClose={onClose} onClose={onClose}
indexName="astro" indexName="astro"
apiKey="0f387260ad74f9cbf4353facd29c919c" apiKey="0f387260ad74f9cbf4353facd29c919c"
// Set facetFilters once Astro docs have been indexed by language // Set facetFilters once Astro docs have been indexed by language
// searchParameters={{ facetFilters: [`lang:${lang}`] }} // searchParameters={{ facetFilters: [`lang:${lang}`] }}
transformItems={(items) => { transformItems={(items) => {
return items.map((item) => { return items.map((item) => {
// We transform the absolute URL into a relative URL to // We transform the absolute URL into a relative URL to
// work better on localhost, preview URLS. // work better on localhost, preview URLS.
const a = document.createElement('a'); const a = document.createElement('a');
a.href = item.url; a.href = item.url;
const hash = a.hash === '#overview' ? '' : a.hash; const hash = a.hash === '#overview' ? '' : a.hash;
return { return {
...item, ...item,
url: `${a.pathname}${hash}`, url: `${a.pathname}${hash}`,
}; };
}); });
}} }}
/>, />,
document.body document.body
)} )}
</> </>
); );
} }

View file

@ -3,42 +3,42 @@ import { h, Fragment } from 'preact';
import { useState, useEffect } from 'preact/hooks'; import { useState, useEffect } from 'preact/hooks';
const MenuToggle: FunctionalComponent = () => { const MenuToggle: FunctionalComponent = () => {
const [sidebarShown, setSidebarShown] = useState(false); const [sidebarShown, setSidebarShown] = useState(false);
useEffect(() => { useEffect(() => {
const body = document.getElementsByTagName('body')[0]; const body = document.getElementsByTagName('body')[0];
if (sidebarShown) { if (sidebarShown) {
body.classList.add('mobile-sidebar-toggle'); body.classList.add('mobile-sidebar-toggle');
} else { } else {
body.classList.remove('mobile-sidebar-toggle'); body.classList.remove('mobile-sidebar-toggle');
} }
}, [sidebarShown]); }, [sidebarShown]);
return ( return (
<button <button
type="button" type="button"
aria-pressed={sidebarShown ? 'true' : 'false'} aria-pressed={sidebarShown ? 'true' : 'false'}
id="menu-toggle" id="menu-toggle"
onClick={() => setSidebarShown(!sidebarShown)} onClick={() => setSidebarShown(!sidebarShown)}
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="1em" width="1em"
height="1em" height="1em"
fill="none" fill="none"
viewBox="0 0 24 24" viewBox="0 0 24 24"
stroke="currentColor" stroke="currentColor"
> >
<path <path
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
stroke-width="2" stroke-width="2"
d="M4 6h16M4 12h16M4 18h16" d="M4 6h16M4 12h16M4 18h16"
/> />
</svg> </svg>
<span className="sr-only">Toggle sidebar</span> <span className="sr-only">Toggle sidebar</span>
</button> </button>
); );
}; };
export default MenuToggle; export default MenuToggle;

View file

@ -1,21 +1,22 @@
<style>
.skiplink,
.skiplink:focus,
.skiplink:focus-visible {
position: absolute;
padding: 0.25em;
font-size: larger;
top: 0;
left: 0;
right: 0;
z-index: 9;
display: block;
text-align: center;
background-color: var(--theme-text-accent);
color: var(--theme-bg);
border-radius: 0.25em;
outline: var(--theme-bg) solid 1px;
outline-offset: 0;
}
</style>
<a href="#article" class="sr-only skiplink"><span>Skip to Content</span></a> <a href="#article" class="sr-only skiplink"><span>Skip to Content</span></a>
<style>
.skiplink,
.skiplink:focus,
.skiplink:focus-visible {
position: absolute;
padding: 0.25em;
font-size: larger;
top: 0;
left: 0;
right: 0;
z-index: 9;
display: block;
text-align: center;
background-color: var(--theme-text-accent);
color: var(--theme-bg);
border-radius: 0.25em;
outline: var(--theme-bg) solid 1px;
outline-offset: 0;
}
</style>

View file

@ -1,153 +1,186 @@
--- ---
import { SIDEBAR } from '../../config.ts'; import { SIDEBAR } from '../../config.ts';
import { getLanguageFromURL, removeLeadingSlash, removeTrailingSlash } from '../../util.ts'; import {
const {currentPage} = Astro.props; getLanguageFromURL,
removeLeadingSlash,
removeTrailingSlash,
} from '../../util.ts';
const { currentPage } = Astro.props;
// Get the slug w/o a leading or trailing slash // Get the slug w/o a leading or trailing slash
const currentPageMatch = removeLeadingSlash(removeTrailingSlash(currentPage)); const currentPageMatch = removeLeadingSlash(removeTrailingSlash(currentPage));
const langCode = getLanguageFromURL(currentPage); const langCode = getLanguageFromURL(currentPage);
// SIDEBAR is a flat array. Group it by sections to properly render. // SIDEBAR is a flat array. Group it by sections to properly render.
const sidebarSections = SIDEBAR[langCode].reduce((col, item) => { const sidebarSections = SIDEBAR[langCode].reduce((col, item) => {
if (item.header) { if (item.header) {
col.push({...item, children: []}); col.push({ ...item, children: [] });
} else { } else {
col[col.length-1].children.push(item); col[col.length - 1].children.push(item);
} }
return col; return col;
}, []); }, []);
--- ---
<nav aria-labelledby="grid-left"> <nav aria-labelledby="grid-left">
<ul class="nav-groups"> <ul class="nav-groups">
<li> <li>
<div class="nav-group"> <div class="nav-group">
<h2 class="sponsors-title">Sponsored by</h2> <h2 class="sponsors-title">Sponsored by</h2>
<div class="sponsors"> <div class="sponsors">
<a href="https://www.netlify.com/" aria-label="Go to Netlify website"> <a href="https://www.netlify.com/" aria-label="Go to Netlify website">
<svg class="sponsor-logo__netlify" viewBox="0 0 147 40" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><radialGradient id="netlify-gradient" cx="-779.0521" cy="1839.7205" gradientTransform="matrix(0 38.301 44.1228 0 -81154.2578 29839.2441)" gradientUnits="userSpaceOnUse" r="1.0011"><stop offset="0" stop-color="#20c6b7"/><stop offset="1" stop-color="#4d9abf"/></radialGradient><path clip-rule="evenodd" d="m53.37 12.98.12 2.2c1.4-1.7 3.24-2.55 5.53-2.55 3.95 0 5.96 2.27 6.03 6.8v12.57h-4.26v-12.32c0-1.21-.26-2.1-.78-2.68s-1.37-.87-2.55-.87c-1.72 0-3 .78-3.84 2.34v13.53h-4.26v-19.02zm24.38 19.37c-2.7 0-4.89-.85-6.57-2.56-1.68-1.7-2.52-3.98-2.52-6.81v-.53c0-1.9.36-3.59 1.1-5.09.73-1.49 1.76-2.66 3.08-3.49s2.79-1.25 4.42-1.25c2.58 0 4.58.83 5.99 2.48s2.11 3.99 2.11 7.01v1.72h-12.4c.13 1.57.65 2.81 1.57 3.73s2.07 1.37 3.46 1.37c1.95 0 3.54-.79 4.77-2.37l2.3 2.2c-.76 1.14-1.77 2.02-3.04 2.65s-2.69.94-4.27.94zm-.51-16.29c-1.17 0-2.11.41-2.83 1.23s-1.18 1.96-1.38 3.43h8.12v-.32c-.09-1.43-.47-2.51-1.14-3.24-.67-.74-1.59-1.1-2.77-1.1zm16.76-7.7v4.62h3.35v3.16h-3.35v10.62c0 .73.14 1.25.43 1.57s.8.48 1.54.48c.5 0 1-.06 1.49-.18v3.31c-.97.27-1.9.4-2.81.4-3.27 0-4.91-1.81-4.91-5.43v-10.77h-3.12v-3.16h3.12v-4.63zm11.14 23.64h-4.26v-27h4.26zm9.17 0h-4.26v-19.02h4.26zm-4.52-23.96c0-.65.21-1.2.62-1.63.42-.43 1.01-.65 1.78-.65s1.37.22 1.79.65.63.98.63 1.64c0 .64-.21 1.18-.63 1.61s-1.02.64-1.79.64-1.36-.21-1.78-.64c-.41-.44-.62-.98-.62-1.62zm10.66 23.96v-15.86h-2.89v-3.16h2.89v-1.74c0-2.11.58-3.74 1.75-4.89s2.81-1.72 4.91-1.72c.75 0 1.54.11 2.39.32l-.1 3.34c-.54-.1-1.08-.15-1.63-.14-2.04 0-3.05 1.05-3.05 3.15v1.69h3.86v3.16h-3.86v15.85zm17.87-6.12 3.86-12.9h4.54l-7.54 21.9c-1.16 3.2-3.12 4.8-5.89 4.8-.62 0-1.3-.11-2.05-.32v-3.31l.81.05c1.07 0 1.88-.2 2.43-.59.54-.39.97-1.05 1.29-1.98l.61-1.64-6.66-18.93h4.6z" fill-rule="evenodd"/><path d="m27.89 14.14-.01-.01c-.01 0-.02-.01-.02-.01-.02-.02-.03-.06-.03-.09l.77-4.73 3.62 3.63-3.77 1.6c-.01 0-.02.01-.03.01h-.02s-.01-.01-.02-.02c-.14-.16-.31-.29-.49-.38zm5.26-.29 3.88 3.88c.81.81 1.21 1.21 1.35 1.67.02.07.04.14.05.21l-9.26-3.92s-.01 0-.01-.01c-.04-.02-.08-.03-.08-.07s.04-.06.08-.07l.01-.01zm5.12 7c-.2.38-.59.77-1.25 1.43l-4.37 4.37-5.65-1.18-.03-.01c-.05-.01-.1-.02-.1-.06-.04-.47-.28-.9-.66-1.19-.02-.02-.02-.06-.01-.09v-.01l1.06-6.53v-.02c.01-.05.01-.11.06-.11.46-.06.88-.3 1.16-.67.01-.01.01-.02.03-.03.03-.01.07 0 .1.01zm-6.62 6.8-7.19 7.19 1.23-7.56v-.01c0-.01 0-.02.01-.03.01-.02.04-.03.06-.04h.01c.27-.11.51-.29.69-.52.02-.03.05-.06.09-.06h.03zm-8.71 8.71-.81.81-8.95-12.94s-.01-.01-.01-.01c-.01-.02-.03-.04-.03-.06s.01-.03.02-.04l.01-.01c.03-.04.05-.08.07-.12l.02-.03c.01-.02.03-.05.05-.06s.05-.01.07 0l9.92 2.05c.03 0 .05.02.08.03.01.01.02.03.02.04.14.53.52.97 1.03 1.17.03.01.02.05 0 .08-.01.01-.01.03-.01.05-.12.74-1.19 7.27-1.48 9.04zm-1.69 1.69c-.6.59-.95.9-1.35 1.03-.39.12-.81.12-1.21 0-.47-.15-.87-.55-1.67-1.36l-8.99-8.99 2.35-3.64c.01-.02.02-.03.04-.05s.06-.01.09 0c.54.16 1.12.13 1.64-.08.03-.01.05-.02.07 0l.03.03zm-14.09-10.19-2.06-2.06 4.07-1.74c.01 0 .02-.01.03-.01.03 0 .05.03.07.07.04.06.08.12.13.18l.01.02c.01.02 0 .03-.01.05zm-2.98-2.97-2.61-2.61c-.44-.44-.77-.77-.99-1.04l7.94 1.65h.03c.05.01.1.02.1.06 0 .05-.06.07-.11.09l-.02.01zm-4.05-5c.01-.17.04-.33.09-.5.15-.47.55-.87 1.36-1.67l3.34-3.34c1.54 2.23 3.08 4.46 4.63 6.69.03.04.06.08.03.11-.15.16-.29.34-.4.53-.01.02-.03.05-.05.06-.01.01-.03 0-.04 0zm5.68-6.4 4.49-4.49c.42.19 1.96.83 3.33 1.41 1.04.44 1.99.84 2.29.97.03.01.06.02.07.05.01.02 0 .04 0 .06-.14.66.05 1.35.52 1.83.03.03 0 .07-.03.11l-.01.02-4.56 7.06c-.01.02-.02.04-.04.05s-.06.01-.09 0c-.18-.05-.36-.07-.54-.07-.16 0-.34.03-.52.06-.02 0-.04.01-.05 0-.02-.01-.03-.03-.05-.05zm5.4-5.4 5.81-5.81c.81-.81 1.21-1.21 1.67-1.36.39-.12.81-.12 1.21 0 .47.15.87.55 1.67 1.36l1.26 1.26-4.14 6.4c-.01.02-.02.03-.04.05s-.06.01-.09 0c-.66-.2-1.38-.06-1.92.37-.03.03-.07.01-.1 0-.53-.24-4.73-2.01-5.33-2.27zm12.5-3.67 3.82 3.82-.92 5.7v.02c0 .01 0 .03-.01.04-.01.02-.03.02-.05.03-.2.06-.38.15-.55.27-.01.01-.01.01-.02.02s-.02.02-.04.02c-.01 0-.03 0-.04-.01l-5.82-2.47-.01-.01c-.04-.02-.08-.03-.08-.07-.03-.32-.14-.64-.31-.91-.03-.05-.06-.09-.03-.14zm-3.93 8.6 5.45 2.31c.03.01.06.03.08.06.01.02.01.04 0 .06-.02.08-.03.17-.03.26v.15c0 .04-.04.05-.08.07h-.01c-.86.37-12.13 5.17-12.15 5.17s-.03 0-.05-.02c-.03-.03 0-.07.03-.11 0-.01.01-.01.01-.02l4.48-6.94.01-.01c.03-.04.06-.09.1-.09l.05.01c.1.01.19.03.28.03.68 0 1.31-.33 1.69-.9.01-.02.02-.03.03-.04.04-.01.08 0 .11.01zm-6.25 9.19 12.28-5.24s.02 0 .03.02c.07.07.12.11.18.15l.03.02c.02.01.05.03.05.06v.02l-1.05 6.46v.03c-.01.05-.01.11-.06.11-.57.04-1.08.36-1.37.85v.01c-.01.02-.03.05-.05.06s-.05.01-.07 0l-9.79-2.02c-.02-.02-.16-.53-.18-.53z" fill="url(#netlify-gradient)"/></svg> <svg
</a> class="sponsor-logo__netlify"
</div> viewBox="0 0 147 40"
</div> xmlns="http://www.w3.org/2000/svg"
</li> xmlns:xlink="http://www.w3.org/1999/xlink"
{sidebarSections.map(section => ( ><radialGradient
<li> id="netlify-gradient"
<div class="nav-group"> cx="-779.0521"
<h2 class="nav-group-title">{section.text}</h2> cy="1839.7205"
<ul> gradientTransform="matrix(0 38.301 44.1228 0 -81154.2578 29839.2441)"
{section.children.map(child => ( gradientUnits="userSpaceOnUse"
<li class="nav-link"><a href={`${Astro.site.pathname}${child.link}`} aria-current={`${currentPageMatch === child.link ? 'page' : 'false'}`}>{child.text}</a></li> r="1.0011"
))} ><stop offset="0" stop-color="#20c6b7"></stop><stop
</ul> offset="1"
</div> stop-color="#4d9abf"></stop></radialGradient
</li> ><path
))} clip-rule="evenodd"
</ul> d="m53.37 12.98.12 2.2c1.4-1.7 3.24-2.55 5.53-2.55 3.95 0 5.96 2.27 6.03 6.8v12.57h-4.26v-12.32c0-1.21-.26-2.1-.78-2.68s-1.37-.87-2.55-.87c-1.72 0-3 .78-3.84 2.34v13.53h-4.26v-19.02zm24.38 19.37c-2.7 0-4.89-.85-6.57-2.56-1.68-1.7-2.52-3.98-2.52-6.81v-.53c0-1.9.36-3.59 1.1-5.09.73-1.49 1.76-2.66 3.08-3.49s2.79-1.25 4.42-1.25c2.58 0 4.58.83 5.99 2.48s2.11 3.99 2.11 7.01v1.72h-12.4c.13 1.57.65 2.81 1.57 3.73s2.07 1.37 3.46 1.37c1.95 0 3.54-.79 4.77-2.37l2.3 2.2c-.76 1.14-1.77 2.02-3.04 2.65s-2.69.94-4.27.94zm-.51-16.29c-1.17 0-2.11.41-2.83 1.23s-1.18 1.96-1.38 3.43h8.12v-.32c-.09-1.43-.47-2.51-1.14-3.24-.67-.74-1.59-1.1-2.77-1.1zm16.76-7.7v4.62h3.35v3.16h-3.35v10.62c0 .73.14 1.25.43 1.57s.8.48 1.54.48c.5 0 1-.06 1.49-.18v3.31c-.97.27-1.9.4-2.81.4-3.27 0-4.91-1.81-4.91-5.43v-10.77h-3.12v-3.16h3.12v-4.63zm11.14 23.64h-4.26v-27h4.26zm9.17 0h-4.26v-19.02h4.26zm-4.52-23.96c0-.65.21-1.2.62-1.63.42-.43 1.01-.65 1.78-.65s1.37.22 1.79.65.63.98.63 1.64c0 .64-.21 1.18-.63 1.61s-1.02.64-1.79.64-1.36-.21-1.78-.64c-.41-.44-.62-.98-.62-1.62zm10.66 23.96v-15.86h-2.89v-3.16h2.89v-1.74c0-2.11.58-3.74 1.75-4.89s2.81-1.72 4.91-1.72c.75 0 1.54.11 2.39.32l-.1 3.34c-.54-.1-1.08-.15-1.63-.14-2.04 0-3.05 1.05-3.05 3.15v1.69h3.86v3.16h-3.86v15.85zm17.87-6.12 3.86-12.9h4.54l-7.54 21.9c-1.16 3.2-3.12 4.8-5.89 4.8-.62 0-1.3-.11-2.05-.32v-3.31l.81.05c1.07 0 1.88-.2 2.43-.59.54-.39.97-1.05 1.29-1.98l.61-1.64-6.66-18.93h4.6z"
fill-rule="evenodd"></path><path
d="m27.89 14.14-.01-.01c-.01 0-.02-.01-.02-.01-.02-.02-.03-.06-.03-.09l.77-4.73 3.62 3.63-3.77 1.6c-.01 0-.02.01-.03.01h-.02s-.01-.01-.02-.02c-.14-.16-.31-.29-.49-.38zm5.26-.29 3.88 3.88c.81.81 1.21 1.21 1.35 1.67.02.07.04.14.05.21l-9.26-3.92s-.01 0-.01-.01c-.04-.02-.08-.03-.08-.07s.04-.06.08-.07l.01-.01zm5.12 7c-.2.38-.59.77-1.25 1.43l-4.37 4.37-5.65-1.18-.03-.01c-.05-.01-.1-.02-.1-.06-.04-.47-.28-.9-.66-1.19-.02-.02-.02-.06-.01-.09v-.01l1.06-6.53v-.02c.01-.05.01-.11.06-.11.46-.06.88-.3 1.16-.67.01-.01.01-.02.03-.03.03-.01.07 0 .1.01zm-6.62 6.8-7.19 7.19 1.23-7.56v-.01c0-.01 0-.02.01-.03.01-.02.04-.03.06-.04h.01c.27-.11.51-.29.69-.52.02-.03.05-.06.09-.06h.03zm-8.71 8.71-.81.81-8.95-12.94s-.01-.01-.01-.01c-.01-.02-.03-.04-.03-.06s.01-.03.02-.04l.01-.01c.03-.04.05-.08.07-.12l.02-.03c.01-.02.03-.05.05-.06s.05-.01.07 0l9.92 2.05c.03 0 .05.02.08.03.01.01.02.03.02.04.14.53.52.97 1.03 1.17.03.01.02.05 0 .08-.01.01-.01.03-.01.05-.12.74-1.19 7.27-1.48 9.04zm-1.69 1.69c-.6.59-.95.9-1.35 1.03-.39.12-.81.12-1.21 0-.47-.15-.87-.55-1.67-1.36l-8.99-8.99 2.35-3.64c.01-.02.02-.03.04-.05s.06-.01.09 0c.54.16 1.12.13 1.64-.08.03-.01.05-.02.07 0l.03.03zm-14.09-10.19-2.06-2.06 4.07-1.74c.01 0 .02-.01.03-.01.03 0 .05.03.07.07.04.06.08.12.13.18l.01.02c.01.02 0 .03-.01.05zm-2.98-2.97-2.61-2.61c-.44-.44-.77-.77-.99-1.04l7.94 1.65h.03c.05.01.1.02.1.06 0 .05-.06.07-.11.09l-.02.01zm-4.05-5c.01-.17.04-.33.09-.5.15-.47.55-.87 1.36-1.67l3.34-3.34c1.54 2.23 3.08 4.46 4.63 6.69.03.04.06.08.03.11-.15.16-.29.34-.4.53-.01.02-.03.05-.05.06-.01.01-.03 0-.04 0zm5.68-6.4 4.49-4.49c.42.19 1.96.83 3.33 1.41 1.04.44 1.99.84 2.29.97.03.01.06.02.07.05.01.02 0 .04 0 .06-.14.66.05 1.35.52 1.83.03.03 0 .07-.03.11l-.01.02-4.56 7.06c-.01.02-.02.04-.04.05s-.06.01-.09 0c-.18-.05-.36-.07-.54-.07-.16 0-.34.03-.52.06-.02 0-.04.01-.05 0-.02-.01-.03-.03-.05-.05zm5.4-5.4 5.81-5.81c.81-.81 1.21-1.21 1.67-1.36.39-.12.81-.12 1.21 0 .47.15.87.55 1.67 1.36l1.26 1.26-4.14 6.4c-.01.02-.02.03-.04.05s-.06.01-.09 0c-.66-.2-1.38-.06-1.92.37-.03.03-.07.01-.1 0-.53-.24-4.73-2.01-5.33-2.27zm12.5-3.67 3.82 3.82-.92 5.7v.02c0 .01 0 .03-.01.04-.01.02-.03.02-.05.03-.2.06-.38.15-.55.27-.01.01-.01.01-.02.02s-.02.02-.04.02c-.01 0-.03 0-.04-.01l-5.82-2.47-.01-.01c-.04-.02-.08-.03-.08-.07-.03-.32-.14-.64-.31-.91-.03-.05-.06-.09-.03-.14zm-3.93 8.6 5.45 2.31c.03.01.06.03.08.06.01.02.01.04 0 .06-.02.08-.03.17-.03.26v.15c0 .04-.04.05-.08.07h-.01c-.86.37-12.13 5.17-12.15 5.17s-.03 0-.05-.02c-.03-.03 0-.07.03-.11 0-.01.01-.01.01-.02l4.48-6.94.01-.01c.03-.04.06-.09.1-.09l.05.01c.1.01.19.03.28.03.68 0 1.31-.33 1.69-.9.01-.02.02-.03.03-.04.04-.01.08 0 .11.01zm-6.25 9.19 12.28-5.24s.02 0 .03.02c.07.07.12.11.18.15l.03.02c.02.01.05.03.05.06v.02l-1.05 6.46v.03c-.01.05-.01.11-.06.11-.57.04-1.08.36-1.37.85v.01c-.01.02-.03.05-.05.06s-.05.01-.07 0l-9.79-2.02c-.02-.02-.16-.53-.18-.53z"
fill="url(#netlify-gradient)"></path></svg
>
</a>
</div>
</div>
</li>
{sidebarSections.map((section) => (
<li>
<div class="nav-group">
<h2 class="nav-group-title">{section.text}</h2>
<ul>
{section.children.map((child) => (
<li class="nav-link">
<a
href={`${Astro.site.pathname}${child.link}`}
aria-current={`${
currentPageMatch === child.link ? 'page' : 'false'
}`}
>
{child.text}
</a>
</li>
))}
</ul>
</div>
</li>
))}
</ul>
</nav> </nav>
<script> <script>
window.addEventListener('DOMContentLoaded', (event) => { window.addEventListener('DOMContentLoaded', (event) => {
var target = document.querySelector('[aria-current="page"]'); var target = document.querySelector('[aria-current="page"]');
if (target && (target.offsetTop > (window.innerHeight - 100))) { if (target && target.offsetTop > window.innerHeight - 100) {
document.querySelector('.nav-groups').scrollTop = target.offsetTop; document.querySelector('.nav-groups').scrollTop = target.offsetTop;
} }
}); });
</script> </script>
<style lang="scss"> <style lang="scss">
nav { nav {
width: 100%; width: 100%;
margin-right: 1rem; margin-right: 1rem;
} }
.nav-groups { .nav-groups {
height: 100%; height: 100%;
padding: 2rem 0; padding: 2rem 0;
overflow-x: visible; overflow-x: visible;
overflow-y: auto; overflow-y: auto;
max-height: 100vh; max-height: 100vh;
> li + li { > li + li {
margin-top: 1.75rem; margin-top: 1.75rem;
} }
> :first-child { > :first-child {
padding-top: var(--doc-padding); padding-top: var(--doc-padding);
} }
> :last-child { > :last-child {
padding-bottom: 2rem; padding-bottom: 2rem;
margin-bottom: var(--theme-navbar-height); margin-bottom: var(--theme-navbar-height);
} }
@media (min-width: 50em) { @media (min-width: 50em) {
padding: 0; padding: 0;
} }
} }
.nav-group-title { .nav-group-title {
font-size: 1.0rem; font-size: 1rem;
font-weight: 700; font-weight: 700;
padding: 0.1rem 1rem; padding: 0.1rem 1rem;
text-transform: uppercase; text-transform: uppercase;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.nav-link a { .nav-link a {
font-size: 1.0rem; font-size: 1rem;
margin: 1px; margin: 1px;
padding: 0.3rem 1rem; padding: 0.3rem 1rem;
font: inherit; font: inherit;
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
display: block; display: block;
&:hover, &:hover,
&:focus { &:focus {
background-color: var(--theme-bg-hover); background-color: var(--theme-bg-hover);
} }
&[aria-current="page"] { &[aria-current='page'] {
color: var(--theme-text-accent); color: var(--theme-text-accent);
background-color: var(--theme-bg-accent); background-color: var(--theme-bg-accent);
font-weight: 600; font-weight: 600;
} }
} }
:global(:root.theme-dark) .nav-link a[aria-current="page"] { :global(:root.theme-dark) .nav-link a[aria-current='page'] {
color: hsla(var(--color-base-white), 100%, 1); color: hsla(var(--color-base-white), 100%, 1);
} }
.sponsors { .sponsors {
display: grid; display: grid;
padding-left: 1rem; padding-left: 1rem;
padding-top: 0.25rem; padding-top: 0.25rem;
margin-bottom: -0.375rem; // logo overshoot creates extra perceived space margin-bottom: -0.375rem; // logo overshoot creates extra perceived space
grid-gap: 0.5rem; grid-gap: 0.5rem;
grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
svg { svg {
color: var(--theme-text); color: var(--theme-text);
fill: currentColor; fill: currentColor;
} }
} }
.sponsor-logo__netlify { .sponsor-logo__netlify {
width: 90px; width: 90px;
} }
.sponsor-logo__vercel { .sponsor-logo__vercel {
width: 90px; width: 90px;
} }
:global(:root.theme-dark .sponsors-title) { :global(:root.theme-dark .sponsors-title) {
color: hsl(var(--color-base-gray), 75%); color: hsl(var(--color-base-gray), 75%);
} }
.sponsors-title { .sponsors-title {
color: hsl(var(--color-base-gray), 25%); color: hsl(var(--color-base-gray), 25%);
font-size: 0.8em; font-size: 0.8em;
font-weight: 300; font-weight: 300;
letter-spacing: 0.0625em; letter-spacing: 0.0625em;
margin: 0 0 0.5rem; margin: 0 0 0.5rem;
padding-left: 1rem; padding-left: 1rem;
text-transform: uppercase; text-transform: uppercase;
} }
</style> </style>

View file

@ -1,59 +1,78 @@
--- ---
import MoreMenu from '../RightSidebar/MoreMenu.astro'; import MoreMenu from '../RightSidebar/MoreMenu.astro';
import TableOfContents from '../RightSidebar/TableOfContents.tsx'; import TableOfContents from '../RightSidebar/TableOfContents.tsx';
import {getLanguageFromURL} from '../../util.ts'; import { getLanguageFromURL } from '../../util.ts';
import {SIDEBAR} from '../../config.ts'; import { SIDEBAR } from '../../config.ts';
const {content, githubEditUrl, currentPage} = Astro.props; const { content, githubEditUrl, currentPage } = Astro.props;
const title = content.title; const title = content.title;
const headers = content.astro?.headers; const headers = content.astro?.headers;
const langCode = getLanguageFromURL(currentPage); const langCode = getLanguageFromURL(currentPage);
const links = SIDEBAR[langCode].filter(x => x.link && typeof x.header === 'undefined'); const links = SIDEBAR[langCode].filter(
(x) => x.link && typeof x.header === 'undefined'
);
// handle cases with a trailing slash or not // handle cases with a trailing slash or not
const index = links.findIndex(x => `/${x.link}/` === currentPage || `/${x.link}` === currentPage); const index = links.findIndex(
const next = index !== -1 ? (index === links.length - 1 ? null : links[index + 1]) : null; (x) => `/${x.link}/` === currentPage || `/${x.link}` === currentPage
);
const next =
index !== -1 ? (index === links.length - 1 ? null : links[index + 1]) : null;
const previous = index !== -1 ? (index === 0 ? null : links[index - 1]) : null; const previous = index !== -1 ? (index === 0 ? null : links[index - 1]) : null;
--- ---
<style>
.content {
padding: 0;
max-width: 75ch;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.content > section {
margin-bottom: 4rem;
}
.block {
display: block;
}
@media (min-width: 50em) {
.sm\:hidden {
display: none;
}
}
</style>
<article id="article" class="content"> <article id="article" class="content">
<section class="main-section"> <section class="main-section">
<h1 class="content-title" id="overview">{title}</h1> <h1 class="content-title" id="overview">{title}</h1>
{headers && <nav class="block sm:hidden"> {headers && (
<TableOfContents client:media="(max-width: 50em)" headers={headers}/> <nav class="block sm:hidden">
</nav>} <TableOfContents client:media="(max-width: 50em)" headers={headers} />
<slot /> </nav>
</section> )}
<nav class="block sm:hidden"> <slot />
<MoreMenu editHref={githubEditUrl}/> </section>
</nav> <nav class="block sm:hidden">
{ <MoreMenu editHref={githubEditUrl} />
(previous || next) && <aside> </nav>
{ {(previous || next) && (
previous && <div>Previous Article: <a rel="prev" href={new URL(previous.link, Astro.site).pathname}>{previous.text}</a></div> <aside>
} {previous && (
{ <div>
next && <div>Next Article: <a rel="next" href={new URL(next.link, Astro.site).pathname}>{next.text}</a></div> Previous Article:{' '}
} <a rel="prev" href={new URL(previous.link, Astro.site).pathname}>
</aside> {previous.text}
} </a>
</article> </div>
)}
{next && (
<div>
Next Article:{' '}
<a rel="next" href={new URL(next.link, Astro.site).pathname}>
{next.text}
</a>
</div>
)}
</aside>
)}
</article>
<style>
.content {
padding: 0;
max-width: 75ch;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.content > section {
margin-bottom: 4rem;
}
.block {
display: block;
}
@media (min-width: 50em) {
.sm\:hidden {
display: none;
}
}
</style>

View file

@ -1,68 +1,91 @@
--- ---
import ThemeToggleButton from './ThemeToggleButton.tsx'; import ThemeToggleButton from './ThemeToggleButton.tsx';
const {editHref} = Astro.props; const { editHref } = Astro.props;
--- ---
<style>
.edit-on-github {
text-decoration: none;
font: inherit;
color: inherit;
font-size: 1rem;
}
</style>
<h2 class="heading">More</h2> <h2 class="heading">More</h2>
<ul> <ul>
<li class={`header-link depth-2`}> <li class={`header-link depth-2`}>
<a class="edit-on-github" href={editHref} target="_blank"> <a class="edit-on-github" href={editHref} target="_blank">
<svg <svg
aria-hidden="true" aria-hidden="true"
focusable="false" focusable="false"
data-prefix="fas" data-prefix="fas"
data-icon="pen" data-icon="pen"
class="svg-inline--fa fa-pen fa-w-16" class="svg-inline--fa fa-pen fa-w-16"
role="img" role="img"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512" viewBox="0 0 512 512"
height="1em" height="1em"
width="1em" width="1em"
> >
<path <path
fill="currentColor" fill="currentColor"
d="M290.74 93.24l128.02 128.02-277.99 277.99-114.14 12.6C11.35 513.54-1.56 500.62.14 485.34l12.7-114.22 277.9-277.88zm207.2-19.06l-60.11-60.11c-18.75-18.75-49.16-18.75-67.91 0l-56.55 56.55 128.02 128.02 56.55-56.55c18.75-18.76 18.75-49.16 0-67.91z" d="M290.74 93.24l128.02 128.02-277.99 277.99-114.14 12.6C11.35 513.54-1.56 500.62.14 485.34l12.7-114.22 277.9-277.88zm207.2-19.06l-60.11-60.11c-18.75-18.75-49.16-18.75-67.91 0l-56.55 56.55 128.02 128.02 56.55-56.55c18.75-18.76 18.75-49.16 0-67.91z"
></path> ></path>
</svg> </svg>
<span>Edit this page</span> <span>Edit this page</span>
</a> </a>
</li> </li>
<li class={`header-link depth-2`}> <li class={`header-link depth-2`}>
<a href="https://github.com/withastro/astro/blob/main/CONTRIBUTING.md#translations" target="_blank"> <a
<svg aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 88.6 77.3" height="1.24em" width="1.24em" style="margin: -2px;"> <path fill="currentColor" d="M61,24.6h7.9l18.7,51.6h-7.7l-5.4-15.5H54.3l-5.6,15.5h-7.2L61,24.6z M72.6,55l-8-22.8L56.3,55H72.6z" /> <path fill="currentColor" d="M53.6,60.6c-10-4-16-9-22-14c0,0,1.3,1.3,0,0c-6,5-20,13-20,13l-4-6c8-5,10-6,19-13c-2.1-1.9-12-13-13-19h8 c4,9,10,14,10,14c10-8,10-19,10-19h8c0,0-1,13-12,24l0,0c5,5,10,9,19,13L53.6,60.6z M1.6,16.6h56v-8h-23v-7h-9v7h-24V16.6z" /> </svg> href="https://github.com/withastro/astro/blob/main/CONTRIBUTING.md#translations"
<span>Translate this page</span> target="_blank"
</a> >
</li> <svg
<li class={`header-link depth-2`}> aria-hidden="true"
<a href="https://astro.build/chat" target="_blank"> focusable="false"
<svg role="img"
aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
focusable="false" viewBox="0 0 88.6 77.3"
data-prefix="fas" height="1.24em"
data-icon="comment-alt" width="1.24em"
class="svg-inline--fa fa-comment-alt fa-w-16" style="margin: -2px;"
role="img" >
xmlns="http://www.w3.org/2000/svg" <path
viewBox="0 0 512 512" fill="currentColor"
height="1em" d="M61,24.6h7.9l18.7,51.6h-7.7l-5.4-15.5H54.3l-5.6,15.5h-7.2L61,24.6z M72.6,55l-8-22.8L56.3,55H72.6z"
width="1em" ></path>
> <path
<path fill="currentColor"
fill="currentColor" d="M53.6,60.6c-10-4-16-9-22-14c0,0,1.3,1.3,0,0c-6,5-20,13-20,13l-4-6c8-5,10-6,19-13c-2.1-1.9-12-13-13-19h8 c4,9,10,14,10,14c10-8,10-19,10-19h8c0,0-1,13-12,24l0,0c5,5,10,9,19,13L53.6,60.6z M1.6,16.6h56v-8h-23v-7h-9v7h-24V16.6z"
d="M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 9.8 11.2 15.5 19.1 9.7L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64z" ></path>
></path> </svg>
</svg> <span>Translate this page</span>
<span>Join our community</span> </a>
</a> </li>
</li> <li class={`header-link depth-2`}>
<a href="https://astro.build/chat" target="_blank">
<svg
aria-hidden="true"
focusable="false"
data-prefix="fas"
data-icon="comment-alt"
class="svg-inline--fa fa-comment-alt fa-w-16"
role="img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
height="1em"
width="1em"
>
<path
fill="currentColor"
d="M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 9.8 11.2 15.5 19.1 9.7L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64z"
></path>
</svg>
<span>Join our community</span>
</a>
</li>
</ul> </ul>
<div style="margin: 2rem 0; text-align: center;"> <div style="margin: 2rem 0; text-align: center;">
<ThemeToggleButton client:visible /> <ThemeToggleButton client:visible />
</div> </div>
<style>
.edit-on-github {
text-decoration: none;
font: inherit;
color: inherit;
font-size: 1rem;
}
</style>

View file

@ -1,25 +1,29 @@
--- ---
import TableOfContents from './TableOfContents.tsx'; import TableOfContents from './TableOfContents.tsx';
import MoreMenu from './MoreMenu.astro'; import MoreMenu from './MoreMenu.astro';
const {content, githubEditUrl} = Astro.props; const { content, githubEditUrl } = Astro.props;
const headers = content.astro?.headers; const headers = content.astro?.headers;
--- ---
<style>
.sidebar-nav {
width: 100%;
position: sticky;
top: 0;
}
.sidebar-nav-inner {
height: 100%;
padding: 0;
padding-top: var(--doc-padding);
overflow: auto;
}
</style>
<nav class="sidebar-nav" aria-labelledby="grid-right"> <nav class="sidebar-nav" aria-labelledby="grid-right">
<div class="sidebar-nav-inner"> <div class="sidebar-nav-inner">
{headers && <TableOfContents client:media="(min-width: 50em)" headers={headers} />} {headers && (
<MoreMenu editHref={githubEditUrl} /> <TableOfContents client:media="(min-width: 50em)" headers={headers} />
</div> )}
</nav> <MoreMenu editHref={githubEditUrl} />
</div>
</nav>
<style>
.sidebar-nav {
width: 100%;
position: sticky;
top: 0;
}
.sidebar-nav-inner {
height: 100%;
padding: 0;
padding-top: var(--doc-padding);
overflow: auto;
}
</style>

View file

@ -3,53 +3,53 @@ import { h, Fragment } from 'preact';
import { useState, useEffect, useRef } from 'preact/hooks'; import { useState, useEffect, useRef } from 'preact/hooks';
const TableOfContents: FunctionalComponent<{ headers: any[] }> = ({ const TableOfContents: FunctionalComponent<{ headers: any[] }> = ({
headers = [], headers = [],
}) => { }) => {
const itemOffsets = useRef([]); const itemOffsets = useRef([]);
const [activeId, setActiveId] = useState<string>(undefined); const [activeId, setActiveId] = useState<string>(undefined);
useEffect(() => { useEffect(() => {
const getItemOffsets = () => { const getItemOffsets = () => {
const titles = document.querySelectorAll('article :is(h1, h2, h3, h4)'); const titles = document.querySelectorAll('article :is(h1, h2, h3, h4)');
itemOffsets.current = Array.from(titles).map((title) => ({ itemOffsets.current = Array.from(titles).map((title) => ({
id: title.id, id: title.id,
topOffset: title.getBoundingClientRect().top + window.scrollY, topOffset: title.getBoundingClientRect().top + window.scrollY,
})); }));
}; };
getItemOffsets(); getItemOffsets();
window.addEventListener('resize', getItemOffsets); window.addEventListener('resize', getItemOffsets);
return () => { return () => {
window.removeEventListener('resize', getItemOffsets); window.removeEventListener('resize', getItemOffsets);
}; };
}, []); }, []);
return ( return (
<> <>
<h2 class="heading">On this page</h2> <h2 class="heading">On this page</h2>
<ul> <ul>
<li <li
class={`header-link depth-2 ${ class={`header-link depth-2 ${
activeId === 'overview' ? 'active' : '' activeId === 'overview' ? 'active' : ''
}`.trim()} }`.trim()}
> >
<a href="#overview">Overview</a> <a href="#overview">Overview</a>
</li> </li>
{headers {headers
.filter(({ depth }) => depth > 1 && depth < 4) .filter(({ depth }) => depth > 1 && depth < 4)
.map((header) => ( .map((header) => (
<li <li
class={`header-link depth-${header.depth} ${ class={`header-link depth-${header.depth} ${
activeId === header.slug ? 'active' : '' activeId === header.slug ? 'active' : ''
}`.trim()} }`.trim()}
> >
<a href={`#${header.slug}`}>{header.text}</a> <a href={`#${header.slug}`}>{header.text}</a>
</li> </li>
))} ))}
</ul> </ul>
</> </>
); );
}; };
export default TableOfContents; export default TableOfContents;

View file

@ -1,38 +1,38 @@
.theme-toggle { .theme-toggle {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 0.25em; gap: 0.25em;
padding: 0.33em 0.67em; padding: 0.33em 0.67em;
border-radius: 99em; border-radius: 99em;
background-color: var(--theme-code-inline-bg); background-color: var(--theme-code-inline-bg);
} }
.theme-toggle > label:focus-within { .theme-toggle > label:focus-within {
outline: 2px solid transparent; outline: 2px solid transparent;
box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white; box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white;
} }
.theme-toggle > label { .theme-toggle > label {
color: var(--theme-code-inline-text); color: var(--theme-code-inline-text);
position: relative; position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
opacity: 0.5; opacity: 0.5;
cursor: pointer; cursor: pointer;
} }
.theme-toggle .checked { .theme-toggle .checked {
color: var(--theme-accent); color: var(--theme-accent);
opacity: 1; opacity: 1;
} }
input[name='theme-toggle'] { input[name='theme-toggle'] {
position: absolute; position: absolute;
opacity: 0; opacity: 0;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: -1; z-index: -1;
} }

View file

@ -6,78 +6,78 @@ import './ThemeToggleButton.css';
const themes = ['light', 'dark']; const themes = ['light', 'dark'];
const icons = [ const icons = [
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="20" width="20"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
> >
<path <path
fill-rule="evenodd" fill-rule="evenodd"
d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
clip-rule="evenodd" clip-rule="evenodd"
/> />
</svg>, </svg>,
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="20" width="20"
height="20" height="20"
viewBox="0 0 20 20" viewBox="0 0 20 20"
fill="currentColor" fill="currentColor"
> >
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" /> <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
</svg>, </svg>,
]; ];
function ThemeToggle() { function ThemeToggle() {
const [theme, setTheme] = useState(() => { const [theme, setTheme] = useState(() => {
if (import.meta.env.SSR) { if (import.meta.env.SSR) {
return undefined; return undefined;
} }
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) { if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
return localStorage.getItem('theme'); return localStorage.getItem('theme');
} }
if (window.matchMedia('(prefers-color-scheme: dark)').matches) { if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark'; return 'dark';
} }
return 'light'; return 'light';
}); });
useEffect(() => { useEffect(() => {
const root = document.documentElement; const root = document.documentElement;
if (theme === 'light') { if (theme === 'light') {
root.classList.remove('theme-dark'); root.classList.remove('theme-dark');
} else { } else {
root.classList.add('theme-dark'); root.classList.add('theme-dark');
} }
}, [theme]); }, [theme]);
return ( return (
<div class="theme-toggle"> <div class="theme-toggle">
{themes.map((t, i) => { {themes.map((t, i) => {
const icon = icons[i]; const icon = icons[i];
const checked = t === theme; const checked = t === theme;
return ( return (
<label class={checked ? 'checked' : ''}> <label class={checked ? 'checked' : ''}>
{icon} {icon}
<input <input
type="radio" type="radio"
name="theme-toggle" name="theme-toggle"
checked={checked} checked={checked}
value={t} value={t}
title={`Use ${t} theme`} title={`Use ${t} theme`}
aria-label={`Use ${t} theme`} aria-label={`Use ${t} theme`}
onChange={() => { onChange={() => {
localStorage.setItem('theme', t); localStorage.setItem('theme', t);
setTheme(t); setTheme(t);
}} }}
/> />
</label> </label>
); );
})} })}
</div> </div>
); );
} }
export default ThemeToggle; export default ThemeToggle;

View file

@ -1,204 +1,204 @@
export const SIDEBAR = { export const SIDEBAR = {
en: [ en: [
{ text: 'Setup', header: true }, { text: 'Setup', header: true },
{ text: 'Getting Started', link: 'getting-started' }, { text: 'Getting Started', link: 'getting-started' },
{ text: 'Quickstart', link: 'quick-start' }, { text: 'Quickstart', link: 'quick-start' },
{ text: 'Installation', link: 'installation' }, { text: 'Installation', link: 'installation' },
{ text: 'Themes', link: 'themes' }, { text: 'Themes', link: 'themes' },
{ text: 'Astro vs. X', link: 'comparing-astro-vs-other-tools' }, { text: 'Astro vs. X', link: 'comparing-astro-vs-other-tools' },
{ text: 'Migrate to v0.21', link: 'migration/0.21.0' }, { text: 'Migrate to v0.21', link: 'migration/0.21.0' },
{ text: 'Basics', header: true }, { text: 'Basics', header: true },
{ text: 'Project Structure', link: 'core-concepts/project-structure' }, { text: 'Project Structure', link: 'core-concepts/project-structure' },
{ text: 'Component Syntax', link: 'core-concepts/astro-components' }, { text: 'Component Syntax', link: 'core-concepts/astro-components' },
{ text: 'Pages', link: 'core-concepts/astro-pages' }, { text: 'Pages', link: 'core-concepts/astro-pages' },
{ text: 'Layouts', link: 'core-concepts/layouts' }, { text: 'Layouts', link: 'core-concepts/layouts' },
{ text: 'Routing', link: 'core-concepts/routing' }, { text: 'Routing', link: 'core-concepts/routing' },
{ text: 'Partial Hydration', link: 'core-concepts/component-hydration' }, { text: 'Partial Hydration', link: 'core-concepts/component-hydration' },
{ text: 'Guides', header: true }, { text: 'Guides', header: true },
{ text: 'Styling & CSS', link: 'guides/styling' }, { text: 'Styling & CSS', link: 'guides/styling' },
{ text: 'Markdown', link: 'guides/markdown-content' }, { text: 'Markdown', link: 'guides/markdown-content' },
{ text: 'Debugging', link: 'guides/debugging' }, { text: 'Debugging', link: 'guides/debugging' },
{ text: 'Data Fetching', link: 'guides/data-fetching' }, { text: 'Data Fetching', link: 'guides/data-fetching' },
{ text: 'Pagination', link: 'guides/pagination' }, { text: 'Pagination', link: 'guides/pagination' },
{ text: 'RSS', link: 'guides/rss' }, { text: 'RSS', link: 'guides/rss' },
{ text: 'Supported Imports', link: 'guides/imports' }, { text: 'Supported Imports', link: 'guides/imports' },
{ text: 'Aliases', link: 'guides/aliases' }, { text: 'Aliases', link: 'guides/aliases' },
{ text: 'Environment Variables', link: 'guides/environment-variables' }, { text: 'Environment Variables', link: 'guides/environment-variables' },
{ text: 'Deploy to the web', link: 'guides/deploy' }, { text: 'Deploy to the web', link: 'guides/deploy' },
{ text: 'Publish to npm', link: 'guides/publish-to-npm' }, { text: 'Publish to npm', link: 'guides/publish-to-npm' },
{ text: 'Reference', header: true }, { text: 'Reference', header: true },
{ text: 'Built-In Components', link: 'reference/builtin-components' }, { text: 'Built-In Components', link: 'reference/builtin-components' },
{ text: 'API Reference', link: 'reference/api-reference' }, { text: 'API Reference', link: 'reference/api-reference' },
{ text: 'CLI Reference', link: 'reference/cli-reference' }, { text: 'CLI Reference', link: 'reference/cli-reference' },
{ {
text: 'Configuration Reference', text: 'Configuration Reference',
link: 'reference/configuration-reference', link: 'reference/configuration-reference',
}, },
{ text: 'Renderer Reference', link: 'reference/renderer-reference' }, { text: 'Renderer Reference', link: 'reference/renderer-reference' },
], ],
de: [ de: [
{ text: 'Einrichtung', header: true }, { text: 'Einrichtung', header: true },
{ text: 'Erste Schritte', link: 'de/getting-started' }, { text: 'Erste Schritte', link: 'de/getting-started' },
{ text: 'Schnellstart', link: 'de/quick-start' }, { text: 'Schnellstart', link: 'de/quick-start' },
{ text: 'Installation', link: 'de/installation' }, { text: 'Installation', link: 'de/installation' },
{ text: 'Vorlagen', link: 'de/themes' }, { text: 'Vorlagen', link: 'de/themes' },
{ text: 'Astro vs. X', link: 'de/comparing-astro-vs-other-tools' }, { text: 'Astro vs. X', link: 'de/comparing-astro-vs-other-tools' },
{ text: 'Umstellung auf v0.21', link: 'de/migration/0.21.0' }, { text: 'Umstellung auf v0.21', link: 'de/migration/0.21.0' },
{ text: 'Grundlagen', header: true }, { text: 'Grundlagen', header: true },
{ text: 'Projektstruktur', link: 'de/core-concepts/project-structure' }, { text: 'Projektstruktur', link: 'de/core-concepts/project-structure' },
{ text: 'Astro-Komponenten', link: 'de/core-concepts/astro-components' }, { text: 'Astro-Komponenten', link: 'de/core-concepts/astro-components' },
{ text: 'Astro-Seiten', link: 'de/core-concepts/astro-pages' }, { text: 'Astro-Seiten', link: 'de/core-concepts/astro-pages' },
{ text: 'Layouts', link: 'de/core-concepts/layouts' }, { text: 'Layouts', link: 'de/core-concepts/layouts' },
{ text: 'Routing', link: 'de/core-concepts/routing' }, { text: 'Routing', link: 'de/core-concepts/routing' },
{ text: 'Partial Hydration', link: 'de/core-concepts/component-hydration' }, { text: 'Partial Hydration', link: 'de/core-concepts/component-hydration' },
{ text: 'Anleitungen', header: true }, { text: 'Anleitungen', header: true },
{ text: 'Styling & CSS', link: 'de/guides/styling' }, { text: 'Styling & CSS', link: 'de/guides/styling' },
{ text: 'Referenz', header: true }, { text: 'Referenz', header: true },
], ],
nl: [ nl: [
{ text: 'Welkom', header: true }, { text: 'Welkom', header: true },
{ text: 'Beginnen', link: 'nl/getting-started' }, { text: 'Beginnen', link: 'nl/getting-started' },
{ text: 'Snel start', link: 'nl/quick-start' }, { text: 'Snel start', link: 'nl/quick-start' },
], ],
fi: [ fi: [
{ text: 'Tervetuloa', header: true }, { text: 'Tervetuloa', header: true },
{ text: 'Aloittaminen', link: 'fi/getting-started' }, { text: 'Aloittaminen', link: 'fi/getting-started' },
{ text: 'Pika-aloitus', link: 'fi/quick-start' }, { text: 'Pika-aloitus', link: 'fi/quick-start' },
{ text: 'Asennus', link: 'fi/installation' }, { text: 'Asennus', link: 'fi/installation' },
], ],
es: [ es: [
{ text: 'Configuración', header: true }, { text: 'Configuración', header: true },
{ text: 'Empezando', link: 'es/getting-started' }, { text: 'Empezando', link: 'es/getting-started' },
{ text: 'Comienzo rápido', link: 'es/quick-start' }, { text: 'Comienzo rápido', link: 'es/quick-start' },
{ text: 'Instalación', link: 'es/installation' }, { text: 'Instalación', link: 'es/installation' },
{ text: 'Astro vs. X', link: 'es/comparing-astro-vs-other-tools' }, { text: 'Astro vs. X', link: 'es/comparing-astro-vs-other-tools' },
{ text: 'Fundamentos', header: true }, { text: 'Fundamentos', header: true },
{ {
text: 'Estructura del Proyecto', text: 'Estructura del Proyecto',
link: 'es/core-concepts/project-structure', link: 'es/core-concepts/project-structure',
}, },
{ {
text: 'Sintaxis del Componente', text: 'Sintaxis del Componente',
link: 'es/core-concepts/astro-components', link: 'es/core-concepts/astro-components',
}, },
{ text: 'Páginas', link: 'es/core-concepts/astro-pages' }, { text: 'Páginas', link: 'es/core-concepts/astro-pages' },
{ text: 'Maquetas', link: 'es/core-concepts/layouts' }, { text: 'Maquetas', link: 'es/core-concepts/layouts' },
{ text: 'Enrutamiento', link: 'es/core-concepts/routing' }, { text: 'Enrutamiento', link: 'es/core-concepts/routing' },
{ {
text: 'Hidratación parcial', text: 'Hidratación parcial',
link: 'es/core-concepts/component-hydration', link: 'es/core-concepts/component-hydration',
}, },
{ text: 'Guías', header: true }, { text: 'Guías', header: true },
{ text: 'Estilo y CSS', link: 'es/guides/styling' }, { text: 'Estilo y CSS', link: 'es/guides/styling' },
{ text: 'Markdown', link: 'es/guides/markdown-content' }, { text: 'Markdown', link: 'es/guides/markdown-content' },
{ text: 'Depuración', link: 'es/guides/debugging' }, { text: 'Depuración', link: 'es/guides/debugging' },
{ text: 'Obtención de datos', link: 'es/guides/data-fetching' }, { text: 'Obtención de datos', link: 'es/guides/data-fetching' },
{ text: 'Paginación', link: 'es/guides/pagination' }, { text: 'Paginación', link: 'es/guides/pagination' },
{ text: 'RSS', link: 'es/guides/rss' }, { text: 'RSS', link: 'es/guides/rss' },
{ text: 'Importaciones admitidas', link: 'es/guides/imports' }, { text: 'Importaciones admitidas', link: 'es/guides/imports' },
{ text: 'Alias', link: 'es/guides/aliases' }, { text: 'Alias', link: 'es/guides/aliases' },
{ text: 'Desplegar en la web', link: 'es/guides/deploy' }, { text: 'Desplegar en la web', link: 'es/guides/deploy' },
{ text: 'Publicar en npm', link: 'es/guides/publish-to-npm' }, { text: 'Publicar en npm', link: 'es/guides/publish-to-npm' },
{ text: 'Referencia', header: true }, { text: 'Referencia', header: true },
{ {
text: 'Componentes incorporados', text: 'Componentes incorporados',
link: 'es/reference/builtin-components', link: 'es/reference/builtin-components',
}, },
{ text: 'Referencia de API', link: 'es/reference/api-reference' }, { text: 'Referencia de API', link: 'es/reference/api-reference' },
{ text: 'Referencia de CLI', link: 'es/reference/cli-reference' }, { text: 'Referencia de CLI', link: 'es/reference/cli-reference' },
{ {
text: 'Referencia de configuración', text: 'Referencia de configuración',
link: 'es/reference/configuration-reference', link: 'es/reference/configuration-reference',
}, },
{ {
text: 'Referencia de renderizador', text: 'Referencia de renderizador',
link: 'es/reference/renderer-reference', link: 'es/reference/renderer-reference',
}, },
], ],
'zh-CN': [ 'zh-CN': [
{ text: '起步', header: true }, { text: '起步', header: true },
{ text: '入门指南', link: 'zh-CN/getting-started' }, { text: '入门指南', link: 'zh-CN/getting-started' },
{ text: '快速入门', link: 'zh-CN/quick-start' }, { text: '快速入门', link: 'zh-CN/quick-start' },
{ text: '安装指南', link: 'zh-CN/installation' }, { text: '安装指南', link: 'zh-CN/installation' },
{ text: '模板样例', link: 'zh-CN/examples' }, { text: '模板样例', link: 'zh-CN/examples' },
{ {
text: 'Astro 对比其他框架', text: 'Astro 对比其他框架',
link: 'zh-CN/comparing-astro-vs-other-tools', link: 'zh-CN/comparing-astro-vs-other-tools',
}, },
], ],
'zh-TW': [ 'zh-TW': [
{ text: '設定', header: true }, { text: '設定', header: true },
{ text: '新手上路', link: 'zh-TW/getting-started' }, { text: '新手上路', link: 'zh-TW/getting-started' },
{ text: '快速開始', link: 'zh-TW/quick-start' }, { text: '快速開始', link: 'zh-TW/quick-start' },
{ text: '安裝', link: 'zh-TW/installation' }, { text: '安裝', link: 'zh-TW/installation' },
{ text: '佈景主題', link: 'zh-TW/themes' }, { text: '佈景主題', link: 'zh-TW/themes' },
], ],
bg: [ bg: [
{ text: 'Главни', header: true }, { text: 'Главни', header: true },
{ text: 'Започваме!', link: 'bg/getting-started' }, { text: 'Започваме!', link: 'bg/getting-started' },
], ],
fr: [ fr: [
{ text: 'Bienvenue', header: true }, { text: 'Bienvenue', header: true },
{ text: 'Bien démarrer', link: 'fr/getting-started' }, { text: 'Bien démarrer', link: 'fr/getting-started' },
{ text: 'Démarrage rapide', link: 'fr/quick-start' }, { text: 'Démarrage rapide', link: 'fr/quick-start' },
{ text: 'Installation', link: 'fr/installation' }, { text: 'Installation', link: 'fr/installation' },
], ],
bn: [ bn: [
{ text: 'সেটআপ', header: true }, { text: 'সেটআপ', header: true },
{ text: 'শুরু করুন', link: 'bn/getting-started' }, { text: 'শুরু করুন', link: 'bn/getting-started' },
], ],
kr: [ kr: [
{ text: '환영합니다', header: true }, { text: '환영합니다', header: true },
{ text: '시작하기', link: 'kr/getting-started' }, { text: '시작하기', link: 'kr/getting-started' },
], ],
ar: [ ar: [
{ text: 'التهيئة', header: true }, { text: 'التهيئة', header: true },
{ text: 'باشر البدأ', link: 'ar/getting-started' }, { text: 'باشر البدأ', link: 'ar/getting-started' },
], ],
da: [ da: [
{ text: 'Velkommen', header: true }, { text: 'Velkommen', header: true },
{ text: 'Introduktion', link: 'da/getting-started' }, { text: 'Introduktion', link: 'da/getting-started' },
], ],
ja: [ ja: [
{ text: 'セットアップ', header: true }, { text: 'セットアップ', header: true },
{ text: 'はじめに', link: 'ja/getting-started' }, { text: 'はじめに', link: 'ja/getting-started' },
{ text: 'クイックスタート', link: 'ja/quick-start' }, { text: 'クイックスタート', link: 'ja/quick-start' },
{ text: 'インストール', link: 'ja/installation' }, { text: 'インストール', link: 'ja/installation' },
{ text: 'テーマ', link: 'ja/themes' }, { text: 'テーマ', link: 'ja/themes' },
{ text: 'Astro vs. X', link: 'ja/comparing-astro-vs-other-tools' }, { text: 'Astro vs. X', link: 'ja/comparing-astro-vs-other-tools' },
], ],
ru: [ ru: [
{ text: 'Введение', header: true }, { text: 'Введение', header: true },
{ text: 'Начало работы', link: 'ru/getting-started' }, { text: 'Начало работы', link: 'ru/getting-started' },
{ text: 'Быстрый старт', link: 'ru/quick-start' }, { text: 'Быстрый старт', link: 'ru/quick-start' },
], ],
it: [ it: [
{ text: 'Impostare', header: true }, { text: 'Impostare', header: true },
{ text: 'Come iniziare', link: 'it/getting-started' }, { text: 'Come iniziare', link: 'it/getting-started' },
], ],
}; };
export const SITE = { export const SITE = {
title: 'Astro Documentation', title: 'Astro Documentation',
description: 'Build faster websites with less client-side Javascript.', description: 'Build faster websites with less client-side Javascript.',
}; };
export const OPEN_GRAPH = { export const OPEN_GRAPH = {
locale: 'en_US', locale: 'en_US',
image: { image: {
src: '/default-og-image.png?v=1', src: '/default-og-image.png?v=1',
alt: alt:
'astro logo on a starry expanse of space,' + 'astro logo on a starry expanse of space,' +
' with a purple saturn-like planet floating in the right foreground', ' with a purple saturn-like planet floating in the right foreground',
}, },
twitter: 'astrodotbuild', twitter: 'astrodotbuild',
}; };

View file

@ -1,122 +1,126 @@
--- ---
import HeadCommon from "../components/HeadCommon.astro"; import HeadCommon from '../components/HeadCommon.astro';
import HeadSEO from "../components/HeadSEO.astro"; import HeadSEO from '../components/HeadSEO.astro';
import Header from '../components/Header/Header.astro'; import Header from '../components/Header/Header.astro';
import Footer from '../components/Footer/Footer.astro'; import Footer from '../components/Footer/Footer.astro';
import PageContent from '../components/PageContent/PageContent.astro'; import PageContent from '../components/PageContent/PageContent.astro';
import LeftSidebar from '../components/LeftSidebar/LeftSidebar.astro'; import LeftSidebar from '../components/LeftSidebar/LeftSidebar.astro';
import RightSidebar from '../components/RightSidebar/RightSidebar.astro'; import RightSidebar from '../components/RightSidebar/RightSidebar.astro';
import { SITE } from "../config.ts"; import { SITE } from '../config.ts';
const { content = {}, hideRightSidebar = false} = Astro.props; const { content = {}, hideRightSidebar = false } = Astro.props;
const currentPage = Astro.request.url.pathname; const currentPage = Astro.request.url.pathname;
const currentFile = `src/pages${currentPage.replace(/\/$/, "")}.md`; const currentFile = `src/pages${currentPage.replace(/\/$/, '')}.md`;
const githubEditUrl = `https://github.com/withastro/astro/blob/main/docs/${currentFile}`; const githubEditUrl = `https://github.com/withastro/astro/blob/main/docs/${currentFile}`;
const formatTitle = (content, SITE) => content.title ? `${content.title} 🚀 ${SITE.title}` : SITE.title; const formatTitle = (content, SITE) =>
content.title ? `${content.title} 🚀 ${SITE.title}` : SITE.title;
--- ---
<html dir={content.dir ?? 'ltr'} lang={content.lang ?? 'en-us'} class="initial"> <html dir={content.dir ?? 'ltr'} lang={content.lang ?? 'en-us'} class="initial">
<head> <head>
<HeadCommon /> <HeadCommon />
<HeadSEO {content} canonicalURL={Astro.request.canonicalURL} /> <HeadSEO {content} canonicalURL={Astro.request.canonicalURL} />
<title>{formatTitle(content, SITE)}</title> <title>{formatTitle(content, SITE)}</title>
<style> <style>
body { body {
width: 100%; width: 100%;
display: grid; display: grid;
grid-template-rows: var(--theme-navbar-height) 1fr; grid-template-rows: var(--theme-navbar-height) 1fr;
--gutter: 0.5rem; --gutter: 0.5rem;
--doc-padding: 2rem; --doc-padding: 2rem;
} }
.layout { .layout {
display: grid; display: grid;
grid-auto-flow: column; grid-auto-flow: column;
grid-template-columns: grid-template-columns:
minmax(var(--gutter), 1fr) minmax(var(--gutter), 1fr)
minmax(0, var(--max-width)) minmax(0, var(--max-width))
minmax(var(--gutter), 1fr); minmax(var(--gutter), 1fr);
overflow-x: hidden; overflow-x: hidden;
} }
.layout :global(> *) { .layout :global(> *) {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.grid-sidebar { .grid-sidebar {
height: 100vh; height: 100vh;
position: sticky; position: sticky;
top: 0; top: 0;
padding: 0; padding: 0;
} }
#grid-left { #grid-left {
position: fixed; position: fixed;
background-color: var(--theme-bg); background-color: var(--theme-bg);
z-index: 10; z-index: 10;
display: none; display: none;
} }
#grid-main { #grid-main {
padding: var(--doc-padding) var(--gutter); padding: var(--doc-padding) var(--gutter);
grid-column: 2; grid-column: 2;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
} }
#grid-right { #grid-right {
display: none; display: none;
} }
:global(.mobile-sidebar-toggle) { :global(.mobile-sidebar-toggle) {
overflow: hidden; overflow: hidden;
} }
:global(.mobile-sidebar-toggle #grid-left) { :global(.mobile-sidebar-toggle #grid-left) {
display: block; display: block;
top: 2rem; top: 2rem;
} }
@media (min-width: 50em) { @media (min-width: 50em) {
.layout { .layout {
overflow: initial; overflow: initial;
grid-template-columns: grid-template-columns:
20rem 20rem
minmax(0, var(--max-width)); minmax(0, var(--max-width));
gap: 1em; gap: 1em;
} }
#grid-left { #grid-left {
display: flex; display: flex;
padding-left: 2rem; padding-left: 2rem;
position: sticky; position: sticky;
grid-column: 1; grid-column: 1;
} }
} }
@media (min-width: 72em) { @media (min-width: 72em) {
.layout { .layout {
grid-template-columns: grid-template-columns:
20rem 20rem
minmax(0, var(--max-width)) minmax(0, var(--max-width))
18rem; 18rem;
padding-left: 0; padding-left: 0;
padding-right: 0; padding-right: 0;
margin: 0 auto; margin: 0 auto;
} }
#grid-right { #grid-right {
grid-column: 3; grid-column: 3;
display: flex; display: flex;
} }
} }
</style> </style>
</head> </head>
<body> <body>
<Header currentPage={currentPage} /> <Header {currentPage} />
<main class="layout"> <main class="layout">
<aside id="grid-left" class="grid-sidebar" title="Site Navigation"> <aside id="grid-left" class="grid-sidebar" title="Site Navigation">
<LeftSidebar currentPage={currentPage} /> <LeftSidebar {currentPage} />
</aside> </aside>
<div id="grid-main"> <div id="grid-main">
<PageContent content={content} githubEditUrl={githubEditUrl} currentPage={currentPage}> <PageContent {content} {githubEditUrl} {currentPage}>
<slot /> <slot />
</PageContent> </PageContent>
</div> </div>
<aside id="grid-right" class="grid-sidebar" title="Table of Contents"> <aside id="grid-right" class="grid-sidebar" title="Table of Contents">
{!hideRightSidebar && <RightSidebar content={content} githubEditUrl={githubEditUrl} />} {!hideRightSidebar && (
</aside> <RightSidebar content={content} githubEditUrl={githubEditUrl} />
</main> )}
</body> </aside>
</main>
</body>
</html> </html>

View file

@ -1,48 +1,48 @@
--- ---
import HeadCommon from "../components/HeadCommon.astro"; import HeadCommon from '../components/HeadCommon.astro';
import Header from '../components/Header/Header.astro'; import Header from '../components/Header/Header.astro';
import { SITE } from "../config.ts"; import { SITE } from '../config.ts';
const { title } = Astro.props; const { title } = Astro.props;
--- ---
<html dir="ltr" lang="en-us" class="initial"> <html dir="ltr" lang="en-us" class="initial">
<head> <head>
<HeadCommon /> <HeadCommon />
<title>{`${title} 🚀 ${SITE.title}`}</title> <title>{`${title} 🚀 ${SITE.title}`}</title>
<style> <style>
body { body {
width: 100%; width: 100%;
display: grid; display: grid;
grid-template-rows: var(--theme-navbar-height) 1fr; grid-template-rows: var(--theme-navbar-height) 1fr;
--gutter: 0.5rem; --gutter: 0.5rem;
--doc-padding: 2rem; --doc-padding: 2rem;
} }
.layout { .layout {
display: grid; display: grid;
grid-auto-flow: column; grid-auto-flow: column;
grid-template-columns: grid-template-columns:
minmax(var(--gutter), 1fr) minmax(var(--gutter), 1fr)
minmax(0, var(--max-width)) minmax(0, var(--max-width))
minmax(var(--gutter), 1fr); minmax(var(--gutter), 1fr);
overflow-x: hidden; overflow-x: hidden;
} }
article { article {
padding: var(--doc-padding) var(--gutter); padding: var(--doc-padding) var(--gutter);
grid-column: 2; grid-column: 2;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
} }
</style> </style>
</head> </head>
<body> <body>
<Header /> <Header />
<main class="layout splash-layout"> <main class="layout splash-layout">
<article> <article>
<slot /> <slot />
</article> </article>
</main> </main>
</body> </body>
</html> </html>

View file

@ -3,7 +3,7 @@ import SplashLayout from '../layouts/SplashLayout.astro';
--- ---
<SplashLayout title="Not Found"> <SplashLayout title="Not Found">
<h1>404</h1> <h1>404</h1>
<p>This page isn't in our solar system.</p> <p>This page isn't in our solar system.</p>
<a href="/">Take me home.</a> <a href="/">Take me home.</a>
</SplashLayout> </SplashLayout>

View file

@ -3,7 +3,7 @@ import SplashLayout from '../../layouts/SplashLayout.astro';
--- ---
<SplashLayout title="Nicht gefunden"> <SplashLayout title="Nicht gefunden">
<h1>404</h1> <h1>404</h1>
<p>Diese Seite befindet sich nicht in unserem Sonnensystem.</p> <p>Diese Seite befindet sich nicht in unserem Sonnensystem.</p>
<a href="/">Bring mich nach Hause.</a> <a href="/">Bring mich nach Hause.</a>
</SplashLayout> </SplashLayout>

View file

@ -5,48 +5,49 @@ import { Markdown } from 'astro/components';
import themes from '../../data/themes.json'; import themes from '../../data/themes.json';
import components from '../../data/components.json'; import components from '../../data/components.json';
--- ---
<Layout content={{title: 'Vorlagen'}} hideRightSidebar>
<style>
.card-grid {
display: grid;
grid-column-gap: 15px;
grid-row-gap: 15px;
grid-auto-flow: dense;
grid-template-columns: repeat(auto-fit,minmax(300px,1fr))
}
</style>
<Markdown>
## Vorgestellte Vorlagen
</Markdown>
<div class="card-grid">
{themes.featured.map((item)=>(<Card data={item} />))}
</div>
<Markdown>
## Offizielle Vorlagen
Astro pflegt verschiedene offizielle Vorlagen für Dokumentationssites, Portfolios und mehr. <Layout content={{ title: 'Vorlagen' }} hideRightSidebar>
</Markdown> <style>
<div class="card-grid"> .card-grid {
{themes.official.map((item)=>(<Card data={item} />))} display: grid;
</div> grid-column-gap: 15px;
<Markdown> grid-row-gap: 15px;
## Vorlagen aus der Community grid-auto-flow: dense;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
</style>
<Markdown>
## Vorgestellte Vorlagen
</Markdown>
<div class="card-grid">
{themes.featured.map((item) => <Card data={item} />)}
</div>
<Markdown>
## Offizielle Vorlagen
Sieh dir einige von unserer Community entwickelte Vorlagen an! Astro pflegt verschiedene offizielle Vorlagen für Dokumentationssites, Portfolios und mehr.
</Markdown> </Markdown>
<div class="card-grid"> <div class="card-grid">
{themes.community.map((item)=>(<Card data={item} />))} {themes.official.map((item) => <Card data={item} />)}
</div> </div>
<Markdown> <Markdown>
## Vorgestellte Packages ## Vorlagen aus der Community
Unser Package-Ökosystem wächst stetig! Sieh dir die hier vorgestellten Packages unserer Community an. Durchsuche unsere vollständige Sammlung [auf npm.](https://www.npmjs.com/search?q=keywords%3Aastro-component) Sieh dir einige von unserer Community entwickelte Vorlagen an!
</Markdown> </Markdown>
<div class="card-grid"> <div class="card-grid">
{components.community.map((item)=>(<Card data={item} />))} {themes.community.map((item) => <Card data={item} />)}
</div> </div>
<Markdown> <Markdown>
> Möchtest du deine eigene Arbeit hier sehen? [Teile sie in Discord!](https://astro.build/chat) ## Vorgestellte Packages
Wir teilen hier regelmäßig unsere Favoriten aus dem #showcase-Channel.
</Markdown> Unser Package-Ökosystem wächst stetig! Sieh dir die hier vorgestellten Packages unserer Community an. Durchsuche unsere vollständige Sammlung [auf npm.](https://www.npmjs.com/search?q=keywords%3Aastro-component)
</Markdown>
<div class="card-grid">
{components.community.map((item) => <Card data={item} />)}
</div>
<Markdown>
> Möchtest du deine eigene Arbeit hier sehen? [Teile sie in Discord!](https://astro.build/chat)
> Wir teilen hier regelmäßig unsere Favoriten aus dem #showcase-Channel.
</Markdown>
</Layout> </Layout>

View file

@ -4,10 +4,9 @@ import MainLayout from '~/layouts/MainLayout.astro';
const [content] = Astro.fetchContent('/src/pages/guides/markdown-content.md'); const [content] = Astro.fetchContent('/src/pages/guides/markdown-content.md');
--- ---
<MainLayout content="{content}"> <MainLayout {content}>
<Markdown> <Markdown>
> Esta página todavía no está disponible en Español. Se muestra la versión en inglés. > Esta página todavía no está disponible en Español. Se muestra la versión en inglés.
</Markdown> </Markdown>
{content.astro.html} {content.astro.html}
</MainLayout> </MainLayout>

View file

@ -4,10 +4,9 @@ import MainLayout from '~/layouts/MainLayout.astro';
const [content] = Astro.fetchContent('/src/pages/guides/pagination.md'); const [content] = Astro.fetchContent('/src/pages/guides/pagination.md');
--- ---
<MainLayout content="{content}"> <MainLayout {content}>
<Markdown> <Markdown>
> Esta página todavía no está disponible en Español. Se muestra la versión en inglés. > Esta página todavía no está disponible en Español. Se muestra la versión en inglés.
</Markdown> </Markdown>
{content.astro.html} {content.astro.html}
</MainLayout> </MainLayout>

View file

@ -4,10 +4,9 @@ import MainLayout from '~/layouts/MainLayout.astro';
const [content] = Astro.fetchContent('/src/pages/guides/publish-to-npm.md'); const [content] = Astro.fetchContent('/src/pages/guides/publish-to-npm.md');
--- ---
<MainLayout content="{content}"> <MainLayout {content}>
<Markdown> <Markdown>
> Esta página todavía no está disponible en Español. Se muestra la versión en inglés. > Esta página todavía no está disponible en Español. Se muestra la versión en inglés.
</Markdown> </Markdown>
{content.astro.html} {content.astro.html}
</MainLayout> </MainLayout>

View file

@ -4,10 +4,9 @@ import MainLayout from '~/layouts/MainLayout.astro';
const [content] = Astro.fetchContent('/src/pages/guides/styling.md'); const [content] = Astro.fetchContent('/src/pages/guides/styling.md');
--- ---
<MainLayout content="{content}"> <MainLayout {content}>
<Markdown> <Markdown>
> Esta página todavía no está disponible en Español. Se muestra la versión en inglés. > Esta página todavía no está disponible en Español. Se muestra la versión en inglés.
</Markdown> </Markdown>
{content.astro.html} {content.astro.html}
</MainLayout> </MainLayout>

View file

@ -1,13 +1,14 @@
--- ---
import { Markdown } from 'astro/components'; import { Markdown } from 'astro/components';
import MainLayout from '~/layouts/MainLayout.astro'; import MainLayout from '~/layouts/MainLayout.astro';
const [content] = Astro.fetchContent('/src/pages/reference/renderer-reference.md'); const [content] = Astro.fetchContent(
'/src/pages/reference/renderer-reference.md'
);
--- ---
<MainLayout content="{content}"> <MainLayout {content}>
<Markdown> <Markdown>
> Esta página todavía no está disponible en Español. Se muestra la versión en inglés. > Esta página todavía no está disponible en Español. Se muestra la versión en inglés.
</Markdown> </Markdown>
{content.astro.html} {content.astro.html}
</MainLayout> </MainLayout>

View file

@ -3,19 +3,37 @@ import Layout from '../layouts/MainLayout.astro';
--- ---
<script> <script>
// WIP: trigger a client-side redirect based on the browser language. // WIP: trigger a client-side redirect based on the browser language.
// A vercel.json redirect is enforced in production, so no user should ever see this page. // A vercel.json redirect is enforced in production, so no user should ever see this page.
// Remove the vercel.json redirect when this is ready. // Remove the vercel.json redirect when this is ready.
const KNOWN_LANGUAGES = ['bg', 'de','en','es','fi','nl','pt-br','zh-CN','zh-TW', 'fr', 'kr', 'da', 'ja']; const KNOWN_LANGUAGES = [
let newLangWithRegion = (window.navigator.userLanguage || window.navigator.language || 'en-US').substr(0, 5); 'bg',
let newLang = newLangWithRegion.substr(0, 2); 'de',
if (newLang === 'en') { 'en',
window.location.pathname = '/getting-started'; 'es',
} else if (KNOWN_LANGUAGES.includes(newLangWithRegion)) { 'fi',
window.location.pathname = '/' + newLangWithRegion + '/getting-started'; 'nl',
} else if (KNOWN_LANGUAGES.includes(newLang)) { 'pt-br',
window.location.pathname = '/' + newLang + '/getting-started'; 'zh-CN',
} else { 'zh-TW',
window.location.pathname = '/getting-started'; 'fr',
} 'kr',
'da',
'ja',
];
let newLangWithRegion = (
window.navigator.userLanguage ||
window.navigator.language ||
'en-US'
).substr(0, 5);
let newLang = newLangWithRegion.substr(0, 2);
if (newLang === 'en') {
window.location.pathname = '/getting-started';
} else if (KNOWN_LANGUAGES.includes(newLangWithRegion)) {
window.location.pathname = '/' + newLangWithRegion + '/getting-started';
} else if (KNOWN_LANGUAGES.includes(newLang)) {
window.location.pathname = '/' + newLang + '/getting-started';
} else {
window.location.pathname = '/getting-started';
}
</script> </script>

View file

@ -1,52 +1,53 @@
--- ---
import Layout from '../../layouts/MainLayout.astro'; import Layout from '../../layouts/MainLayout.astro';
import Card from '../../components/Card.astro'; import Card from '../../components/Card.astro';
import {Markdown} from 'astro/components'; import { Markdown } from 'astro/components';
import themes from '../../data/themes.json'; import themes from '../../data/themes.json';
import components from '../../data/components.json'; import components from '../../data/components.json';
--- ---
<Layout content={{title: 'テーマ'}} hideRightSidebar>
<style>
.card-grid {
display: grid;
grid-column-gap: 15px;
grid-row-gap: 15px;
grid-auto-flow: dense;
grid-template-columns: repeat(auto-fit,minmax(300px,1fr))
}
</style>
<Markdown>
## 注目のテーマ
</Markdown>
<div class="card-grid">
{themes.featured.map((item)=>(<Card data={item} />))}
</div>
<Markdown>
## 公式テーマ
Astroでは、ドキュメントサイトやポートフォリオなど、いくつかの公式テーマを用意しています。 <Layout content={{ title: 'テーマ' }} hideRightSidebar>
</Markdown> <style>
<div class="card-grid"> .card-grid {
{themes.official.map((item)=>(<Card data={item} />))} display: grid;
</div> grid-column-gap: 15px;
<Markdown> grid-row-gap: 15px;
## コミュニティテーマ grid-auto-flow: dense;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
</style>
<Markdown>
## 注目のテーマ
</Markdown>
<div class="card-grid">
{themes.featured.map((item) => <Card data={item} />)}
</div>
<Markdown>
## 公式テーマ
コミュニティが開発したテーマをご覧ください。 Astro では、ドキュメントサイトやポートフォリオなど、いくつかの公式テーマを用意しています
</Markdown> </Markdown>
<div class="card-grid"> <div class="card-grid">
{themes.community.map((item)=>(<Card data={item} />))} {themes.official.map((item) => <Card data={item} />)}
</div> </div>
<Markdown> <Markdown>
## 注目のパッケージ ## コミュニティテーマ
私たちのパッケージエコシステムは成長し続けています。注目のコミュニティパッケージをご覧ください。コレクション全体は[npm](https://www.npmjs.com/search?q=keywords%3Aastro-component)で検索できます。 コミュニティが開発したテーマをご覧ください。
</Markdown> </Markdown>
<div class="card-grid"> <div class="card-grid">
{components.community.map((item)=>(<Card data={item} />))} {themes.community.map((item) => <Card data={item} />)}
</div> </div>
<Markdown> <Markdown>
> 自分のテーマを紹介したい場合は、[Discordでシェアしてください](https://astro.build/chat) ## 注目のパッケージ
`#showcase` チャンネルに投稿されたお気に入りの作品をよくピックアップしています。
</Markdown> 私たちのパッケージエコシステムは成長し続けています。注目のコミュニティパッケージをご覧ください。コレクション全体は[npm](https://www.npmjs.com/search?q=keywords%3Aastro-component)で検索できます。
</Markdown>
<div class="card-grid">
{components.community.map((item) => <Card data={item} />)}
</div>
<Markdown>
> 自分のテーマを紹介したい場合は、[Discord でシェアしてください!](https://astro.build/chat)
> `#showcase` チャンネルに投稿されたお気に入りの作品をよくピックアップしています。
</Markdown>
</Layout> </Layout>

View file

@ -5,48 +5,49 @@ import { Markdown } from 'astro/components';
import themes from '../data/themes.json'; import themes from '../data/themes.json';
import components from '../data/components.json'; import components from '../data/components.json';
--- ---
<Layout content={{title: 'Themes'}} hideRightSidebar>
<style>
.card-grid {
display: grid;
grid-column-gap: 15px;
grid-row-gap: 15px;
grid-auto-flow: dense;
grid-template-columns: repeat(auto-fit,minmax(300px,1fr))
}
</style>
<Markdown>
## Featured Theme
</Markdown>
<div class="card-grid">
{themes.featured.map((item)=>(<Card data={item} />))}
</div>
<Markdown>
## Official Themes
Astro maintains several official themes for documentation sites, portfolios, and more. <Layout content={{ title: 'Themes' }} hideRightSidebar>
</Markdown> <style>
<div class="card-grid"> .card-grid {
{themes.official.map((item)=>(<Card data={item} />))} display: grid;
</div> grid-column-gap: 15px;
<Markdown> grid-row-gap: 15px;
## Community Themes grid-auto-flow: dense;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
</style>
<Markdown>
## Featured Theme
</Markdown>
<div class="card-grid">
{themes.featured.map((item) => <Card data={item} />)}
</div>
<Markdown>
## Official Themes
Checkout some themes developed by our community! Astro maintains several official themes for documentation sites, portfolios, and more.
</Markdown> </Markdown>
<div class="card-grid"> <div class="card-grid">
{themes.community.map((item)=>(<Card data={item} />))} {themes.official.map((item) => <Card data={item} />)}
</div> </div>
<Markdown> <Markdown>
## Featured Packages ## Community Themes
Our package ecosystem is growing! Check out these featured community packages. Search the entire collection [on npm.](https://www.npmjs.com/search?q=keywords%3Aastro-component) Checkout some themes developed by our community!
</Markdown> </Markdown>
<div class="card-grid"> <div class="card-grid">
{components.community.map((item)=>(<Card data={item} />))} {themes.community.map((item) => <Card data={item} />)}
</div> </div>
<Markdown> <Markdown>
> Want to see your own work featured? [Share it to Discord!](https://astro.build/chat) ## Featured Packages
We'll often take our favorites from the `#showcase` channel and post them here.
</Markdown> Our package ecosystem is growing! Check out these featured community packages. Search the entire collection [on npm.](https://www.npmjs.com/search?q=keywords%3Aastro-component)
</Markdown>
<div class="card-grid">
{components.community.map((item) => <Card data={item} />)}
</div>
<Markdown>
> Want to see your own work featured? [Share it to Discord!](https://astro.build/chat)
> We'll often take our favorites from the `#showcase` channel and post them here.
</Markdown>
</Layout> </Layout>

View file

@ -5,48 +5,49 @@ import { Markdown } from 'astro/components';
import themes from '../../data/themes.json'; import themes from '../../data/themes.json';
import components from '../../data/components.json'; import components from '../../data/components.json';
--- ---
<Layout content={{title: '佈景主題'}} hideRightSidebar>
<style>
.card-grid {
display: grid;
grid-column-gap: 15px;
grid-row-gap: 15px;
grid-auto-flow: dense;
grid-template-columns: repeat(auto-fit,minmax(300px,1fr))
}
</style>
<Markdown>
## 精選佈景主題
</Markdown>
<div class="card-grid">
{themes.featured.map((item)=>(<Card data={item} />))}
</div>
<Markdown>
## 官方佈景主題
Astro 維護的文件網站、作品集⋯等官方佈景主題。 <Layout content={{ title: '佈景主題' }} hideRightSidebar>
</Markdown> <style>
<div class="card-grid"> .card-grid {
{themes.official.map((item)=>(<Card data={item} />))} display: grid;
</div> grid-column-gap: 15px;
<Markdown> grid-row-gap: 15px;
## 社群佈景主題 grid-auto-flow: dense;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
</style>
<Markdown>
## 精選佈景主題
</Markdown>
<div class="card-grid">
{themes.featured.map((item) => <Card data={item} />)}
</div>
<Markdown>
## 官方佈景主題
趕緊來看看社群開發的佈景主題! Astro 維護的文件網站、作品集 ⋯ 等官方佈景主題。
</Markdown> </Markdown>
<div class="card-grid"> <div class="card-grid">
{themes.community.map((item)=>(<Card data={item} />))} {themes.official.map((item) => <Card data={item} />)}
</div> </div>
<Markdown> <Markdown>
## 精選套件 ## 社群佈景主題
我們的套件生態持續成長!所有精選社群套件都可以在 [npm](https://www.npmjs.com/search?q=keywords%3Aastro-component) 發掘。 趕緊來看看社群開發的佈景主題!
</Markdown> </Markdown>
<div class="card-grid"> <div class="card-grid">
{components.community.map((item)=>(<Card data={item} />))} {themes.community.map((item) => <Card data={item} />)}
</div> </div>
<Markdown> <Markdown>
> 想要讓自己的作品成為精選嗎?[在 Discord 分享!](https://astro.build/chat) ## 精選套件
我們常在 `#showcase` 頻道取材,把深受喜愛的在這裡發布。
</Markdown> 我們的套件生態持續成長!所有精選社群套件都可以在 [npm](https://www.npmjs.com/search?q=keywords%3Aastro-component) 發掘。
</Markdown>
<div class="card-grid">
{components.community.map((item) => <Card data={item} />)}
</div>
<Markdown>
> 想要讓自己的作品成為精選嗎?[在 Discord 分享!](https://astro.build/chat)
> 我們常在 `#showcase` 頻道取材,把深受喜愛的在這裡發布。
</Markdown>
</Layout> </Layout>

View file

@ -1,14 +1,14 @@
export function getLanguageFromURL(pathname: string) { export function getLanguageFromURL(pathname: string) {
const langCodeMatch = pathname.match(/\/([a-z]{2}-?[A-Z]{0,2})\//); const langCodeMatch = pathname.match(/\/([a-z]{2}-?[A-Z]{0,2})\//);
return langCodeMatch ? langCodeMatch[1] : 'en'; return langCodeMatch ? langCodeMatch[1] : 'en';
} }
/** Remove \ and / from beginning of string */ /** Remove \ and / from beginning of string */
export function removeLeadingSlash(path: string) { export function removeLeadingSlash(path: string) {
return path.replace(/^[/\\]+/, ''); return path.replace(/^[/\\]+/, '');
} }
/** Remove \ and / from end of string */ /** Remove \ and / from end of string */
export function removeTrailingSlash(path: string) { export function removeTrailingSlash(path: string) {
return path.replace(/[/\\]+$/, ''); return path.replace(/[/\\]+$/, '');
} }

View file

@ -8,6 +8,6 @@
// @ts-check // @ts-check
export default /** @type {import('astro').AstroUserConfig} */ ({ export default /** @type {import('astro').AstroUserConfig} */ ({
// Enable the Preact renderer to support Preact JSX components. // Enable the Preact renderer to support Preact JSX components.
renderers: ['@astrojs/renderer-preact'], renderers: ['@astrojs/renderer-preact'],
}); });

View file

@ -1,45 +1,45 @@
--- ---
export interface Props { export interface Props {
title: string; title: string;
description: string; description: string;
image?: string; image?: string;
type?: string; type?: string;
next?: string; next?: string;
prev?: string; prev?: string;
canonicalURL?: string | URL; canonicalURL?: string | URL;
} }
const { title, description, image, type, next, prev, canonicalURL } = Astro.props as Props; const { title, description, image, type, next, prev, canonicalURL } = Astro.props as Props;
--- ---
<!-- Common --> <!-- Common -->
<meta charset="UTF-8"> <meta charset="UTF-8" />
<title>{title}</title> <title>{title}</title>
<meta name="description" content={description}> <meta name="description" content={description} />
<link rel="preconnect" href="https://fonts.gstatic.com"> <link rel="preconnect" href="https://fonts.gstatic.com" />
<link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href={Astro.resolve('../styles/global.css')} /> <link rel="stylesheet" href={Astro.resolve('../styles/global.css')} />
<!-- Sitemap --> <!-- Sitemap -->
<link rel="sitemap" href="/sitemap.xml"> <link rel="sitemap" href="/sitemap.xml" />
<!-- RSS --> <!-- RSS -->
<link rel="alternate" type="application/rss+xml" href="/feed/posts.xml"> <link rel="alternate" type="application/rss+xml" href="/feed/posts.xml" />
<!-- Favicon --> <!-- Favicon -->
<link rel="icon" type="image/x-icon" href="/favicon.ico" /> <link rel="icon" type="image/x-icon" href="/favicon.ico" />
<!-- SEO --> <!-- SEO -->
<link rel="canonical" href={canonicalURL}> <link rel="canonical" href={canonicalURL} />
{next && <link rel="next" aria-label="Previous Page" href={new URL(next, canonicalURL).href}>} {next && <link rel="next" aria-label="Previous Page" href={new URL(next, canonicalURL).href}>}
{prev && <link rel="prev" aria-label="Next Page" href={new URL(prev, canonicalURL).href}>} {prev && <link rel="prev" aria-label="Next Page" href={new URL(prev, canonicalURL).href}>}
<!-- OpenGraph --> <!-- OpenGraph -->
<meta property="og:title" content={title}> <meta property="og:title" content={title} />
<meta property="og:description" content={description}> <meta property="og:description" content={description} />
{image && (<meta property="og:image" content={new URL(image, canonicalURL)}>)} {image && (<meta property="og:image" content={new URL(image, canonicalURL)}>)}
<!-- Twitter --> <!-- Twitter -->
<meta name="twitter:card" content={image ? 'summary_large_image' : 'summary'}> <meta name="twitter:card" content={image ? 'summary_large_image' : 'summary'} />
<meta name="twitter:site" content="@astro"> <meta name="twitter:site" content="@astro" />
<meta name="twitter:title" content={title}> <meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description}> <meta name="twitter:description" content={description} />
{image && (<meta name="twitter:image" content={image}>)} {image && (<meta name="twitter:image" content={image}>)}

View file

@ -1,63 +1,63 @@
--- ---
export interface Props { export interface Props {
title: string; title: string;
} }
const { title } = Astro.props; const { title } = Astro.props;
--- ---
<style lang="scss">
.header {
text-align: center;
@media (min-width: 600px) {
display: flex;
align-items: center;
padding: 2rem;
}
}
.title {
margin: 0;
font-size: 1.2em;
letter-spacing: -0.03em;
font-weight: 400;
margin-right: 1em;
}
.nav {
text-align: center;
@media (min-width: 600px) {
display: flex;
}
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
margin: 0;
}
a {
display: block;
font-size: 1.2em;
letter-spacing: -0.02em;
margin-left: 0.75em;
margin-right: 0.75em;
}
</style>
<nav class="header"> <nav class="header">
<h1 class="title">Dons Blog</h1> <h1 class="title">Dons Blog</h1>
<ul class="nav"> <ul class="nav">
<li><a href="/">Home</a></li> <li><a href="/">Home</a></li>
<li><a href="/posts">All Posts</a></li> <li><a href="/posts">All Posts</a></li>
<li><a href="/authors/don">Author: Don</a></li> <li><a href="/authors/don">Author: Don</a></li>
<li><a href="/authors/sancho">Author: Sancho</a></li> <li><a href="/authors/sancho">Author: Sancho</a></li>
<li><a href="/about">About</a></li> <li><a href="/about">About</a></li>
</ul> </ul>
</nav> </nav>
<style lang="scss">
.header {
text-align: center;
@media (min-width: 600px) {
display: flex;
align-items: center;
padding: 2rem;
}
}
.title {
margin: 0;
font-size: 1.2em;
letter-spacing: -0.03em;
font-weight: 400;
margin-right: 1em;
}
.nav {
text-align: center;
@media (min-width: 600px) {
display: flex;
}
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
margin: 0;
}
a {
display: block;
font-size: 1.2em;
letter-spacing: -0.02em;
margin-left: 0.75em;
margin-right: 0.75em;
}
</style>

View file

@ -1,44 +1,44 @@
--- ---
export interface Props { export interface Props {
prevUrl: string; prevUrl: string;
nextUrl: string; nextUrl: string;
} }
const { prevUrl, nextUrl } = Astro.props; const { prevUrl, nextUrl } = Astro.props;
--- ---
<style lang="scss">
.nav {
display: flex;
margin-right: auto;
margin-left: auto;
padding-top: 4rem;
padding-bottom: 4rem;
}
.prev,
.next {
display: block;
text-transform: uppercase;
font-size: 0.8em;
&[href="#"] {
display: none;
}
}
.prev {
margin-right: auto;
}
.next {
margin-left: auto;
}
</style>
<div class="wrapper"> <div class="wrapper">
<nav class="nav"> <nav class="nav">
<a class="prev" href={prevUrl || '#'} aria-label="Previous Page">Prev</a> <a class="prev" href={prevUrl || '#'} aria-label="Previous Page">Prev</a>
<a class="next" href={nextUrl || '#'} aria-label="Next Page">Next</a> <a class="next" href={nextUrl || '#'} aria-label="Next Page">Next</a>
</nav> </nav>
</div> </div>
<style lang="scss">
.nav {
display: flex;
margin-right: auto;
margin-left: auto;
padding-top: 4rem;
padding-bottom: 4rem;
}
.prev,
.next {
display: block;
text-transform: uppercase;
font-size: 0.8em;
&[href='#'] {
display: none;
}
}
.prev {
margin-right: auto;
}
.next {
margin-left: auto;
}
</style>

View file

@ -1,66 +1,65 @@
--- ---
export interface Props { export interface Props {
post: any; post: any;
author: string; author: string;
} }
const { post, author } = Astro.props; const { post, author } = Astro.props;
function formatDate(date) { function formatDate(date) {
return new Date(date).toUTCString().replace(/(\d\d\d\d) .*/, '$1'); // remove everything after YYYY return new Date(date).toUTCString().replace(/(\d\d\d\d) .*/, '$1'); // remove everything after YYYY
} }
--- ---
<style lang="scss">
.post {
padding-top: 6rem;
padding-bottom: 6rem;
border-bottom: 1px solid rgba(black, 0.25);
text-align: center;
}
.author {
text-transform: uppercase;
}
.date {
font-style: italic;
}
.description {
font-size: 1.25em;
}
.link {
text-transform: uppercase;
font-size: 0.8em;
margin-left: 1em;
}
h2 {
font-weight: 700;
font-size: 2.75em;
line-height: 1;
letter-spacing: -0.04em;
margin-top: 0;
margin-bottom: 0;
}
time {
display: block;
margin-top: 0.25rem;
margin-bottom: 0.5em;
}
</style>
<article class="post"> <article class="post">
<div class="data">
<div class="data"> <h2>{post.title}</h2>
<h2>{post.title}</h2> <a class="author" href={`/authors/${post.author}`}>{author.name}</a>
<a class="author" href={`/authors/${post.author}`}>{author.name}</a> <time class="date" datetime={post.date}>{formatDate(post.date)}</time>
<time class="date" datetime={post.date}>{formatDate(post.date)}</time> <p class="description">
<p class="description"> {post.description}
{post.description} <a class="link" href={post.url} aria-label={`Read ${post.title}`}>Read</a>
<a class="link" href={post.url} aria-label={`Read ${post.title}`}>Read</a> </p>
</p> </div>
</div>
</article> </article>
<style lang="scss">
.post {
padding-top: 6rem;
padding-bottom: 6rem;
border-bottom: 1px solid rgba(black, 0.25);
text-align: center;
}
.author {
text-transform: uppercase;
}
.date {
font-style: italic;
}
.description {
font-size: 1.25em;
}
.link {
text-transform: uppercase;
font-size: 0.8em;
margin-left: 1em;
}
h2 {
font-weight: 700;
font-size: 2.75em;
line-height: 1;
letter-spacing: -0.04em;
margin-top: 0;
margin-bottom: 0;
}
time {
display: block;
margin-top: 0.25rem;
margin-bottom: 0.5em;
}
</style>

View file

@ -7,73 +7,72 @@ const { content } = Astro.props;
let canonicalURL = Astro.request.canonicalURL; let canonicalURL = Astro.request.canonicalURL;
--- ---
<html lang={ content.lang || 'en' }> <html lang={content.lang || 'en'}>
<head> <head>
<title>{content.title}</title> <title>{content.title}</title>
<MainHead title={content.title} description={content.description} image={content.image} canonicalURL={canonicalURL} /> <MainHead title={content.title} description={content.description} image={content.image} {canonicalURL} />
<style lang="scss"> <style lang="scss">
.title { .title {
margin-top: 4rem; margin-top: 4rem;
margin-bottom: 4rem; margin-bottom: 4rem;
font-size: 3em; font-size: 3em;
letter-spacing: -0.04em; letter-spacing: -0.04em;
text-align: center; text-align: center;
} }
.description { .description {
margin-bottom: 4rem; margin-bottom: 4rem;
font-size: 1.4em; font-size: 1.4em;
font-weight: 400; font-weight: 400;
text-align: justify; text-align: justify;
text-transform: uppercase; text-transform: uppercase;
} }
.img { .img {
display: block; display: block;
width: 100%; width: 100%;
height: auto; height: auto;
} }
.article { .article {
margin-top: 4rem; margin-top: 4rem;
margin-bottom: 6rem; margin-bottom: 6rem;
:global(p) { :global(p) {
font-size: 1.3em; font-size: 1.3em;
line-height: 2; line-height: 2;
margin-top: 2em; margin-top: 2em;
margin-bottom: 2em; margin-bottom: 2em;
} }
} }
.posts { .posts {
text-transform: uppercase; text-transform: uppercase;
} }
.footer { .footer {
margin-top: 6rem; margin-top: 6rem;
padding-bottom: 6rem; padding-bottom: 6rem;
text-align: center; text-align: center;
} }
</style> </style>
</head> </head>
<body> <body>
<Nav /> <Nav />
<main class="wrapper"> <main class="wrapper">
<h2 class="title">{content.title}</h2> <h2 class="title">{content.title}</h2>
<p class="description">{content.description}</p> <p class="description">{content.description}</p>
<img class="img" src={content.image} alt=""> <img class="img" src={content.image} alt="" />
<article class="article"> <article class="article">
<slot /> <slot />
</article> </article>
<footer class="footer"> <footer class="footer">
<a class="posts" href="/posts">All Posts</a> <a class="posts" href="/posts">All Posts</a>
</footer> </footer>
</main> </main>
<footer> <footer></footer>
</footer> </body>
</body>
</html> </html>

View file

@ -2,65 +2,69 @@
import MainHead from '../components/MainHead.astro'; import MainHead from '../components/MainHead.astro';
import Nav from '../components/Nav.astro'; import Nav from '../components/Nav.astro';
let title = "About"; let title = 'About';
let description = "About page of an example blog on Astro"; let description = 'About page of an example blog on Astro';
let canonicalURL = Astro.request.canonicalURL; let canonicalURL = Astro.request.canonicalURL;
--- ---
<html lang="en"> <html lang="en">
<head> <head>
<MainHead <MainHead {title} {description} {canonicalURL} />
title={title} <style lang="scss">
description={description} .text {
canonicalURL={canonicalURL} padding-bottom: 6rem;
/>
<style lang="scss">
.text { p {
padding-bottom: 6rem; font-size: 1.2em;
line-height: 2;
margin-top: 2em;
margin-bottom: 2em;
}
}
p { .hero {
font-size: 1.2em; display: block;
line-height: 2; height: 16rem;
margin-top: 2em; overflow: hidden;
margin-bottom: 2em; margin: 4rem 0;
}
}
.hero { &-img {
display: block; width: 100%;
height: 16rem; height: 100%;
overflow: hidden; object-fit: cover;
margin: 4rem 0; }
}
&-img { .title {
width: 100%; font-size: 3em;
height: 100%; letter-spacing: -0.04em;
object-fit: cover; margin-top: 2rem;
} margin-bottom: 0;
} text-align: center;
}
</style>
</head>
<body>
<Nav {title} />
.title { <main class="wrapper">
font-size: 3em; <h2 class="title">{title}</h2>
letter-spacing: -0.04em; <div class="hero">
margin-top: 2rem; <img class="hero-img" src="/images/chapter-01.jpg" alt="" />
margin-bottom: 0; </div>
text-align: center; <div class="text">
} <p>
</style> The book cover and spine above and the images which follow were not part of the original Ormsby translation—they are taken from the 1880 edition of J. W. Clark,
</head> illustrated by Gustave Doré. Clark in his edition states that, “The English text of Don Quixote adopted in this edition is that of Jarvis, with occasional corrections
<body> from Motteaux.”
<Nav title={title} /> </p>
<p>
<main class="wrapper"> See in the introduction below John Ormsbys critique of both the Jarvis and Motteaux translations. It has been elected in the present Project Gutenberg edition to attach
<h2 class="title">{title}</h2> the famous engravings of Gustave Doré to the Ormsby translation instead of the Jarvis/Motteaux. The detail of many of the Doré engravings can be fully appreciated only by
<div class="hero"> utilizing the “Full Size” button to expand them to their original dimensions. Ormsby in his Preface has criticized the fanciful nature of Dorés illustrations; others
<img class="hero-img" src="/images/chapter-01.jpg" alt=""> feel these woodcuts and steel engravings well match Quixotes dreams.
</div> </p>
<div class="text"> </div>
<p>The book cover and spine above and the images which follow were not part of the original Ormsby translation—they are taken from the 1880 edition of J. W. Clark, illustrated by Gustave Doré. Clark in his edition states that, “The English text of Don Quixote adopted in this edition is that of Jarvis, with occasional corrections from Motteaux.”</p> </main>
<p>See in the introduction below John Ormsbys critique of both the Jarvis and Motteaux translations. It has been elected in the present Project Gutenberg edition to attach the famous engravings of Gustave Doré to the Ormsby translation instead of the Jarvis/Motteaux. The detail of many of the Doré engravings can be fully appreciated only by utilizing the “Full Size” button to expand them to their original dimensions. Ormsby in his Preface has criticized the fanciful nature of Dorés illustrations; others feel these woodcuts and steel engravings well match Quixotes dreams.</p> </body>
</div>
</main>
</body>
</html> </html>

View file

@ -1,5 +1,4 @@
--- ---
import MainHead from '../../components/MainHead.astro'; import MainHead from '../../components/MainHead.astro';
import Nav from '../../components/Nav.astro'; import Nav from '../../components/Nav.astro';
import PostPreview from '../../components/PostPreview.astro'; import PostPreview from '../../components/PostPreview.astro';
@ -7,16 +6,16 @@ import Pagination from '../../components/Pagination.astro';
import authorData from '../../data/authors.json'; import authorData from '../../data/authors.json';
export function getStaticPaths() { export function getStaticPaths() {
const allPosts = Astro.fetchContent<MarkdownFrontmatter>('../post/*.md'); const allPosts = Astro.fetchContent<MarkdownFrontmatter>('../post/*.md');
let allAuthorsUnique = [...new Set(allPosts.map(p => p.author))]; let allAuthorsUnique = [...new Set(allPosts.map((p) => p.author))];
return allAuthorsUnique.map(author => ({params: {author}, props: {allPosts}})); return allAuthorsUnique.map((author) => ({ params: { author }, props: { allPosts } }));
} }
interface MarkdownFrontmatter { interface MarkdownFrontmatter {
date: number; date: number;
description: string; description: string;
title: string; title: string;
author: string; author: string;
} }
const { allPosts } = Astro.props; const { allPosts } = Astro.props;
@ -25,65 +24,58 @@ const title = 'Dons Blog';
const description = 'An example blog on Astro'; const description = 'An example blog on Astro';
/** filter posts by author, sort by date */ /** filter posts by author, sort by date */
const posts = allPosts const posts = allPosts.filter((post) => post.author === params.author).sort((a, b) => new Date(b.date).valueOf() - new Date(a.date).valueOf());
.filter((post) => post.author === params.author)
.sort((a, b) => new Date(b.date).valueOf() - new Date(a.date).valueOf());
const author = authorData[posts[0].author]; const author = authorData[posts[0].author];
--- ---
<html lang="en"> <html lang="en">
<head> <head>
<title>{title}</title> <title>{title}</title>
<MainHead <MainHead {title} {description} image={posts[0].image} canonicalURL={canonicalURL.toString()} />
title={title}
description={description}
image={posts[0].image}
canonicalURL={canonicalURL.toString()}
/>
<style lang="scss"> <style lang="scss">
.title { .title {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 3em; font-size: 3em;
letter-spacing: -0.04em; letter-spacing: -0.04em;
margin-top: 2rem; margin-top: 2rem;
margin-bottom: 0; margin-bottom: 0;
} }
.avatar { .avatar {
width: 1em; width: 1em;
height: 1em; height: 1em;
margin-right: 0.5em; margin-right: 0.5em;
border-radius: 50%; border-radius: 50%;
overflow:hidden; overflow: hidden;
&-img { &-img {
display: block; display: block;
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: cover; object-fit: cover;
} }
} }
.count { .count {
font-size: 1em; font-size: 1em;
display: block; display: block;
text-align: center; text-align: center;
} }
</style> </style>
</head> </head>
<body> <body>
<Nav title={title} /> <Nav {title} />
<main class="wrapper"> <main class="wrapper">
<h2 class="title"> <h2 class="title">
<div class="avatar"><img class="avatar-img" src={author.image} alt="" /></div> <div class="avatar"><img class="avatar-img" src={author.image} alt="" /></div>
{author.name} {author.name}
</h2> </h2>
{posts.map((post) => <PostPreview post={post} author={author} />)} {posts.map((post) => <PostPreview post={post} author={author} />)}
</main> </main>
</body> </body>
</html> </html>

View file

@ -7,9 +7,9 @@ import Pagination from '../components/Pagination.astro';
import authorData from '../data/authors.json'; import authorData from '../data/authors.json';
interface MarkdownFrontmatter { interface MarkdownFrontmatter {
date: number; date: number;
image: string; image: string;
author: string; author: string;
} }
// Component Script: // Component Script:
@ -28,26 +28,22 @@ let firstPage = allPosts.slice(0, 2);
// Full Astro Component Syntax: // Full Astro Component Syntax:
// https://docs.astro.build/core-concepts/astro-components/ // https://docs.astro.build/core-concepts/astro-components/
--- ---
<html lang="en"> <html lang="en">
<head> <head>
<title>{title}</title> <title>{title}</title>
<MainHead <MainHead {title} {description} image={allPosts[0].image} {canonicalURL} />
title={title} </head>
description={description}
image={allPosts[0].image}
canonicalURL={canonicalURL}
/>
</head>
<body> <body>
<Nav title={title} /> <Nav {title} />
<main class="wrapper"> <main class="wrapper">
{allPosts.map((post) => <PostPreview post={post} author={authorData[post.author]} />)} {allPosts.map((post) => <PostPreview post={post} author={authorData[post.author]} />)}
</main> </main>
<footer> <footer>
<Pagination prevUrl="/posts" nextUrl="/posts/2" /> <Pagination prevUrl="/posts" nextUrl="/posts/2" />
</footer> </footer>
</body> </body>
</html> </html>

View file

@ -5,26 +5,26 @@ import PostPreview from '../../components/PostPreview.astro';
import Pagination from '../../components/Pagination.astro'; import Pagination from '../../components/Pagination.astro';
import authorData from '../../data/authors.json'; import authorData from '../../data/authors.json';
export async function getStaticPaths({paginate, rss}) { export async function getStaticPaths({ paginate, rss }) {
const allPosts = Astro.fetchContent<MarkdownFrontmatter>('../post/*.md'); const allPosts = Astro.fetchContent<MarkdownFrontmatter>('../post/*.md');
const sortedPosts = allPosts.sort((a, b) => new Date(b.date).valueOf() - new Date(a.date).valueOf()); const sortedPosts = allPosts.sort((a, b) => new Date(b.date).valueOf() - new Date(a.date).valueOf());
// Generate an RSS feed from this collection of posts. // Generate an RSS feed from this collection of posts.
// NOTE: This is disabled by default, since it requires `buildOptions.site` to be set in your "astro.config.mjs" file. // NOTE: This is disabled by default, since it requires `buildOptions.site` to be set in your "astro.config.mjs" file.
// rss({ // rss({
// title: 'Dons Blog', // title: 'Dons Blog',
// description: 'An example blog on Astro', // description: 'An example blog on Astro',
// customData: `<language>en-us</language>`, // customData: `<language>en-us</language>`,
// items: sortedPosts.map(item => ({ // items: sortedPosts.map(item => ({
// title: item.title, // title: item.title,
// description: item.description, // description: item.description,
// link: item.url, // link: item.url,
// pubDate: item.date, // pubDate: item.date,
// })), // })),
// }); // });
// Return a paginated collection of paths for all posts // Return a paginated collection of paths for all posts
return paginate(sortedPosts, {pageSize: 1}); return paginate(sortedPosts, { pageSize: 1 });
} }
// page // page
@ -34,55 +34,47 @@ let canonicalURL = Astro.request.canonicalURL;
// collection // collection
interface MarkdownFrontmatter { interface MarkdownFrontmatter {
date: number; date: number;
description: string; description: string;
title: string; title: string;
} }
const { page } = Astro.props; const { page } = Astro.props;
--- ---
<html lang="en"> <html lang="en">
<head> <head>
<title>{title}</title> <title>{title}</title>
<MainHead <MainHead {title} {description} image={page.data[0].image} canonicalURL={canonicalURL.toString()} prev={page.url.prev} next={page.url.next} />
title={title}
description={description}
image={page.data[0].image}
canonicalURL={canonicalURL.toString()}
prev={page.url.prev}
next={page.url.next}
/>
<style lang="scss"> <style lang="scss">
.title { .title {
font-size: 3em; font-size: 3em;
letter-spacing: -0.04em; letter-spacing: -0.04em;
margin-top: 2rem; margin-top: 2rem;
margin-bottom: 0; margin-bottom: 0;
text-align: center; text-align: center;
} }
.count { .count {
font-size: 1em; font-size: 1em;
display: block; display: block;
text-align: center; text-align: center;
} }
</style> </style>
</head> </head>
<body> <body>
<Nav title={title} /> <Nav {title} />
<main class="wrapper"> <main class="wrapper">
<h2 class="title">All Posts</h2> <h2 class="title">All Posts</h2>
<small class="count">{page.start + 1}{page.end + 1} of {page.total}</small> <small class="count">{page.start + 1}{page.end + 1} of {page.total}</small>
{page.data.map((post) => <PostPreview post={post} author={authorData[post.author]} />)} {page.data.map((post) => <PostPreview post={post} author={authorData[post.author]} />)}
</main> </main>
<footer> <footer>
<Pagination prevUrl={page.url.prev} nextUrl={page.url.next} /> <Pagination prevUrl={page.url.prev} nextUrl={page.url.next} />
</footer> </footer>
</body> </body>
</html> </html>

View file

@ -1,25 +1,25 @@
body { body {
font-family: 'Spectral', serif; font-family: 'Spectral', serif;
line-height: 1.4; line-height: 1.4;
} }
p { p {
line-height: 2; line-height: 2;
} }
a { a {
color: crimson; color: crimson;
} }
img { img {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
} }
.wrapper { .wrapper {
max-width: 60rem; max-width: 60rem;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
padding-left: 2rem; padding-left: 2rem;
padding-right: 2rem; padding-right: 2rem;
} }

View file

@ -8,6 +8,6 @@
// @ts-check // @ts-check
export default /** @type {import('astro').AstroUserConfig} */ ({ export default /** @type {import('astro').AstroUserConfig} */ ({
// Enable the Preact renderer to support Preact JSX components. // Enable the Preact renderer to support Preact JSX components.
renderers: ['@astrojs/renderer-preact'], renderers: ['@astrojs/renderer-preact'],
}); });

View file

@ -1,16 +1,18 @@
--- ---
export interface Props { export interface Props {
name: string; name: string;
href: string; href: string;
} }
const { name, href } = Astro.props; const { name, href } = Astro.props;
--- ---
<style>
.author {
margin-bottom: 0.75rem;
}
</style>
<div class="author"> <div class="author">
<p><a href={href}>{name}</a></p> <p><a {href}>{name}</a></p>
</div> </div>
<style>
.author {
margin-bottom: 0.75rem;
}
</style>

View file

@ -1,8 +1,8 @@
--- ---
export interface Props { export interface Props {
title: string; title: string;
description: string; description: string;
permalink: string; permalink: string;
} }
const { title, description, permalink } = Astro.props; const { title, description, permalink } = Astro.props;
--- ---
@ -12,7 +12,6 @@ const { title, description, permalink } = Astro.props;
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" /> <link rel="icon" type="image/x-icon" href="/favicon.ico" />
<!-- Primary Meta Tags --> <!-- Primary Meta Tags -->
<title>{title}</title> <title>{title}</title>
<meta name="title" content={title} /> <meta name="title" content={title} />
@ -34,4 +33,4 @@ const { title, description, permalink } = Astro.props;
<!-- Fonts --> <!-- Fonts -->
<link rel="preconnect" href="https://fonts.gstatic.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&family=IBM+Plex+Sans:wght@400;700&display=swap"> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&family=IBM+Plex+Sans:wght@400;700&display=swap" />

View file

@ -1,90 +1,90 @@
<style>
header {
padding-top: 1rem;
padding-bottom: 1rem;
height: 5rem;
}
article {
display: flex;
align-items: center;
justify-content: space-between;
}
.header-subitem {
display: flex;
flex-grow: 0;
gap: 0.5em;
align-items: center;
justify-content: center;
color: var(--theme-text-lighter);
font-size: initial;
padding: 0.5rem;
}
.header-subitem:hover {
color: var(--theme-accent);
}
.header-subitem svg {
width: 1.5rem;
height: 1.5rem;
}
@media (max-width: 32em) {
.header-subitem {
display: none;
}
}
h1 {
margin: 0;
font-size: 1.5rem;
max-width: 100%;
display: flex;
flex-grow: 1;
}
.logo {
transform: translateY(0.25rem);
}
svg {
width: 2.5rem;
height: 2.5rem;
}
h1 a {
text-decoration: none;
display: inline-flex;
}
</style>
<header class="wrapper"> <header class="wrapper">
<article> <article>
<h1> <h1>
<a href="/"> <a href="/">
<svg class="logo" width="32" height="32" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg class="logo" width="32" height="32" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg">
<style> <style>
#flame { #flame {
fill: #ff5d01; fill: #ff5d01;
} }
#a { #a {
fill: #000014; fill: #000014;
} }
</style> </style>
<title>Logo</title> <title>Logo</title>
<path <path
id="a" id="a"
fill-rule="evenodd" fill-rule="evenodd"
clip-rule="evenodd" clip-rule="evenodd"
d="M163.008 18.929c1.944 2.413 2.935 5.67 4.917 12.181l43.309 142.27a180.277 180.277 0 00-51.778-17.53l-28.198-95.29a3.67 3.67 0 00-7.042.01l-27.857 95.232a180.225 180.225 0 00-52.01 17.557l43.52-142.281c1.99-6.502 2.983-9.752 4.927-12.16a15.999 15.999 0 016.484-4.798c2.872-1.154 6.271-1.154 13.07-1.154h31.085c6.807 0 10.211 0 13.086 1.157a16.004 16.004 0 016.487 4.806z" d="M163.008 18.929c1.944 2.413 2.935 5.67 4.917 12.181l43.309 142.27a180.277 180.277 0 00-51.778-17.53l-28.198-95.29a3.67 3.67 0 00-7.042.01l-27.857 95.232a180.225 180.225 0 00-52.01 17.557l43.52-142.281c1.99-6.502 2.983-9.752 4.927-12.16a15.999 15.999 0 016.484-4.798c2.872-1.154 6.271-1.154 13.07-1.154h31.085c6.807 0 10.211 0 13.086 1.157a16.004 16.004 0 016.487 4.806z"
/> ></path>
<path <path
id="flame" id="flame"
fill-rule="evenodd" fill-rule="evenodd"
clip-rule="evenodd" clip-rule="evenodd"
d="M168.19 180.151c-7.139 6.105-21.39 10.268-37.804 10.268-20.147 0-37.033-6.272-41.513-14.707-1.602 4.835-1.961 10.367-1.961 13.902 0 0-1.056 17.355 11.015 29.426 0-6.268 5.081-11.349 11.349-11.349 10.743 0 10.731 9.373 10.721 16.977v.679c0 11.542 7.054 21.436 17.086 25.606a23.27 23.27 0 01-2.339-10.2c0-11.008 6.463-15.107 13.974-19.87 5.976-3.79 12.616-8.001 17.192-16.449a31.024 31.024 0 003.743-14.82c0-3.299-.513-6.479-1.463-9.463z" d="M168.19 180.151c-7.139 6.105-21.39 10.268-37.804 10.268-20.147 0-37.033-6.272-41.513-14.707-1.602 4.835-1.961 10.367-1.961 13.902 0 0-1.056 17.355 11.015 29.426 0-6.268 5.081-11.349 11.349-11.349 10.743 0 10.731 9.373 10.721 16.977v.679c0 11.542 7.054 21.436 17.086 25.606a23.27 23.27 0 01-2.339-10.2c0-11.008 6.463-15.107 13.974-19.87 5.976-3.79 12.616-8.001 17.192-16.449a31.024 31.024 0 003.743-14.82c0-3.299-.513-6.479-1.463-9.463z"
/> ></path>
</svg> </svg>
<span>My Blog</span> <span>My Blog</span>
</a> </a>
</h1> </h1>
</article> </article>
</header> </header>
<style>
header {
padding-top: 1rem;
padding-bottom: 1rem;
height: 5rem;
}
article {
display: flex;
align-items: center;
justify-content: space-between;
}
.header-subitem {
display: flex;
flex-grow: 0;
gap: 0.5em;
align-items: center;
justify-content: center;
color: var(--theme-text-lighter);
font-size: initial;
padding: 0.5rem;
}
.header-subitem:hover {
color: var(--theme-accent);
}
.header-subitem svg {
width: 1.5rem;
height: 1.5rem;
}
@media (max-width: 32em) {
.header-subitem {
display: none;
}
}
h1 {
margin: 0;
font-size: 1.5rem;
max-width: 100%;
display: flex;
flex-grow: 1;
}
.logo {
transform: translateY(0.25rem);
}
svg {
width: 2.5rem;
height: 2.5rem;
}
h1 a {
text-decoration: none;
display: inline-flex;
}
</style>

View file

@ -2,87 +2,87 @@
import Author from './Author.astro'; import Author from './Author.astro';
export interface Props { export interface Props {
title: string; title: string;
author: string; author: string;
publishDate: string; publishDate: string;
heroImage: string; heroImage: string;
alt: string; alt: string;
} }
const { title, author, publishDate, heroImage, alt } = Astro.props; const { title, author, publishDate, heroImage, alt } = Astro.props;
--- ---
<div class="layout"> <div class="layout">
<article class="content"> <article class="content">
<div> <div>
<header> <header>
{heroImage && <img width="720" height="420" class="hero-image" loading="lazy" src={heroImage} alt={alt} />} {heroImage && <img width="720" height="420" class="hero-image" loading="lazy" src={heroImage} alt={alt} />}
<p class="publish-date">{publishDate}</p> <p class="publish-date">{publishDate}</p>
<h1 class="title">{title}</h1> <h1 class="title">{title}</h1>
<Author name="@FredKSchott" href="https://twitter.com/FredKSchott" /> <Author name="@FredKSchott" href="https://twitter.com/FredKSchott" />
</header> </header>
<main> <main>
<slot /> <slot />
</main> </main>
</div> </div>
</article> </article>
</div> </div>
<style> <style>
.hero-image { .hero-image {
width: 100vw; width: 100vw;
object-fit: cover; object-fit: cover;
object-position: center; object-position: center;
margin-top: 2rem; margin-top: 2rem;
margin-bottom: 4rem; margin-bottom: 4rem;
max-width: 1280px; max-width: 1280px;
} }
@media (max-width: 50em) { @media (max-width: 50em) {
.hero-image { .hero-image {
height: 260px; height: 260px;
margin-top: 0; margin-top: 0;
margin-bottom: 2rem; margin-bottom: 2rem;
} }
} }
.content { .content {
margin-bottom: 8rem; margin-bottom: 8rem;
} }
.content :global(main > * + *) { .content :global(main > * + *) {
margin-top: 1rem; margin-top: 1rem;
} }
.content :global(h2) { .content :global(h2) {
margin-top: 4rem; margin-top: 4rem;
} }
header { header {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
text-align: center; text-align: center;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding-bottom: 2rem; padding-bottom: 2rem;
margin-bottom: 2rem; margin-bottom: 2rem;
border-bottom: 4px solid var(--theme-divider); border-bottom: 4px solid var(--theme-divider);
} }
.title, .title,
.author, .author,
.publish-date { .publish-date {
margin: 0; margin: 0;
} }
.publish-date, .publish-date,
.author { .author {
color: var(--theme-text-lighter); color: var(--theme-text-lighter);
} }
.title { .title {
font-size: 2.25rem; font-size: 2.25rem;
font-weight: 700; font-weight: 700;
} }
</style> </style>

View file

@ -1,54 +1,55 @@
--- ---
export interface Props { export interface Props {
post: any; post: any;
} }
const { post } = Astro.props; const { post } = Astro.props;
--- ---
<article class="post-preview"> <article class="post-preview">
<header> <header>
<p class="publish-date">{post.publishDate}</p> <p class="publish-date">{post.publishDate}</p>
<a href={post.url}><h1 class="title">{post.title}</h1></a> <a href={post.url}><h1 class="title">{post.title}</h1></a>
</header> </header>
<p>{post.description}</p> <p>{post.description}</p>
<a href={post.url}>Read more</a> <a href={post.url}>Read more</a>
</article> </article>
<style> <style>
.content :global(main > * + *) { .content :global(main > * + *) {
margin-top: 1rem; margin-top: 1rem;
} }
.post-preview { .post-preview {
padding-bottom: 2rem; padding-bottom: 2rem;
margin-bottom: 2rem; margin-bottom: 2rem;
border-bottom: 4px solid var(--theme-divider); border-bottom: 4px solid var(--theme-divider);
} }
header { header {
align-items: flex-start; align-items: flex-start;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
padding-bottom: 2rem; padding-bottom: 2rem;
text-align: left; text-align: left;
} }
.title, .title,
.author, .author,
.publish-date { .publish-date {
margin: 0; margin: 0;
} }
.publish-date, .publish-date,
.author { .author {
font-size: 1.25rem; font-size: 1.25rem;
color: var(--theme-text-lighter); color: var(--theme-text-lighter);
} }
.title { .title {
font-size: 2.25rem; font-size: 2.25rem;
font-weight: 700; font-weight: 700;
color: var(--theme-text); color: var(--theme-text);
} }
</style> </style>

View file

@ -1,9 +1,9 @@
<h1> <h1>
<slot/> <slot />
</h1> </h1>
<style> <style>
h1 { h1 {
color: red; color: red;
} }
</style> </style>

View file

@ -1,56 +1,86 @@
<svg class="logo" width="158" height="170" viewBox="0 0 158 170" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg class="logo" width="158" height="170" viewBox="0 0 158 170" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M96.5039 9.46441C97.4758 10.671 97.9714 12.2991 98.9626 15.5553L120.617 86.6902C112.611 82.5368 103.907 79.5413 94.7281 77.9252L80.6289 30.2798C80.3982 29.5002 79.6822 28.9654 78.8692 28.9654C78.0541 28.9654 77.3367 29.503 77.1079 30.2853L63.1795 77.9011C53.9579 79.51 45.2146 82.5109 37.1741 86.6793L58.9347 15.5388C59.929 12.2882 60.4262 10.6629 61.3981 9.45854C62.2562 8.39532 63.3723 7.56959 64.64 7.06003C66.076 6.48285 67.7756 6.48285 71.1749 6.48285H86.7174C90.1211 6.48285 91.823 6.48285 93.2603 7.06124C94.5291 7.575 95.6459 8.39925 96.5039 9.46441Z" fill="white" /> <path
<path fill-rule="evenodd" clip-rule="evenodd" d="M99.0951 90.0755C95.5253 93.1279 88.4002 95.2097 80.1929 95.2097C70.1197 95.2097 61.6767 92.0737 59.4363 87.8561C58.6354 90.2733 58.4558 93.0397 58.4558 94.8069C58.4558 94.8069 57.9281 103.485 63.9636 109.52C63.9636 106.386 66.5042 103.846 69.6381 103.846C75.0097 103.846 75.0036 108.532 74.9987 112.334C74.9986 112.448 74.9984 112.561 74.9984 112.673C74.9984 118.444 78.5255 123.391 83.5416 125.477C82.7924 123.936 82.3721 122.205 82.3721 120.377C82.3721 114.873 85.6034 112.823 89.3588 110.441C92.3469 108.546 95.6668 106.441 97.9548 102.217C99.1486 100.013 99.8265 97.4893 99.8265 94.8069C99.8265 93.1573 99.5702 91.5676 99.0951 90.0755Z" fill="#FF5D01" /> fill-rule="evenodd"
<path fill-rule="evenodd" clip-rule="evenodd" d="M99.0951 90.0755C95.5253 93.1279 88.4002 95.2097 80.1929 95.2097C70.1197 95.2097 61.6767 92.0737 59.4363 87.8561C58.6354 90.2733 58.4558 93.0397 58.4558 94.8069C58.4558 94.8069 57.9281 103.485 63.9636 109.52C63.9636 106.386 66.5042 103.846 69.6381 103.846C75.0097 103.846 75.0036 108.532 74.9987 112.334C74.9986 112.448 74.9984 112.561 74.9984 112.673C74.9984 118.444 78.5255 123.391 83.5416 125.477C82.7924 123.936 82.3721 122.205 82.3721 120.377C82.3721 114.873 85.6034 112.823 89.3588 110.441C92.3469 108.546 95.6668 106.441 97.9548 102.217C99.1486 100.013 99.8265 97.4893 99.8265 94.8069C99.8265 93.1573 99.5702 91.5676 99.0951 90.0755Z" fill="url(#paint1_linear)" /> clip-rule="evenodd"
<path d="M11.9957 169.024C20.0117 169.024 24.8597 167.104 27.6917 163.12C27.6917 164.896 27.7877 166.576 28.0277 168.112H32.7797C32.3477 165.616 32.2517 163.984 32.2517 159.472V153.328C32.2517 146.704 27.1157 143.2 17.3237 143.2C7.8677 143.2 1.7237 146.848 0.955701 152.128H5.9957C6.7637 148.576 10.7477 146.704 17.3237 146.704C23.8037 146.704 27.6437 148.96 27.6437 152.8V153.28L12.6677 154.144C6.5717 154.48 4.3157 155.344 2.5877 156.592C0.955701 157.792 0.0437012 159.664 0.0437012 161.824C0.0437012 166.384 4.7477 169.024 11.9957 169.024ZM13.5317 165.616C7.9637 165.616 4.8917 164.32 4.8917 161.728C4.8917 158.944 6.8117 157.696 13.5797 157.264L27.6437 156.4V157.504C27.6437 162.544 21.7397 165.616 13.5317 165.616Z" fill="white" /> d="M96.5039 9.46441C97.4758 10.671 97.9714 12.2991 98.9626 15.5553L120.617 86.6902C112.611 82.5368 103.907 79.5413 94.7281 77.9252L80.6289 30.2798C80.3982 29.5002 79.6822 28.9654 78.8692 28.9654C78.0541 28.9654 77.3367 29.503 77.1079 30.2853L63.1795 77.9011C53.9579 79.51 45.2146 82.5109 37.1741 86.6793L58.9347 15.5388C59.929 12.2882 60.4262 10.6629 61.3981 9.45854C62.2562 8.39532 63.3723 7.56959 64.64 7.06003C66.076 6.48285 67.7756 6.48285 71.1749 6.48285H86.7174C90.1211 6.48285 91.823 6.48285 93.2603 7.06124C94.5291 7.575 95.6459 8.39925 96.5039 9.46441Z"
<path d="M55.9352 169.024C65.8712 169.024 69.8552 165.76 69.8552 161.008C69.8552 157.072 67.4072 155.056 61.1672 154.528L49.5032 153.616C46.3352 153.376 44.5592 152.464 44.5592 150.496C44.5592 148 47.2952 146.704 53.1992 146.704C59.9192 146.704 63.4232 148.048 65.7272 151.024L69.6152 149.152C67.2152 145.408 61.8872 143.2 53.6312 143.2C45.1352 143.2 40.0472 146.032 40.0472 150.688C40.0472 154.864 43.0712 156.88 48.7832 157.36L60.3512 158.272C64.1432 158.56 65.2952 159.328 65.2952 161.296C65.2952 164.128 62.3672 165.472 56.5592 165.472C49.5032 165.472 45.0392 163.552 42.8792 160.048L39.0872 162.112C42.0152 166.528 47.1512 169.024 55.9352 169.024Z" fill="white" /> fill="white"
<path d="M79.6765 147.712V159.28C79.6765 164.032 81.3085 168.784 90.1885 168.784C92.4445 168.784 95.1805 168.352 96.3805 167.824V163.936C94.7005 164.32 92.6845 164.608 90.7165 164.608C86.5405 164.608 84.2845 162.976 84.2845 158.848V147.712H96.2845V144.112H84.2845V136L79.6765 137.872V144.112H72.1404V147.712H79.6765Z" fill="white" /> />
<path d="M107.728 144.112H103.504V168.112H108.064V159.136C108.064 155.68 108.736 152.752 110.656 150.736C112.336 148.864 114.496 147.808 118.288 147.808C119.584 147.808 120.4 147.904 121.504 148.096V143.68C120.496 143.44 119.632 143.392 118.336 143.392C113.2 143.392 109.12 146.416 107.728 151.072V144.112Z" fill="white" /> <path
<path d="M140.724 169.024C150.948 169.024 157.956 163.84 157.956 156.112C157.956 148.384 150.948 143.2 140.724 143.2C130.5 143.2 123.492 148.384 123.492 156.112C123.492 163.84 130.5 169.024 140.724 169.024ZM140.724 165.232C133.188 165.232 128.34 161.68 128.34 156.112C128.34 150.544 133.188 146.992 140.724 146.992C148.212 146.992 153.108 150.544 153.108 156.112C153.108 161.68 148.212 165.232 140.724 165.232Z" fill="white" /> fill-rule="evenodd"
<defs> clip-rule="evenodd"
<linearGradient id="paint1_linear" x1="115.168" y1="65.245" x2="94.0326" y2="109.491" gradientUnits="userSpaceOnUse"> d="M99.0951 90.0755C95.5253 93.1279 88.4002 95.2097 80.1929 95.2097C70.1197 95.2097 61.6767 92.0737 59.4363 87.8561C58.6354 90.2733 58.4558 93.0397 58.4558 94.8069C58.4558 94.8069 57.9281 103.485 63.9636 109.52C63.9636 106.386 66.5042 103.846 69.6381 103.846C75.0097 103.846 75.0036 108.532 74.9987 112.334C74.9986 112.448 74.9984 112.561 74.9984 112.673C74.9984 118.444 78.5255 123.391 83.5416 125.477C82.7924 123.936 82.3721 122.205 82.3721 120.377C82.3721 114.873 85.6034 112.823 89.3588 110.441C92.3469 108.546 95.6668 106.441 97.9548 102.217C99.1486 100.013 99.8265 97.4893 99.8265 94.8069C99.8265 93.1573 99.5702 91.5676 99.0951 90.0755Z"
<stop stop-color="#FF1639" /> fill="#FF5D01"
<stop offset="1" stop-color="#FF1639" stop-opacity="0" /> />
</linearGradient> <path
</defs> fill-rule="evenodd"
clip-rule="evenodd"
d="M99.0951 90.0755C95.5253 93.1279 88.4002 95.2097 80.1929 95.2097C70.1197 95.2097 61.6767 92.0737 59.4363 87.8561C58.6354 90.2733 58.4558 93.0397 58.4558 94.8069C58.4558 94.8069 57.9281 103.485 63.9636 109.52C63.9636 106.386 66.5042 103.846 69.6381 103.846C75.0097 103.846 75.0036 108.532 74.9987 112.334C74.9986 112.448 74.9984 112.561 74.9984 112.673C74.9984 118.444 78.5255 123.391 83.5416 125.477C82.7924 123.936 82.3721 122.205 82.3721 120.377C82.3721 114.873 85.6034 112.823 89.3588 110.441C92.3469 108.546 95.6668 106.441 97.9548 102.217C99.1486 100.013 99.8265 97.4893 99.8265 94.8069C99.8265 93.1573 99.5702 91.5676 99.0951 90.0755Z"
fill="url(#paint1_linear)"
/>
<path
d="M11.9957 169.024C20.0117 169.024 24.8597 167.104 27.6917 163.12C27.6917 164.896 27.7877 166.576 28.0277 168.112H32.7797C32.3477 165.616 32.2517 163.984 32.2517 159.472V153.328C32.2517 146.704 27.1157 143.2 17.3237 143.2C7.8677 143.2 1.7237 146.848 0.955701 152.128H5.9957C6.7637 148.576 10.7477 146.704 17.3237 146.704C23.8037 146.704 27.6437 148.96 27.6437 152.8V153.28L12.6677 154.144C6.5717 154.48 4.3157 155.344 2.5877 156.592C0.955701 157.792 0.0437012 159.664 0.0437012 161.824C0.0437012 166.384 4.7477 169.024 11.9957 169.024ZM13.5317 165.616C7.9637 165.616 4.8917 164.32 4.8917 161.728C4.8917 158.944 6.8117 157.696 13.5797 157.264L27.6437 156.4V157.504C27.6437 162.544 21.7397 165.616 13.5317 165.616Z"
fill="white"
/>
<path
d="M55.9352 169.024C65.8712 169.024 69.8552 165.76 69.8552 161.008C69.8552 157.072 67.4072 155.056 61.1672 154.528L49.5032 153.616C46.3352 153.376 44.5592 152.464 44.5592 150.496C44.5592 148 47.2952 146.704 53.1992 146.704C59.9192 146.704 63.4232 148.048 65.7272 151.024L69.6152 149.152C67.2152 145.408 61.8872 143.2 53.6312 143.2C45.1352 143.2 40.0472 146.032 40.0472 150.688C40.0472 154.864 43.0712 156.88 48.7832 157.36L60.3512 158.272C64.1432 158.56 65.2952 159.328 65.2952 161.296C65.2952 164.128 62.3672 165.472 56.5592 165.472C49.5032 165.472 45.0392 163.552 42.8792 160.048L39.0872 162.112C42.0152 166.528 47.1512 169.024 55.9352 169.024Z"
fill="white"
/>
<path
d="M79.6765 147.712V159.28C79.6765 164.032 81.3085 168.784 90.1885 168.784C92.4445 168.784 95.1805 168.352 96.3805 167.824V163.936C94.7005 164.32 92.6845 164.608 90.7165 164.608C86.5405 164.608 84.2845 162.976 84.2845 158.848V147.712H96.2845V144.112H84.2845V136L79.6765 137.872V144.112H72.1404V147.712H79.6765Z"
fill="white"
/>
<path
d="M107.728 144.112H103.504V168.112H108.064V159.136C108.064 155.68 108.736 152.752 110.656 150.736C112.336 148.864 114.496 147.808 118.288 147.808C119.584 147.808 120.4 147.904 121.504 148.096V143.68C120.496 143.44 119.632 143.392 118.336 143.392C113.2 143.392 109.12 146.416 107.728 151.072V144.112Z"
fill="white"
/>
<path
d="M140.724 169.024C150.948 169.024 157.956 163.84 157.956 156.112C157.956 148.384 150.948 143.2 140.724 143.2C130.5 143.2 123.492 148.384 123.492 156.112C123.492 163.84 130.5 169.024 140.724 169.024ZM140.724 165.232C133.188 165.232 128.34 161.68 128.34 156.112C128.34 150.544 133.188 146.992 140.724 146.992C148.212 146.992 153.108 150.544 153.108 156.112C153.108 161.68 148.212 165.232 140.724 165.232Z"
fill="white"
/>
<defs>
<linearGradient id="paint1_linear" x1="115.168" y1="65.245" x2="94.0326" y2="109.491" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF1639" />
<stop offset="1" stop-color="#FF1639" stop-opacity="0" />
</linearGradient>
</defs>
</svg> </svg>
<style lang="scss"> <style lang="scss">
.logo { .logo {
margin: 2rem auto; margin: 2rem auto;
} }
.title { .title {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 1rem; font-size: 1rem;
} }
.title svg { .title svg {
margin-right: -100%; margin-right: -100%;
} }
.title svg text { .title svg text {
font-size: 16px; font-size: 16px;
font-family: var(--font-sans); font-family: var(--font-sans);
} }
.title svg text.span { .title svg text.span {
fill: white; fill: white;
font-size: 16.2px; font-size: 16.2px;
transform: translate(0, 18px); transform: translate(0, 18px);
} }
.title svg text.em { .title svg text.em {
fill: var(--color-green); fill: var(--color-green);
transform: translate(0, 36px); transform: translate(0, 36px);
} }
@media (min-width: 40em) { @media (min-width: 40em) {
.title svg { .title svg {
margin-right: 0; margin-right: 0;
margin-bottom: -40px; margin-bottom: -40px;
} }
.title svg text.span { .title svg text.span {
font-size: 16px; font-size: 16px;
} }
.title svg text.em { .title svg text.em {
transform: translate(190px, 18px); transform: translate(190px, 18px);
} }
} }
</style> </style>

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View file

@ -3,23 +3,22 @@ import BaseHead from '../components/BaseHead.astro';
import BlogHeader from '../components/BlogHeader.astro'; import BlogHeader from '../components/BlogHeader.astro';
import BlogPost from '../components/BlogPost.astro'; import BlogPost from '../components/BlogPost.astro';
const {content} = Astro.props; const { content } = Astro.props;
const {title, description, publishDate, author, heroImage, permalink, alt} = content; const { title, description, publishDate, author, heroImage, permalink, alt } = content;
--- ---
<html lang={ content.lang || 'en' }> <html lang={content.lang || 'en'}>
<head> <head>
<BaseHead title={title} description={description} permalink={permalink} /> <BaseHead {title} {description} {permalink} />
<link rel="stylesheet" href={Astro.resolve('../styles/blog.css')} /> <link rel="stylesheet" href={Astro.resolve('../styles/blog.css')} />
</head> </head>
<body> <body>
<BlogHeader /> <BlogHeader />
<div class="wrapper"> <div class="wrapper">
<BlogPost title={title} author={author} heroImage={heroImage} publishDate={publishDate} alt={alt}> <BlogPost {title} {author} {heroImage} {publishDate} {alt}>
<slot /> <slot />
</BlogPost> </BlogPost>
</div> </div>
</body> </body>
</html> </html>

View file

@ -5,7 +5,7 @@ import BlogHeader from '../components/BlogHeader.astro';
import BlogPostPreview from '../components/BlogPostPreview.astro'; import BlogPostPreview from '../components/BlogPostPreview.astro';
interface MarkdownFrontmatter { interface MarkdownFrontmatter {
publishDate: number; publishDate: number;
} }
// Component Script: // Component Script:
@ -24,59 +24,60 @@ allPosts = allPosts.sort((a, b) => new Date(b.publishDate).valueOf() - new Date(
// Full Astro Component Syntax: // Full Astro Component Syntax:
// https://docs.astro.build/core-concepts/astro-components/ // https://docs.astro.build/core-concepts/astro-components/
--- ---
<html lang="en"> <html lang="en">
<head> <head>
<BaseHead title={title} description={description} permalink={permalink} /> <BaseHead {title} {description} {permalink} />
<link rel="stylesheet" href={Astro.resolve('../styles/blog.css')} /> <link rel="stylesheet" href={Astro.resolve('../styles/blog.css')} />
<style> <style>
header { header {
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: var(--theme-bg-offset); background-color: var(--theme-bg-offset);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.content { .content {
margin-top: 4rem; margin-top: 4rem;
margin-bottom: 8rem; margin-bottom: 8rem;
} }
.content :global(main > * + *) { .content :global(main > * + *) {
margin-top: 1rem; margin-top: 1rem;
} }
.intro { .intro {
padding-bottom: 4rem; padding-bottom: 4rem;
margin-bottom: 2rem; margin-bottom: 2rem;
border-bottom: 4px solid var(--theme-divider); border-bottom: 4px solid var(--theme-divider);
} }
.intro > * { .intro > * {
margin: 0; margin: 0;
} }
.latest { .latest {
font-size: 2.5rem; font-size: 2.5rem;
font-weight: 700; font-weight: 700;
} }
</style> </style>
</head> </head>
<body> <body>
<BlogHeader /> <BlogHeader />
<div class="wrapper"> <div class="wrapper">
<main class="content"> <main class="content">
<section class="intro"> <section class="intro">
<h1 class="latest">{title}</h1> <h1 class="latest">{title}</h1>
<p>{description}</p> <p>{description}</p>
</section> </section>
<section aria-label="Blog post list"> <section aria-label="Blog post list">
{allPosts.map(p => <BlogPostPreview post={p} />)} {allPosts.map((p) => <BlogPostPreview post={p} />)}
</section> </section>
</main> </main>
</div> </div>
</body> </body>
</html> </html>

View file

@ -1,284 +1,284 @@
:root { :root {
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji; --font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
--font-body: 'IBM Plex Sans', var(--font-fallback); --font-body: 'IBM Plex Sans', var(--font-fallback);
--font-mono: 'IBM Plex Mono', Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', --font-mono: 'IBM Plex Mono', Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono',
'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace; 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace;
--color-white: #fff; --color-white: #fff;
--color-black: #000014; --color-black: #000014;
--color-gray-50: #f9fafb; --color-gray-50: #f9fafb;
--color-gray-100: #f3f4f6; --color-gray-100: #f3f4f6;
--color-gray-200: #e5e7eb; --color-gray-200: #e5e7eb;
--color-gray-300: #d1d5db; --color-gray-300: #d1d5db;
--color-gray-400: #9ca3af; --color-gray-400: #9ca3af;
--color-gray-500: #6b7280; --color-gray-500: #6b7280;
--color-gray-600: #4b5563; --color-gray-600: #4b5563;
--color-gray-700: #374151; --color-gray-700: #374151;
--color-gray-800: #1f2937; --color-gray-800: #1f2937;
--color-gray-900: #111827; --color-gray-900: #111827;
--color-blue: #3894ff; --color-blue: #3894ff;
--color-blue-rgb: 56, 148, 255; --color-blue-rgb: 56, 148, 255;
--color-green: #17c083; --color-green: #17c083;
--color-green-rgb: 23, 192, 131; --color-green-rgb: 23, 192, 131;
--color-orange: #ff5d01; --color-orange: #ff5d01;
--color-orange-rgb: 255, 93, 1; --color-orange-rgb: 255, 93, 1;
--color-purple: #882de7; --color-purple: #882de7;
--color-purple-rgb: 136, 45, 231; --color-purple-rgb: 136, 45, 231;
--color-red: #ff1639; --color-red: #ff1639;
--color-red-rgb: 255, 22, 57; --color-red-rgb: 255, 22, 57;
--color-yellow: #ffbe2d; --color-yellow: #ffbe2d;
--color-yellow-rgb: 255, 190, 45; --color-yellow-rgb: 255, 190, 45;
} }
:root { :root {
color-scheme: light; color-scheme: light;
--theme-accent: var(--color-orange); --theme-accent: var(--color-orange);
--theme-accent-rgb: var(--color-orange-rgb); --theme-accent-rgb: var(--color-orange-rgb);
--theme-accent-opacity: 0.1; --theme-accent-opacity: 0.1;
--theme-divider: var(--color-gray-100); --theme-divider: var(--color-gray-100);
--theme-text: var(--color-gray-800); --theme-text: var(--color-gray-800);
--theme-text-light: var(--color-gray-600); --theme-text-light: var(--color-gray-600);
--theme-text-lighter: var(--color-gray-400); --theme-text-lighter: var(--color-gray-400);
--theme-bg: var(--color-white); --theme-bg: var(--color-white);
--theme-bg-offset: var(--color-gray-100); --theme-bg-offset: var(--color-gray-100);
--theme-bg-accent: rgba(var(--theme-accent-rgb), var(--theme-accent-opacity)); --theme-bg-accent: rgba(var(--theme-accent-rgb), var(--theme-accent-opacity));
--theme-code-inline-bg: var(--color-gray-100); --theme-code-inline-bg: var(--color-gray-100);
--theme-code-text: var(--color-gray-100); --theme-code-text: var(--color-gray-100);
--theme-code-bg: var(--color-gray-700); --theme-code-bg: var(--color-gray-700);
} }
body { body {
background: var(--theme-bg); background: var(--theme-bg);
color: var(--theme-text); color: var(--theme-text);
} }
:root.theme-dark { :root.theme-dark {
color-scheme: dark; color-scheme: dark;
--theme-accent-opacity: 0.3; --theme-accent-opacity: 0.3;
--theme-divider: var(--color-gray-900); --theme-divider: var(--color-gray-900);
--theme-text: var(--color-gray-200); --theme-text: var(--color-gray-200);
--theme-text-light: var(--color-gray-400); --theme-text-light: var(--color-gray-400);
--theme-text-lighter: var(--color-gray-600); --theme-text-lighter: var(--color-gray-600);
--theme-bg: var(--color-black); --theme-bg: var(--color-black);
--theme-bg-offset: var(--color-gray-900); --theme-bg-offset: var(--color-gray-900);
--theme-code-inline-bg: var(--color-gray-800); --theme-code-inline-bg: var(--color-gray-800);
--theme-code-text: var(--color-gray-200); --theme-code-text: var(--color-gray-200);
--theme-code-bg: var(--color-gray-900); --theme-code-bg: var(--color-gray-900);
} }
::selection { ::selection {
color: var(--theme-accent); color: var(--theme-accent);
background-color: rgba(var(--theme-accent-rgb), var(--theme-accent-opacity)); background-color: rgba(var(--theme-accent-rgb), var(--theme-accent-opacity));
} }
* { * {
box-sizing: border-box; box-sizing: border-box;
margin: 0; margin: 0;
} }
:root { :root {
--user-font-scale: 1rem - 16px; --user-font-scale: 1rem - 16px;
--max-width: calc(100% - 2rem); --max-width: calc(100% - 2rem);
} }
@media (min-width: 50em) { @media (min-width: 50em) {
:root { :root {
--max-width: 40em; --max-width: 40em;
} }
} }
body { body {
font-family: var(--font-body); font-family: var(--font-body);
font-size: 1rem; font-size: 1rem;
font-size: clamp(0.875rem, 0.4626rem + 1.0309vw + var(--user-font-scale), 1.125rem); font-size: clamp(0.875rem, 0.4626rem + 1.0309vw + var(--user-font-scale), 1.125rem);
line-height: 1.625; line-height: 1.625;
} }
.wrapper { .wrapper {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
max-width: 65em; max-width: 65em;
padding-left: 2rem; padding-left: 2rem;
padding-right: 2rem; padding-right: 2rem;
width: 100%; width: 100%;
} }
nav ul { nav ul {
list-style: none; list-style: none;
padding: 0; padding: 0;
} }
/* Typography */ /* Typography */
:is(h1, h2, h3, h4, h5, h6) { :is(h1, h2, h3, h4, h5, h6) {
margin-bottom: 1.38rem; margin-bottom: 1.38rem;
font-weight: 400; font-weight: 400;
line-height: 1.3; line-height: 1.3;
} }
:is(h1, h2) { :is(h1, h2) {
max-width: 40ch; max-width: 40ch;
} }
:is(h2, h3):not(:first-child) { :is(h2, h3):not(:first-child) {
margin-top: 3rem; margin-top: 3rem;
} }
h1 { h1 {
font-size: clamp(2.488rem, 1.924rem + 1.41vw, 3.052rem); font-size: clamp(2.488rem, 1.924rem + 1.41vw, 3.052rem);
} }
h2 { h2 {
font-size: clamp(2.074rem, 1.707rem + 0.9175vw, 2.441rem); font-size: clamp(2.074rem, 1.707rem + 0.9175vw, 2.441rem);
} }
h3 { h3 {
font-size: clamp(1.728rem, 1.503rem + 0.5625vw, 1.953rem); font-size: clamp(1.728rem, 1.503rem + 0.5625vw, 1.953rem);
} }
h4 { h4 {
font-size: clamp(1.44rem, 1.317rem + 0.3075vw, 1.563rem); font-size: clamp(1.44rem, 1.317rem + 0.3075vw, 1.563rem);
} }
h5 { h5 {
font-size: clamp(1.2rem, 1.15rem + 0.125vw, 1.25rem); font-size: clamp(1.2rem, 1.15rem + 0.125vw, 1.25rem);
} }
p { p {
color: var(--theme-text-light); color: var(--theme-text-light);
} }
small, small,
.text_small { .text_small {
font-size: 0.833rem; font-size: 0.833rem;
} }
a { a {
color: var(--theme-accent); color: var(--theme-accent);
font-weight: 400; font-weight: 400;
text-underline-offset: 0.08em; text-underline-offset: 0.08em;
text-decoration: none; text-decoration: none;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
} }
a > code:not([class*='language']) { a > code:not([class*='language']) {
position: relative; position: relative;
color: var(--theme-accent); color: var(--theme-accent);
background: transparent; background: transparent;
text-underline-offset: var(--padding-block); text-underline-offset: var(--padding-block);
} }
a > code:not([class*='language'])::before { a > code:not([class*='language'])::before {
content: ''; content: '';
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
display: block; display: block;
background: var(--theme-accent); background: var(--theme-accent);
opacity: var(--theme-accent-opacity); opacity: var(--theme-accent-opacity);
border-radius: var(--border-radius); border-radius: var(--border-radius);
} }
a:hover, a:hover,
a:focus { a:focus {
text-decoration: underline; text-decoration: underline;
} }
a:focus { a:focus {
outline: 2px solid currentColor; outline: 2px solid currentColor;
outline-offset: 0.25em; outline-offset: 0.25em;
} }
strong { strong {
font-weight: 600; font-weight: 600;
color: inherit; color: inherit;
} }
/* Supporting Content */ /* Supporting Content */
code:not([class*='language']) { code:not([class*='language']) {
--border-radius: 3px; --border-radius: 3px;
--padding-block: 0.2rem; --padding-block: 0.2rem;
--padding-inline: 0.33rem; --padding-inline: 0.33rem;
font-family: var(--font-mono); font-family: var(--font-mono);
font-size: 0.85em; font-size: 0.85em;
color: inherit; color: inherit;
background-color: var(--theme-code-inline-bg); background-color: var(--theme-code-inline-bg);
padding: var(--padding-block) var(--padding-inline); padding: var(--padding-block) var(--padding-inline);
margin: calc(var(--padding-block) * -1) -0.125em; margin: calc(var(--padding-block) * -1) -0.125em;
border-radius: var(--border-radius); border-radius: var(--border-radius);
word-break: break-word; word-break: break-word;
} }
pre > code:not([class*='language']) { pre > code:not([class*='language']) {
background-color: transparent; background-color: transparent;
padding: 0; padding: 0;
margin: 0; margin: 0;
border-radius: 0; border-radius: 0;
color: inherit; color: inherit;
} }
pre { pre {
position: relative; position: relative;
background-color: var(--theme-code-bg); background-color: var(--theme-code-bg);
color: var(--theme-code-text); color: var(--theme-code-text);
--padding-block: 1rem; --padding-block: 1rem;
--padding-inline: 2rem; --padding-inline: 2rem;
padding: var(--padding-block) var(--padding-inline); padding: var(--padding-block) var(--padding-inline);
padding-right: calc(var(--padding-inline) * 2); padding-right: calc(var(--padding-inline) * 2);
margin-left: calc(50vw - var(--padding-inline)); margin-left: calc(50vw - var(--padding-inline));
transform: translateX(-50vw); transform: translateX(-50vw);
line-height: 1.414; line-height: 1.414;
width: calc(100vw + (var(--padding-inline) * 2)); width: calc(100vw + (var(--padding-inline) * 2));
max-width: calc(100% + (var(--padding-inline) * 2)); max-width: calc(100% + (var(--padding-inline) * 2));
overflow-y: hidden; overflow-y: hidden;
overflow-x: auto; overflow-x: auto;
} }
@media (min-width: 37.75em) { @media (min-width: 37.75em) {
pre { pre {
--padding-inline: 1.25rem; --padding-inline: 1.25rem;
border-radius: 8px; border-radius: 8px;
} }
} }
.flex { .flex {
display: flex; display: flex;
align-items: center; align-items: center;
} }
img.cover { img.cover {
width: 100%; width: 100%;
max-height: 50vh; max-height: 50vh;
object-fit: cover; object-fit: cover;
} }
blockquote { blockquote {
font-size: 1.5rem; font-size: 1.5rem;
--padding-block: 1rem; --padding-block: 1rem;
--padding-inline: 1.25rem; --padding-inline: 1.25rem;
--color: var(--theme-divider); --color: var(--theme-divider);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: var(--padding-block) var(--padding-inline); padding: var(--padding-block) var(--padding-inline);
margin-left: calc(var(--padding-inline) * -1); margin-left: calc(var(--padding-inline) * -1);
margin-right: calc(var(--padding-inline) * -1); margin-right: calc(var(--padding-inline) * -1);
background: transparent; background: transparent;
border-left: calc(var(--padding-inline) / 2) solid var(--color); border-left: calc(var(--padding-inline) / 2) solid var(--color);
border-radius: 0; border-radius: 0;
} }
blockquote .source { blockquote .source {
font-weight: 500; font-weight: 500;
color: var(--color); color: var(--color);
font-size: 1rem; font-size: 1rem;
} }

View file

@ -8,6 +8,6 @@
// @ts-check // @ts-check
export default /** @type {import('astro').AstroUserConfig} */ ({ export default /** @type {import('astro').AstroUserConfig} */ ({
// Comment out "renderers: []" to enable Astro's default component support. // Comment out "renderers: []" to enable Astro's default component support.
renderers: [], renderers: [],
}); });

View file

@ -1,29 +1,24 @@
--- ---
import * as Component from '@example/my-component' import * as Component from '@example/my-component';
--- ---
<html lang="en"> <html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Welcome to Astro</title>
<style global>
h {
display: block;
font-size: 2em;
font-weight: bold;
margin-block: 0.67em;
}
</style>
</head>
<head> <body>
<meta charset="utf-8" /> <Component.Heading>Welcome to Astro</Component.Heading>
<meta name="viewport" content="width=device-width" /> <Component.Button>Plain Button</Component.Button>
<title>Welcome to Astro</title> </body>
<style global> </html>
h {
display: block;
font-size: 2em;
font-weight: bold;
margin-block: 0.67em;
}
</style>
</head>
<body>
<Component.Heading>
Welcome to Astro
</Component.Heading>
<Component.Button>
Plain Button
</Component.Button>
</body>
</html>

View file

@ -1,15 +1,13 @@
--- ---
export interface Props extends Record<any, any> { export interface Props extends Record<any, any> {
type?: string type?: string;
} }
const { const { type, ...props } = {
type, ...Astro.props,
...props } as Props;
} = {
...Astro.props
} as Props
props.type = type || 'button' props.type = type || 'button';
--- ---
<button {...props}><slot /></button>
<button {...props}><slot /></button>

View file

@ -1,18 +1,15 @@
--- ---
export interface Props extends Record<any, any> { export interface Props extends Record<any, any> {
level?: number | string level?: number | string;
role?: string role?: string;
} }
const { const { level, role, ...props } = {
level, ...Astro.props,
role, } as Props;
...props
} = {
...Astro.props
} as Props
props.role = role || 'heading' props.role = role || 'heading';
props['aria-level'] = level || '1' props['aria-level'] = level || '1';
--- ---
<h {...props}><slot /></h>
<h {...props}><slot /></h>

View file

@ -8,10 +8,10 @@
// @ts-check // @ts-check
export default /** @type {import('astro').AstroUserConfig} */ ({ export default /** @type {import('astro').AstroUserConfig} */ ({
renderers: [ renderers: [
// Enable the Preact renderer to support Preact JSX components. // Enable the Preact renderer to support Preact JSX components.
'@astrojs/renderer-preact', '@astrojs/renderer-preact',
// Enable the React renderer, for the Algolia search component // Enable the React renderer, for the Algolia search component
'@astrojs/renderer-react', '@astrojs/renderer-react',
], ],
}); });

View file

@ -1,3 +1,3 @@
Array.from(document.getElementsByTagName('pre')).forEach((element) => { Array.from(document.getElementsByTagName('pre')).forEach((element) => {
element.setAttribute('tabindex', '0'); element.setAttribute('tabindex', '0');
}); });

View file

@ -1,151 +1,149 @@
--- ---
// fetch all commits for just this page's path // fetch all commits for just this page's path
const path = "docs/" + Astro.props.path; const path = 'docs/' + Astro.props.path;
const url = `https://api.github.com/repos/withastro/astro/commits?path=${path}`; const url = `https://api.github.com/repos/withastro/astro/commits?path=${path}`;
const commitsURL = `https://github.com/withastro/astro/commits/main/${path}`; const commitsURL = `https://github.com/withastro/astro/commits/main/${path}`;
async function getCommits(url) { async function getCommits(url) {
try { try {
const token = import.meta.env.SNOWPACK_PUBLIC_GITHUB_TOKEN; const token = import.meta.env.SNOWPACK_PUBLIC_GITHUB_TOKEN;
if (!token) { if (!token) {
throw new Error( throw new Error('Cannot find "SNOWPACK_PUBLIC_GITHUB_TOKEN" used for escaping rate-limiting.');
'Cannot find "SNOWPACK_PUBLIC_GITHUB_TOKEN" used for escaping rate-limiting.' }
);
}
const auth = `Basic ${Buffer.from(token, "binary").toString("base64")}`; const auth = `Basic ${Buffer.from(token, 'binary').toString('base64')}`;
const res = await fetch(url, { const res = await fetch(url, {
method: "GET", method: 'GET',
headers: { headers: {
Authorization: auth, Authorization: auth,
"User-Agent": "astro-docs/1.0", 'User-Agent': 'astro-docs/1.0',
}, },
}); });
const data = await res.json(); const data = await res.json();
if (!res.ok) { if (!res.ok) {
throw new Error( throw new Error(
`Request to fetch commits failed. Reason: ${res.statusText} `Request to fetch commits failed. Reason: ${res.statusText}
Message: ${data.message}` Message: ${data.message}`
); );
} }
return data; return data;
} catch (e) { } catch (e) {
console.warn(`[error] /src/components/AvatarList.astro console.warn(`[error] /src/components/AvatarList.astro
${e?.message ?? e}`); ${e?.message ?? e}`);
return new Array(); return new Array();
} }
} }
function removeDups(arr) { function removeDups(arr) {
if (!arr) { if (!arr) {
return new Array(); return new Array();
} }
let map = new Map(); let map = new Map();
for (let item of arr) { for (let item of arr) {
let author = item.author; let author = item.author;
// Deduplicate based on author.id // Deduplicate based on author.id
map.set(author.id, { login: author.login, id: author.id }); map.set(author.id, { login: author.login, id: author.id });
} }
return Array.from(map.values()); return Array.from(map.values());
} }
const data = await getCommits(url); const data = await getCommits(url);
const unique = removeDups(data); const unique = removeDups(data);
const recentContributors = unique.slice(0, 3); // only show avatars for the 3 most recent contributors const recentContributors = unique.slice(0, 3); // only show avatars for the 3 most recent contributors
const additionalContributors = unique.length - recentContributors.length; // list the rest of them as # of extra contributors const additionalContributors = unique.length - recentContributors.length; // list the rest of them as # of extra contributors
--- ---
<!-- Thanks to @5t3ph for https://smolcss.dev/#smol-avatar-list! --> <!-- Thanks to @5t3ph for https://smolcss.dev/#smol-avatar-list! -->
<div class="contributors"> <div class="contributors">
<ul class="avatar-list" style={`--avatar-count: ${recentContributors.length}`}> <ul class="avatar-list" style={`--avatar-count: ${recentContributors.length}`}>
{recentContributors.map((item) => (
{recentContributors.map((item) => ( <li>
<li><a href={`https://github.com/${item.login}`}><img alt={`Contributor ${item.login}`} title={`Contributor ${item.login}`} width="64" height="64" src={`https://avatars.githubusercontent.com/u/${item.id}`}/></a></li> <a href={`https://github.com/${item.login}`}>
<img alt={`Contributor ${item.login}`} title={`Contributor ${item.login}`} width="64" height="64" src={`https://avatars.githubusercontent.com/u/${item.id}`} />
))} </a>
</ul> </li>
{additionalContributors > 0 && <span><a href={commitsURL}>{`and ${additionalContributors} additional contributor${additionalContributors > 1 ? 's' : ''}.`}</a></span>} ))}
{unique.length === 0 && <a href={commitsURL}>Contributors</a>} </ul>
{additionalContributors > 0 && (
<span>
<a href={commitsURL}>{`and ${additionalContributors} additional contributor${additionalContributors > 1 ? 's' : ''}.`}</a>
</span>
)}
{unique.length === 0 && <a href={commitsURL}>Contributors</a>}
</div> </div>
<style> <style>
.avatar-list { .avatar-list {
--avatar-size: 2.5rem; --avatar-size: 2.5rem;
--avatar-count: 3; --avatar-count: 3;
display: grid; display: grid;
list-style: none; list-style: none;
/* Default to displaying most of the avatar to /* Default to displaying most of the avatar to
enable easier access on touch devices, ensuring enable easier access on touch devices, ensuring
the WCAG touch target size is met or exceeded */ the WCAG touch target size is met or exceeded */
grid-template-columns: repeat( grid-template-columns: repeat(var(--avatar-count), max(44px, calc(var(--avatar-size) / 1.15)));
var(--avatar-count), /* `padding` matches added visual dimensions of
max(44px, calc(var(--avatar-size) / 1.15))
);
/* `padding` matches added visual dimensions of
the `box-shadow` to help create a more accurate the `box-shadow` to help create a more accurate
computed component size */ computed component size */
padding: 0.08em; padding: 0.08em;
font-size: var(--avatar-size); font-size: var(--avatar-size);
} }
@media (any-hover: hover) and (any-pointer: fine) { @media (any-hover: hover) and (any-pointer: fine) {
.avatar-list { .avatar-list {
/* We create 1 extra cell to enable the computed /* We create 1 extra cell to enable the computed
width to match the final visual width */ width to match the final visual width */
grid-template-columns: repeat( grid-template-columns: repeat(calc(var(--avatar-count) + 1), calc(var(--avatar-size) / 1.75));
calc(var(--avatar-count) + 1), }
calc(var(--avatar-size) / 1.75) }
);
}
}
.avatar-list li { .avatar-list li {
width: var(--avatar-size); width: var(--avatar-size);
height: var(--avatar-size); height: var(--avatar-size);
} }
.avatar-list li:hover ~ li a, .avatar-list li:hover ~ li a,
.avatar-list li:focus-within ~ li a { .avatar-list li:focus-within ~ li a {
transform: translateX(33%); transform: translateX(33%);
} }
.avatar-list img, .avatar-list img,
.avatar-list a { .avatar-list a {
display: block; display: block;
border-radius: 50%; border-radius: 50%;
} }
.avatar-list a { .avatar-list a {
transition: transform 180ms ease-in-out; transition: transform 180ms ease-in-out;
} }
.avatar-list img { .avatar-list img {
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: cover; object-fit: cover;
background-color: #fff; background-color: #fff;
box-shadow: 0 0 0 0.05em #fff, 0 0 0 0.08em rgba(0, 0, 0, 0.15); box-shadow: 0 0 0 0.05em #fff, 0 0 0 0.08em rgba(0, 0, 0, 0.15);
} }
.avatar-list a:focus { .avatar-list a:focus {
outline: 2px solid transparent; outline: 2px solid transparent;
/* Double-layer trick to work for dark and light backgrounds */ /* Double-layer trick to work for dark and light backgrounds */
box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white; box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white;
} }
.contributors { .contributors {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.contributors > * + * { .contributors > * + * {
margin-left: .75rem; margin-left: 0.75rem;
} }
</style> </style>

View file

@ -4,13 +4,13 @@ const { path } = Astro.props;
--- ---
<footer> <footer>
<AvatarList path={path} /> <AvatarList {path} />
</footer> </footer>
<style> <style>
footer { footer {
margin-top: auto; margin-top: auto;
padding: 2rem 0; padding: 2rem 0;
border-top: 3px solid var(--theme-divider); border-top: 3px solid var(--theme-divider);
} }
</style> </style>

View file

@ -1,11 +1,11 @@
<!-- Global Metadata --> <!-- Global Metadata -->
<meta charset="utf-8"> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="alternate icon" type="image/x-icon" href="/favicon.ico" /> <link rel="alternate icon" type="image/x-icon" href="/favicon.ico" />
<link rel="sitemap" href="/sitemap.xml"/> <link rel="sitemap" href="/sitemap.xml" />
<!-- Global CSS --> <!-- Global CSS -->
<link rel="stylesheet" href={Astro.resolve('../styles/theme.css')} /> <link rel="stylesheet" href={Astro.resolve('../styles/theme.css')} />
@ -13,22 +13,22 @@
<link rel="stylesheet" href={Astro.resolve('../styles/index.css')} /> <link rel="stylesheet" href={Astro.resolve('../styles/index.css')} />
<!-- Preload Fonts --> <!-- Preload Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital@0;1&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital@0;1&display=swap" rel="stylesheet" />
<!-- Scrollable a11y code helper --> <!-- Scrollable a11y code helper -->
<script type="module" src="/make-scrollable-code-focusable.js" /> <script type="module" src="/make-scrollable-code-focusable.js"></script>
<!-- This is intentionally inlined to avoid FOUC --> <!-- This is intentionally inlined to avoid FOUC -->
<script> <script>
const root = document.documentElement; const root = document.documentElement;
const theme = localStorage.getItem('theme'); const theme = localStorage.getItem('theme');
if (theme === 'dark' || (!theme) && window.matchMedia('(prefers-color-scheme: dark)').matches) { if (theme === 'dark' || (!theme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
root.classList.add('theme-dark'); root.classList.add('theme-dark');
} else { } else {
root.classList.remove('theme-dark'); root.classList.remove('theme-dark');
} }
</script> </script>
<!-- Global site tag (gtag.js) - Google Analytics --> <!-- Global site tag (gtag.js) - Google Analytics -->
@ -38,4 +38,4 @@
function gtag(){dataLayer.push(arguments);} function gtag(){dataLayer.push(arguments);}
gtag('js', new Date()); gtag('js', new Date());
gtag('config', 'G-TEL60V1WM9'); gtag('config', 'G-TEL60V1WM9');
</script> --> </script> -->

View file

@ -1,36 +1,37 @@
--- ---
import {SITE, OPEN_GRAPH} from '../config.ts'; import { SITE, OPEN_GRAPH } from '../config.ts';
export interface Props { export interface Props {
content: any, content: any;
site: any, site: any;
canonicalURL: URL | string, canonicalURL: URL | string;
}; }
const { content = {}, canonicalURL } = Astro.props; const { content = {}, canonicalURL } = Astro.props;
const formattedContentTitle = content.title ? `${content.title} 🚀 ${SITE.title}` : SITE.title; const formattedContentTitle = content.title ? `${content.title} 🚀 ${SITE.title}` : SITE.title;
const imageSrc = content?.image?.src ?? OPEN_GRAPH.image.src; const imageSrc = content?.image?.src ?? OPEN_GRAPH.image.src;
const canonicalImageSrc = new URL(imageSrc, Astro.site); const canonicalImageSrc = new URL(imageSrc, Astro.site);
const imageAlt = content?.image?.alt ?? OPEN_GRAPH.image.alt; const imageAlt = content?.image?.alt ?? OPEN_GRAPH.image.alt;
--- ---
<!-- Page Metadata --> <!-- Page Metadata -->
<link rel="canonical" href={canonicalURL}/> <link rel="canonical" href={canonicalURL} />
<!-- OpenGraph Tags --> <!-- OpenGraph Tags -->
<meta property="og:title" content={formattedContentTitle}/> <meta property="og:title" content={formattedContentTitle} />
<meta property="og:type" content="article"/> <meta property="og:type" content="article" />
<meta property="og:url" content={canonicalURL}/> <meta property="og:url" content={canonicalURL} />
<meta property="og:locale" content={content.ogLocale ?? SITE.defaultLanguage}/> <meta property="og:locale" content={content.ogLocale ?? SITE.defaultLanguage} />
<meta property="og:image" content={canonicalImageSrc}/> <meta property="og:image" content={canonicalImageSrc} />
<meta property="og:image:alt" content={imageAlt}/> <meta property="og:image:alt" content={imageAlt} />
<meta name="description" property="og:description" content={content.description ? content.description : SITE.description}/> <meta name="description" property="og:description" content={content.description ? content.description : SITE.description} />
<meta property="og:site_name" content={SITE.title}/> <meta property="og:site_name" content={SITE.title} />
<!-- Twitter Tags --> <!-- Twitter Tags -->
<meta name="twitter:card" content="summary_large_image"/> <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content={OPEN_GRAPH.twitter}/> <meta name="twitter:site" content={OPEN_GRAPH.twitter} />
<meta name="twitter:title" content={formattedContentTitle}/> <meta name="twitter:title" content={formattedContentTitle} />
<meta name="twitter:description" content={content.description ? content.description : SITE.description}/> <meta name="twitter:description" content={content.description ? content.description : SITE.description} />
<meta name="twitter:image" content={canonicalImageSrc}/> <meta name="twitter:image" content={canonicalImageSrc} />
<meta name="twitter:image:alt" content={imageAlt}/> <meta name="twitter:image:alt" content={imageAlt} />
<!-- <!--
TODO: Add json+ld data, maybe https://schema.org/APIReference makes sense? TODO: Add json+ld data, maybe https://schema.org/APIReference makes sense?

View file

@ -1,18 +1,27 @@
--- ---
const {size} = Astro.props; const { size } = Astro.props;
--- ---
<svg class="logo" width={size} height={size} viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg class="logo" width={size} height={size} viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg">
<style> <style>
#flame { #flame {
fill: var(--theme-text-accent); fill: var(--theme-text-accent);
} }
#a { #a {
fill: var(--theme-text-accent); fill: var(--theme-text-accent);
} }
</style> </style>
<title>Logo</title> <title>Logo</title>
<path id="a" fill-rule="evenodd" clip-rule="evenodd" <path
d="M163.008 18.929c1.944 2.413 2.935 5.67 4.917 12.181l43.309 142.27a180.277 180.277 0 00-51.778-17.53l-28.198-95.29a3.67 3.67 0 00-7.042.01l-27.857 95.232a180.225 180.225 0 00-52.01 17.557l43.52-142.281c1.99-6.502 2.983-9.752 4.927-12.16a15.999 15.999 0 016.484-4.798c2.872-1.154 6.271-1.154 13.07-1.154h31.085c6.807 0 10.211 0 13.086 1.157a16.004 16.004 0 016.487 4.806z" /> id="a"
<path id="flame" fill-rule="evenodd" clip-rule="evenodd" fill-rule="evenodd"
d="M168.19 180.151c-7.139 6.105-21.39 10.268-37.804 10.268-20.147 0-37.033-6.272-41.513-14.707-1.602 4.835-1.961 10.367-1.961 13.902 0 0-1.056 17.355 11.015 29.426 0-6.268 5.081-11.349 11.349-11.349 10.743 0 10.731 9.373 10.721 16.977v.679c0 11.542 7.054 21.436 17.086 25.606a23.27 23.27 0 01-2.339-10.2c0-11.008 6.463-15.107 13.974-19.87 5.976-3.79 12.616-8.001 17.192-16.449a31.024 31.024 0 003.743-14.82c0-3.299-.513-6.479-1.463-9.463z" /> clip-rule="evenodd"
</svg> d="M163.008 18.929c1.944 2.413 2.935 5.67 4.917 12.181l43.309 142.27a180.277 180.277 0 00-51.778-17.53l-28.198-95.29a3.67 3.67 0 00-7.042.01l-27.857 95.232a180.225 180.225 0 00-52.01 17.557l43.52-142.281c1.99-6.502 2.983-9.752 4.927-12.16a15.999 15.999 0 016.484-4.798c2.872-1.154 6.271-1.154 13.07-1.154h31.085c6.807 0 10.211 0 13.086 1.157a16.004 16.004 0 016.487 4.806z"
></path>
<path
id="flame"
fill-rule="evenodd"
clip-rule="evenodd"
d="M168.19 180.151c-7.139 6.105-21.39 10.268-37.804 10.268-20.147 0-37.033-6.272-41.513-14.707-1.602 4.835-1.961 10.367-1.961 13.902 0 0-1.056 17.355 11.015 29.426 0-6.268 5.081-11.349 11.349-11.349 10.743 0 10.731 9.373 10.721 16.977v.679c0 11.542 7.054 21.436 17.086 25.606a23.27 23.27 0 01-2.339-10.2c0-11.008 6.463-15.107 13.974-19.87 5.976-3.79 12.616-8.001 17.192-16.449a31.024 31.024 0 003.743-14.82c0-3.299-.513-6.479-1.463-9.463z"
></path>
</svg>

View file

@ -5,128 +5,133 @@ import AstroLogo from './AstroLogo.astro';
import SkipToContent from './SkipToContent.astro'; import SkipToContent from './SkipToContent.astro';
import SidebarToggle from './SidebarToggle.tsx'; import SidebarToggle from './SidebarToggle.tsx';
import LanguageSelect from './LanguageSelect.tsx'; import LanguageSelect from './LanguageSelect.tsx';
import Search from "./Search.tsx"; import Search from './Search.tsx';
const {currentPage} = Astro.props; const { currentPage } = Astro.props;
const lang = currentPage && getLanguageFromURL(currentPage); const lang = currentPage && getLanguageFromURL(currentPage);
--- ---
<style>
header {
z-index: 11;
height: var(--theme-navbar-height);
width: 100%;
background-color: var(--theme-navbar-bg);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
position: sticky;
top: 0;
}
.logo {
display: flex;
overflow: hidden;
width: 30px;
font-size: 2rem;
flex-shrink: 0;
font-weight: 600;
line-height: 1;
color: hsla(var(--color-base-white), 100%, 1);
gap: 0.25em;
z-index: -1;
}
.logo a {
padding: 0.5em 0.25em;
margin: -0.5em -0.25em;
text-decoration: none;
font-weight: bold;
}
.logo a {
transition: color 100ms ease-out;
color: var(--theme-text);
}
.logo a:hover,
.logo a:focus {
color: var(--theme-text-accent);
}
.logo h1 {
font: inherit;
color: inherit;
margin: 0;
}
.nav-wrapper {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 1em;
width: 100%;
max-width: 82em;
padding: 0 1rem;
}
@media (min-width: 50em) {
header {
position: static;
padding: 2rem 0rem;
}
.logo {
width: auto;
margin: 0;
z-index: 0;
}
.menu-toggle {
display: none;
}
.logo {
width: auto;
}
}
/** Style Algolia */
:root {
--docsearch-primary-color: var(--theme-accent);
--docsearch-logo-color: var(--theme-text);
}
.search-item {
display: none;
position: relative;
z-index: 10;
flex-grow: 1;
padding-right: 0.7rem;
display: flex;
max-width: 200px;
}
:global(.search-item > *) {
flex-grow: 1;
}
@media (min-width: 50em) {
.search-item {
max-width: 400px;
}
}
</style>
<header> <header>
<SkipToContent /> <SkipToContent />
<nav class="nav-wrapper" title="Top Navigation"> <nav class="nav-wrapper" title="Top Navigation">
<div class="menu-toggle"> <div class="menu-toggle">
<SidebarToggle client:idle/> <SidebarToggle client:idle />
</div> </div>
<div class="logo flex"> <div class="logo flex">
<AstroLogo size={40} /> <AstroLogo size={40} />
<a href="/"> <a href="/">
<h1>Documentation</h1> <h1>Documentation</h1>
</a> </a>
</div> </div>
<div style="flex-grow: 1;"></div> <div style="flex-grow: 1;"></div>
{KNOWN_LANGUAGE_CODES.length > 1 && <LanguageSelect lang={lang} client:idle />} {KNOWN_LANGUAGE_CODES.length > 1 && <LanguageSelect lang={lang} client:idle />}
{CONFIG.ALGOLIA && <div class="search-item"><Search client:idle /></div>} {CONFIG.ALGOLIA && (
</nav> <div class="search-item">
</header> <Search client:idle />
</div>
)}
</nav>
</header>
<style>
header {
z-index: 11;
height: var(--theme-navbar-height);
width: 100%;
background-color: var(--theme-navbar-bg);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
position: sticky;
top: 0;
}
.logo {
display: flex;
overflow: hidden;
width: 30px;
font-size: 2rem;
flex-shrink: 0;
font-weight: 600;
line-height: 1;
color: hsla(var(--color-base-white), 100%, 1);
gap: 0.25em;
z-index: -1;
}
.logo a {
padding: 0.5em 0.25em;
margin: -0.5em -0.25em;
text-decoration: none;
font-weight: bold;
}
.logo a {
transition: color 100ms ease-out;
color: var(--theme-text);
}
.logo a:hover,
.logo a:focus {
color: var(--theme-text-accent);
}
.logo h1 {
font: inherit;
color: inherit;
margin: 0;
}
.nav-wrapper {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 1em;
width: 100%;
max-width: 82em;
padding: 0 1rem;
}
@media (min-width: 50em) {
header {
position: static;
padding: 2rem 0rem;
}
.logo {
width: auto;
margin: 0;
z-index: 0;
}
.menu-toggle {
display: none;
}
.logo {
width: auto;
}
}
/** Style Algolia */
:root {
--docsearch-primary-color: var(--theme-accent);
--docsearch-logo-color: var(--theme-text);
}
.search-item {
display: none;
position: relative;
z-index: 10;
flex-grow: 1;
padding-right: 0.7rem;
display: flex;
max-width: 200px;
}
:global(.search-item > *) {
flex-grow: 1;
}
@media (min-width: 50em) {
.search-item {
max-width: 400px;
}
}
</style>

View file

@ -1,47 +1,47 @@
.language-select { .language-select {
flex-grow: 1; flex-grow: 1;
width: 48px; width: 48px;
box-sizing: border-box; box-sizing: border-box;
margin: 0; margin: 0;
padding: 0.33em 0.5em; padding: 0.33em 0.5em;
overflow: visible; overflow: visible;
font-weight: 500; font-weight: 500;
font-size: 1rem; font-size: 1rem;
font-family: inherit; font-family: inherit;
line-height: inherit; line-height: inherit;
background-color: var(--theme-bg); background-color: var(--theme-bg);
border-color: var(--theme-text-lighter); border-color: var(--theme-text-lighter);
color: var(--theme-text-light); color: var(--theme-text-light);
border-style: solid; border-style: solid;
border-width: 1px; border-width: 1px;
border-radius: 0.25rem; border-radius: 0.25rem;
outline: 0; outline: 0;
cursor: pointer; cursor: pointer;
transition-timing-function: ease-out; transition-timing-function: ease-out;
transition-duration: 0.2s; transition-duration: 0.2s;
transition-property: border-color, color; transition-property: border-color, color;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
padding-left: 30px; padding-left: 30px;
padding-right: 1rem; padding-right: 1rem;
} }
.language-select-wrapper .language-select:hover, .language-select-wrapper .language-select:hover,
.language-select-wrapper .language-select:focus { .language-select-wrapper .language-select:focus {
color: var(--theme-text); color: var(--theme-text);
border-color: var(--theme-text-light); border-color: var(--theme-text-light);
} }
.language-select-wrapper { .language-select-wrapper {
color: var(--theme-text-light); color: var(--theme-text-light);
position: relative; position: relative;
} }
.language-select-wrapper > svg { .language-select-wrapper > svg {
position: absolute; position: absolute;
top: 7px; top: 7px;
left: 10px; left: 10px;
pointer-events: none; pointer-events: none;
} }
@media (min-width: 50em) { @media (min-width: 50em) {
.language-select { .language-select {
width: 100%; width: 100%;
} }
} }

View file

@ -4,35 +4,35 @@ import './LanguageSelect.css';
import { KNOWN_LANGUAGES, langPathRegex } from '../../languages'; import { KNOWN_LANGUAGES, langPathRegex } from '../../languages';
const LanguageSelect: FunctionalComponent<{ lang: string }> = ({ lang }) => { const LanguageSelect: FunctionalComponent<{ lang: string }> = ({ lang }) => {
return ( return (
<div class="language-select-wrapper"> <div class="language-select-wrapper">
<svg aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 88.6 77.3" height="1.2em" width="1.2em"> <svg aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 88.6 77.3" height="1.2em" width="1.2em">
<path fill="currentColor" d="M61,24.6h7.9l18.7,51.6h-7.7l-5.4-15.5H54.3l-5.6,15.5h-7.2L61,24.6z M72.6,55l-8-22.8L56.3,55H72.6z" /> <path fill="currentColor" d="M61,24.6h7.9l18.7,51.6h-7.7l-5.4-15.5H54.3l-5.6,15.5h-7.2L61,24.6z M72.6,55l-8-22.8L56.3,55H72.6z" />
<path <path
fill="currentColor" fill="currentColor"
d="M53.6,60.6c-10-4-16-9-22-14c0,0,1.3,1.3,0,0c-6,5-20,13-20,13l-4-6c8-5,10-6,19-13c-2.1-1.9-12-13-13-19h8 c4,9,10,14,10,14c10-8,10-19,10-19h8c0,0-1,13-12,24l0,0c5,5,10,9,19,13L53.6,60.6z M1.6,16.6h56v-8h-23v-7h-9v7h-24V16.6z" d="M53.6,60.6c-10-4-16-9-22-14c0,0,1.3,1.3,0,0c-6,5-20,13-20,13l-4-6c8-5,10-6,19-13c-2.1-1.9-12-13-13-19h8 c4,9,10,14,10,14c10-8,10-19,10-19h8c0,0-1,13-12,24l0,0c5,5,10,9,19,13L53.6,60.6z M1.6,16.6h56v-8h-23v-7h-9v7h-24V16.6z"
/> />
</svg> </svg>
<select <select
class="language-select" class="language-select"
value={lang} value={lang}
onChange={(e) => { onChange={(e) => {
const newLang = e.target.value; const newLang = e.target.value;
let actualDest = window.location.pathname.replace(langPathRegex, '/'); let actualDest = window.location.pathname.replace(langPathRegex, '/');
if (actualDest == '/') actualDest = `/introduction`; if (actualDest == '/') actualDest = `/introduction`;
window.location.pathname = '/' + newLang + actualDest; window.location.pathname = '/' + newLang + actualDest;
}} }}
> >
{Object.keys(KNOWN_LANGUAGES).map((key) => { {Object.keys(KNOWN_LANGUAGES).map((key) => {
return ( return (
<option value={KNOWN_LANGUAGES[key]}> <option value={KNOWN_LANGUAGES[key]}>
<span>{key}</span> <span>{key}</span>
</option> </option>
); );
})} })}
</select> </select>
</div> </div>
); );
}; };
export default LanguageSelect; export default LanguageSelect;

View file

@ -1,69 +1,69 @@
/** Style Algolia */ /** Style Algolia */
:root { :root {
--docsearch-primary-color: var(--theme-accent); --docsearch-primary-color: var(--theme-accent);
--docsearch-logo-color: var(--theme-text); --docsearch-logo-color: var(--theme-text);
} }
.search-input { .search-input {
flex-grow: 1; flex-grow: 1;
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
margin: 0; margin: 0;
padding: 0.33em 0.5em; padding: 0.33em 0.5em;
overflow: visible; overflow: visible;
font-weight: 500; font-weight: 500;
font-size: 1rem; font-size: 1rem;
font-family: inherit; font-family: inherit;
line-height: inherit; line-height: inherit;
background-color: var(--theme-divider); background-color: var(--theme-divider);
border-color: var(--theme-divider); border-color: var(--theme-divider);
color: var(--theme-text-light); color: var(--theme-text-light);
border-style: solid; border-style: solid;
border-width: 1px; border-width: 1px;
border-radius: 0.25rem; border-radius: 0.25rem;
outline: 0; outline: 0;
cursor: pointer; cursor: pointer;
transition-timing-function: ease-out; transition-timing-function: ease-out;
transition-duration: 0.2s; transition-duration: 0.2s;
transition-property: border-color, color; transition-property: border-color, color;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
} }
.search-input:hover, .search-input:hover,
.search-input:focus { .search-input:focus {
color: var(--theme-text); color: var(--theme-text);
border-color: var(--theme-text-light); border-color: var(--theme-text-light);
} }
.search-input:hover::placeholder, .search-input:hover::placeholder,
.search-input:focus::placeholder { .search-input:focus::placeholder {
color: var(--theme-text-light); color: var(--theme-text-light);
} }
.search-input::placeholder { .search-input::placeholder {
color: var(--theme-text-light); color: var(--theme-text-light);
} }
.search-hint { .search-hint {
position: absolute; position: absolute;
top: 7px; top: 7px;
right: 19px; right: 19px;
padding: 3px 5px; padding: 3px 5px;
display: none; display: none;
display: none; display: none;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
letter-spacing: 0.125em; letter-spacing: 0.125em;
font-size: 13px; font-size: 13px;
font-family: var(--font-mono); font-family: var(--font-mono);
pointer-events: none; pointer-events: none;
border-color: var(--theme-text-lighter); border-color: var(--theme-text-lighter);
color: var(--theme-text-light); color: var(--theme-text-light);
border-style: solid; border-style: solid;
border-width: 1px; border-width: 1px;
border-radius: 0.25rem; border-radius: 0.25rem;
line-height: 14px; line-height: 14px;
} }
@media (min-width: 50em) { @media (min-width: 50em) {
.search-hint { .search-hint {
display: flex; display: flex;
} }
} }
/* ------------------------------------------------------------ *\ /* ------------------------------------------------------------ *\
@ -71,6 +71,6 @@
\* ------------------------------------------------------------ */ \* ------------------------------------------------------------ */
.DocSearch-Modal .DocSearch-Hit a { .DocSearch-Modal .DocSearch-Hit a {
box-shadow: none; box-shadow: none;
border: 1px solid var(--theme-accent); border: 1px solid var(--theme-accent);
} }

View file

@ -7,71 +7,71 @@ import '@docsearch/css/dist/style.css';
import './Search.css'; import './Search.css';
export default function Search() { export default function Search() {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const searchButtonRef = useRef(); const searchButtonRef = useRef();
const [initialQuery, setInitialQuery] = useState(null); const [initialQuery, setInitialQuery] = useState(null);
const onOpen = useCallback(() => { const onOpen = useCallback(() => {
setIsOpen(true); setIsOpen(true);
}, [setIsOpen]); }, [setIsOpen]);
const onClose = useCallback(() => { const onClose = useCallback(() => {
setIsOpen(false); setIsOpen(false);
}, [setIsOpen]); }, [setIsOpen]);
const onInput = useCallback( const onInput = useCallback(
(e) => { (e) => {
setIsOpen(true); setIsOpen(true);
setInitialQuery(e.key); setInitialQuery(e.key);
}, },
[setIsOpen, setInitialQuery] [setIsOpen, setInitialQuery]
); );
useDocSearchKeyboardEvents({ useDocSearchKeyboardEvents({
isOpen, isOpen,
onOpen, onOpen,
onClose, onClose,
onInput, onInput,
searchButtonRef, searchButtonRef,
}); });
return ( return (
<> <>
<button type="button" ref={searchButtonRef} onClick={onOpen} className="search-input"> <button type="button" ref={searchButtonRef} onClick={onOpen} className="search-input">
<svg width="24" height="24" fill="none"> <svg width="24" height="24" fill="none">
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" /> <path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg> </svg>
<span>Search</span> <span>Search</span>
<span className="search-hint"> <span className="search-hint">
<span className="sr-only">Press </span> <span className="sr-only">Press </span>
<kbd>/</kbd> <kbd>/</kbd>
<span className="sr-only"> to search</span> <span className="sr-only"> to search</span>
</span> </span>
</button> </button>
{isOpen && {isOpen &&
createPortal( createPortal(
<DocSearchModal <DocSearchModal
initialQuery={initialQuery} initialQuery={initialQuery}
initialScrollY={window.scrollY} initialScrollY={window.scrollY}
onClose={onClose} onClose={onClose}
indexName={(CONFIG as any).ALGOLIA.indexName} indexName={(CONFIG as any).ALGOLIA.indexName}
apiKey={(CONFIG as any).ALGOLIA.apiKey} apiKey={(CONFIG as any).ALGOLIA.apiKey}
transformItems={(items) => { transformItems={(items) => {
return items.map((item) => { return items.map((item) => {
// We transform the absolute URL into a relative URL to // We transform the absolute URL into a relative URL to
// work better on localhost, preview URLS. // work better on localhost, preview URLS.
const a = document.createElement('a'); const a = document.createElement('a');
a.href = item.url; a.href = item.url;
const hash = a.hash === '#overview' ? '' : a.hash; const hash = a.hash === '#overview' ? '' : a.hash;
return { return {
...item, ...item,
url: `${a.pathname}${hash}`, url: `${a.pathname}${hash}`,
}; };
}); });
}} }}
/>, />,
document.body document.body
)} )}
</> </>
); );
} }

View file

@ -3,25 +3,25 @@ import { h, Fragment } from 'preact';
import { useState, useEffect } from 'preact/hooks'; import { useState, useEffect } from 'preact/hooks';
const MenuToggle: FunctionalComponent = () => { const MenuToggle: FunctionalComponent = () => {
const [sidebarShown, setSidebarShown] = useState(false); const [sidebarShown, setSidebarShown] = useState(false);
useEffect(() => { useEffect(() => {
const body = document.getElementsByTagName('body')[0]; const body = document.getElementsByTagName('body')[0];
if (sidebarShown) { if (sidebarShown) {
body.classList.add('mobile-sidebar-toggle'); body.classList.add('mobile-sidebar-toggle');
} else { } else {
body.classList.remove('mobile-sidebar-toggle'); body.classList.remove('mobile-sidebar-toggle');
} }
}, [sidebarShown]); }, [sidebarShown]);
return ( return (
<button type="button" aria-pressed={sidebarShown ? 'true' : 'false'} id="menu-toggle" onClick={() => setSidebarShown(!sidebarShown)}> <button type="button" aria-pressed={sidebarShown ? 'true' : 'false'} id="menu-toggle" onClick={() => setSidebarShown(!sidebarShown)}>
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg> </svg>
<span className="sr-only">Toggle sidebar</span> <span className="sr-only">Toggle sidebar</span>
</button> </button>
); );
}; };
export default MenuToggle; export default MenuToggle;

View file

@ -1,21 +1,22 @@
<style>
.skiplink,
.skiplink:focus,
.skiplink:focus-visible {
position: absolute;
padding: 0.25em;
font-size: larger;
top: 0;
left: 0;
right: 0;
z-index: 9;
display: block;
text-align: center;
background-color: var(--theme-text-accent);
color: var(--theme-bg);
border-radius: 0.25em;
outline: var(--theme-bg) solid 1px;
outline-offset: 0;
}
</style>
<a href="#article" class="sr-only skiplink"><span>Skip to Content</span></a> <a href="#article" class="sr-only skiplink"><span>Skip to Content</span></a>
<style>
.skiplink,
.skiplink:focus,
.skiplink:focus-visible {
position: absolute;
padding: 0.25em;
font-size: larger;
top: 0;
left: 0;
right: 0;
z-index: 9;
display: block;
text-align: center;
background-color: var(--theme-text-accent);
color: var(--theme-bg);
border-radius: 0.25em;
outline: var(--theme-bg) solid 1px;
outline-offset: 0;
}
</style>

View file

@ -1,109 +1,111 @@
--- ---
import { getLanguageFromURL } from '../../languages.ts'; import { getLanguageFromURL } from '../../languages.ts';
import { SIDEBAR } from '../../config.ts'; import { SIDEBAR } from '../../config.ts';
const {currentPage} = Astro.props; const { currentPage } = Astro.props;
const currentPageMatch = currentPage.slice(1); const currentPageMatch = currentPage.slice(1);
const langCode = getLanguageFromURL(currentPage); const langCode = getLanguageFromURL(currentPage);
// SIDEBAR is a flat array. Group it by sections to properly render. // SIDEBAR is a flat array. Group it by sections to properly render.
const sidebarSections = SIDEBAR[langCode].reduce((col, item) => { const sidebarSections = SIDEBAR[langCode].reduce((col, item) => {
if (item.header) { if (item.header) {
col.push({...item, children: []}); col.push({ ...item, children: [] });
} else { } else {
col[col.length-1].children.push(item); col[col.length - 1].children.push(item);
} }
return col; return col;
}, []); }, []);
--- ---
<nav aria-labelledby="grid-left"> <nav aria-labelledby="grid-left">
<ul class="nav-groups"> <ul class="nav-groups">
{sidebarSections.map(section => ( {sidebarSections.map((section) => (
<li> <li>
<div class="nav-group"> <div class="nav-group">
<h2 class="nav-group-title">{section.text}</h2> <h2 class="nav-group-title">{section.text}</h2>
<ul> <ul>
{section.children.map(child => ( {section.children.map((child) => (
<li class="nav-link"><a href={`${Astro.site.pathname}${child.link}`} aria-current={`${currentPageMatch === child.link ? 'page' : 'false'}`}>{child.text}</a></li> <li class="nav-link">
))} <a href={`${Astro.site.pathname}${child.link}`} aria-current={`${currentPageMatch === child.link ? 'page' : 'false'}`}>
</ul> {child.text}
</div> </a>
</li> </li>
))} ))}
</ul> </ul>
</div>
</li>
))}
</ul>
</nav> </nav>
<script> <script>
window.addEventListener('DOMContentLoaded', (event) => { window.addEventListener('DOMContentLoaded', (event) => {
var target = document.querySelector('[aria-current="page"]'); var target = document.querySelector('[aria-current="page"]');
if (target && (target.offsetTop > (window.innerHeight - 100))) { if (target && target.offsetTop > window.innerHeight - 100) {
document.querySelector('.nav-groups').scrollTop = target.offsetTop; document.querySelector('.nav-groups').scrollTop = target.offsetTop;
} }
}); });
</script> </script>
<style> <style>
nav { nav {
width: 100%; width: 100%;
margin-right: 1rem; margin-right: 1rem;
} }
.nav-groups { .nav-groups {
height: 100%; height: 100%;
padding: 2rem 0; padding: 2rem 0;
overflow-x: visible; overflow-x: visible;
overflow-y: auto; overflow-y: auto;
max-height: 100vh; max-height: 100vh;
} }
.nav-groups > li + li { .nav-groups > li + li {
margin-top: 2rem; margin-top: 2rem;
} }
.nav-groups > :first-child { .nav-groups > :first-child {
padding-top: var(--doc-padding); padding-top: var(--doc-padding);
} }
.nav-groups > :last-child { .nav-groups > :last-child {
padding-bottom: 2rem; padding-bottom: 2rem;
margin-bottom: var(--theme-navbar-height); margin-bottom: var(--theme-navbar-height);
} }
.nav-group-title { .nav-group-title {
font-size: 1.0rem; font-size: 1rem;
font-weight: 700; font-weight: 700;
padding: 0.1rem 1rem; padding: 0.1rem 1rem;
text-transform: uppercase; text-transform: uppercase;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.nav-link a { .nav-link a {
font-size: 1.0rem; font-size: 1rem;
margin: 1px; margin: 1px;
padding: 0.3rem 1rem; padding: 0.3rem 1rem;
font: inherit; font: inherit;
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
display: block; display: block;
} }
.nav-link a:hover, .nav-link a:hover,
.nav-link a:focus { .nav-link a:focus {
background-color: var(--theme-bg-hover); background-color: var(--theme-bg-hover);
} }
.nav-link a[aria-current="page"] { .nav-link a[aria-current='page'] {
color: var(--theme-text-accent); color: var(--theme-text-accent);
background-color: var(--theme-bg-accent); background-color: var(--theme-bg-accent);
font-weight: 600; font-weight: 600;
} }
:global(:root.theme-dark) .nav-link a[aria-current="page"] { :global(:root.theme-dark) .nav-link a[aria-current='page'] {
color: hsla(var(--color-base-white), 100%, 1); color: hsla(var(--color-base-white), 100%, 1);
} }
@media (min-width: 50em) {
.nav-groups {
padding: 0;
}
}
@media (min-width: 50em) {
.nav-groups {
padding: 0;
}
}
</style> </style>

View file

@ -2,41 +2,43 @@
import MoreMenu from '../RightSidebar/MoreMenu.astro'; import MoreMenu from '../RightSidebar/MoreMenu.astro';
import TableOfContents from '../RightSidebar/TableOfContents.tsx'; import TableOfContents from '../RightSidebar/TableOfContents.tsx';
const {content, githubEditUrl} = Astro.props; const { content, githubEditUrl } = Astro.props;
const title = content.title; const title = content.title;
const headers = content.astro.headers; const headers = content.astro.headers;
--- ---
<style>
.content {
padding: 0;
max-width: 75ch;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.content > section {
margin-bottom: 4rem;
}
.block {
display: block;
}
@media (min-width: 50em) {
.sm\:hidden {
display: none;
}
}
</style>
<article id="article" class="content"> <article id="article" class="content">
<section class="main-section"> <section class="main-section">
<h1 class="content-title" id="overview">{title}</h1> <h1 class="content-title" id="overview">{title}</h1>
<nav class="block sm:hidden"> <nav class="block sm:hidden">
<TableOfContents client:media="(max-width: 50em)" headers={headers} /> <TableOfContents client:media="(max-width: 50em)" {headers} />
</nav> </nav>
<slot /> <slot />
</section> </section>
<nav class="block sm:hidden"> <nav class="block sm:hidden">
<MoreMenu editHref={githubEditUrl}/> <MoreMenu editHref={githubEditUrl} />
</nav> </nav>
</article> </article>
<style>
.content {
padding: 0;
max-width: 75ch;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.content > section {
margin-bottom: 4rem;
}
.block {
display: block;
}
@media (min-width: 50em) {
.sm\:hidden {
display: none;
}
}
</style>

View file

@ -1,68 +1,70 @@
--- ---
import ThemeToggleButton from './ThemeToggleButton.tsx'; import ThemeToggleButton from './ThemeToggleButton.tsx';
import * as CONFIG from '../../config'; import * as CONFIG from '../../config';
const {editHref} = Astro.props; const { editHref } = Astro.props;
const showMoreSection = (CONFIG.COMMUNITY_INVITE_URL || editHref); const showMoreSection = CONFIG.COMMUNITY_INVITE_URL || editHref;
--- ---
<style>
.edit-on-github {
text-decoration: none;
font: inherit;
color: inherit;
font-size: 1rem;
}
</style>
{showMoreSection && <h2 class="heading">More</h2>} {showMoreSection && <h2 class="heading">More</h2>}
<ul> <ul>
{editHref && {editHref && (
<li class={`header-link depth-2`}> <li class={`header-link depth-2`}>
<a class="edit-on-github" href={editHref} target="_blank"> <a class="edit-on-github" href={editHref} target="_blank">
<svg <svg
aria-hidden="true" aria-hidden="true"
focusable="false" focusable="false"
data-prefix="fas" data-prefix="fas"
data-icon="pen" data-icon="pen"
class="svg-inline--fa fa-pen fa-w-16" class="svg-inline--fa fa-pen fa-w-16"
role="img" role="img"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512" viewBox="0 0 512 512"
height="1em" height="1em"
width="1em" width="1em"
> >
<path <path
fill="currentColor" fill="currentColor"
d="M290.74 93.24l128.02 128.02-277.99 277.99-114.14 12.6C11.35 513.54-1.56 500.62.14 485.34l12.7-114.22 277.9-277.88zm207.2-19.06l-60.11-60.11c-18.75-18.75-49.16-18.75-67.91 0l-56.55 56.55 128.02 128.02 56.55-56.55c18.75-18.76 18.75-49.16 0-67.91z" d="M290.74 93.24l128.02 128.02-277.99 277.99-114.14 12.6C11.35 513.54-1.56 500.62.14 485.34l12.7-114.22 277.9-277.88zm207.2-19.06l-60.11-60.11c-18.75-18.75-49.16-18.75-67.91 0l-56.55 56.55 128.02 128.02 56.55-56.55c18.75-18.76 18.75-49.16 0-67.91z"
></path> ></path>
</svg> </svg>
<span>Edit this page</span> <span>Edit this page</span>
</a> </a>
</li> </li>
} )}
{CONFIG.COMMUNITY_INVITE_URL && {CONFIG.COMMUNITY_INVITE_URL && (
<li class={`header-link depth-2`}> <li class={`header-link depth-2`}>
<a href={CONFIG.COMMUNITY_INVITE_URL} target="_blank"> <a href={CONFIG.COMMUNITY_INVITE_URL} target="_blank">
<svg <svg
aria-hidden="true" aria-hidden="true"
focusable="false" focusable="false"
data-prefix="fas" data-prefix="fas"
data-icon="comment-alt" data-icon="comment-alt"
class="svg-inline--fa fa-comment-alt fa-w-16" class="svg-inline--fa fa-comment-alt fa-w-16"
role="img" role="img"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512" viewBox="0 0 512 512"
height="1em" height="1em"
width="1em" width="1em"
> >
<path <path
fill="currentColor" fill="currentColor"
d="M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 9.8 11.2 15.5 19.1 9.7L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64z" d="M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 9.8 11.2 15.5 19.1 9.7L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64z"
></path> ></path>
</svg> </svg>
<span>Join our community</span> <span>Join our community</span>
</a> </a>
</li> </li>
} )}
</ul> </ul>
<div style="margin: 2rem 0; text-align: center;"> <div style="margin: 2rem 0; text-align: center;">
<ThemeToggleButton client:visible /> <ThemeToggleButton client:visible />
</div> </div>
<style>
.edit-on-github {
text-decoration: none;
font: inherit;
color: inherit;
font-size: 1rem;
}
</style>

View file

@ -1,25 +1,27 @@
--- ---
import TableOfContents from './TableOfContents.tsx'; import TableOfContents from './TableOfContents.tsx';
import MoreMenu from './MoreMenu.astro'; import MoreMenu from './MoreMenu.astro';
const {content, githubEditUrl} = Astro.props; const { content, githubEditUrl } = Astro.props;
const headers = content.astro.headers; const headers = content.astro.headers;
--- ---
<style>
.sidebar-nav {
width: 100%;
position: sticky;
top: 0;
}
.sidebar-nav-inner {
height: 100%;
padding: 0;
padding-top: var(--doc-padding);
overflow: auto;
}
</style>
<nav class="sidebar-nav" aria-labelledby="grid-right"> <nav class="sidebar-nav" aria-labelledby="grid-right">
<div class="sidebar-nav-inner"> <div class="sidebar-nav-inner">
<TableOfContents client:media="(min-width: 50em)" headers={headers} /> <TableOfContents client:media="(min-width: 50em)" {headers} />
<MoreMenu editHref={githubEditUrl} /> <MoreMenu editHref={githubEditUrl} />
</div> </div>
</nav> </nav>
<style>
.sidebar-nav {
width: 100%;
position: sticky;
top: 0;
}
.sidebar-nav-inner {
height: 100%;
padding: 0;
padding-top: var(--doc-padding);
overflow: auto;
}
</style>

View file

@ -3,43 +3,43 @@ import { h, Fragment } from 'preact';
import { useState, useEffect, useRef } from 'preact/hooks'; import { useState, useEffect, useRef } from 'preact/hooks';
const TableOfContents: FunctionalComponent<{ headers: any[] }> = ({ headers = [] }) => { const TableOfContents: FunctionalComponent<{ headers: any[] }> = ({ headers = [] }) => {
const itemOffsets = useRef([]); const itemOffsets = useRef([]);
const [activeId, setActiveId] = useState<string>(undefined); const [activeId, setActiveId] = useState<string>(undefined);
useEffect(() => { useEffect(() => {
const getItemOffsets = () => { const getItemOffsets = () => {
const titles = document.querySelectorAll('article :is(h1, h2, h3, h4)'); const titles = document.querySelectorAll('article :is(h1, h2, h3, h4)');
itemOffsets.current = Array.from(titles).map((title) => ({ itemOffsets.current = Array.from(titles).map((title) => ({
id: title.id, id: title.id,
topOffset: title.getBoundingClientRect().top + window.scrollY, topOffset: title.getBoundingClientRect().top + window.scrollY,
})); }));
}; };
getItemOffsets(); getItemOffsets();
window.addEventListener('resize', getItemOffsets); window.addEventListener('resize', getItemOffsets);
return () => { return () => {
window.removeEventListener('resize', getItemOffsets); window.removeEventListener('resize', getItemOffsets);
}; };
}, []); }, []);
return ( return (
<> <>
<h2 class="heading">On this page</h2> <h2 class="heading">On this page</h2>
<ul> <ul>
<li class={`header-link depth-2 ${activeId === 'overview' ? 'active' : ''}`.trim()}> <li class={`header-link depth-2 ${activeId === 'overview' ? 'active' : ''}`.trim()}>
<a href="#overview">Overview</a> <a href="#overview">Overview</a>
</li> </li>
{headers {headers
.filter(({ depth }) => depth > 1 && depth < 4) .filter(({ depth }) => depth > 1 && depth < 4)
.map((header) => ( .map((header) => (
<li class={`header-link depth-${header.depth} ${activeId === header.slug ? 'active' : ''}`.trim()}> <li class={`header-link depth-${header.depth} ${activeId === header.slug ? 'active' : ''}`.trim()}>
<a href={`#${header.slug}`}>{header.text}</a> <a href={`#${header.slug}`}>{header.text}</a>
</li> </li>
))} ))}
</ul> </ul>
</> </>
); );
}; };
export default TableOfContents; export default TableOfContents;

View file

@ -1,37 +1,37 @@
.theme-toggle { .theme-toggle {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 0.25em; gap: 0.25em;
padding: 0.33em 0.67em; padding: 0.33em 0.67em;
border-radius: 99em; border-radius: 99em;
background-color: var(--theme-code-inline-bg); background-color: var(--theme-code-inline-bg);
} }
.theme-toggle > label:focus-within { .theme-toggle > label:focus-within {
outline: 2px solid transparent; outline: 2px solid transparent;
box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white; box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white;
} }
.theme-toggle > label { .theme-toggle > label {
color: var(--theme-code-inline-text); color: var(--theme-code-inline-text);
position: relative; position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
opacity: 0.5; opacity: 0.5;
} }
.theme-toggle .checked { .theme-toggle .checked {
color: var(--theme-accent); color: var(--theme-accent);
opacity: 1; opacity: 1;
} }
input[name='theme-toggle'] { input[name='theme-toggle'] {
position: absolute; position: absolute;
opacity: 0; opacity: 0;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: -1; z-index: -1;
} }

View file

@ -6,66 +6,66 @@ import './ThemeToggleButton.css';
const themes = ['light', 'dark']; const themes = ['light', 'dark'];
const icons = [ const icons = [
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="currentColor">
<path <path
fillRule="evenodd" fillRule="evenodd"
d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
clipRule="evenodd" clipRule="evenodd"
/> />
</svg>, </svg>,
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="currentColor">
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" /> <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" />
</svg>, </svg>,
]; ];
const ThemeToggle: FunctionalComponent = () => { const ThemeToggle: FunctionalComponent = () => {
const [theme, setTheme] = useState(() => { const [theme, setTheme] = useState(() => {
if (import.meta.env.SSR) { if (import.meta.env.SSR) {
return undefined; return undefined;
} }
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) { if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
return localStorage.getItem('theme'); return localStorage.getItem('theme');
} }
if (window.matchMedia('(prefers-color-scheme: dark)').matches) { if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark'; return 'dark';
} }
return 'light'; return 'light';
}); });
useEffect(() => { useEffect(() => {
const root = document.documentElement; const root = document.documentElement;
if (theme === 'light') { if (theme === 'light') {
root.classList.remove('theme-dark'); root.classList.remove('theme-dark');
} else { } else {
root.classList.add('theme-dark'); root.classList.add('theme-dark');
} }
}, [theme]); }, [theme]);
return ( return (
<div class="theme-toggle"> <div class="theme-toggle">
{themes.map((t, i) => { {themes.map((t, i) => {
const icon = icons[i]; const icon = icons[i];
const checked = t === theme; const checked = t === theme;
return ( return (
<label className={checked ? ' checked' : ''}> <label className={checked ? ' checked' : ''}>
{icon} {icon}
<input <input
type="radio" type="radio"
name="theme-toggle" name="theme-toggle"
checked={checked} checked={checked}
value={t} value={t}
title={`Use ${t} theme`} title={`Use ${t} theme`}
aria-label={`Use ${t} theme`} aria-label={`Use ${t} theme`}
onChange={() => { onChange={() => {
localStorage.setItem('theme', t); localStorage.setItem('theme', t);
setTheme(t); setTheme(t);
}} }}
/> />
</label> </label>
); );
})} })}
</div> </div>
); );
}; };
export default ThemeToggle; export default ThemeToggle;

View file

@ -1,19 +1,19 @@
export const SITE = { export const SITE = {
title: 'Your Documentation Website', title: 'Your Documentation Website',
description: 'Your website description.', description: 'Your website description.',
defaultLanguage: 'en_US', defaultLanguage: 'en_US',
}; };
export const OPEN_GRAPH = { export const OPEN_GRAPH = {
image: { image: {
src: 'https://github.com/withastro/astro/blob/main/assets/social/banner.jpg?raw=true', src: 'https://github.com/withastro/astro/blob/main/assets/social/banner.jpg?raw=true',
alt: 'astro logo on a starry expanse of space,' + ' with a purple saturn-like planet floating in the right foreground', alt: 'astro logo on a starry expanse of space,' + ' with a purple saturn-like planet floating in the right foreground',
}, },
twitter: 'astrodotbuild', twitter: 'astrodotbuild',
}; };
export const KNOWN_LANGUAGES = { export const KNOWN_LANGUAGES = {
English: 'en', English: 'en',
}; };
// Uncomment this to add an "Edit this page" button to every page of documentation. // Uncomment this to add an "Edit this page" button to every page of documentation.
@ -30,14 +30,14 @@ export const KNOWN_LANGUAGES = {
// } // }
export const SIDEBAR = { export const SIDEBAR = {
en: [ en: [
{ text: '', header: true }, { text: '', header: true },
{ text: 'Section Header', header: true }, { text: 'Section Header', header: true },
{ text: 'Introduction', link: 'en/introduction' }, { text: 'Introduction', link: 'en/introduction' },
{ text: 'Page 2', link: 'en/page-2' }, { text: 'Page 2', link: 'en/page-2' },
{ text: 'Page 3', link: 'en/page-3' }, { text: 'Page 3', link: 'en/page-3' },
{ text: 'Another Section', header: true }, { text: 'Another Section', header: true },
{ text: 'Page 4', link: 'en/page-4' }, { text: 'Page 4', link: 'en/page-4' },
], ],
}; };

View file

@ -5,6 +5,6 @@ export const KNOWN_LANGUAGE_CODES = Object.values(KNOWN_LANGUAGES);
export const langPathRegex = /\/([a-z]{2}-?[A-Z]{0,2})\//; export const langPathRegex = /\/([a-z]{2}-?[A-Z]{0,2})\//;
export function getLanguageFromURL(pathname: string) { export function getLanguageFromURL(pathname: string) {
const langCodeMatch = pathname.match(langPathRegex); const langCodeMatch = pathname.match(langPathRegex);
return langCodeMatch ? langCodeMatch[1] : 'en'; return langCodeMatch ? langCodeMatch[1] : 'en';
} }

View file

@ -1,122 +1,122 @@
--- ---
import HeadCommon from "../components/HeadCommon.astro"; import HeadCommon from '../components/HeadCommon.astro';
import HeadSEO from "../components/HeadSEO.astro"; import HeadSEO from '../components/HeadSEO.astro';
import Header from '../components/Header/Header.astro'; import Header from '../components/Header/Header.astro';
import Footer from '../components/Footer/Footer.astro'; import Footer from '../components/Footer/Footer.astro';
import PageContent from '../components/PageContent/PageContent.astro'; import PageContent from '../components/PageContent/PageContent.astro';
import LeftSidebar from '../components/LeftSidebar/LeftSidebar.astro'; import LeftSidebar from '../components/LeftSidebar/LeftSidebar.astro';
import RightSidebar from '../components/RightSidebar/RightSidebar.astro'; import RightSidebar from '../components/RightSidebar/RightSidebar.astro';
import * as CONFIG from "../config"; import * as CONFIG from '../config';
const { content = {} } = Astro.props; const { content = {} } = Astro.props;
const currentPage = Astro.request.url.pathname; const currentPage = Astro.request.url.pathname;
const currentFile = `src/pages${currentPage.replace(/\/$/, "")}.md`; const currentFile = `src/pages${currentPage.replace(/\/$/, '')}.md`;
const githubEditUrl = CONFIG.GITHUB_EDIT_URL && (CONFIG.GITHUB_EDIT_URL + currentFile); const githubEditUrl = CONFIG.GITHUB_EDIT_URL && CONFIG.GITHUB_EDIT_URL + currentFile;
--- ---
<html dir={content.dir ?? 'ltr'} lang={content.lang ?? 'en-us'} class="initial"> <html dir={content.dir ?? 'ltr'} lang={content.lang ?? 'en-us'} class="initial">
<head> <head>
<HeadCommon /> <HeadCommon />
<HeadSEO {content} canonicalURL={Astro.request.canonicalURL} /> <HeadSEO {content} canonicalURL={Astro.request.canonicalURL} />
<title>{content.title ? `${content.title} 🚀 ${CONFIG.SITE.title}` : CONFIG.SITE.title}</title> <title>{content.title ? `${content.title} 🚀 ${CONFIG.SITE.title}` : CONFIG.SITE.title}</title>
<style> <style>
body { body {
width: 100%; width: 100%;
display: grid; display: grid;
grid-template-rows: var(--theme-navbar-height) 1fr; grid-template-rows: var(--theme-navbar-height) 1fr;
--gutter: 0.5rem; --gutter: 0.5rem;
--doc-padding: 2rem; --doc-padding: 2rem;
} }
.layout { .layout {
display: grid; display: grid;
grid-auto-flow: column; grid-auto-flow: column;
grid-template-columns: grid-template-columns:
minmax(var(--gutter), 1fr) minmax(var(--gutter), 1fr)
minmax(0, var(--max-width)) minmax(0, var(--max-width))
minmax(var(--gutter), 1fr); minmax(var(--gutter), 1fr);
overflow-x: hidden; overflow-x: hidden;
} }
.layout :global(> *) { .layout :global(> *) {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.grid-sidebar { .grid-sidebar {
height: 100vh; height: 100vh;
position: sticky; position: sticky;
top: 0; top: 0;
padding: 0; padding: 0;
} }
#grid-left { #grid-left {
position: fixed; position: fixed;
background-color: var(--theme-bg); background-color: var(--theme-bg);
z-index: 10; z-index: 10;
display: none; display: none;
} }
#grid-main { #grid-main {
padding: var(--doc-padding) var(--gutter); padding: var(--doc-padding) var(--gutter);
grid-column: 2; grid-column: 2;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
} }
#grid-right { #grid-right {
display: none; display: none;
} }
:global(.mobile-sidebar-toggle) { :global(.mobile-sidebar-toggle) {
overflow: hidden; overflow: hidden;
} }
:global(.mobile-sidebar-toggle) #grid-left { :global(.mobile-sidebar-toggle) #grid-left {
display: block; display: block;
top: 2rem; top: 2rem;
} }
@media (min-width: 50em) { @media (min-width: 50em) {
.layout { .layout {
overflow: initial; overflow: initial;
grid-template-columns: grid-template-columns:
20rem 20rem
minmax(0, var(--max-width)); minmax(0, var(--max-width));
gap: 1em; gap: 1em;
} }
#grid-left { #grid-left {
display: flex; display: flex;
padding-left: 2rem; padding-left: 2rem;
position: sticky; position: sticky;
grid-column: 1; grid-column: 1;
} }
} }
@media (min-width: 72em) { @media (min-width: 72em) {
.layout { .layout {
grid-template-columns: grid-template-columns:
20rem 20rem
minmax(0, var(--max-width)) minmax(0, var(--max-width))
18rem; 18rem;
padding-left: 0; padding-left: 0;
padding-right: 0; padding-right: 0;
margin: 0 auto; margin: 0 auto;
} }
#grid-right { #grid-right {
grid-column: 3; grid-column: 3;
display: flex; display: flex;
} }
} }
</style> </style>
</head> </head>
<body> <body>
<Header currentPage={currentPage} /> <Header {currentPage} />
<main class="layout"> <main class="layout">
<aside id="grid-left" class="grid-sidebar" title="Site Navigation"> <aside id="grid-left" class="grid-sidebar" title="Site Navigation">
<LeftSidebar currentPage={currentPage} /> <LeftSidebar {currentPage} />
</aside> </aside>
<div id="grid-main"> <div id="grid-main">
<PageContent content={content} githubEditUrl={githubEditUrl}> <PageContent {content} {githubEditUrl}>
<slot /> <slot />
</PageContent> </PageContent>
</div> </div>
<aside id="grid-right" class="grid-sidebar" title="Table of Contents"> <aside id="grid-right" class="grid-sidebar" title="Table of Contents">
<RightSidebar content={content} githubEditUrl={githubEditUrl} /> <RightSidebar {content} {githubEditUrl} />
</aside> </aside>
</main> </main>
</body> </body>
</html> </html>

View file

@ -1,5 +1,5 @@
<script> <script>
// Redirect your homepage to the first page of documentation. // Redirect your homepage to the first page of documentation.
// If you have a landing page, remove this script and add it here! // If you have a landing page, remove this script and add it here!
window.location.pathname = `/en/introduction`; window.location.pathname = `/en/introduction`;
</script> </script>

View file

@ -1,29 +1,29 @@
.language-css > code, .language-css > code,
.language-sass > code, .language-sass > code,
.language-scss > code { .language-scss > code {
color: #fd9170; color: #fd9170;
} }
[class*='language-'] .namespace { [class*='language-'] .namespace {
opacity: 0.7; opacity: 0.7;
} }
.token.plain-text, .token.plain-text,
[class*='language-bash'] span.token, [class*='language-bash'] span.token,
[class*='language-shell'] span.token { [class*='language-shell'] span.token {
color: hsla(var(--color-gray-90), 1); color: hsla(var(--color-gray-90), 1);
} }
[class*='language-bash'] span.token, [class*='language-bash'] span.token,
[class*='language-shell'] span.token { [class*='language-shell'] span.token {
font-style: bold; font-style: bold;
} }
.token.prolog, .token.prolog,
.token.comment, .token.comment,
[class*='language-bash'] span.token.comment, [class*='language-bash'] span.token.comment,
[class*='language-shell'] span.token.comment { [class*='language-shell'] span.token.comment {
color: hsla(var(--color-gray-70), 1); color: hsla(var(--color-gray-70), 1);
} }
.token.selector, .token.selector,
@ -33,7 +33,7 @@
.token.variable, .token.variable,
.token.entity, .token.entity,
.token.deleted { .token.deleted {
color: #fa5e5b; color: #fa5e5b;
} }
.token.boolean, .token.boolean,
@ -46,7 +46,7 @@
.token.hexcode, .token.hexcode,
.token.class-name, .token.class-name,
.token.attr-name { .token.attr-name {
color: hsla(var(--color-yellow), 1); color: hsla(var(--color-yellow), 1);
} }
.token.atrule, .token.atrule,
@ -56,41 +56,41 @@
.token.pseudo-class, .token.pseudo-class,
.token.pseudo-element, .token.pseudo-element,
.token.string { .token.string {
color: hsla(var(--color-green), 1); color: hsla(var(--color-green), 1);
} }
.token.symbol, .token.symbol,
.token.function, .token.function,
.token.id, .token.id,
.token.important { .token.important {
color: hsla(var(--color-blue), 1); color: hsla(var(--color-blue), 1);
} }
.token.important, .token.important,
.token.id { .token.id {
font-weight: bold; font-weight: bold;
} }
.token.cdata, .token.cdata,
.token.char, .token.char,
.token.property { .token.property {
color: #23b1af; color: #23b1af;
} }
.token.inserted { .token.inserted {
color: hsla(var(--color-green), 1); color: hsla(var(--color-green), 1);
} }
.token.keyword { .token.keyword {
color: #ff657c; color: #ff657c;
font-style: italic; font-style: italic;
} }
.token.operator { .token.operator {
color: hsla(var(--color-gray-70), 1); color: hsla(var(--color-gray-70), 1);
} }
.token.attr-value .token.attr-equals, .token.attr-value .token.attr-equals,
.token.punctuation { .token.punctuation {
color: hsla(var(--color-gray-80), 1); color: hsla(var(--color-gray-80), 1);
} }

View file

@ -1,46 +1,46 @@
* { * {
box-sizing: border-box; box-sizing: border-box;
margin: 0; margin: 0;
} }
/* Global focus outline reset */ /* Global focus outline reset */
*:focus:not(:focus-visible) { *:focus:not(:focus-visible) {
outline: none; outline: none;
} }
:root { :root {
--user-font-scale: 1rem - 16px; --user-font-scale: 1rem - 16px;
--max-width: calc(100% - 1rem); --max-width: calc(100% - 1rem);
} }
@media (min-width: 50em) { @media (min-width: 50em) {
:root { :root {
--max-width: 46em; --max-width: 46em;
} }
} }
body { body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 100vh; min-height: 100vh;
font-family: var(--font-body); font-family: var(--font-body);
font-size: 1rem; font-size: 1rem;
font-size: clamp(0.9rem, 0.75rem + 0.375vw + var(--user-font-scale), 1rem); font-size: clamp(0.9rem, 0.75rem + 0.375vw + var(--user-font-scale), 1rem);
line-height: 1.5; line-height: 1.5;
max-width: 100vw; max-width: 100vw;
} }
nav ul { nav ul {
list-style: none; list-style: none;
padding: 0; padding: 0;
} }
.content > section > * + * { .content > section > * + * {
margin-top: 1.25rem; margin-top: 1.25rem;
} }
.content > section > :first-child { .content > section > :first-child {
margin-top: 0; margin-top: 0;
} }
/* Typography */ /* Typography */
@ -50,339 +50,339 @@ h3,
h4, h4,
h5, h5,
h6 { h6 {
margin-bottom: 1rem; margin-bottom: 1rem;
font-weight: bold; font-weight: bold;
line-height: 1; line-height: 1;
} }
h1, h1,
h2 { h2 {
max-width: 40ch; max-width: 40ch;
} }
:is(h2, h3):not(:first-child) { :is(h2, h3):not(:first-child) {
margin-top: 3rem; margin-top: 3rem;
} }
:is(h4, h5, h6):not(:first-child) { :is(h4, h5, h6):not(:first-child) {
margin-top: 2rem; margin-top: 2rem;
} }
h1 { h1 {
font-size: 3.25rem; font-size: 3.25rem;
font-weight: 800; font-weight: 800;
} }
h2 { h2 {
font-size: 2.5rem; font-size: 2.5rem;
} }
h3 { h3 {
font-size: 1.75rem; font-size: 1.75rem;
} }
h4 { h4 {
font-size: 1.3rem; font-size: 1.3rem;
} }
h5 { h5 {
font-size: 1rem; font-size: 1rem;
} }
p { p {
line-height: 1.65em; line-height: 1.65em;
} }
.content ul { .content ul {
line-height: 1.1em; line-height: 1.1em;
} }
p, p,
.content ul { .content ul {
color: var(--theme-text-light); color: var(--theme-text-light);
} }
small, small,
.text_small { .text_small {
font-size: 0.833rem; font-size: 0.833rem;
} }
a { a {
color: var(--theme-text-accent); color: var(--theme-text-accent);
font-weight: 400; font-weight: 400;
text-underline-offset: 0.08em; text-underline-offset: 0.08em;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
} }
article > section :is(ul, ol) > * + * { article > section :is(ul, ol) > * + * {
margin-top: 0.75rem; margin-top: 0.75rem;
} }
article > section nav :is(ul, ol) > * + * { article > section nav :is(ul, ol) > * + * {
margin-top: inherit; margin-top: inherit;
} }
article > section li > :is(p, pre, blockquote):not(:first-child) { article > section li > :is(p, pre, blockquote):not(:first-child) {
margin-top: 1rem; margin-top: 1rem;
} }
article > section :is(ul, ol) { article > section :is(ul, ol) {
padding-left: 1em; padding-left: 1em;
} }
article > section nav :is(ul, ol) { article > section nav :is(ul, ol) {
padding-left: inherit; padding-left: inherit;
} }
article > section nav { article > section nav {
margin-top: 1rem; margin-top: 1rem;
margin-bottom: 2rem; margin-bottom: 2rem;
} }
article > section ::marker { article > section ::marker {
font-weight: bold; font-weight: bold;
color: var(--theme-text-light); color: var(--theme-text-light);
} }
article > section iframe { article > section iframe {
width: 100%; width: 100%;
height: auto; height: auto;
aspect-ratio: 16 / 9; aspect-ratio: 16 / 9;
} }
a > code:not([class*='language']) { a > code:not([class*='language']) {
position: relative; position: relative;
color: var(--theme-text-accent); color: var(--theme-text-accent);
background: transparent; background: transparent;
text-underline-offset: var(--padding-block); text-underline-offset: var(--padding-block);
} }
a > code:not([class*='language'])::before { a > code:not([class*='language'])::before {
content: ''; content: '';
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
display: block; display: block;
background: var(--theme-accent); background: var(--theme-accent);
opacity: var(--theme-accent-opacity); opacity: var(--theme-accent-opacity);
border-radius: var(--border-radius); border-radius: var(--border-radius);
} }
a:hover, a:hover,
a:focus { a:focus {
text-decoration: underline; text-decoration: underline;
} }
a:focus { a:focus {
outline: 2px solid currentColor; outline: 2px solid currentColor;
outline-offset: 0.25em; outline-offset: 0.25em;
} }
strong { strong {
font-weight: 600; font-weight: 600;
color: inherit; color: inherit;
} }
/* Supporting Content */ /* Supporting Content */
code { code {
font-family: var(--font-mono); font-family: var(--font-mono);
font-size: 0.85em; font-size: 0.85em;
} }
code:not([class*='language']) { code:not([class*='language']) {
--border-radius: 3px; --border-radius: 3px;
--padding-block: 0.2rem; --padding-block: 0.2rem;
--padding-inline: 0.4rem; --padding-inline: 0.4rem;
color: var(--theme-code-inline-text); color: var(--theme-code-inline-text);
background-color: var(--theme-code-inline-bg); background-color: var(--theme-code-inline-bg);
padding: var(--padding-block) var(--padding-inline); padding: var(--padding-block) var(--padding-inline);
margin: calc(var(--padding-block) * -1) -0.125em; margin: calc(var(--padding-block) * -1) -0.125em;
border-radius: var(--border-radius); border-radius: var(--border-radius);
box-shadow: 0 2px 1px 0 rgba(0, 0, 0, 0.08); box-shadow: 0 2px 1px 0 rgba(0, 0, 0, 0.08);
word-break: break-word; word-break: break-word;
} }
pre > code:not([class*='language']) { pre > code:not([class*='language']) {
background-color: transparent; background-color: transparent;
padding: 0; padding: 0;
margin: 0; margin: 0;
border-radius: 0; border-radius: 0;
color: inherit; color: inherit;
} }
pre > code { pre > code {
font-size: 1em; font-size: 1em;
} }
table, table,
pre { pre {
position: relative; position: relative;
--padding-block: 1rem; --padding-block: 1rem;
--padding-inline: 2rem; --padding-inline: 2rem;
padding: var(--padding-block) var(--padding-inline); padding: var(--padding-block) var(--padding-inline);
padding-right: calc(var(--padding-inline) * 2); padding-right: calc(var(--padding-inline) * 2);
margin-left: calc(var(--padding-inline) * -1); margin-left: calc(var(--padding-inline) * -1);
margin-right: calc(var(--padding-inline) * -1); margin-right: calc(var(--padding-inline) * -1);
font-family: var(--font-mono); font-family: var(--font-mono);
line-height: 1.5; line-height: 1.5;
font-size: 0.85em; font-size: 0.85em;
overflow-y: hidden; overflow-y: hidden;
overflow-x: auto; overflow-x: auto;
} }
table { table {
width: 100%; width: 100%;
padding: var(--padding-block) 0; padding: var(--padding-block) 0;
margin: 0; margin: 0;
border-collapse: collapse; border-collapse: collapse;
} }
/* Zebra striping */ /* Zebra striping */
tr:nth-of-type(odd) { tr:nth-of-type(odd) {
background: var(--theme-bg-hover); background: var(--theme-bg-hover);
} }
th { th {
background: var(--color-black); background: var(--color-black);
color: var(--theme-color); color: var(--theme-color);
font-weight: bold; font-weight: bold;
} }
td, td,
th { th {
padding: 6px; padding: 6px;
text-align: left; text-align: left;
} }
pre { pre {
background-color: var(--theme-code-bg); background-color: var(--theme-code-bg);
color: var(--theme-code-text); color: var(--theme-code-text);
} }
blockquote code:not([class*='language']) { blockquote code:not([class*='language']) {
background-color: var(--theme-bg); background-color: var(--theme-bg);
} }
@media (min-width: 37.75em) { @media (min-width: 37.75em) {
pre { pre {
--padding-inline: 1.25rem; --padding-inline: 1.25rem;
border-radius: 8px; border-radius: 8px;
margin-left: 0; margin-left: 0;
margin-right: 0; margin-right: 0;
} }
} }
blockquote { blockquote {
margin: 2rem 0; margin: 2rem 0;
padding: 1.25em 1.5rem; padding: 1.25em 1.5rem;
border-left: 3px solid var(--theme-text-light); border-left: 3px solid var(--theme-text-light);
background-color: var(--theme-bg-offset); background-color: var(--theme-bg-offset);
border-radius: 0 0.25rem 0.25rem 0; border-radius: 0 0.25rem 0.25rem 0;
line-height: 1.7; line-height: 1.7;
} }
img { img {
max-width: 100%; max-width: 100%;
} }
.flex { .flex {
display: flex; display: flex;
align-items: center; align-items: center;
} }
button { button {
display: flex; display: flex;
align-items: center; align-items: center;
justify-items: center; justify-items: center;
gap: 0.25em; gap: 0.25em;
padding: 0.33em 0.67em; padding: 0.33em 0.67em;
border: 0; border: 0;
background: var(--theme-bg); background: var(--theme-bg);
display: flex; display: flex;
font-size: 1rem; font-size: 1rem;
align-items: center; align-items: center;
gap: 0.25em; gap: 0.25em;
border-radius: 99em; border-radius: 99em;
color: var(--theme-text); color: var(--theme-text);
background-color: var(--theme-bg); background-color: var(--theme-bg);
} }
h2.heading { h2.heading {
font-size: 1rem; font-size: 1rem;
font-weight: 700; font-weight: 700;
padding: 0.1rem 1rem; padding: 0.1rem 1rem;
text-transform: uppercase; text-transform: uppercase;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.header-link { .header-link {
font-size: 1rem; font-size: 1rem;
padding: 0.1rem 0 0.1rem 1rem; padding: 0.1rem 0 0.1rem 1rem;
border-left: 4px solid var(--theme-divider); border-left: 4px solid var(--theme-divider);
} }
.header-link:hover, .header-link:hover,
.header-link:focus { .header-link:focus {
border-left-color: var(--theme-accent); border-left-color: var(--theme-accent);
color: var(--theme-accent); color: var(--theme-accent);
} }
.header-link:focus-within { .header-link:focus-within {
color: var(--theme-text-light); color: var(--theme-text-light);
border-left-color: hsla(var(--color-gray-40), 1); border-left-color: hsla(var(--color-gray-40), 1);
} }
.header-link svg { .header-link svg {
opacity: 0.6; opacity: 0.6;
} }
.header-link:hover svg { .header-link:hover svg {
opacity: 0.8; opacity: 0.8;
} }
.header-link a { .header-link a {
display: inline-flex; display: inline-flex;
gap: 0.5em; gap: 0.5em;
width: 100%; width: 100%;
padding: 0.15em 0 0.15em 0; padding: 0.15em 0 0.15em 0;
} }
.header-link.depth-3 { .header-link.depth-3 {
padding-left: 2rem; padding-left: 2rem;
} }
.header-link.depth-4 { .header-link.depth-4 {
padding-left: 3rem; padding-left: 3rem;
} }
.header-link a { .header-link a {
font: inherit; font: inherit;
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
} }
/* Screenreader Only Text */ /* Screenreader Only Text */
.sr-only { .sr-only {
position: absolute; position: absolute;
width: 1px; width: 1px;
height: 1px; height: 1px;
padding: 0; padding: 0;
margin: -1px; margin: -1px;
overflow: hidden; overflow: hidden;
clip: rect(0, 0, 0, 0); clip: rect(0, 0, 0, 0);
white-space: nowrap; white-space: nowrap;
border-width: 0; border-width: 0;
} }
.focus\:not-sr-only:focus, .focus\:not-sr-only:focus,
.focus\:not-sr-only:focus-visible { .focus\:not-sr-only:focus-visible {
position: static; position: static;
width: auto; width: auto;
height: auto; height: auto;
padding: 0; padding: 0;
margin: 0; margin: 0;
overflow: visible; overflow: visible;
clip: auto; clip: auto;
white-space: normal; white-space: normal;
} }
:target { :target {
scroll-margin: calc(var(--theme-sidebar-offset, 5rem) + 2rem) 0 2rem; scroll-margin: calc(var(--theme-sidebar-offset, 5rem) + 2rem) 0 2rem;
} }

View file

@ -1,10 +1,10 @@
:root { :root {
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji; --font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
--font-body: system-ui, var(--font-fallback); --font-body: system-ui, var(--font-fallback);
--font-mono: 'IBM Plex Mono', Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', --font-mono: 'IBM Plex Mono', Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono',
'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace; 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace;
/* /*
* Variables with --color-base prefix define * Variables with --color-base prefix define
* the hue, and saturation values to be used for * the hue, and saturation values to be used for
* hsla colors. * hsla colors.
@ -15,109 +15,109 @@
* *
*/ */
--color-base-white: 0, 0%; --color-base-white: 0, 0%;
--color-base-black: 240, 100%; --color-base-black: 240, 100%;
--color-base-gray: 215, 14%; --color-base-gray: 215, 14%;
--color-base-blue: 212, 100%; --color-base-blue: 212, 100%;
--color-base-blue-dark: 212, 72%; --color-base-blue-dark: 212, 72%;
--color-base-green: 158, 79%; --color-base-green: 158, 79%;
--color-base-orange: 22, 100%; --color-base-orange: 22, 100%;
--color-base-purple: 269, 79%; --color-base-purple: 269, 79%;
--color-base-red: 351, 100%; --color-base-red: 351, 100%;
--color-base-yellow: 41, 100%; --color-base-yellow: 41, 100%;
/* /*
* Color palettes are made using --color-base * Color palettes are made using --color-base
* variables, along with a lightness value to * variables, along with a lightness value to
* define different variants. * define different variants.
* *
*/ */
--color-gray-5: var(--color-base-gray), 5%; --color-gray-5: var(--color-base-gray), 5%;
--color-gray-10: var(--color-base-gray), 10%; --color-gray-10: var(--color-base-gray), 10%;
--color-gray-20: var(--color-base-gray), 20%; --color-gray-20: var(--color-base-gray), 20%;
--color-gray-30: var(--color-base-gray), 30%; --color-gray-30: var(--color-base-gray), 30%;
--color-gray-40: var(--color-base-gray), 40%; --color-gray-40: var(--color-base-gray), 40%;
--color-gray-50: var(--color-base-gray), 50%; --color-gray-50: var(--color-base-gray), 50%;
--color-gray-60: var(--color-base-gray), 60%; --color-gray-60: var(--color-base-gray), 60%;
--color-gray-70: var(--color-base-gray), 70%; --color-gray-70: var(--color-base-gray), 70%;
--color-gray-80: var(--color-base-gray), 80%; --color-gray-80: var(--color-base-gray), 80%;
--color-gray-90: var(--color-base-gray), 90%; --color-gray-90: var(--color-base-gray), 90%;
--color-gray-95: var(--color-base-gray), 95%; --color-gray-95: var(--color-base-gray), 95%;
--color-blue: var(--color-base-blue), 61%; --color-blue: var(--color-base-blue), 61%;
--color-blue-dark: var(--color-base-blue-dark), 39%; --color-blue-dark: var(--color-base-blue-dark), 39%;
--color-green: var(--color-base-green), 42%; --color-green: var(--color-base-green), 42%;
--color-orange: var(--color-base-orange), 50%; --color-orange: var(--color-base-orange), 50%;
--color-purple: var(--color-base-purple), 54%; --color-purple: var(--color-base-purple), 54%;
--color-red: var(--color-base-red), 54%; --color-red: var(--color-base-red), 54%;
--color-yellow: var(--color-base-yellow), 59%; --color-yellow: var(--color-base-yellow), 59%;
} }
:root { :root {
color-scheme: light; color-scheme: light;
--theme-accent: hsla(var(--color-blue), 1); --theme-accent: hsla(var(--color-blue), 1);
--theme-text-accent: hsla(var(--color-blue), 1); --theme-text-accent: hsla(var(--color-blue), 1);
--theme-accent-opacity: 0.15; --theme-accent-opacity: 0.15;
--theme-divider: hsla(var(--color-gray-95), 1); --theme-divider: hsla(var(--color-gray-95), 1);
--theme-text: hsla(var(--color-gray-10), 1); --theme-text: hsla(var(--color-gray-10), 1);
--theme-text-light: hsla(var(--color-gray-40), 1); --theme-text-light: hsla(var(--color-gray-40), 1);
/* @@@: not used anywhere */ /* @@@: not used anywhere */
--theme-text-lighter: hsla(var(--color-gray-80), 1); --theme-text-lighter: hsla(var(--color-gray-80), 1);
--theme-bg: hsla(var(--color-base-white), 100%, 1); --theme-bg: hsla(var(--color-base-white), 100%, 1);
--theme-bg-hover: hsla(var(--color-gray-95), 1); --theme-bg-hover: hsla(var(--color-gray-95), 1);
--theme-bg-offset: hsla(var(--color-gray-90), 1); --theme-bg-offset: hsla(var(--color-gray-90), 1);
--theme-bg-accent: hsla(var(--color-blue), var(--theme-accent-opacity)); --theme-bg-accent: hsla(var(--color-blue), var(--theme-accent-opacity));
--theme-code-inline-bg: hsla(var(--color-gray-95), 1); --theme-code-inline-bg: hsla(var(--color-gray-95), 1);
--theme-code-inline-text: var(--theme-text); --theme-code-inline-text: var(--theme-text);
--theme-code-bg: hsla(217, 19%, 27%, 1); --theme-code-bg: hsla(217, 19%, 27%, 1);
--theme-code-text: hsla(var(--color-gray-95), 1); --theme-code-text: hsla(var(--color-gray-95), 1);
--theme-navbar-bg: hsla(var(--color-base-white), 100%, 1); --theme-navbar-bg: hsla(var(--color-base-white), 100%, 1);
--theme-navbar-height: 6rem; --theme-navbar-height: 6rem;
--theme-selection-color: hsla(var(--color-blue), 1); --theme-selection-color: hsla(var(--color-blue), 1);
--theme-selection-bg: hsla(var(--color-blue), var(--theme-accent-opacity)); --theme-selection-bg: hsla(var(--color-blue), var(--theme-accent-opacity));
} }
body { body {
background: var(--theme-bg); background: var(--theme-bg);
color: var(--theme-text); color: var(--theme-text);
} }
:root.theme-dark { :root.theme-dark {
color-scheme: dark; color-scheme: dark;
--theme-accent-opacity: 0.15; --theme-accent-opacity: 0.15;
--theme-accent: hsla(var(--color-blue), 1); --theme-accent: hsla(var(--color-blue), 1);
--theme-text-accent: hsla(var(--color-blue), 1); --theme-text-accent: hsla(var(--color-blue), 1);
--theme-divider: hsla(var(--color-gray-10), 1); --theme-divider: hsla(var(--color-gray-10), 1);
--theme-text: hsla(var(--color-gray-90), 1); --theme-text: hsla(var(--color-gray-90), 1);
--theme-text-light: hsla(var(--color-gray-80), 1); --theme-text-light: hsla(var(--color-gray-80), 1);
/* @@@: not used anywhere */ /* @@@: not used anywhere */
--theme-text-lighter: hsla(var(--color-gray-40), 1); --theme-text-lighter: hsla(var(--color-gray-40), 1);
--theme-bg: hsla(215, 28%, 17%, 1); --theme-bg: hsla(215, 28%, 17%, 1);
--theme-bg-hover: hsla(var(--color-gray-40), 1); --theme-bg-hover: hsla(var(--color-gray-40), 1);
--theme-bg-offset: hsla(var(--color-gray-5), 1); --theme-bg-offset: hsla(var(--color-gray-5), 1);
--theme-code-inline-bg: hsla(var(--color-gray-10), 1); --theme-code-inline-bg: hsla(var(--color-gray-10), 1);
--theme-code-inline-text: hsla(var(--color-base-white), 100%, 1); --theme-code-inline-text: hsla(var(--color-base-white), 100%, 1);
--theme-code-bg: hsla(var(--color-gray-5), 1); --theme-code-bg: hsla(var(--color-gray-5), 1);
--theme-code-text: hsla(var(--color-base-white), 100%, 1); --theme-code-text: hsla(var(--color-base-white), 100%, 1);
--theme-navbar-bg: hsla(215, 28%, 17%, 1); --theme-navbar-bg: hsla(215, 28%, 17%, 1);
--theme-selection-color: hsla(var(--color-base-white), 100%, 1); --theme-selection-color: hsla(var(--color-base-white), 100%, 1);
--theme-selection-bg: hsla(var(--color-purple), var(--theme-accent-opacity)); --theme-selection-bg: hsla(var(--color-purple), var(--theme-accent-opacity));
/* DocSearch [Algolia] */ /* DocSearch [Algolia] */
--docsearch-modal-background: var(--theme-bg); --docsearch-modal-background: var(--theme-bg);
--docsearch-searchbox-focus-background: var(--theme-divider); --docsearch-searchbox-focus-background: var(--theme-divider);
--docsearch-footer-background: var(--theme-divider); --docsearch-footer-background: var(--theme-divider);
--docsearch-text-color: var(--theme-text); --docsearch-text-color: var(--theme-text);
--docsearch-hit-background: var(--theme-divider); --docsearch-hit-background: var(--theme-divider);
--docsearch-hit-shadow: none; --docsearch-hit-shadow: none;
--docsearch-hit-color: var(--theme-text); --docsearch-hit-color: var(--theme-text);
--docsearch-footer-shadow: inset 0 2px 10px #000; --docsearch-footer-shadow: inset 0 2px 10px #000;
--docsearch-modal-shadow: inset 0 0 8px #000; --docsearch-modal-shadow: inset 0 0 8px #000;
} }
::selection { ::selection {
color: var(--theme-selection-color); color: var(--theme-selection-color);
background-color: var(--theme-selection-bg); background-color: var(--theme-selection-bg);
} }

View file

@ -2,8 +2,8 @@ import { imagetools } from 'vite-imagetools';
// @ts-check // @ts-check
export default /** @type {import('astro').AstroUserConfig} */ ({ export default /** @type {import('astro').AstroUserConfig} */ ({
renderers: ['@astrojs/renderer-vue'], renderers: ['@astrojs/renderer-vue'],
vite: { vite: {
plugins: [imagetools()], plugins: [imagetools()],
}, },
}); });

View file

@ -1,20 +1,20 @@
<script> <script>
export default { export default {
data() { data() {
return { return {
greeting: 'Hello World!', greeting: 'Hello World!',
}; };
}, },
}; };
</script> </script>
<template> <template>
<p class="greeting">{{ greeting }}</p> <p class="greeting">{{ greeting }}</p>
</template> </template>
<style> <style>
.greeting { .greeting {
color: red; color: red;
font-weight: bold; font-weight: bold;
} }
</style> </style>

View file

@ -5,28 +5,30 @@ import Greeting from '../components/Greeting.vue';
--- ---
<html> <html>
<head> <head>
<title>Demo app</title> <title>Demo app</title>
<style> <style>
h1 { color: salmon; } h1 {
</style> color: salmon;
</head> }
<body> </style>
<section> </head>
<h1>Images</h1> <body>
<section>
<h1>Images</h1>
<h2>Imported in JS</h2> <h2>Imported in JS</h2>
<img src={imgUrl} /> <img src={imgUrl} />
</section> </section>
<section> <section>
<h1>Component CSS</h1> <h1>Component CSS</h1>
<Greeting /> <Greeting />
</section> </section>
<section> <section>
<h1>ImageTools</h1> <h1>ImageTools</h1>
<img src={grayscaleUrl} /> <img src={grayscaleUrl} />
</section> </section>
</body> </body>
</html> </html>

Some files were not shown because too many files have changed in this diff Show more