starlight-theme-bejamas 0.1.18 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,123 @@
1
+ export const CURRENT_THEME_STYLESHEET_SELECTOR =
2
+ "link[data-current-theme-stylesheet]";
3
+
4
+ export function buildCurrentThemeStylesheetHref(
5
+ href: string,
6
+ version: string | number,
7
+ ) {
8
+ const url = new URL(href, "https://ui.bejamas.com");
9
+ url.searchParams.set("v", String(version));
10
+
11
+ const isAbsolute = /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(href);
12
+ return isAbsolute
13
+ ? url.toString()
14
+ : `${url.pathname}${url.search}${url.hash}`;
15
+ }
16
+
17
+ const PENDING_THEME_STYLESHEET_SELECTOR =
18
+ "link[data-pending-current-theme-stylesheet]";
19
+
20
+ let stylesheetSwapToken = 0;
21
+ let stylesheetVersionCounter = 0;
22
+ let cancelPendingThemeStylesheetSwap: (() => void) | null = null;
23
+
24
+ function getAnimationFrame() {
25
+ if (typeof window !== "undefined" && window.requestAnimationFrame) {
26
+ return window.requestAnimationFrame.bind(window);
27
+ }
28
+
29
+ return (callback: FrameRequestCallback) =>
30
+ window.setTimeout(() => callback(performance.now()), 0);
31
+ }
32
+
33
+ export function refreshCurrentThemeStylesheet() {
34
+ const currentStylesheet = document.querySelector<HTMLLinkElement>(
35
+ "link[data-current-theme-stylesheet]",
36
+ );
37
+
38
+ if (!currentStylesheet) {
39
+ return Promise.resolve();
40
+ }
41
+
42
+ cancelPendingThemeStylesheetSwap?.();
43
+
44
+ // Strictly-monotonic version so two refreshes in the same millisecond can
45
+ // never collide on a cached response (which would swap in a stale theme).
46
+ const nextHref = buildCurrentThemeStylesheetHref(
47
+ currentStylesheet.href,
48
+ `${Date.now()}-${++stylesheetVersionCounter}`,
49
+ );
50
+ const nextStylesheet = currentStylesheet.cloneNode(true) as HTMLLinkElement;
51
+ const swapToken = ++stylesheetSwapToken;
52
+ const requestAnimationFrame = getAnimationFrame();
53
+
54
+ nextStylesheet.href = nextHref;
55
+ nextStylesheet.removeAttribute("data-current-theme-stylesheet");
56
+ nextStylesheet.setAttribute("data-pending-current-theme-stylesheet", "");
57
+
58
+ document
59
+ .querySelectorAll<HTMLLinkElement>(PENDING_THEME_STYLESHEET_SELECTOR)
60
+ .forEach((link) => {
61
+ if (link !== nextStylesheet) {
62
+ link.remove();
63
+ }
64
+ });
65
+
66
+ return new Promise<void>((resolve) => {
67
+ let settled = false;
68
+
69
+ const settle = () => {
70
+ if (settled) {
71
+ return;
72
+ }
73
+
74
+ settled = true;
75
+ if (cancelPendingThemeStylesheetSwap === cancel) {
76
+ cancelPendingThemeStylesheetSwap = null;
77
+ }
78
+ resolve();
79
+ };
80
+
81
+ const cleanup = () => {
82
+ nextStylesheet.removeEventListener("load", onLoad);
83
+ nextStylesheet.removeEventListener("error", onError);
84
+ };
85
+
86
+ const cancel = () => {
87
+ cleanup();
88
+ nextStylesheet.remove();
89
+ settle();
90
+ };
91
+
92
+ const onError = () => {
93
+ cancel();
94
+ };
95
+
96
+ const onLoad = () => {
97
+ cleanup();
98
+
99
+ if (swapToken !== stylesheetSwapToken) {
100
+ nextStylesheet.remove();
101
+ settle();
102
+ return;
103
+ }
104
+
105
+ currentStylesheet.removeAttribute("data-current-theme-stylesheet");
106
+ nextStylesheet.removeAttribute("data-pending-current-theme-stylesheet");
107
+ nextStylesheet.setAttribute("data-current-theme-stylesheet", "");
108
+
109
+ requestAnimationFrame(() => {
110
+ if (swapToken === stylesheetSwapToken) {
111
+ currentStylesheet.remove();
112
+ }
113
+
114
+ settle();
115
+ });
116
+ };
117
+
118
+ cancelPendingThemeStylesheetSwap = cancel;
119
+ nextStylesheet.addEventListener("load", onLoad, { once: true });
120
+ nextStylesheet.addEventListener("error", onError, { once: true });
121
+ currentStylesheet.insertAdjacentElement("afterend", nextStylesheet);
122
+ });
123
+ }
@@ -87,12 +87,12 @@ const { toc } = Astro.locals.starlightRoute;
87
87
  align-items: center;
