Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default defineConfig({
Hero: "./src/components/Hero.astro",
SiteTitle: "./src/components/SiteTitle.astro",
ThemeProvider: "./src/components/ThemeProvider.astro",
ThemeSelect: "./src/components/ThemeSelect.astro",
},
head: [
{
Expand Down
86 changes: 86 additions & 0 deletions src/components/ThemeSelect.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
---

<starlight-theme-select>
<button id="theme-toggle" aria-label="Switch to dark mode" title="Toggle theme">
{/* Sun — visible in dark mode; clicking goes to light */}
<svg class="icon-light" aria-hidden="true" width="1em" height="1em" viewBox="0 0 24 24" fill="currentColor">
<path d="M5 12a1 1 0 0 0-1-1H3a1 1 0 0 0 0 2h1a1 1 0 0 0 1-1Zm.64 5-.71.71a1 1 0 0 0 0 1.41 1 1 0 0 0 1.41 0l.71-.71A1 1 0 0 0 5.64 17ZM12 5a1 1 0 0 0 1-1V3a1 1 0 0 0-2 0v1a1 1 0 0 0 1 1Zm5.66 2.34a1 1 0 0 0 .7-.29l.71-.71a1 1 0 1 0-1.41-1.41l-.66.71a1 1 0 0 0 0 1.41 1 1 0 0 0 .66.29Zm-12-.29a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-.71-.71a1.004 1.004 0 1 0-1.43 1.41l.73.71ZM21 11h-1a1 1 0 0 0 0 2h1a1 1 0 0 0 0-2Zm-2.64 6A1 1 0 0 0 17 18.36l.71.71a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-.76-.66ZM12 6.5a5.5 5.5 0 1 0 5.5 5.5A5.51 5.51 0 0 0 12 6.5Zm0 9a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7Zm0 3.5a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1a1 1 0 0 0-1-1Z"/>
</svg>
{/* Moon — visible in light mode; clicking goes to dark */}
<svg class="icon-dark" aria-hidden="true" width="1em" height="1em" viewBox="0 0 24 24" fill="currentColor">
<path d="M21.64 13a1 1 0 0 0-1.05-.14 8.049 8.049 0 0 1-3.37.73 8.15 8.15 0 0 1-8.14-8.1 8.59 8.59 0 0 1 .25-2A1 1 0 0 0 8 2.36a10.14 10.14 0 1 0 14 11.69 1 1 0 0 0-.36-1.05Zm-9.5 6.69A8.14 8.14 0 0 1 7.08 5.22v.27a10.15 10.15 0 0 0 10.14 10.14 9.784 9.784 0 0 0 2.1-.22 8.11 8.11 0 0 1-7.18 4.32v-.04Z"/>
</svg>
</button>
</starlight-theme-select>

<script is:inline>
StarlightThemeProvider.updatePickers();
</script>

<script>
type Theme = 'dark' | 'light';

const storageKey = 'starlight-theme';

const parseTheme = (theme: unknown): Theme =>
theme === 'dark' ? 'dark' : 'light';

const loadTheme = (): Theme =>
parseTheme(typeof localStorage !== 'undefined' && localStorage.getItem(storageKey));

function storeTheme(theme: Theme): void {
if (typeof localStorage !== 'undefined') {
localStorage.setItem(storageKey, theme);
}
}

function applyTheme(theme: Theme): void {
document.documentElement.dataset.theme = theme;
storeTheme(theme);
document.querySelectorAll('starlight-theme-select button').forEach((btn) => {
btn.setAttribute(
'aria-label',
theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'
);
});
}

class StarlightThemeSelect extends HTMLElement {
constructor() {
super();
applyTheme(loadTheme());
this.querySelector('button')?.addEventListener('click', () => {
applyTheme(loadTheme() === 'dark' ? 'light' : 'dark');
});
}
}
customElements.define('starlight-theme-select', StarlightThemeSelect);
</script>

<style>
starlight-theme-select button {
background: none;
border: none;
cursor: pointer;
padding: 0.375rem;
color: var(--sl-color-text);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.25rem;
border-radius: 0.25rem;
line-height: 1;
transition: color 0.2s ease, background 0.2s ease;
}

starlight-theme-select button:hover {
color: var(--sl-color-text-accent);
background: var(--sl-color-bg-sidebar);
}

/* In light mode: hide the sun (show the moon → clicking goes dark) */
:root[data-theme='light'] .icon-light { display: none; }
/* In dark mode: hide the moon (show the sun → clicking goes light) */
:root[data-theme='dark'] .icon-dark { display: none; }
</style>
Loading