jjj 0.2.1

A modal interface for Jujutsu.
---
import Select from './Select.astro';
---

<starlight-theme-select>
	{/* TODO: Can we give this select a width that works well for each language’s strings? */}
	<Select
		icon="laptop"
		label={Astro.locals.t('themeSelect.accessibleLabel')}
		value="auto"
		options={[
			{ label: Astro.locals.t('themeSelect.dark'), selected: false, value: 'dark' },
			{ label: Astro.locals.t('themeSelect.light'), selected: false, value: 'light' },
			{ label: Astro.locals.t('themeSelect.auto'), selected: true, value: 'auto' },
		]}
		width="6.25em"
	/>
</starlight-theme-select>

{/* Inlined to avoid FOUC. Uses global scope from `ThemeProvider.astro` */}
<script is:inline>
	StarlightThemeProvider.updatePickers();
</script>

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

	/** Key in `localStorage` to store color theme preference at. */
	const storageKey = 'starlight-theme';

	/** Get a typesafe theme string from any JS value (unknown values are coerced to `'auto'`). */
	const parseTheme = (theme: unknown): Theme =>
		theme === 'auto' || theme === 'dark' || theme === 'light' ? theme : 'auto';

	/** Load the user’s preference from `localStorage`. */
	const loadTheme = (): Theme =>
		parseTheme(typeof localStorage !== 'undefined' && localStorage.getItem(storageKey));

	/** Store the user’s preference in `localStorage`. */
	function storeTheme(theme: Theme): void {
		if (typeof localStorage !== 'undefined') {
			localStorage.setItem(storageKey, theme === 'light' || theme === 'dark' ? theme : '');
		}
	}

	/** Get the preferred system color scheme. */
	const getPreferredColorScheme = (): Theme =>
		matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';

	/** Update select menu UI, document theme, and local storage state. */
	function onThemeChange(theme: Theme): void {
		StarlightThemeProvider.updatePickers(theme);
		document.documentElement.dataset.theme = theme === 'auto' ? getPreferredColorScheme() : theme;
		storeTheme(theme);
	}

	// React to changes in system color scheme.
	matchMedia(`(prefers-color-scheme: light)`).addEventListener('change', () => {
		if (loadTheme() === 'auto') onThemeChange('auto');
	});

	class StarlightThemeSelect extends HTMLElement {
		constructor() {
			super();
			onThemeChange(loadTheme());
			this.querySelector('select')?.addEventListener('change', (e) => {
				if (e.currentTarget instanceof HTMLSelectElement) {
					onThemeChange(parseTheme(e.currentTarget.value));
				}
			});
		}
	}
	customElements.define('starlight-theme-select', StarlightThemeSelect);
</script>