diff --git a/.changeset/flat-hounds-poke.md b/.changeset/flat-hounds-poke.md
new file mode 100644
index 00000000000..20f60fa3ce3
--- /dev/null
+++ b/.changeset/flat-hounds-poke.md
@@ -0,0 +1,5 @@
+---
+"@astrojs/starlight-tailwind": minor
+---
+
+Add Tailwind plugin
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 02cedc805f2..b3592a95ce8 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -14,5 +14,8 @@ i18n:
'🌟 core':
- packages/starlight/**
+'🌟 tailwind':
+ - packages/tailwind/**
+
'đź“š docs':
- docs/**
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 41900459fff..b0cc8365881 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -27,9 +27,8 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- run: pnpm i
- - name: Test packages/starlight
- working-directory: ./packages/starlight
- run: pnpm test:coverage
+ - name: Test packages
+ run: pnpm -r test:coverage
pa11y:
name: Check for accessibility issues
diff --git a/.gitignore b/.gitignore
index 34b4dc19b6d..9f880cb7098 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,6 @@ pnpm-debug.log*
# macOS-specific files
.DS_Store
+
+# Vitest
+__coverage__/
diff --git a/docs/src/content/docs/guides/css-and-tailwind.mdx b/docs/src/content/docs/guides/css-and-tailwind.mdx
new file mode 100644
index 00000000000..fc04b23e8e5
--- /dev/null
+++ b/docs/src/content/docs/guides/css-and-tailwind.mdx
@@ -0,0 +1,233 @@
+---
+title: CSS & Styling
+description: Learn how to style your Starlight site with custom CSS or integrate with Tailwind CSS.
+---
+
+You can style your Starlight site with custom CSS files or use the Starlight Tailwind plugin.
+
+## Custom CSS styles
+
+Customize the styles applied to your Starlight site by providing additional CSS files to modify or extend Starlight’s default styles.
+
+1. Add a CSS file to your `src/` directory.
+ For example, you could override Starlight’s default blue accent hue to purple:
+
+ ```css
+ /* src/styles/custom.css */
+ :root {
+ --sl-hue-accent: 270;
+ }
+ ```
+
+2. Add the path to your CSS file to Starlight’s `customCss` array in `astro.config.mjs`:
+
+ ```js
+ // astro.config.mjs
+ import { defineConfig } from 'astro/config';
+ import starlight from '@astrojs/starlight';
+
+ export default defineConfig({
+ integrations: [
+ starlight({
+ title: 'Docs With Custom CSS',
+ customCss: [
+ // Relative path to your custom CSS file
+ './src/styles/custom.css',
+ ],
+ }),
+ ],
+ });
+ ```
+
+You can see all the CSS custom properties used by Starlight that you can set to customize your site in the [`props.css` file on GitHub](https://github.com/withastro/starlight/blob/main/packages/starlight/style/props.css).
+
+## Tailwind CSS
+
+Tailwind CSS support in Astro projects is provided by the [Astro Tailwind integration](https://docs.astro.build/en/guides/integrations-guide/tailwind/).
+Starlight provides a complementary Tailwind plugin to help configure Tailwind for compatibility with Starlight’s styles.
+
+The Starlight Tailwind plugin applies the following configuration:
+
+- Configures Tailwind’s `dark:` variants to work with Starlight’s dark mode.
+- Uses Tailwind [theme colors and fonts](#styling-starlight-with-tailwind) in Starlight’s UI.
+- Disables Tailwind’s [Preflight](https://tailwindcss.com/docs/preflight) reset styles while selectively restoring essential parts of Preflight required for Tailwind’s border utility classes.
+
+### Create a new project with Tailwind
+
+import { Tabs, TabItem } from '@astrojs/starlight/components';
+
+Start a new Starlight project with Tailwind CSS pre-configured using `create astro`:
+
+
+
+
+```sh
+npm create astro@latest -- --template withastro/starlight/examples/tailwind
+```
+
+
+
+
+```sh
+pnpm create astro --template withastro/starlight/examples/tailwind
+```
+
+
+
+
+```sh
+yarn create astro --template withastro/starlight/examples/tailwind
+```
+
+
+
+
+### Add Tailwind to an existing project
+
+If you already have a Starlight site and want to add Tailwind CSS, follow these steps.
+
+1. Add Astro’s Tailwind integration:
+
+
+
+
+
+ ```sh
+ npx astro add tailwind
+ ```
+
+
+
+
+
+ ```sh
+ pnpm astro add tailwind
+ ```
+
+
+
+
+
+ ```sh
+ yarn astro add tailwind
+ ```
+
+
+
+
+
+2. Install the Starlight Tailwind plugin:
+
+
+
+
+
+ ```sh
+ npm install @astrojs/starlight-tailwind
+ ```
+
+
+
+
+
+ ```sh
+ pnpm install @astrojs/starlight-tailwind
+ ```
+
+
+
+
+
+ ```sh
+ yarn add @astrojs/starlight-tailwind
+ ```
+
+
+
+
+
+3. Create a CSS file for Tailwind’s base styles, for example at `src/tailwind.css`:
+
+ ```css
+ /* src/tailwind.css */
+ @tailwind base;
+ @tailwind components;
+ @tailwind utilities;
+ ```
+
+4. Update your Astro config file to use your Tailwind base styles and disable the default base styles:
+
+ ```js {11-12,16-17}
+ // astro.config.mjs
+ import { defineConfig } from 'astro/config';
+ import starlight from '@astrojs/starlight';
+ import tailwind from '@astrojs/tailwind';
+
+ export default defineConfig({
+ integrations: [
+ starlight({
+ title: 'Docs with Tailwind',
+ customCss: [
+ // Path to your Tailwind base styles:
+ './src/tailwind.css',
+ ],
+ }),
+ tailwind({
+ // Disable the default base styles:
+ applyBaseStyles: false,
+ }),
+ ],
+ });
+ ```
+
+5. Add the Starlight Tailwind plugin to `tailwind.config.cjs`:
+
+ ```js ins={2,7}
+ // tailwind.config.cjs
+ const starlightPlugin = require('@astrojs/starlight-tailwind');
+
+ /** @type {import('tailwindcss').Config} */
+ module.exports = {
+ content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
+ plugins: [starlightPlugin()],
+ };
+ ```
+
+### Styling Starlight with Tailwind
+
+Starlight will use values from your [Tailwind theme config](https://tailwindcss.com/docs/theme) in its UI.
+
+If set, the following options will override Starlight’s default styles:
+
+- `colors.accent` — used for links and current item highlighting
+- `colors.gray` — used for background colors and borders
+- `fontFamily.sans` — used for UI and content text
+- `fontFamily.mono` — used for code examples
+
+```js {12,14,18,20}
+// tailwind.config.cjs
+const starlightPlugin = require('@astrojs/starlight-tailwind');
+const colors = require('tailwindcss/colors');
+
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
+ theme: {
+ extend: {
+ colors: {
+ // Your preferred accent color. Indigo is closest to Starlight’s defaults.
+ accent: colors.indigo,
+ // Your preferred gray scale. Zinc is closest to Starlight’s defaults.
+ gray: colors.zinc,
+ },
+ fontFamily: {
+ // Your preferred text font. Starlight uses a system font stack by default.
+ sans: ['"Atkinson Hyperlegible"'],
+ // Your preferred code font. Starlight uses system monospace fonts by default.
+ mono: ['"IBM Plex Mono"'],
+ },
+ },
+ },
+ plugins: [starlightPlugin()],
+};
+```
diff --git a/docs/src/content/docs/guides/customization.mdx b/docs/src/content/docs/guides/customization.mdx
index d337b260879..733ff6ceb9a 100644
--- a/docs/src/content/docs/guides/customization.mdx
+++ b/docs/src/content/docs/guides/customization.mdx
@@ -1,6 +1,6 @@
---
title: Customizing Starlight
-description: Learn how to make your Starlight site your own with custom styles, fonts, and more.
+description: Learn how to make your Starlight site your own with your logo, custom fonts, landing page design and more.
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
@@ -263,42 +263,6 @@ hero:
---
```
-## Custom CSS styles
-
-Customize the styles applied to your Starlight site by providing additional CSS files to modify or extend Starlight’s default styles.
-
-1. Add a CSS file to your `src/` directory.
- For example, you could override Starlight’s default blue accent hue to purple:
-
- ```css
- /* src/styles/custom.css */
- :root {
- --sl-hue-accent: 270;
- }
- ```
-
-2. Add the path to your CSS file to Starlight’s `customCss` array in `astro.config.mjs`:
-
- ```js
- // astro.config.mjs
- import { defineConfig } from 'astro/config';
- import starlight from '@astrojs/starlight';
-
- export default defineConfig({
- integrations: [
- starlight({
- title: 'Docs With Custom CSS',
- customCss: [
- // Relative path to your custom CSS file
- './src/styles/custom.css',
- ],
- }),
- ],
- });
- ```
-
-You can see all the CSS custom properties used by Starlight that you can set to customize your site in the [`props.css` file on GitHub](https://github.com/withastro/starlight/blob/main/packages/starlight/style/props.css).
-
## Custom fonts
By default, Starlight uses sans-serif fonts available on a user’s local device for all text.
@@ -426,7 +390,7 @@ It provides npm modules you can install for the fonts you want to use and includ
### Use fonts
-To apply the font you set up to your site, use your chosen font’s name in a custom CSS file.
+To apply the font you set up to your site, use your chosen font’s name in a [custom CSS file](/guides/css-and-tailwind/#custom-css-styles).
For example, to override Starlight’s default font everywhere, set the `--sl-font` custom property:
```css
@@ -448,4 +412,4 @@ main {
}
```
-Follow the [custom CSS instructions](#custom-css-styles) to add your styles to your site.
+Follow the [custom CSS instructions](/guides/css-and-tailwind/#custom-css-styles) to add your styles to your site.
diff --git a/examples/tailwind/.gitignore b/examples/tailwind/.gitignore
new file mode 100644
index 00000000000..6240da8b10b
--- /dev/null
+++ b/examples/tailwind/.gitignore
@@ -0,0 +1,21 @@
+# build output
+dist/
+# generated types
+.astro/
+
+# dependencies
+node_modules/
+
+# logs
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+
+# environment variables
+.env
+.env.production
+
+# macOS-specific files
+.DS_Store
diff --git a/examples/tailwind/.vscode/extensions.json b/examples/tailwind/.vscode/extensions.json
new file mode 100644
index 00000000000..22a15055d63
--- /dev/null
+++ b/examples/tailwind/.vscode/extensions.json
@@ -0,0 +1,4 @@
+{
+ "recommendations": ["astro-build.astro-vscode"],
+ "unwantedRecommendations": []
+}
diff --git a/examples/tailwind/.vscode/launch.json b/examples/tailwind/.vscode/launch.json
new file mode 100644
index 00000000000..d6422097621
--- /dev/null
+++ b/examples/tailwind/.vscode/launch.json
@@ -0,0 +1,11 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "command": "./node_modules/.bin/astro dev",
+ "name": "Development server",
+ "request": "launch",
+ "type": "node-terminal"
+ }
+ ]
+}
diff --git a/examples/tailwind/README.md b/examples/tailwind/README.md
new file mode 100644
index 00000000000..39debfb78e8
--- /dev/null
+++ b/examples/tailwind/README.md
@@ -0,0 +1,52 @@
+# Starlight Starter Kit: Tailwind
+
+```
+npm create astro@latest -- --template withastro/starlight/examples/tailwind
+```
+
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/starlight/tree/main/examples/basics)
+[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/starlight/tree/main/examples/basics)
+
+> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
+
+## 🚀 Project Structure
+
+Inside of your Astro + Starlight project, you'll see the following folders and files:
+
+```
+.
+├── public/
+├── src/
+│ ├── assets/
+│ ├── content/
+│ │ ├── docs/
+│ │ └── config.ts
+│ └── env.d.ts
+├── astro.config.mjs
+├── package.json
+├── tailwind.config.cjs
+└── tsconfig.json
+```
+
+Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name.
+
+Images can be added to `src/assets/` and embedded in Markdown with a relative link.
+
+Static assets, like favicons, can be placed in the `public/` directory.
+
+## 🧞 Commands
+
+All commands are run from the root of the project, from a terminal:
+
+| Command | Action |
+| :------------------------ | :----------------------------------------------- |
+| `npm install` | Installs dependencies |
+| `npm run dev` | Starts local dev server at `localhost:3000` |
+| `npm run build` | Build your production site to `./dist/` |
+| `npm run preview` | Preview your build locally, before deploying |
+| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
+| `npm run astro -- --help` | Get help using the Astro CLI |
+
+## đź‘€ Want to learn more?
+
+Check out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).
diff --git a/examples/tailwind/astro.config.mjs b/examples/tailwind/astro.config.mjs
new file mode 100644
index 00000000000..63a3af18ae4
--- /dev/null
+++ b/examples/tailwind/astro.config.mjs
@@ -0,0 +1,36 @@
+import { defineConfig } from 'astro/config';
+import starlight from '@astrojs/starlight';
+import tailwind from '@astrojs/tailwind';
+
+// https://astro.build/config
+export default defineConfig({
+ integrations: [
+ starlight({
+ title: 'Docs with Tailwind',
+ social: {
+ github: 'https://github.com/withastro/starlight',
+ },
+ sidebar: [
+ {
+ label: 'Guides',
+ items: [
+ // Each item here is one entry in the navigation menu.
+ { label: 'Example Guide', link: '/guides/example/' },
+ ],
+ },
+ {
+ label: 'Reference',
+ autogenerate: { directory: 'reference' },
+ },
+ ],
+ customCss: ['./src/tailwind.css'],
+ }),
+ tailwind({ applyBaseStyles: false }),
+ ],
+ // Process images with sharp: https://docs.astro.build/en/guides/assets/#using-sharp
+ image: {
+ service: {
+ entrypoint: 'astro/assets/services/sharp',
+ },
+ },
+});
diff --git a/examples/tailwind/package.json b/examples/tailwind/package.json
new file mode 100644
index 00000000000..773bd8c98eb
--- /dev/null
+++ b/examples/tailwind/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "@example/starlight-tailwind",
+ "type": "module",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "dev": "astro dev",
+ "start": "astro dev",
+ "build": "astro build",
+ "preview": "astro preview",
+ "astro": "astro"
+ },
+ "dependencies": {
+ "@astrojs/starlight": "^0.6.1",
+ "@astrojs/starlight-tailwind": "^0.0.1",
+ "@astrojs/tailwind": "^4.0.0",
+ "astro": "^2.10.3",
+ "sharp": "^0.32.3",
+ "tailwindcss": "^3.3.3"
+ }
+}
diff --git a/examples/tailwind/public/favicon.svg b/examples/tailwind/public/favicon.svg
new file mode 100644
index 00000000000..cba5ac140a2
--- /dev/null
+++ b/examples/tailwind/public/favicon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/tailwind/src/assets/houston.webp b/examples/tailwind/src/assets/houston.webp
new file mode 100644
index 00000000000..930c164974a
Binary files /dev/null and b/examples/tailwind/src/assets/houston.webp differ
diff --git a/examples/tailwind/src/content/config.ts b/examples/tailwind/src/content/config.ts
new file mode 100644
index 00000000000..9df91b60444
--- /dev/null
+++ b/examples/tailwind/src/content/config.ts
@@ -0,0 +1,7 @@
+import { defineCollection } from 'astro:content';
+import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
+
+export const collections = {
+ docs: defineCollection({ schema: docsSchema() }),
+ i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
+};
diff --git a/examples/tailwind/src/content/docs/guides/example.md b/examples/tailwind/src/content/docs/guides/example.md
new file mode 100644
index 00000000000..ebd0f3bc762
--- /dev/null
+++ b/examples/tailwind/src/content/docs/guides/example.md
@@ -0,0 +1,11 @@
+---
+title: Example Guide
+description: A guide in my new Starlight docs site.
+---
+
+Guides lead a user through a specific task they want to accomplish, often with a sequence of steps.
+Writing a good guide requires thinking about what your users are trying to do.
+
+## Further reading
+
+- Read [about how-to guides](https://diataxis.fr/how-to-guides/) in the Diátaxis framework
diff --git a/examples/tailwind/src/content/docs/index.mdx b/examples/tailwind/src/content/docs/index.mdx
new file mode 100644
index 00000000000..aa8d1a65791
--- /dev/null
+++ b/examples/tailwind/src/content/docs/index.mdx
@@ -0,0 +1,46 @@
+---
+title: Welcome to Starlight
+description: Get started building your docs site with Starlight.
+template: splash
+hero:
+ title: |
+ Welcome to Starlight with
+
+ Tailwind
+
+ tagline: Congrats on setting up a new Starlight project!
+ image:
+ file: ../../assets/houston.webp
+ actions:
+ - text: Example Guide
+ link: /guides/example/
+ icon: right-arrow
+ variant: primary
+ - text: Read the Starlight docs
+ link: https://starlight.astro.build
+ icon: external
+---
+
+import { Card, CardGrid } from '@astrojs/starlight/components';
+
+## Next steps
+
+
+
+ Edit `src/content/docs/index.mdx` to see this page change.
+
+
+ Add Markdown or MDX files to `src/content/docs` to create new pages.
+
+
+ Edit your `sidebar` and other config in `astro.config.mjs`.
+
+
+ Learn more in [the Starlight Docs](https://starlight.astro.build/).
+
+
diff --git a/examples/tailwind/src/content/docs/reference/example.md b/examples/tailwind/src/content/docs/reference/example.md
new file mode 100644
index 00000000000..ac8cfa8bc3a
--- /dev/null
+++ b/examples/tailwind/src/content/docs/reference/example.md
@@ -0,0 +1,11 @@
+---
+title: Example Reference
+description: A reference page in my new Starlight docs site.
+---
+
+Reference pages are ideal for outlining how things work in terse and clear terms.
+Less concerned with telling a story or addressing a specific use case, they should give a comprehensive outline of what your documenting.
+
+## Further reading
+
+- Read [about reference](https://diataxis.fr/reference/) in the Diátaxis framework
diff --git a/examples/tailwind/src/env.d.ts b/examples/tailwind/src/env.d.ts
new file mode 100644
index 00000000000..4170bce9458
--- /dev/null
+++ b/examples/tailwind/src/env.d.ts
@@ -0,0 +1,2 @@
+///
+///
diff --git a/examples/tailwind/src/tailwind.css b/examples/tailwind/src/tailwind.css
new file mode 100644
index 00000000000..26664bc8816
--- /dev/null
+++ b/examples/tailwind/src/tailwind.css
@@ -0,0 +1,8 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/*
+Add additional Tailwind styles to this file, for example with @layer:
+https://tailwindcss.com/docs/adding-custom-styles#using-css-and-layer
+*/
diff --git a/examples/tailwind/tailwind.config.cjs b/examples/tailwind/tailwind.config.cjs
new file mode 100644
index 00000000000..474874c6179
--- /dev/null
+++ b/examples/tailwind/tailwind.config.cjs
@@ -0,0 +1,18 @@
+const colors = require('tailwindcss/colors');
+const starlightPlugin = require('@astrojs/starlight-tailwind');
+
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
+ theme: {
+ extend: {
+ colors: {
+ // Your preferred accent color. Indigo is closest to Starlight’s defaults.
+ accent: colors.indigo,
+ // Your preferred gray scale. Zinc is closest to Starlight’s defaults.
+ gray: colors.zinc,
+ },
+ },
+ },
+ plugins: [starlightPlugin()],
+};
diff --git a/examples/tailwind/tsconfig.json b/examples/tailwind/tsconfig.json
new file mode 100644
index 00000000000..bcbf8b50906
--- /dev/null
+++ b/examples/tailwind/tsconfig.json
@@ -0,0 +1,3 @@
+{
+ "extends": "astro/tsconfigs/strict"
+}
diff --git a/packages/starlight/.gitignore b/packages/starlight/.gitignore
index 017362793f1..fed875b1411 100644
--- a/packages/starlight/.gitignore
+++ b/packages/starlight/.gitignore
@@ -1,5 +1,2 @@
-# Vitest
-__coverage__/
-
# Astro generates this during tests, but we want to ignore it.
src/env.d.ts
diff --git a/packages/tailwind/README.md b/packages/tailwind/README.md
new file mode 100644
index 00000000000..a9353f63052
--- /dev/null
+++ b/packages/tailwind/README.md
@@ -0,0 +1,18 @@
+# @astrojs/starlight-tailwind
+
+Tailwind CSS plugin for the [Starlight][starlight] documentation theme for [Astro][astro].
+
+## Documentation
+
+See the [Starlight Tailwind docs][docs] for how to use this plugin.
+
+## License
+
+MIT
+
+Copyright (c) 2023–present [Starlight contributors][contributors]
+
+[starlight]: https://starlight.astro.build/
+[astro]: https://astro.build/
+[docs]: https://starlight.astro.build/guides/css-and-tailwind/#tailwind-css
+[contributors]: https://github.com/withastro/starlight/graphs/contributors
diff --git a/packages/tailwind/__tests__/tailwind.test.ts b/packages/tailwind/__tests__/tailwind.test.ts
new file mode 100644
index 00000000000..9c2692acda6
--- /dev/null
+++ b/packages/tailwind/__tests__/tailwind.test.ts
@@ -0,0 +1,254 @@
+import tailwindcss, { Config } from 'tailwindcss';
+import colors from 'tailwindcss/colors';
+import postcss from 'postcss';
+import { test, expect, describe } from 'vitest';
+import StarlightTailwindPlugin from '..';
+
+/** Generate a CSS string based on the passed CSS and HTML content. */
+const generatePluginCss = ({
+ css = '@tailwind base;',
+ html = '',
+ config = {},
+}: { css?: string; html?: string; config?: Partial } = {}): Promise => {
+ return postcss(
+ tailwindcss({
+ // Enable Starlight plugin.
+ plugins: [StarlightTailwindPlugin()],
+ // Provide content for Tailwind to scan for class names.
+ content: [{ raw: html, extension: 'html' }],
+ // Spread in any custom Tailwind config.
+ ...config,
+ })
+ )
+ .process(css, { from: '' })
+ .then((result) => result.css);
+};
+
+describe('@tailwind base;', async () => {
+ // Generate base CSS with no core Tailwind plugins running to see just Starlight’s output.
+ const base = await generatePluginCss({ config: { corePlugins: [] } });
+
+ test('generates Starlight base CSS', async () => {
+ expect(base).toMatchInlineSnapshot(`
+ "*, ::before, ::after {
+ border-width: 0;
+ border-style: solid;
+ border-color: #e5e7eb;
+ }
+ ::before, ::after {
+ --tw-content: ;
+ }
+ :root {
+ --sl-font: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\";
+ --sl-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\"Liberation Mono\\", \\"Courier New\\", monospace;
+ --sl-color-white: #fff;
+ --sl-color-gray-1: #e5e7eb;
+ --sl-color-gray-2: #d1d5db;
+ --sl-color-gray-3: #9ca3af;
+ --sl-color-gray-4: #4b5563;
+ --sl-color-gray-5: #374151;
+ --sl-color-gray-6: #1f2937;
+ --sl-color-black: #111827;
+ --sl-color-accent-low: #1e1b4b;
+ --sl-color-accent: #4f46e5;
+ --sl-color-accent-high: #c7d2fe;
+ }
+ :root[data-theme=\\"light\\"] {
+ --sl-color-white: #111827;
+ --sl-color-gray-1: #1f2937;
+ --sl-color-gray-2: #374151;
+ --sl-color-gray-3: #6b7280;
+ --sl-color-gray-4: #9ca3af;
+ --sl-color-gray-5: #d1d5db;
+ --sl-color-gray-6: #e5e7eb;
+ --sl-color-gray-7: #f3f4f6;
+ --sl-color-black: #fff;
+ --sl-color-accent-low: #c7d2fe;
+ --sl-color-accent: #4f46e5;
+ --sl-color-accent-high: #312e81;
+ }"
+ `);
+ });
+
+ test('configures `--sl-color-*` variables', () => {
+ expect(base).includes('--sl-color-gray-1: #e5e7eb;');
+ expect(base).includes('--sl-color-accent: #4f46e5;');
+ });
+
+ describe('with user theme config', async () => {
+ const baseWithConfig = await generatePluginCss({
+ config: {
+ corePlugins: [],
+ theme: { extend: { colors: { accent: colors.amber, gray: colors.slate } } },
+ },
+ });
+
+ test('generates different CSS from base without user config', () => {
+ expect(baseWithConfig).not.toEqual(base);
+ });
+
+ test('uses theme values for Starlight colours', () => {
+ expect(baseWithConfig).includes('--sl-color-gray-1: #e2e8f0;');
+ expect(baseWithConfig).includes('--sl-color-accent: #d97706;');
+ });
+ });
+
+ test('disables Tailwind preflight', async () => {
+ const baseWithDefaultPlugins = await generatePluginCss();
+ expect(baseWithDefaultPlugins).not.includes('line-height: 1.5;');
+ expect(baseWithDefaultPlugins).includes('--tw-');
+ expect(baseWithDefaultPlugins).toMatchInlineSnapshot(`
+ "*, ::before, ::after {
+ border-width: 0;
+ border-style: solid;
+ border-color: #e5e7eb;
+ }
+ ::before, ::after {
+ --tw-content: ;
+ }
+ :root {
+ --sl-font: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\";
+ --sl-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\"Liberation Mono\\", \\"Courier New\\", monospace;
+ --sl-color-white: #fff;
+ --sl-color-gray-1: #e5e7eb;
+ --sl-color-gray-2: #d1d5db;
+ --sl-color-gray-3: #9ca3af;
+ --sl-color-gray-4: #4b5563;
+ --sl-color-gray-5: #374151;
+ --sl-color-gray-6: #1f2937;
+ --sl-color-black: #111827;
+ --sl-color-accent-low: #1e1b4b;
+ --sl-color-accent: #4f46e5;
+ --sl-color-accent-high: #c7d2fe;
+ }
+ :root[data-theme=\\"light\\"] {
+ --sl-color-white: #111827;
+ --sl-color-gray-1: #1f2937;
+ --sl-color-gray-2: #374151;
+ --sl-color-gray-3: #6b7280;
+ --sl-color-gray-4: #9ca3af;
+ --sl-color-gray-5: #d1d5db;
+ --sl-color-gray-6: #e5e7eb;
+ --sl-color-gray-7: #f3f4f6;
+ --sl-color-black: #fff;
+ --sl-color-accent-low: #c7d2fe;
+ --sl-color-accent: #4f46e5;
+ --sl-color-accent-high: #312e81;
+ }
+ *, ::before, ::after {
+ --tw-border-spacing-x: 0;
+ --tw-border-spacing-y: 0;
+ --tw-translate-x: 0;
+ --tw-translate-y: 0;
+ --tw-rotate: 0;
+ --tw-skew-x: 0;
+ --tw-skew-y: 0;
+ --tw-scale-x: 1;
+ --tw-scale-y: 1;
+ --tw-pan-x: ;
+ --tw-pan-y: ;
+ --tw-pinch-zoom: ;
+ --tw-scroll-snap-strictness: proximity;
+ --tw-gradient-from-position: ;
+ --tw-gradient-via-position: ;
+ --tw-gradient-to-position: ;
+ --tw-ordinal: ;
+ --tw-slashed-zero: ;
+ --tw-numeric-figure: ;
+ --tw-numeric-spacing: ;
+ --tw-numeric-fraction: ;
+ --tw-ring-inset: ;
+ --tw-ring-offset-width: 0px;
+ --tw-ring-offset-color: #fff;
+ --tw-ring-color: rgb(59 130 246 / 0.5);
+ --tw-ring-offset-shadow: 0 0 #0000;
+ --tw-ring-shadow: 0 0 #0000;
+ --tw-shadow: 0 0 #0000;
+ --tw-shadow-colored: 0 0 #0000;
+ --tw-blur: ;
+ --tw-brightness: ;
+ --tw-contrast: ;
+ --tw-grayscale: ;
+ --tw-hue-rotate: ;
+ --tw-invert: ;
+ --tw-saturate: ;
+ --tw-sepia: ;
+ --tw-drop-shadow: ;
+ --tw-backdrop-blur: ;
+ --tw-backdrop-brightness: ;
+ --tw-backdrop-contrast: ;
+ --tw-backdrop-grayscale: ;
+ --tw-backdrop-hue-rotate: ;
+ --tw-backdrop-invert: ;
+ --tw-backdrop-opacity: ;
+ --tw-backdrop-saturate: ;
+ --tw-backdrop-sepia: ;
+ }
+ ::backdrop {
+ --tw-border-spacing-x: 0;
+ --tw-border-spacing-y: 0;
+ --tw-translate-x: 0;
+ --tw-translate-y: 0;
+ --tw-rotate: 0;
+ --tw-skew-x: 0;
+ --tw-skew-y: 0;
+ --tw-scale-x: 1;
+ --tw-scale-y: 1;
+ --tw-pan-x: ;
+ --tw-pan-y: ;
+ --tw-pinch-zoom: ;
+ --tw-scroll-snap-strictness: proximity;
+ --tw-gradient-from-position: ;
+ --tw-gradient-via-position: ;
+ --tw-gradient-to-position: ;
+ --tw-ordinal: ;
+ --tw-slashed-zero: ;
+ --tw-numeric-figure: ;
+ --tw-numeric-spacing: ;
+ --tw-numeric-fraction: ;
+ --tw-ring-inset: ;
+ --tw-ring-offset-width: 0px;
+ --tw-ring-offset-color: #fff;
+ --tw-ring-color: rgb(59 130 246 / 0.5);
+ --tw-ring-offset-shadow: 0 0 #0000;
+ --tw-ring-shadow: 0 0 #0000;
+ --tw-shadow: 0 0 #0000;
+ --tw-shadow-colored: 0 0 #0000;
+ --tw-blur: ;
+ --tw-brightness: ;
+ --tw-contrast: ;
+ --tw-grayscale: ;
+ --tw-hue-rotate: ;
+ --tw-invert: ;
+ --tw-saturate: ;
+ --tw-sepia: ;
+ --tw-drop-shadow: ;
+ --tw-backdrop-blur: ;
+ --tw-backdrop-brightness: ;
+ --tw-backdrop-contrast: ;
+ --tw-backdrop-grayscale: ;
+ --tw-backdrop-hue-rotate: ;
+ --tw-backdrop-invert: ;
+ --tw-backdrop-opacity: ;
+ --tw-backdrop-saturate: ;
+ --tw-backdrop-sepia: ;
+ }"
+ `);
+ });
+});
+
+describe('@tailwind utilities;', () => {
+ test('uses [data-theme="dark"] for dark: utility classes', async () => {
+ const utils = await generatePluginCss({
+ css: '@tailwind utilities;',
+ html: '',
+ });
+ expect(utils).includes('[data-theme="dark"] .dark');
+ expect(utils).toMatchInlineSnapshot(`
+ ":is([data-theme=\\"dark\\"] .dark\\\\:text-red-50) {
+ --tw-text-opacity: 1;
+ color: rgb(254 242 242 / var(--tw-text-opacity))
+ }"
+ `);
+ });
+});
diff --git a/packages/tailwind/index.ts b/packages/tailwind/index.ts
new file mode 100644
index 00000000000..103bf7dc6c2
--- /dev/null
+++ b/packages/tailwind/index.ts
@@ -0,0 +1,100 @@
+import plugin from 'tailwindcss/plugin';
+
+/**
+ * Starlight Tailwind Plugin
+ *
+ * - Disables Tailwind Preflight.
+ * - Configures `dark:` variants for Starlight dark mode.
+ * - Links Starlight’s colors to `gray` and `accent` in Tailwind theme settings.
+ * - Links Starlight’s fonts to `sans` and `mono` in Tailwind theme settings.
+ *
+ * @example
+ * // tailwind.config.cjs
+ * const colors = require('tailwindcss/colors');
+ * const starlightPlugin = require('@astrojs/starlight/tailwind');
+ *
+ * module.exports = {
+ * plugins: [
+ * // Add Starlight’s Tailwind plugin
+ * starlightPlugin(),
+ * ],
+ * theme: {
+ * extend: {
+ * colors: {
+ * // Set an accent color for Astro to use. Indigo is closest to Astro’s defaults.
+ * accent: colors.yellow,
+ * // Configure your preferred gray scale. Zinc is closest to Astro’s defaults.
+ * gray: colors.zinc,
+ * },
+ * },
+ * },
+ * }
+ */
+const StarlightTailwindPlugin = () =>
+ plugin(
+ ({ addBase, theme }) => {
+ /** Utility to apply accent colors based on a user’s theme config. */
+ const themeAccent = (
+ shade: 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950,
+ fallback: string
+ ) =>
+ shade === 950
+ ? theme(`colors.accent.${shade}`, theme(`colors.accent.900`, fallback))
+ : theme(`colors.accent.${shade}`, fallback);
+
+ addBase({
+ // Restore crucial styles from Tailwind Preflight: https://tailwindcss.com/docs/preflight
+ // Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
+ '*, ::before, ::after': {
+ borderWidth: '0',
+ borderStyle: 'solid',
+ borderColor: theme('borderColor.DEFAULT', 'currentColor'),
+ },
+ '::before, ::after': { '--tw-content': '' },
+
+ // Wire up Starlight theme to use Tailwind config.
+ ':root': {
+ // Use Tailwind-configured font families.
+ '--sl-font': theme('fontFamily.sans'),
+ '--sl-font-mono': theme('fontFamily.mono'),
+ // Dark mode Starlight theme variables.
+ '--sl-color-white': theme('colors.white'),
+ '--sl-color-gray-1': theme('colors.gray.200'),
+ '--sl-color-gray-2': theme('colors.gray.300'),
+ '--sl-color-gray-3': theme('colors.gray.400'),
+ '--sl-color-gray-4': theme('colors.gray.600'),
+ '--sl-color-gray-5': theme('colors.gray.700'),
+ '--sl-color-gray-6': theme('colors.gray.800'),
+ '--sl-color-black': theme('colors.gray.900'),
+ '--sl-color-accent-low': themeAccent(950, '#1e1b4b'),
+ '--sl-color-accent': themeAccent(600, '#4f46e5'),
+ '--sl-color-accent-high': themeAccent(200, '#c7d2fe'),
+ // Light mode Starlight theme variables
+ '&[data-theme="light"]': {
+ '--sl-color-white': theme('colors.gray.900'),
+ '--sl-color-gray-1': theme('colors.gray.800'),
+ '--sl-color-gray-2': theme('colors.gray.700'),
+ '--sl-color-gray-3': theme('colors.gray.500'),
+ '--sl-color-gray-4': theme('colors.gray.400'),
+ '--sl-color-gray-5': theme('colors.gray.300'),
+ '--sl-color-gray-6': theme('colors.gray.200'),
+ '--sl-color-gray-7': theme('colors.gray.100'),
+ '--sl-color-black': theme('colors.white'),
+ '--sl-color-accent-low': themeAccent(200, '#c7d2fe'),
+ '--sl-color-accent': themeAccent(600, '#4f46e5'),
+ '--sl-color-accent-high': themeAccent(900, '#312e81'),
+ },
+ },
+ });
+ },
+ {
+ // Starlight uses a `data-theme` attribute to power its dark mode.
+ darkMode: ['class', '[data-theme="dark"]'],
+ corePlugins: {
+ // Disable Tailwind’s default reset styles which conflict with Starlight.
+ preflight: false,
+ },
+ }
+ );
+
+export default StarlightTailwindPlugin;
diff --git a/packages/tailwind/package.json b/packages/tailwind/package.json
new file mode 100644
index 00000000000..d06cb869fbd
--- /dev/null
+++ b/packages/tailwind/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "@astrojs/starlight-tailwind",
+ "version": "0.0.1",
+ "description": "Tailwind CSS plugin for the Starlight documentation theme for Astro",
+ "author": "Chris Swithinbank ",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/withastro/starlight",
+ "directory": "packages/tailwind"
+ },
+ "bugs": "https://github.com/withastro/starlight/issues",
+ "homepage": "https://starlight.astro.build",
+ "type": "module",
+ "files": [
+ "index.ts"
+ ],
+ "exports": {
+ ".": "./index.ts"
+ },
+ "scripts": {
+ "test": "vitest",
+ "test:coverage": "vitest run --coverage"
+ },
+ "devDependencies": {
+ "@vitest/coverage-v8": "^0.33.0",
+ "postcss": "^8.4.27",
+ "vitest": "^0.33.0"
+ },
+ "peerDependencies": {
+ "@astrojs/starlight": "^0.6.1",
+ "@astrojs/tailwind": "^4.0.0",
+ "tailwindcss": "^3.3.3"
+ }
+}
diff --git a/packages/tailwind/vitest.config.ts b/packages/tailwind/vitest.config.ts
new file mode 100644
index 00000000000..b29e52cd64b
--- /dev/null
+++ b/packages/tailwind/vitest.config.ts
@@ -0,0 +1,14 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ coverage: {
+ reportsDirectory: './__coverage__',
+ thresholdAutoUpdate: true,
+ lines: 100,
+ functions: 100,
+ branches: 100,
+ statements: 100,
+ },
+ },
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 64b6c77ca7e..05ceabf7630 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -106,6 +106,27 @@ importers:
specifier: ^0.32.3
version: 0.32.3
+ examples/tailwind:
+ dependencies:
+ '@astrojs/starlight':
+ specifier: ^0.6.1
+ version: link:../../packages/starlight
+ '@astrojs/starlight-tailwind':
+ specifier: ^0.0.1
+ version: link:../../packages/tailwind
+ '@astrojs/tailwind':
+ specifier: ^4.0.0
+ version: 4.0.0(astro@2.10.4)(tailwindcss@3.3.3)
+ astro:
+ specifier: ^2.10.3
+ version: 2.10.4(sharp@0.32.3)
+ sharp:
+ specifier: ^0.32.3
+ version: 0.32.3
+ tailwindcss:
+ specifier: ^3.3.3
+ version: 3.3.3
+
packages/starlight:
dependencies:
'@astrojs/mdx':
@@ -167,8 +188,35 @@ importers:
specifier: ^0.33.0
version: 0.33.0
+ packages/tailwind:
+ dependencies:
+ '@astrojs/starlight':
+ specifier: ^0.6.1
+ version: link:../starlight
+ '@astrojs/tailwind':
+ specifier: ^4.0.0
+ version: 4.0.0(astro@2.10.4)(tailwindcss@3.3.3)
+ tailwindcss:
+ specifier: ^3.3.3
+ version: 3.3.3
+ devDependencies:
+ '@vitest/coverage-v8':
+ specifier: ^0.33.0
+ version: 0.33.0(vitest@0.33.0)
+ postcss:
+ specifier: ^8.4.27
+ version: 8.4.27
+ vitest:
+ specifier: ^0.33.0
+ version: 0.33.0
+
packages:
+ /@alloc/quick-lru@5.2.0:
+ resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
+ engines: {node: '>=10'}
+ dev: false
+
/@ampproject/remapping@2.2.1:
resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
engines: {node: '>=6.0.0'}
@@ -262,6 +310,21 @@ packages:
zod: 3.21.4
dev: false
+ /@astrojs/tailwind@4.0.0(astro@2.10.4)(tailwindcss@3.3.3):
+ resolution: {integrity: sha512-HmCAXFFes7MUBt5ihdfH1goa8QyGkHejIpz6Z4XBKK9VNYY9G2E3brCn8+pNn5zAOzcwl3FYcuH2AiOa/NGoMQ==}
+ peerDependencies:
+ astro: ^2.6.5
+ tailwindcss: ^3.0.24
+ dependencies:
+ astro: 2.10.4(sharp@0.32.3)
+ autoprefixer: 10.4.14(postcss@8.4.27)
+ postcss: 8.4.27
+ postcss-load-config: 4.0.1(postcss@8.4.27)
+ tailwindcss: 3.3.3
+ transitivePeerDependencies:
+ - ts-node
+ dev: false
+
/@astrojs/telemetry@2.1.1:
resolution: {integrity: sha512-4pRhyeQr0MLB5PKYgkdu+YE8sSpMbHL8dUuslBWBIdgcYjtD1SufPMBI8pgXJ+xlwrQJHKKfK2X1KonHYuOS9A==}
engines: {node: '>=16.12.0'}
@@ -1587,6 +1650,10 @@ packages:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
+ /any-promise@1.3.0:
+ resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
+ dev: false
+
/anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
@@ -1824,6 +1891,22 @@ packages:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: true
+ /autoprefixer@10.4.14(postcss@8.4.27):
+ resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==}
+ engines: {node: ^10 || ^12 || >=14}
+ hasBin: true
+ peerDependencies:
+ postcss: ^8.1.0
+ dependencies:
+ browserslist: 4.21.5
+ caniuse-lite: 1.0.30001466
+ fraction.js: 4.2.0
+ normalize-range: 0.1.2
+ picocolors: 1.0.0
+ postcss: 8.4.27
+ postcss-value-parser: 4.2.0
+ dev: false
+
/available-typed-arrays@1.0.5:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
engines: {node: '>= 0.4'}
@@ -1851,7 +1934,6 @@ packages:
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
- dev: true
/base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -1928,7 +2010,6 @@ packages:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
- dev: true
/braces@3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
@@ -1991,6 +2072,11 @@ packages:
get-intrinsic: 1.2.0
dev: true
+ /camelcase-css@2.0.1:
+ resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
+ engines: {node: '>= 6'}
+ dev: false
+
/camelcase-keys@6.2.2:
resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
engines: {node: '>=8'}
@@ -2197,6 +2283,11 @@ packages:
/comma-separated-tokens@2.0.3:
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
+ /commander@4.1.1:
+ resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
+ engines: {node: '>= 6'}
+ dev: false
+
/commander@6.2.1:
resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==}
engines: {node: '>= 6'}
@@ -2212,7 +2303,6 @@ packages:
/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
- dev: true
/convert-source-map@1.9.0:
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
@@ -2256,6 +2346,12 @@ packages:
engines: {node: '>= 6'}
dev: true
+ /cssesc@3.0.0:
+ resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: false
+
/csv-generate@3.4.3:
resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==}
dev: true
@@ -2383,6 +2479,10 @@ packages:
resolution: {integrity: sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==}
dev: true
+ /didyoumean@1.2.2:
+ resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
+ dev: false
+
/diff-sequences@29.4.3:
resolution: {integrity: sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -3096,6 +3196,10 @@ packages:
fetch-blob: 3.2.0
dev: true
+ /fraction.js@4.2.0:
+ resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
+ dev: false
+
/from@0.1.7:
resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==}
dev: true
@@ -3123,7 +3227,6 @@ packages:
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
- dev: true
/fsevents@2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
@@ -3204,6 +3307,24 @@ packages:
dependencies:
is-glob: 4.0.3
+ /glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ is-glob: 4.0.3
+ dev: false
+
+ /glob@7.1.6:
+ resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==}
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 3.1.2
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+ dev: false
+
/glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
dependencies:
@@ -3549,7 +3670,6 @@ packages:
dependencies:
once: 1.4.0
wrappy: 1.0.2
- dev: true
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -3637,6 +3757,12 @@ packages:
dependencies:
has: 1.0.3
+ /is-core-module@2.13.0:
+ resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==}
+ dependencies:
+ has: 1.0.3
+ dev: false
+
/is-date-object@1.0.5:
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
engines: {node: '>= 0.4'}
@@ -3831,6 +3957,11 @@ packages:
istanbul-lib-report: 3.0.0
dev: true
+ /jiti@1.19.1:
+ resolution: {integrity: sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==}
+ hasBin: true
+ dev: false
+
/joi@17.9.2:
resolution: {integrity: sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw==}
dependencies:
@@ -3903,11 +4034,9 @@ packages:
/lilconfig@2.1.0:
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
engines: {node: '>=10'}
- dev: true
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
- dev: true
/load-yaml-file@0.2.0:
resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==}
@@ -4601,7 +4730,6 @@ packages:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
brace-expansion: 1.1.11
- dev: true
/minimist-options@4.1.0:
resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
@@ -4644,6 +4772,14 @@ packages:
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+ /mz@2.7.0:
+ resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
+ dependencies:
+ any-promise: 1.3.0
+ object-assign: 4.1.1
+ thenify-all: 1.6.0
+ dev: false
+
/nanoid@3.3.6:
resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -4736,6 +4872,11 @@ packages:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
+ /normalize-range@0.1.2:
+ resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
/not@0.1.0:
resolution: {integrity: sha512-5PDmaAsVfnWUgTUbJ3ERwn7u79Z0dYxN9ErxCpVJJqe2RK0PJ3z+iFUxuqjwtlDDegXvtWoxD/3Fzxox7tFGWA==}
dev: false
@@ -4761,7 +4902,11 @@ packages:
/object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
- dev: true
+
+ /object-hash@3.0.0:
+ resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
+ engines: {node: '>= 6'}
+ dev: false
/object-inspect@1.12.3:
resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
@@ -4999,7 +5144,6 @@ packages:
/path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
- dev: true
/path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
@@ -5056,7 +5200,6 @@ packages:
/pify@2.3.0:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
engines: {node: '>=0.10.0'}
- dev: true
/pify@4.0.1:
resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
@@ -5074,6 +5217,11 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
+ /pirates@4.0.6:
+ resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
+ engines: {node: '>= 6'}
+ dev: false
+
/pkg-dir@4.2.0:
resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
engines: {node: '>=8'}
@@ -5088,6 +5236,67 @@ packages:
pathe: 1.1.1
dev: true
+ /postcss-import@15.1.0(postcss@8.4.27):
+ resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ postcss: ^8.0.0
+ dependencies:
+ postcss: 8.4.27
+ postcss-value-parser: 4.2.0
+ read-cache: 1.0.0
+ resolve: 1.22.4
+ dev: false
+
+ /postcss-js@4.0.1(postcss@8.4.27):
+ resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
+ engines: {node: ^12 || ^14 || >= 16}
+ peerDependencies:
+ postcss: ^8.4.21
+ dependencies:
+ camelcase-css: 2.0.1
+ postcss: 8.4.27
+ dev: false
+
+ /postcss-load-config@4.0.1(postcss@8.4.27):
+ resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==}
+ engines: {node: '>= 14'}
+ peerDependencies:
+ postcss: '>=8.0.9'
+ ts-node: '>=9.0.0'
+ peerDependenciesMeta:
+ postcss:
+ optional: true
+ ts-node:
+ optional: true
+ dependencies:
+ lilconfig: 2.1.0
+ postcss: 8.4.27
+ yaml: 2.3.1
+ dev: false
+
+ /postcss-nested@6.0.1(postcss@8.4.27):
+ resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==}
+ engines: {node: '>=12.0'}
+ peerDependencies:
+ postcss: ^8.2.14
+ dependencies:
+ postcss: 8.4.27
+ postcss-selector-parser: 6.0.13
+ dev: false
+
+ /postcss-selector-parser@6.0.13:
+ resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+ dev: false
+
+ /postcss-value-parser@4.2.0:
+ resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+ dev: false
+
/postcss@8.4.27:
resolution: {integrity: sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==}
engines: {node: ^10 || ^12 || >=14}
@@ -5264,6 +5473,12 @@ packages:
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
dev: true
+ /read-cache@1.0.0:
+ resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
+ dependencies:
+ pify: 2.3.0
+ dev: false
+
/read-pkg-up@7.0.1:
resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
engines: {node: '>=8'}
@@ -5444,6 +5659,15 @@ packages:
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
+ /resolve@1.22.4:
+ resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==}
+ hasBin: true
+ dependencies:
+ is-core-module: 2.13.0
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+ dev: false
+
/restore-cursor@4.0.0:
resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -5932,6 +6156,20 @@ packages:
inline-style-parser: 0.1.1
dev: false
+ /sucrase@3.34.0:
+ resolution: {integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==}
+ engines: {node: '>=8'}
+ hasBin: true
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.2
+ commander: 4.1.1
+ glob: 7.1.6
+ lines-and-columns: 1.2.4
+ mz: 2.7.0
+ pirates: 4.0.6
+ ts-interface-checker: 0.1.13
+ dev: false
+
/suf-log@2.5.3:
resolution: {integrity: sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==}
dependencies:
@@ -5960,6 +6198,37 @@ packages:
'@pkgr/utils': 2.3.1
tslib: 2.5.0
+ /tailwindcss@3.3.3:
+ resolution: {integrity: sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==}
+ engines: {node: '>=14.0.0'}
+ hasBin: true
+ dependencies:
+ '@alloc/quick-lru': 5.2.0
+ arg: 5.0.2
+ chokidar: 3.5.3
+ didyoumean: 1.2.2
+ dlv: 1.1.3
+ fast-glob: 3.2.12
+ glob-parent: 6.0.2
+ is-glob: 4.0.3
+ jiti: 1.19.1
+ lilconfig: 2.1.0
+ micromatch: 4.0.5
+ normalize-path: 3.0.0
+ object-hash: 3.0.0
+ picocolors: 1.0.0
+ postcss: 8.4.27
+ postcss-import: 15.1.0(postcss@8.4.27)
+ postcss-js: 4.0.1(postcss@8.4.27)
+ postcss-load-config: 4.0.1(postcss@8.4.27)
+ postcss-nested: 6.0.1(postcss@8.4.27)
+ postcss-selector-parser: 6.0.13
+ resolve: 1.22.4
+ sucrase: 3.34.0
+ transitivePeerDependencies:
+ - ts-node
+ dev: false
+
/tar-fs@2.1.1:
resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
dependencies:
@@ -6006,6 +6275,19 @@ packages:
minimatch: 3.1.2
dev: true
+ /thenify-all@1.6.0:
+ resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
+ engines: {node: '>=0.8'}
+ dependencies:
+ thenify: 3.3.1
+ dev: false
+
+ /thenify@3.3.1:
+ resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+ dependencies:
+ any-promise: 1.3.0
+ dev: false
+
/through@2.3.8:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
dev: true
@@ -6066,6 +6348,10 @@ packages:
resolution: {integrity: sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==}
dev: true
+ /ts-interface-checker@0.1.13:
+ resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
+ dev: false
+
/tsconfig-resolver@3.0.1:
resolution: {integrity: sha512-ZHqlstlQF449v8glscGRXzL6l2dZvASPCdXJRWG4gHEZlUVx2Jtmr+a2zeVG4LCsKhDXKRj5R3h0C/98UcVAQg==}
dependencies:
@@ -6660,6 +6946,11 @@ packages:
/yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+ /yaml@2.3.1:
+ resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==}
+ engines: {node: '>= 14'}
+ dev: false
+
/yargs-parser@18.1.3:
resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
engines: {node: '>=6'}