88
88
  justify-content: space-between;
89
89
  border: 1px solid var(--sl-color-gray-5);
90
- border-radius: 0.5rem;
90
+ border-radius: calc(var(--radius) - 2px);
91
91
  padding-block: 0.5rem;
92
92
  padding-inline-start: 0.75rem;
93
93
  padding-inline-end: 0.5rem;
94
94
  line-height: 1;
95
- background-color: var(--sl-color-black);
95
+ background-color: var(--background);
96
96
  user-select: none;
97
97
  cursor: pointer;
98
98
  font-weight: 500;
@@ -133,11 +133,11 @@ const { toc } = Astro.locals.starlightRoute;
133
133
  transition: background 200ms ease-out;
134
134
  }
135
135
  details[open] .toggle {
136
- color: var(--sl-color-white);
136
+ color: var(--foreground);
137
137
  border-color: var(--sl-color-accent);
138
138
  }
139
139
  details .toggle:hover {
140
- color: var(--sl-color-white);
140
+ color: var(--foreground);
141
141
  border-color: var(--sl-color-gray-2);
142
142
  }
143
143
 
@@ -152,7 +152,7 @@ const { toc } = Astro.locals.starlightRoute;
152
152
  white-space: nowrap;
153
153
  text-overflow: ellipsis;
154
154
  overflow: hidden;
155
- color: var(--sl-color-white);
155
+ color: var(--foreground);
156
156
  }
157
157
 
158
158
  .dropdown {
@@ -164,7 +164,7 @@ const { toc } = Astro.locals.starlightRoute;
164
164
  85vh - var(--sl-nav-height) - var(--sl-mobile-toc-height)
165
165
  );
166
166
  overflow-y: auto;
167
- background-color: var(--sl-color-black);
167
+ background-color: var(--popover);
168
168
  box-shadow: var(--sl-shadow-md);
169
169
  overscroll-behavior: contain;
170
170
  }
@@ -28,83 +28,44 @@ const isSplashTemplate = template === "splash";
28
28
  aria-label={Astro.locals.t("sidebarNav.accessibleLabel")}
29
29
  >
30
30
  <MobileMenuToggle />
31
- <div id="starlight__sidebar" class="sidebar-pane">
31
+ <script>
32
+ if (!customElements.get("sl-sidebar-pane")) {
33
+ class StarlightSidebarPane extends HTMLElement {
34
+ constructor() {
35
+ super();
36
+
37
+ const desktopMediaQuery = matchMedia("(min-width: 64rem)");
38
+ const updatePopover = () => {
39
+ this.popover = desktopMediaQuery.matches ? null : "auto";
40
+ };
41
+ updatePopover();
42
+ desktopMediaQuery.addEventListener("change", updatePopover);
43
+
44
+ this.addEventListener("toggle", () => {
45
+ const isOpen = this.matches(":popover-open");
46
+ document
47
+ .querySelectorAll<HTMLElement>(".main-frame, .sl-skip-link")
48
+ .forEach((element) => element.toggleAttribute("inert", isOpen));
49
+
50
+ if (isOpen && this.closest(".sidebar-splash")) {
51
+ this.scrollTop = 0;
52
+ }
53
+ });
54
+ }
55
+ }
56
+
57
+ customElements.define("sl-sidebar-pane", StarlightSidebarPane);
58
+ }
59
+ </script>
60
+ <sl-sidebar-pane popover="" id="starlight__sidebar" class="sidebar-pane">
32
61
  <div class="sidebar-content sl-flex">
33
62
  <slot name="sidebar" />
34
63
  </div>
35
- </div>
64
+ </sl-sidebar-pane>
36
65
  </nav>
