├── .astro
└── types.d.ts
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── code_of_conduct.md
├── contributing.md
└── workflows
│ ├── ci.yml
│ └── release-please.yml
├── .gitignore
├── .husky
├── commit-msg
└── pre-commit
├── .prettierignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── Themes.astro.template
├── Themes.ts
├── build.js
├── example
├── .astro
│ └── types.d.ts
├── public
│ └── slow.js
└── src
│ ├── env.d.ts
│ └── pages
│ ├── index.astro
│ ├── options.astro
│ └── slow.astro
├── index.ts
├── package-lock.json
├── package.json
├── playwright.config.ts
├── tests
├── basic.test.ts
├── fouc.test.ts
└── options.test.ts
└── tsconfig.json
/.astro/types.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "\U0001F41B Bug Report: "
5 | labels: bug
6 | assignees: ''
7 | ---
8 |
9 | **Describe the bug**
10 | A clear and concise description of what the bug is.
11 |
12 | **To Reproduce**
13 | Steps to reproduce the behavior:
14 |
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 |
28 | - OS: [e.g. iOS]
29 | - Browser [e.g. chrome, safari]
30 | - Version [e.g. 22]
31 |
32 | **Additional context**
33 | Add any other context about the problem here.
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "\U0001F4A1Feature Request: "
5 | labels: enhancement
6 | assignees: ''
7 | ---
8 |
9 | **Is your feature request related to a problem? Please describe.**
10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11 |
12 | **Describe the solution you'd like**
13 | A clear and concise description of what you want to happen.
14 |
15 | **Describe alternatives you've considered**
16 | A clear and concise description of any alternative solutions or features you've considered.
17 |
18 | **Additional context**
19 | Add any other context or screenshots about the feature request here.
20 |
--------------------------------------------------------------------------------
/.github/code_of_conduct.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | - Demonstrating empathy and kindness toward other people
21 | - Being respectful of differing opinions, viewpoints, and experiences
22 | - Giving and gracefully accepting constructive feedback
23 | - Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | - Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | - The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | - Trolling, insulting or derogatory comments, and personal or political attacks
33 | - Public or private harassment
34 | - Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | - Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | hello@alexgrover.me.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/.github/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | First of all, welcome to `astro-themes` and thanks for your interest in contributing! Please note that we have a [code of conduct](https://github.com/alex-grover/astro-themes/blob/main/.github/code_of_conduct.md) that all participants are expected to follow.
4 |
5 | ## Suggesting features or reporting bugs
6 |
7 | Please [submit an issue](https://github.com/alex-grover/astro-themes/issues/new) before making a pull request! This package aims to be easy to use, not to support every possible use case, so a discussion ahead of time will lead to the highest chance of your change being accepted.
8 |
9 | I'll do my best to respond in a timely manner, but if I don't get back to you in a few days please feel free to ping me in the issue or PR!
10 |
11 | ## Making contributions
12 |
13 | Once the change has been discussed:
14 |
15 | - Fork the repo
16 | - Code it up!
17 | - Open a PR
18 |
19 | ### Expectations for all changes
20 |
21 | - Tests
22 | - Reasonable browser support (~95% on caniuse.com or 5 years)
23 |
24 | Commit messages and formatting are enforced by the commit hooks. Please use `npm run cz` to commit.
25 |
26 | Thanks again and happy coding!
27 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: ci
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 |
9 | jobs:
10 | lint:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 | with:
15 | fetch-depth: 0
16 | - uses: actions/setup-node@v4
17 | with:
18 | node-version: 20
19 | cache: npm
20 | - name: Install dependencies
21 | run: |
22 | npm ci
23 | npm link
24 | npm link astro-themes
25 | - name: Check code
26 | run: npm run check:code
27 | - name: Check formatting
28 | run: npm run check:format
29 | - name: Check styles
30 | run: npm run check:styles
31 | - name: Check commit messages
32 | run: npx commitlint --from HEAD~${{ github.event.pull_request.commits }} --to HEAD --verbose
33 |
34 | test:
35 | runs-on: ubuntu-latest
36 | steps:
37 | - uses: actions/checkout@v4
38 | - uses: actions/setup-node@v4
39 | with:
40 | node-version: 20
41 | cache: npm
42 | - name: Install dependencies
43 | run: |
44 | npm ci
45 | npm link
46 | npm link astro-themes
47 | - name: Install Playwright Browsers
48 | run: npm run test:install
49 | - name: Run Playwright tests
50 | run: npm test
51 | - uses: actions/upload-artifact@v4
52 | with:
53 | name: playwright-report
54 | path: playwright-report/
55 | retention-days: 30
56 |
--------------------------------------------------------------------------------
/.github/workflows/release-please.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - main
5 |
6 | name: release-please
7 | jobs:
8 | release-please:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: google-github-actions/release-please-action@v3
12 | id: release
13 | with:
14 | release-type: node
15 | package-name: astro-themes
16 | bump-minor-pre-major: true
17 | bump-patch-for-minor-pre-major: true
18 | - uses: actions/checkout@v3
19 | if: ${{ steps.release.outputs.release_created }}
20 | - uses: actions/setup-node@v3
21 | with:
22 | node-version: 20
23 | registry-url: 'https://registry.npmjs.org'
24 | if: ${{ steps.release.outputs.release_created }}
25 | - run: npm ci
26 | if: ${{ steps.release.outputs.release_created }}
27 | - run: npm run build
28 | if: ${{ steps.release.outputs.release_created }}
29 | - run: npm publish
30 | env:
31 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
32 | if: ${{ steps.release.outputs.release_created }}
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Keep .prettierignore in sync with this file!
2 |
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 |
10 | # Dependency directories
11 | node_modules/
12 |
13 | # TypeScript cache
14 | *.tsbuildinfo
15 |
16 | # Environment variables
17 | .env
18 | .env.test
19 |
20 | # Astro output
21 | src/env.d.ts
22 | dist/
23 |
24 | # esbuild build output
25 | build/
26 |
27 | # Stylelint cache
28 | .cache
29 |
30 | # IDE files
31 | .idea/
32 |
33 | # Test output files
34 | tests/screenshots/
35 | tests/videos/
36 | /test-results/
37 | /playwright-report/
38 | /playwright/.cache/
39 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx --no -- commitlint --edit "$1"
5 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npm run check:code
5 | npx lint-staged
6 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # This is the same as the .gitignore but with the autogenerated changelog added
2 | CHANGELOG.md
3 |
4 | # Logs
5 | logs
6 | *.log
7 | npm-debug.log*
8 | yarn-debug.log*
9 | yarn-error.log*
10 |
11 | # Dependency directories
12 | node_modules/
13 |
14 | # TypeScript cache
15 | *.tsbuildinfo
16 |
17 | # Environment variables
18 | .env
19 | .env.test
20 |
21 | # Astro output
22 | src/env.d.ts
23 | dist/
24 |
25 | # esbuild build output
26 | build/
27 |
28 | # Stylelint cache
29 | .cache
30 |
31 | # IDE files
32 | .idea/
33 |
34 | # Test output files
35 | tests/screenshots/
36 | tests/videos/
37 | /test-results/
38 | /playwright-report/
39 | /playwright/.cache/
40 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [0.2.6](https://github.com/alex-grover/astro-themes/compare/v0.2.5...v0.2.6) (2025-04-23)
4 |
5 |
6 | ### Bug Fixes
7 |
8 | * **themes.astro:** change script to not be a module ([67702f2](https://github.com/alex-grover/astro-themes/commit/67702f2acfb3180a2588e54d08e31a6f3d211a8c))
9 |
10 | ## [0.2.6](https://github.com/alex-grover/astro-themes/compare/v0.2.5...v0.2.6) (2025-04-23)
11 |
12 |
13 | ### Bug Fixes
14 |
15 | * **themes.astro:** change script to not be a module ([67702f2](https://github.com/alex-grover/astro-themes/commit/67702f2acfb3180a2588e54d08e31a6f3d211a8c))
16 |
17 | ## [0.2.5](https://github.com/alex-grover/astro-themes/compare/v0.2.4...v0.2.5) (2024-02-02)
18 |
19 |
20 | ### Bug Fixes
21 |
22 | * rewrite theme after view transition ([d04ee26](https://github.com/alex-grover/astro-themes/commit/d04ee26cc9d98e74ffa4f56d06a9846970784161)), closes [#23](https://github.com/alex-grover/astro-themes/issues/23)
23 |
24 | ## [0.2.4](https://github.com/alex-grover/astro-themes/compare/v0.2.3...v0.2.4) (2023-06-06)
25 |
26 |
27 | ### Bug Fixes
28 |
29 | * **deps:** release to update dependencies ([cc30d3b](https://github.com/alex-grover/astro-themes/commit/cc30d3bb881fdd11f3a6e922b82e939d1cde982f))
30 |
31 | ## [0.2.3](https://github.com/alex-grover/astro-themes/compare/v0.2.2...v0.2.3) (2022-08-26)
32 |
33 |
34 | ### Bug Fixes
35 |
36 | * **build:** run build before publishing ([6dcba83](https://github.com/alex-grover/astro-themes/commit/6dcba83715afe33202d8eee72f412c8d17055e24))
37 |
38 | ## [0.2.2](https://github.com/alex-grover/astro-themes/compare/v0.2.1...v0.2.2) (2022-08-26)
39 |
40 |
41 | ### Features
42 |
43 | * minify snippet ([0a9ab05](https://github.com/alex-grover/astro-themes/commit/0a9ab05ee928fd8b2ec3f69c7987e746f6ace222))
44 |
45 | ## [0.2.1](https://github.com/alex-grover/astro-themes/compare/v0.2.0...v0.2.1) (2022-08-26)
46 |
47 |
48 | ### Bug Fixes
49 |
50 | * dispatch events on document, not window ([c721d72](https://github.com/alex-grover/astro-themes/commit/c721d724b31495f3499a55c8dc1a49453288855f))
51 |
52 | ## [0.2.0](https://github.com/alex-grover/astro-themes/compare/v0.1.0...v0.2.0) (2022-08-26)
53 |
54 |
55 | ### ⚠ BREAKING CHANGES
56 |
57 | * update get/set methods
58 |
59 | ### Code Refactoring
60 |
61 | * use web builtins to get and set theme ([db399fe](https://github.com/alex-grover/astro-themes/commit/db399fe7a9c92455f6a36bae8298358fb4ba2292))
62 |
63 | ## [0.1.0](https://github.com/alex-grover/astro-themes/compare/v0.0.1...v0.1.0) (2022-08-25)
64 |
65 |
66 | ### ⚠ BREAKING CHANGES
67 |
68 | * Update theme get/set methods
69 |
70 | ### Features
71 |
72 | * add listener for browser color scheme preference changes ([494a84a](https://github.com/alex-grover/astro-themes/commit/494a84a58415cab738f39a53668df15494f31c8c))
73 |
74 |
75 | ### Code Refactoring
76 |
77 | * update API to only expose one object on window ([dd1e8fd](https://github.com/alex-grover/astro-themes/commit/dd1e8fd56d8716eeecd6647a2b7fc01c035ff52e))
78 |
79 | ## 0.0.1 (2022-08-24)
80 |
81 |
82 | ### Features
83 |
84 | * implement theme component ([251c76b](https://github.com/alex-grover/astro-themes/commit/251c76bbbc7e250f7dfd266fc0d779f68a9064d6))
85 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Alex Grover
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🚀 astro-themes [](https://github.com/alex-grover/astro-themes/actions/workflows/ci.yml?query=branch%3Amain) [](https://www.npmjs.com/package/astro-themes)
2 |
3 | Easy dark mode for Astro websites. Add themes in 2 lines of code! Zero dependencies, supports SSR, and works with any
4 | framework or UI.
5 |
6 | ## Install
7 |
8 | ```sh
9 | npm install --save-dev astro-themes
10 | ```
11 |
12 | ## Use
13 |
14 | Add the `` component in your app. Works best in a centralized layout component, so it's shared everywhere.
15 |
16 | 
17 |
18 | ### Usage
19 |
20 | `astro-themes` gives you the ability to get and set the theme, with builtin browser standards. No polluting the global
21 | scope or any other hacks! These methods will work without a framework, or from within your React/Svelte/Vue/etc
22 | components.
23 |
24 | Set the theme:
25 |
26 | ```ts
27 | document.dispatchEvent(new CustomEvent('set-theme', { detail: 'dark' })) // or pass `null` to clear the saved setting
28 | ```
29 |
30 | Get the current theme:
31 |
32 | ```ts
33 | document.documentElement.attributes.getNamedItem('data-theme')?.value // 'light' | 'dark'
34 | ```
35 |
36 | Set a default theme (only applied if the browser doesn't specify a preference for dark mode):
37 |
38 | ```astro
39 |
40 | ```
41 |
42 | #### Compatibility with Tailwind
43 |
44 | By default, Tailwind expects `class="dark"` on the `html` element rather than `data-theme`. To ensure that `dark:` classes work correctly, you can configure your dark mode selector as described [here](https://tailwindcss.com/docs/dark-mode#customizing-the-selector).
45 |
46 | ## What does it do?
47 |
48 | - Provides ability to get and set the theme from any framework, or none at all
49 | - Set theme by dispatching a custom browser event: `document.dispatchEvent(new CustomEvent('set-theme', { detail: 'dark' }))`
50 | - Get current theme: `document.documentElement.attributes.getNamedItem('data-theme')?.value`
51 | - Sets `data-theme` attribute on the `html` element, so you can implement dark mode in CSS
52 | - Sets `color-scheme` CSS attribute on the `html` element, so the browser renders built in elements appropriately
53 | - Reads user theme preference on page load
54 | - From `localStorage`, if they've set it in the past
55 | - From `prefers-color-scheme: dark`, if supported
56 | - Falls back to the `defaultTheme` option, or `light` if not specified
57 | - Synchronizes setting across tabs
58 | - Responds to changes in OS preference (for example, the OS automatically switching to dark mode in the evening)
59 |
60 | ## Run example locally
61 |
62 | ```sh
63 | gh repo clone alex-grover/astro-themes
64 | cd astro-themes
65 | npm install
66 | npm link
67 | npm link astro-themes
68 | npm run example
69 | ```
70 |
71 | ## Feedback
72 |
73 | Ideas, bug reports, or questions are welcomed! Please don't hesitate to [open an issue](https://github.com/alex-grover/astro-themes/issues/new).
74 |
75 | This component was inspired by the excellent [`next-themes`](https://github.com/pacocoursey/next-themes).
76 |
--------------------------------------------------------------------------------
/Themes.astro.template:
--------------------------------------------------------------------------------
1 | ---
2 | {types}
3 |
4 | const { defaultTheme = 'light' } = Astro.props as Props
5 | ---
6 |
7 |
10 |
--------------------------------------------------------------------------------
/Themes.ts:
--------------------------------------------------------------------------------
1 | export type Theme = 'light' | 'dark'
2 |
3 | declare const defaultTheme: Theme
4 |
5 | declare global {
6 | interface DocumentEventMap {
7 | 'set-theme': CustomEvent
8 | }
9 | }
10 |
11 | export interface Props {
12 | defaultTheme?: Theme
13 | }
14 |
15 | const STORAGE_KEY = 'theme'
16 |
17 | const prefersDark = window.matchMedia('(prefers-color-scheme: dark)')
18 |
19 | function getThemePreference(): Theme {
20 | return prefersDark.matches ? 'dark' : defaultTheme
21 | }
22 |
23 | function resolveTheme(setting?: Theme | null): Theme {
24 | const storageValue =
25 | setting !== undefined
26 | ? setting
27 | : (localStorage.getItem(STORAGE_KEY) as Theme)
28 |
29 | return storageValue ?? getThemePreference()
30 | }
31 |
32 | function writeTheme(theme: Theme): void {
33 | document.documentElement.setAttribute('data-theme', theme)
34 | document.documentElement.style.colorScheme = theme
35 | }
36 |
37 | function handleStorageChange(event: StorageEvent): void {
38 | if (event.key !== STORAGE_KEY) return
39 | writeTheme(resolveTheme(event.newValue as Theme))
40 | }
41 |
42 | function rewriteTheme(): void {
43 | writeTheme(resolveTheme())
44 | }
45 |
46 | function handleThemeChange(event: CustomEvent): void {
47 | if (event.detail) {
48 | localStorage.setItem(STORAGE_KEY, event.detail)
49 | writeTheme(event.detail)
50 | } else {
51 | localStorage.removeItem(STORAGE_KEY)
52 | writeTheme(resolveTheme(event.detail))
53 | }
54 | }
55 |
56 | document.addEventListener('set-theme', handleThemeChange)
57 | window.addEventListener('storage', handleStorageChange)
58 | prefersDark.addEventListener('change', rewriteTheme)
59 | document.addEventListener('astro:after-swap', rewriteTheme)
60 | writeTheme(resolveTheme())
61 |
--------------------------------------------------------------------------------
/build.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs/promises'
2 |
3 | import { transform } from 'esbuild'
4 | import ts from 'typescript'
5 |
6 | import tsconfig from './tsconfig.json' with { type: 'json' }
7 |
8 | console.log('Building...')
9 |
10 | console.log('Starting transpile and minify...')
11 |
12 | const input = await fs.readFile('Themes.ts')
13 |
14 | const snippet = await transform(input, {
15 | target: 'es6',
16 | format: 'esm',
17 | loader: 'ts',
18 | minify: true,
19 | })
20 |
21 | console.log('Starting type generation...')
22 |
23 | let types
24 | const host = ts.createCompilerHost(tsconfig.compilerOptions)
25 | host.writeFile = (fileName, contents) => (types = contents)
26 | ts.createProgram(['Themes.ts'], tsconfig.compilerOptions, host).emit()
27 |
28 | console.log('Writing output file...')
29 |
30 | const template = await fs.readFile('Themes.astro.template')
31 |
32 | const output = template
33 | .toString()
34 | .replace('{types}', types.trim())
35 | .replace('{snippet}', snippet.code.trim())
36 |
37 | await fs.mkdir('build', { recursive: true })
38 | await fs.writeFile('build/Themes.astro', output)
39 |
40 | console.log('Build complete!')
41 |
--------------------------------------------------------------------------------
/example/.astro/types.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/example/public/slow.js:
--------------------------------------------------------------------------------
1 | console.log('hi')
2 |
--------------------------------------------------------------------------------
/example/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/example/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Themes from 'astro-themes'
3 | ---
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Astro Themes Example
12 |
13 |
27 |
28 |
29 |