Skip to content

Commit

Permalink
Merge branch 'main' into hd-feat-docs-components
Browse files Browse the repository at this point in the history
* main: (37 commits)
  [ci] format
  i18n(ko-KR): update `manual-setup.mdx` (withastro#2294)
  i18n(ko-KR): update `configuration.mdx` (withastro#2295)
  [ci] release (withastro#2292)
  Add support for SSR (withastro#1255)
  Add Markdoc preset and example (withastro#2249)
  Refactor sidebar persistence logic for better slow device performance (withastro#2242)
  [ci] format
  Add docs.ryzekit.com to showcase (withastro#2291)
  Update astro dependency to 4.15.3 across monorepo (withastro#2289)
  [ci] release (withastro#2290)
  Prevent Zod errors from crashing build (withastro#2288)
  i18n(fr): update `guides/css-and-tailwind` (withastro#2286)
  i18n(ko-KR): update `css-and-tailwind.mdx` (withastro#2284)
  Add WCAG AAA colour contrast option to theme editor (withastro#2282)
  [ci] release (withastro#2283)
  Parse `<StarlightPage />` frontmatter asynchronously (withastro#2279)
  Ensure unhandled directives are restored without any extra whitespace (withastro#2281)
  i18n(fr): update `resources/plugins` (withastro#2278)
  i18n(ko-KR): update `plugins.mdx` (withastro#2277)
  ...
  • Loading branch information
HiDeoo committed Sep 7, 2024
2 parents 1b3e216 + 21b5932 commit 1ac47f1
Show file tree
Hide file tree
Showing 137 changed files with 3,201 additions and 1,212 deletions.
3 changes: 3 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,8 @@ i18n:
'🌟 tailwind':
- packages/tailwind/**

'🌟 markdoc':
- packages/markdoc/**

'📚 docs':
- docs/**
File renamed without changes.
12 changes: 12 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"cwd": "${workspaceFolder}/docs",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}
4 changes: 3 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ E2E are most useful for testing what happens on a page after it has been loaded
Translations help make Starlight accessible to more people.
Check out the dedicated [i18n contribution guidelines](https://contribute.docs.astro.build/guides/i18n/#quality-standards--adaptation) in the Astro docs contributor guide for more details regarding our translation process and quality standards.
### Translating Starlight’s UI
Starlight’s UI comes with some built-in text elements. For example, the table of contents on a Starlight page has a heading of “On this page” and the theme picker shows “Light”, “Dark”, and “Auto” labels. Starlight aims to provide these in as many languages as possible.
Expand All @@ -244,7 +246,7 @@ Visit **<https://i18n.starlight.astro.build>** to track translation progress for
#### Adding a new language to Starlight’s docs
To add a language, you will need its BCP-47 tag and a label. See [“Adding a new language”](https://contribute.docs.astro.build/guides/i18n/#adding-a-new-language) in the Astro docs repo for some helpful tips around choosing these.
To add a language, you will need its BCP-47 tag and a label. See [“Adding a new language”](https://contribute.docs.astro.build/guides/i18n/#adding-a-new-language) in the Astro docs contributor guide for some helpful tips around choosing these.
- Add your language to the `locales` config in `docs/astro.config.mjs`
- Add your language to the `locales` config in `docs/lunaria.config.json`
Expand Down
8 changes: 4 additions & 4 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
"@astro-community/astro-embed-youtube": "^0.5.2",
"@astrojs/starlight": "workspace:*",
"@lunariajs/core": "^0.1.1",
"@types/culori": "^2.0.0",
"astro": "^4.10.2",
"culori": "^3.2.0",
"@types/culori": "^2.1.1",
"astro": "^4.15.3",
"culori": "^4.0.1",
"sharp": "^0.32.5"
},
"devDependencies": {
"pa11y-ci": "^3.0.1",
"starlight-links-validator": "^0.9.0",
"starlight-links-validator": "^0.11.0",
"start-server-and-test": "^2.0.4"
}
}
Binary file added docs/src/assets/showcase/docs.ryzekit.com.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/src/assets/showcase/yummacss.com.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions docs/src/components/showcase-sites.astro
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,10 @@ import FluidGrid from './fluid-grid.astro';
href="https://developers.cloudflare.com/"
thumbnail="developers.cloudflare.com.png"
/>
<Card title="Yumma CSS" href="https://www.yummacss.com/" thumbnail="yummacss.com.png" />
<Card
title="RyzeKit Astro SaaS Starter"
href="https://docs.ryzekit.com/"
thumbnail="docs.ryzekit.com.png"
/>
</FluidGrid>
17 changes: 14 additions & 3 deletions docs/src/components/theme-designer.astro
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
---
import { TabItem, Tabs } from '@astrojs/starlight/components';
import ColorEditor, { type Props as EditorProps } from './theme-designer/color-editor.astro';
import ContrastLevel, {
type Props as ContrastLevelProps,
} from './theme-designer/contrast-level.astro';
import Presets, { type Props as PresetsProps } from './theme-designer/presets.astro';
import Preview from './theme-designer/preview.astro';
interface Props {
labels: {
presets: PresetsProps['labels'];
contrast: ContrastLevelProps['labels'];
editor: EditorProps['labels'] & { accentColor: string; grayColor: string };
preview: Record<
'darkMode' | 'lightMode' | 'bodyText' | 'linkText' | 'dimText' | 'inlineCode',
Expand All @@ -15,12 +19,14 @@ interface Props {
};
}
const {
labels: { presets, editor, preview },
labels: { presets, contrast, editor, preview },
} = Astro.props;
---

<Presets labels={presets} />

<ContrastLevel labels={contrast} />

<div>
<theme-designer>
<div class="sl-flex controls not-content">
Expand Down Expand Up @@ -52,7 +58,7 @@ const {

<script>
import { getPalettes } from './theme-designer/color-lib';
import { store } from './theme-designer/store';
import { store, minimumContrast } from './theme-designer/store';

class ThemeDesigner extends HTMLElement {
#stylesheet = new CSSStyleSheet();
Expand All @@ -65,10 +71,15 @@ const {
const onInput = () => this.#update();
store.accent.subscribe(onInput);
store.gray.subscribe(onInput);
minimumContrast.subscribe(onInput);
}

#update() {
const palettes = getPalettes({ accent: store.accent.get(), gray: store.gray.get() });
const palettes = getPalettes({
accent: store.accent.get(),
gray: store.gray.get(),
minimumContrast: minimumContrast.get(),
});
this.#updatePreview(palettes);
this.#updateStylesheet(palettes);
this.#updateTailwindConfig(palettes);
Expand Down
4 changes: 4 additions & 0 deletions docs/src/components/theme-designer/atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ export function map<T extends Record<string, unknown>>(value: T): MapStore<T> {
};
return atom;
}

export function atom<T extends unknown>(value: T): Atom<T> {
return new Atom(value);
}
120 changes: 92 additions & 28 deletions docs/src/components/theme-designer/color-lib.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,121 @@
import { useMode, modeOklch, modeRgb, formatHex, clampChroma } from 'culori/fn';
import {
clampChroma,
formatHex,
modeLrgb,
modeOklch,
modeRgb,
useMode,
wcagContrast,
type Oklch,
} from 'culori/fn';

const rgb = useMode(modeRgb);
export const oklch = useMode(modeOklch);
// We need to initialise LRGB support for culori’s `wcagContrast()` method.
useMode(modeLrgb);

/** Convert an OKLCH color to an RGB hex code. */
export const oklchToHex = (l: number, c: number, h: number) => {
const okLchColor = oklch(`oklch(${l}% ${c} ${h})`)!;
/** Convert a culori OKLCH color object to an RGB hex code. */
const oklchColorToHex = (okLchColor: Oklch) => {
const rgbColor = rgb(clampChroma(okLchColor, 'oklch'));
return formatHex(rgbColor);
};
/** Construct a culori OKLCH color object from LCH parameters. */
const oklchColorFromParts = (l: number, c: number, h: number) => oklch(`oklch(${l}% ${c} ${h})`)!;
/** Convert OKLCH parameters to an RGB hex code. */
export const oklchToHex = (l: number, c: number, h: number) =>
oklchColorToHex(oklchColorFromParts(l, c, h));

/**
* Ensure a text colour passes a contrast threshold against a specific background colour.
* If necessary, colours will be darkened/lightened to increase contrast until the threshold is passed.
*
* @param text The text colour to adjust if necessary.
* @param bg The background colour to test contrast against.
* @param threshold The minimum contrast ratio required. Defaults to `4.5` to meet WCAG AA standards.
* @returns The adjusted text colour as a culori OKLCH color object.
*/
const contrastColor = (text: Oklch, bg: Oklch, threshold = 4.5): Oklch => {
/** Clone of the input foreground colour to mutate. */
const fgColor = { ...text };
// Brighten text in dark mode, darken text in light mode.
const increment = fgColor.l > bg.l ? 0.005 : -0.005;
while (wcagContrast(fgColor, bg) < threshold && fgColor.l < 100 && fgColor.l > 0) {
fgColor.l += increment;
}
return fgColor;
};

/** Generate dark and light palettes based on user-selected hue and chroma values. */
export function getPalettes(config: {
accent: { hue: number; chroma: number };
gray: { hue: number; chroma: number };
minimumContrast?: number;
}) {
const {
accent: { hue: ah, chroma: ac },
gray: { hue: gh, chroma: gc },
minimumContrast: mc,
} = config;
return {

const palettes = {
dark: {
// Accents
'accent-low': oklchToHex(25.94, ac / 3, ah),
accent: oklchToHex(52.28, ac, ah),
'accent-high': oklchToHex(83.38, ac / 3, ah),
'accent-low': oklchColorFromParts(25.94, ac / 3, ah),
accent: oklchColorFromParts(52.28, ac, ah),
'accent-high': oklchColorFromParts(83.38, ac / 3, ah),
// Grays
white: oklchToHex(100, 0, 0),
'gray-1': oklchToHex(94.77, gc / 2.5, gh),
'gray-2': oklchToHex(81.34, gc / 2, gh),
'gray-3': oklchToHex(63.78, gc, gh),
'gray-4': oklchToHex(46.01, gc, gh),
'gray-5': oklchToHex(34.09, gc, gh),
'gray-6': oklchToHex(27.14, gc, gh),
black: oklchToHex(20.94, gc / 2, gh),
white: oklchColorFromParts(100, 0, 0),
'gray-1': oklchColorFromParts(94.77, gc / 2.5, gh),
'gray-2': oklchColorFromParts(81.34, gc / 2, gh),
'gray-3': oklchColorFromParts(63.78, gc, gh),
'gray-4': oklchColorFromParts(46.01, gc, gh),
'gray-5': oklchColorFromParts(34.09, gc, gh),
'gray-6': oklchColorFromParts(27.14, gc, gh),
black: oklchColorFromParts(20.94, gc / 2, gh),
},
light: {
// Accents
'accent-low': oklchToHex(87.81, ac / 4, ah),
accent: oklchToHex(52.95, ac, ah),
'accent-high': oklchToHex(31.77, ac / 2, ah),
'accent-low': oklchColorFromParts(87.81, ac / 4, ah),
accent: oklchColorFromParts(52.95, ac, ah),
'accent-high': oklchColorFromParts(31.77, ac / 2, ah),
// Grays
white: oklchToHex(20.94, gc / 2, gh),
'gray-1': oklchToHex(27.14, gc, gh),
'gray-2': oklchToHex(34.09, gc, gh),
'gray-3': oklchToHex(46.01, gc, gh),
'gray-4': oklchToHex(63.78, gc, gh),
'gray-5': oklchToHex(81.34, gc / 2, gh),
'gray-6': oklchToHex(94.77, gc / 2.5, gh),
'gray-7': oklchToHex(97.35, gc / 5, gh),
black: oklchToHex(100, 0, 0),
white: oklchColorFromParts(20.94, gc / 2, gh),
'gray-1': oklchColorFromParts(27.14, gc, gh),
'gray-2': oklchColorFromParts(34.09, gc, gh),
'gray-3': oklchColorFromParts(46.01, gc, gh),
'gray-4': oklchColorFromParts(63.78, gc, gh),
'gray-5': oklchColorFromParts(81.34, gc / 2, gh),
'gray-6': oklchColorFromParts(94.77, gc / 2.5, gh),
'gray-7': oklchColorFromParts(97.35, gc / 5, gh),
black: oklchColorFromParts(100, 0, 0),
},
};

// Ensure text shades have sufficient contrast against common background colours.

// Dark mode:
// `gray-2` is used against `gray-5` in inline code snippets.
palettes.dark['gray-2'] = contrastColor(palettes.dark['gray-2'], palettes.dark['gray-5'], mc);
// `gray-3` is used in the table of contents.
palettes.dark['gray-3'] = contrastColor(palettes.dark['gray-3'], palettes.dark.black, mc);

// Light mode:
// `accent` is used for links and link buttons and can be slightly under 7:1 for some hues.
palettes.light.accent = contrastColor(palettes.light.accent, palettes.light['gray-6'], mc);
// `gray-2` is used against `gray-6` in inline code snippets.
palettes.light['gray-2'] = contrastColor(palettes.light['gray-2'], palettes.light['gray-6'], mc);
// `gray-3` is used in the table of contents.
palettes.light['gray-3'] = contrastColor(palettes.light['gray-3'], palettes.light.black, mc);

// Convert the palette from OKLCH to RGB hex codes.
return {
dark: Object.fromEntries(
Object.entries(palettes.dark).map(([key, color]) => [key, oklchColorToHex(color)])
) as Record<keyof typeof palettes.dark, string>,
light: Object.fromEntries(
Object.entries(palettes.light).map(([key, color]) => [key, oklchColorToHex(color)])
) as Record<keyof typeof palettes.light, string>,
};
}

/*
Expand Down
86 changes: 86 additions & 0 deletions docs/src/components/theme-designer/contrast-level.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
export interface Props {
labels: {
label: string;
};
}
const { labels = { label: 'WCAG Contrast Level' } } = Astro.props;
---

<contrast-level-toggle class="sl-flex">
<fieldset class="not-content">
<legend>{labels.label}</legend>
<div class="sl-flex">
<label class="sl-flex">
<input type="radio" name="contrast-level" value="4.5" checked />
AA
</label>
<label class="sl-flex">
<input type="radio" name="contrast-level" value="7" />
AAA
</label>
</div>
</fieldset>
</contrast-level-toggle>

<script>
import { minimumContrast } from './store';

class ContrastLevelToggle extends HTMLElement {
#fieldset = this.querySelector('fieldset')!;
constructor() {
super();
this.#fieldset.addEventListener('input', (e) => {
if (e.target instanceof HTMLInputElement) {
const contrast = parseFloat(e.target.value);
minimumContrast.set(contrast);
}
});
}
}

customElements.define('contrast-level-toggle', ContrastLevelToggle);
</script>

<style>
fieldset {
border: 0;
padding: 0;
}
fieldset > * {
float: left;
float: inline-start;
vertical-align: middle;
}
legend {
color: var(--sl-color-white);
margin-inline-end: 0.75rem;
}
label {
align-items: center;
padding: 0.25rem 0.75rem;
gap: 0.375rem;
background-color: var(--sl-color-gray-6);
font-size: var(--sl-text-xs);
cursor: pointer;
}
label:has(:focus-visible) {
outline: 2px solid;
outline-offset: -4px;
}
label:first-child {
border-start-start-radius: 99rem;
border-end-start-radius: 99rem;
}
label:last-child {
border-start-end-radius: 99rem;
border-end-end-radius: 99rem;
}
label:has(:checked) {
color: var(--sl-color-black);
background-color: var(--sl-color-text-accent);
}
input:focus-visible {
outline: none;
}
</style>
4 changes: 4 additions & 0 deletions docs/src/components/theme-designer/presets.astro
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ const resolvedPresets = Object.entries(presets).map(([key, preset]) => {
font-size: var(--sl-text-xs);
cursor: pointer;
}
button:focus-visible {
outline: 2px solid;
outline-offset: -4px;
}
:global([data-theme='light']) [data-preset] {
background-color: var(--light-bg);
color: var(--light-text);
Expand Down
3 changes: 2 additions & 1 deletion docs/src/components/theme-designer/store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { map } from './atom';
import { atom, map } from './atom';

export const presets = {
ocean: {
Expand Down Expand Up @@ -27,6 +27,7 @@ export const store = {
accent: map(presets.default.accent),
gray: map(presets.default.gray),
};
export const minimumContrast = atom(4.5);

export const usePreset = (name: string) => {
if (name in presets) {
Expand Down
Loading

0 comments on commit 1ac47f1

Please sign in to comment.