37
66
  )
38
67
  }
39
68
 
40
- {
41
- isSplashTemplate && (
42
- <script is:inline>
43
- (() => {
44
- const installReset = () => {
45
- const nav = document.querySelector("nav.sidebar-splash");
46
- if (!(nav instanceof HTMLElement)) return () => {};
47
-
48
- const pane = nav.querySelector("#starlight__sidebar");
49
- const toggle = nav.querySelector("starlight-menu-button");
50
-
51
- if (!(pane instanceof HTMLElement)) return () => {};
52
-
53
- const resetToTop = () => {
54
- pane.scrollTop = 0;
55
- };
56
-
57
- // Avoid opening splash menus at a persisted offset.
58
- resetToTop();
59
-
60
- if (!(toggle instanceof HTMLElement)) return () => {};
61
-
62
- const onToggleChange = () => {
63
- if (toggle.getAttribute("aria-expanded") === "true") {
64
- requestAnimationFrame(resetToTop);
65
- }
66
- };
67
-
68
- const onToggleClick = () => {
69
- requestAnimationFrame(onToggleChange);
70
- };
71
-
72
- toggle.addEventListener("click", onToggleClick);
73
-
74
- const observer = new MutationObserver(onToggleChange);
75
- observer.observe(toggle, {
76
- attributes: true,
77
- attributeFilter: ["aria-expanded"],
78
- });
79
-
80
- return () => {
81
- toggle.removeEventListener("click", onToggleClick);
82
- observer.disconnect();
83
- };
84
- };
85
-
86
- let cleanup = installReset();
87
-
88
- const onAstroPageLoad = () => {
89
- cleanup();
90
- cleanup = installReset();
91
- };
92
-
93
- document.addEventListener("astro:page-load", onAstroPageLoad);
94
-
95
- addEventListener(
96
- "pagehide",
97
- () => {
98
- cleanup();
99
- document.removeEventListener("astro:page-load", onAstroPageLoad);
100
- },
101
- { once: true },
102
- );
103
- })();
104
- </script>
105
- )
106
- }
107
-
108
69
  <div class:list={["main-frame", isSplashTemplate && "main-frame-splash"]}>
109
70
  {
110
71
  template === "splash" ? (
@@ -182,15 +143,17 @@ const isSplashTemplate = template === "splash";
182
143
  }
183
144
 
184
145
  .sidebar-pane {
185
- visibility: var(--sl-sidebar-visibility, hidden);
146
+ border: 0;
147
+ margin: 0;
148
+ color: inherit;
149
+ display: none;
186
150
  position: fixed;
187
151
  z-index: var(--sl-z-index-menu);
188
152
  inset-block: var(--sl-nav-height) 0;
189
153
  inset-inline-start: 0;
190
154
  width: 100%;
191
155
  background-color: var(--background);
192
- height: 100svh;
193
- overflow: scroll;
156
+ height: calc(100svh - var(--sl-nav-height));
194
157
  overflow-y: scroll;
195
158
  overflow-x: hidden;
196
159
  scrollbar-width: none;
@@ -198,12 +161,11 @@ const isSplashTemplate = template === "splash";
198
161
  -webkit-overflow-scrolling: touch;
199
162
  overscroll-behavior: contain;
200
163
  overscroll-behavior-y: contain;
201
- top: 0;
202
- padding-top: calc(var(--spacing) * 18);
164
+ padding: 0;
203
165
  }
204
166
 
205
- :global([aria-expanded="true"]) ~ .sidebar-pane {
206
- --sl-sidebar-visibility: visible;
167
+ .sidebar-pane:popover-open {
168
+ display: block;
207
169
  }
208
170
 
209
171
  .sidebar-content {
@@ -219,11 +181,6 @@ const isSplashTemplate = template === "splash";
219
181
  content: "";
220
182
  padding-bottom: 1px;
221
183
  }
222
-
223
- .sidebar-pane {
224
- padding-top: 0;
225
- margin-top: calc(var(--spacing) * 18);
226
- }
227
184
  }
228
185
 
229
186
  .main-frame {
@@ -315,7 +272,7 @@ const isSplashTemplate = template === "splash";
315
272
  padding-inline-end: var(--sl-nav-pad-x);
316
273
  }
317
274
  .sidebar-pane {
318
- --sl-sidebar-visibility: visible;
275
+ display: block;
319
276
  width: var(--sl-sidebar-width);
320
277
  background-color: var(--sl-color-bg-sidebar);
321
278
  border-inline-end: 1px solid var(--sl-color-hairline-shade);
@@ -100,7 +100,7 @@ const isRtl = dir === "rtl";
100
100
  display: flex;
101
101
  justify-content: space-between;
102
102
  flex-wrap: wrap;
103
- margin-top: 0.5rem;
103
+ margin-top: 0;
104
104
  align-items: center;
105
105
  }
106
106
  .sl-bejamas-docs-title-buttons {
@@ -129,7 +129,7 @@ const isRtl = dir === "rtl";
129
129
  font-size: 1.875rem;
130
130
  line-height: 1.2;
131
131
  font-weight: 500;
132
- color: var(--sl-color-white);
132
+ color: var(--foreground);
133
133
  }
134
134
 
135
135
  @media (min-width: 50rem) {
@@ -70,7 +70,7 @@ const { toc, isMobile = false, depth = 0 } = Astro.props;
70
70
  .isMobile a[aria-current="true"],
71
71
  .isMobile a[aria-current="true"]:hover,
72
72
  .isMobile a[aria-current="true"]:focus {
73
- color: var(--sl-color-white);
73
+ color: var(--foreground);
74
74
  background-color: unset;
75
75
  }
76
76
  .isMobile a[aria-current="true"]::after {
@@ -1,7 +1,14 @@
1
+ ---
2
+ import { buildThemeChoiceBootstrapInlineScript } from "../lib/theme-choice";
3
+
4
+ const themeChoiceBootstrapScript = buildThemeChoiceBootstrapInlineScript();
5
+ ---
6
+
7
+ <script is:inline set:html={themeChoiceBootstrapScript} />
8
+
1
9
  {/* This is intentionally inlined to avoid FOUC. */}
2
10
  <script is:inline>
3
11
  window.StarlightThemeProvider = (() => {
4
- const storageKey = "starlight-theme";
5
12
  const themeMetaMedias = [
6
13
  "(prefers-color-scheme: light)",
7
14
  "(prefers-color-scheme: dark)",
@@ -14,12 +21,12 @@
14
21
  theme === "auto" || theme === "dark" || theme === "light"
15
22
  ? theme
16
23
  : "auto";
17
- const getStoredThemeChoice = () =>
18
- parseTheme(
19
- typeof localStorage !== "undefined" && localStorage.getItem(storageKey),
20
- );
24
+ const getPreferredColorScheme = () =>
25
+ window.matchMedia("(prefers-color-scheme: light)").matches
26
+ ? "light"
27
+ : "dark";
21
28
 
22
- const themeColors = (() => {
29
+ const readThemeColors = () => {
23
30
  const html = document.documentElement;
24
31
  const prevTheme = html.dataset.theme;
25
32
  const prevDark = html.classList.contains("dark");
@@ -45,7 +52,7 @@
45
52
  }
46
53
 
47
54
  return { light, dark };
48
- })();
55
+ };
49
56
 
50
57
  function ensureThemeMeta(head, media) {
51
58
  const baseSelector = `meta[name="theme-color"][media="${media}"]`;
@@ -67,6 +74,7 @@
67
74
  }
68
75
 
69
76
  function syncThemeColor(theme) {
77
+ const themeColors = readThemeColors();
70
78
  const color = themeColors[theme];
71
79
  const head = document.head;
72
80
  if (!color || !head) return;
@@ -77,23 +85,25 @@
77
85
  });
78
86
  }
79
87
 
80
- const themeChoice = getStoredThemeChoice();
81
88
  const effectiveTheme =
82
- themeChoice === "auto"
83
- ? window.matchMedia("(prefers-color-scheme: light)").matches
84
- ? "light"
85
- : "dark"
86
- : themeChoice;
87
- document.documentElement.dataset.theme = effectiveTheme;
88
- document.documentElement.dataset.themeChoice = themeChoice;
89
- document.documentElement.classList.toggle(
90
- "dark",
91
- effectiveTheme === "dark",
92
- );
89
+ document.documentElement.dataset.theme === "light" ||
90
+ document.documentElement.dataset.theme === "dark"
91
+ ? document.documentElement.dataset.theme
92
+ : getPreferredColorScheme();
93
93
  syncThemeColor(effectiveTheme);
94
94
  return {
95
+ refreshThemeColors(theme) {
96
+ const themeChoice = parseTheme(
97
+ theme ?? document.documentElement.dataset.themeChoice,
98
+ );
99
+ const effectiveTheme =
100
+ themeChoice === "auto" ? getPreferredColorScheme() : themeChoice;
101
+ syncThemeColor(effectiveTheme);
102
+ },
95
103
  updatePickers(theme) {
96
- const themeChoice = parseTheme(theme ?? getStoredThemeChoice());
104
+ const themeChoice = parseTheme(
105
+ theme ?? document.documentElement.dataset.themeChoice,
106
+ );
97
107
  document
98
108
  .querySelectorAll("starlight-theme-select")
99
109
  .forEach((picker) => {
@@ -110,19 +120,79 @@
110
120
  new CustomEvent("select:set", { detail: { value: themeChoice } }),
111
121
  );
112
122
  }
113
-
114
- /** @type {HTMLTemplateElement | null} */
115
- const tmpl = document.querySelector(`#theme-icons`);
116
- const newIcon =
117
- tmpl && tmpl.content.querySelector("." + themeChoice);
118
- if (newIcon) {
119
- const oldIcon = picker.querySelector("svg.label-icon");
120
- if (oldIcon) {
121
- oldIcon.replaceChildren(...newIcon.cloneNode(true).childNodes);
122
- }
123
- }
124
123
  });
125
124
  },
126
125
  };
127
126
  })();
128
127
  </script>
128
+
129
+ <script>
130
+ import { syncSemanticIconsInRoot } from "@bejamas/semantic-icons/browser";
131
+ import { refreshCurrentThemeStylesheet } from "../lib/theme-stylesheet";
132
+
133
+ const PRESET_CHANGE_EVENT = "bejamas:preset-change";
134
+ const SETUP_KEY = "__bejamasCurrentThemeStylesheetSync";
135
+ let reloadFrame = 0;
136
+ let pendingIconLibrary = null;
137
+
138
+ function syncDocumentIconLibrary() {
139
+ const renderedIcon = document.querySelector("[data-icon-library]");
140
+ const iconLibrary =
141
+ renderedIcon instanceof SVGElement
142
+ ? renderedIcon.dataset.iconLibrary
143
+ : document.documentElement.dataset.iconLibrary;
144
+
145
+ if (iconLibrary) {
146
+ document.documentElement.dataset.iconLibrary = iconLibrary;
147
+ syncSemanticIconsInRoot(document, iconLibrary);
148
+ }
149
+ }
150
+
151
+ const scheduleCurrentThemeStylesheetRefresh = () => {
152
+ if (reloadFrame) {
153
+ return;
154
+ }
155
+
156
+ reloadFrame = requestAnimationFrame(() => {
157
+ reloadFrame = 0;
158
+ void refreshCurrentThemeStylesheet().then(() => {
159
+ if (pendingIconLibrary) {
160
+ document.documentElement.dataset.iconLibrary = pendingIconLibrary;
161
+ syncSemanticIconsInRoot(document, pendingIconLibrary);
162
+ pendingIconLibrary = null;
163
+ }
164
+ window.StarlightThemeProvider?.refreshThemeColors?.();
165
+ });
166
+ });
167
+ };
168
+
169
+ if (!(SETUP_KEY in window)) {
170
+ window[SETUP_KEY] = true;
171
+ syncDocumentIconLibrary();
172
+
173
+ window.addEventListener("theme-toggle-changed", (event) => {
174
+ const themeChoice =
175
+ event instanceof CustomEvent && typeof event.detail?.themeChoice === "string"
176
+ ? event.detail.themeChoice
177
+ : undefined;
178
+
179
+ window.StarlightThemeProvider?.refreshThemeColors?.(themeChoice);
180
+ });
181
+
182
+ window.addEventListener(PRESET_CHANGE_EVENT, (event) => {
183
+ const presetChange = event;
184
+
185
+ pendingIconLibrary =
186
+ presetChange instanceof CustomEvent &&
187
+ typeof presetChange.detail?.iconLibrary === "string"
188
+ ? presetChange.detail.iconLibrary
189
+ : null;
190
+
191
+ scheduleCurrentThemeStylesheetRefresh();
192
+ });
193
+ document.addEventListener("astro:after-swap", () => {
194
+ window.StarlightThemeProvider?.refreshThemeColors?.();
195
+ syncDocumentIconLibrary();
196
+ });
197
+ }
198
+ </script>
@@ -36,61 +36,46 @@ import { SunIcon, MoonIcon, LaptopIcon } from "@lucide/astro";
36
36
  </div>
37
37
  </starlight-theme-select>
38
38
 
39
- <script is:inline>
40
- StarlightThemeProvider.updatePickers();
41
- </script>
42
-
43
39
  <script>
44
- type Theme = "auto" | "dark" | "light";
45
- const storageKey = "starlight-theme";
46
-
47
- const parseTheme = (theme: unknown): Theme =>
48
- theme === "auto" || theme === "dark" || theme === "light" ? theme : "auto";
49
-
50
- const loadTheme = (): Theme =>
51
- parseTheme(
52
- typeof localStorage !== "undefined" && localStorage.getItem(storageKey),
53
- );
54
-
55
- function storeTheme(theme: Theme): void {
56
- if (typeof localStorage !== "undefined") {
57
- localStorage.setItem(
58
- storageKey,
59
- theme === "light" || theme === "dark" ? theme : "",
60
- );
61
- }
62
- }
40
+ import {
41
+ getThemeChoiceFromRoot,
42
+ parseStoredThemeChoice,
43
+ setThemeChoice,
44
+ syncThemeChoiceControls,
45
+ } from "../lib/theme-choice";
63
46
 
64
- const getPreferredColorScheme = (): Theme =>
65
- matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark";
47
+ class StarlightThemeSelect extends HTMLElement {
48
+ private selectRoot: HTMLElement | null = null;
66
49
 
67
- function onThemeChange(theme: Theme): void {
68
- const resolved = theme === "auto" ? getPreferredColorScheme() : theme;
69
- StarlightThemeProvider.updatePickers(theme);
70
- document.documentElement.dataset.theme = resolved;
71
- document.documentElement.dataset.themeChoice = theme;
72
- document.documentElement.classList.toggle("dark", resolved === "dark");
73
- storeTheme(theme);
74
- }
50
+ private onSelectChange = (event: Event) => {
51
+ const value = (event as CustomEvent<{ value?: unknown }>).detail?.value;
52
+ if (typeof value !== "string") return;
75
53
 
76
- matchMedia("(prefers-color-scheme: light)").addEventListener("change", () => {
77
- if (loadTheme() === "auto") onThemeChange("auto");
78
- });
54
+ const nextTheme = parseStoredThemeChoice(value);
55
+ const currentTheme = getThemeChoiceFromRoot(document.documentElement);
56
+ if (nextTheme === currentTheme) return;
79
57
 
80
- class StarlightThemeSelect extends HTMLElement {
81
- constructor() {
82
- super();
83
- onThemeChange(loadTheme());
84
- const select = this.querySelector("#starlight-theme-select");
85
- select?.addEventListener("select:change", (e) => {
86
- if (e.detail.value) {
87
- onThemeChange(parseTheme(e.detail.value));
88
- }
89
- });
58
+ setThemeChoice(nextTheme);
59
+ };
60
+
61
+ connectedCallback() {
62
+ this.selectRoot = this.querySelector<HTMLElement>("#starlight-theme-select");
63
+ syncThemeChoiceControls(
64
+ getThemeChoiceFromRoot(document.documentElement),
65
+ this,
66
+ );
67
+ this.selectRoot?.addEventListener("select:change", this.onSelectChange);
68
+ }
69
+
70
+ disconnectedCallback() {
71
+ this.selectRoot?.removeEventListener("select:change", this.onSelectChange);
72
+ this.selectRoot = null;
90
73
  }
91
74
  }
92
75
 
93
- customElements.define("starlight-theme-select", StarlightThemeSelect);
76
+ if (!customElements.get("starlight-theme-select")) {
77
+ customElements.define("starlight-theme-select", StarlightThemeSelect);
78
+ }
94
79
  </script>
95
80
 
96
81
  <style>