@grove-dev/starlight 0.1.9

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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +200 -0
  3. package/components/custom/ContainerSection.astro +58 -0
  4. package/components/custom/LinkButton.astro +141 -0
  5. package/components/custom/dropdown/Dropdown.astro +616 -0
  6. package/components/custom/dropdown/DropdownContent.astro +179 -0
  7. package/components/custom/dropdown/DropdownItem.astro +72 -0
  8. package/components/custom/dropdown/DropdownLabel.astro +31 -0
  9. package/components/custom/dropdown/DropdownSeparator.astro +18 -0
  10. package/components/custom/dropdown/DropdownShortcut.astro +24 -0
  11. package/components/custom/dropdown/DropdownTrigger.astro +54 -0
  12. package/components/custom/dropdown/index.ts +29 -0
  13. package/components/overrides/ContentPanel.astro +1 -0
  14. package/components/overrides/Footer.astro +54 -0
  15. package/components/overrides/Header.astro +93 -0
  16. package/components/overrides/Hero.astro +260 -0
  17. package/components/overrides/MarkdownContent.astro +17 -0
  18. package/components/overrides/PageFrame.astro +121 -0
  19. package/components/overrides/PageSidebar.astro +20 -0
  20. package/components/overrides/PageTitle.astro +130 -0
  21. package/components/overrides/Pagination.astro +101 -0
  22. package/components/overrides/Search.astro +549 -0
  23. package/components/overrides/Sidebar.astro +111 -0
  24. package/components/overrides/SiteTitle.astro +65 -0
  25. package/components/overrides/SocialIcons.astro +47 -0
  26. package/components/overrides/TableOfContents.astro +36 -0
  27. package/components/overrides/ThemeSelect.astro +156 -0
  28. package/components/overrides/TwoColumnContent.astro +75 -0
  29. package/components/overrides/parts/Drawer.astro +232 -0
  30. package/components/overrides/parts/MobileMenuToggle.astro +42 -0
  31. package/components/overrides/parts/NavBar.astro +110 -0
  32. package/components/overrides/parts/SidebarSublist.astro +115 -0
  33. package/components/overrides/parts/toc/TableOfContentsList.astro +71 -0
  34. package/components/overrides/parts/toc/starlight-toc.ts +119 -0
  35. package/core/config/constants.ts +1 -0
  36. package/core/config/expresive-code.ts +63 -0
  37. package/core/config/override.ts +48 -0
  38. package/core/config/schemas.ts +57 -0
  39. package/core/config/vite.ts +20 -0
  40. package/core/plugin.ts +56 -0
  41. package/global.d.ts +5 -0
  42. package/index.ts +3 -0
  43. package/package.json +54 -0
  44. package/schema.ts +24 -0
  45. package/styles/base.css +897 -0
  46. package/styles/layers.css +1 -0
  47. package/styles/theme.css +67 -0
  48. package/user-components.ts +3 -0
  49. package/virtual.d.ts +51 -0
@@ -0,0 +1,549 @@
1
+ ---
2
+ import '@pagefind/default-ui/css/ui.css';
3
+ import project from 'virtual:starlight/project-context';
4
+
5
+ const pagefindTranslations = {
6
+ placeholder: Astro.locals.t('search.label'),
7
+ ...Object.fromEntries(
8
+ Object.entries(Astro.locals.t.all())
9
+ .filter(([key]) => key.startsWith('pagefind.'))
10
+ .map(([key, value]) => [key.replace('pagefind.', ''), value])
11
+ ),
12
+ };
13
+
14
+ const dataAttributes: DOMStringMap = { 'data-translations': JSON.stringify(pagefindTranslations) };
15
+ if (project.trailingSlash === 'never') dataAttributes['data-strip-trailing-slash'] = '';
16
+ ---
17
+
18
+ <site-search class={Astro.props.class} {...dataAttributes}>
19
+ <button
20
+ data-open-modal
21
+ disabled
22
+ aria-label={Astro.locals.t('search.label')}
23
+ aria-keyshortcuts="Control+K"
24
+ >
25
+ <span aria-hidden="true">{Astro.locals.t('search.label')}</span>
26
+ <kbd class="sl-hidden md:sl-flex" style="display: none;">
27
+ <kbd>{Astro.locals.t('search.ctrlKey')}</kbd><kbd>K</kbd>
28
+ </kbd>
29
+ </button>
30
+
31
+ <dialog style="padding:0" aria-label={Astro.locals.t('search.label')}>
32
+ <div class="dialog-frame sl-flex">
33
+ {
34
+ /* TODO: Make the layout of this button flexible to accommodate different word lengths. Currently hard-coded for English: “Cancel” */
35
+ }
36
+ <button data-close-modal class="sl-flex md:sl-hidden">
37
+ {Astro.locals.t('search.cancelLabel')}
38
+ </button>
39
+ {
40
+ import.meta.env.DEV ? (
41
+ <div style="margin: auto; text-align: center; white-space: pre-line;" dir="ltr">
42
+ <p>{Astro.locals.t('search.devWarning')}</p>
43
+ </div>
44
+ ) : (
45
+ <div class="search-container">
46
+ <div id="starlight__search" />
47
+ </div>
48
+ )
49
+ }
50
+ </div>
51
+ </dialog>
52
+ </site-search>
53
+
54
+ {
55
+ /**
56
+ * This is intentionally inlined to avoid briefly showing an invalid shortcut.
57
+ * Purposely using the deprecated `navigator.platform` property to detect Apple devices, as the
58
+ * user agent is spoofed by some browsers when opening the devtools.
59
+ */
60
+ }
61
+ <script is:inline>
62
+ (() => {
63
+ const openBtn = document.querySelector('button[data-open-modal]');
64
+ const shortcut = openBtn?.querySelector('kbd');
65
+ if (!openBtn || !(shortcut instanceof HTMLElement)) {
66
+ return;
67
+ }
68
+ const updateShortcutDisplay = () => {
69
+ shortcut.style.setProperty(
70
+ 'display',
71
+ matchMedia('(min-width: 40rem)').matches ? 'flex' : 'none',
72
+ 'important'
73
+ );
74
+ };
75
+ const platformKey = shortcut.querySelector('kbd');
76
+ // eslint-disable-next-line regexp/no-unused-capturing-group
77
+ if (platformKey && /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {
78
+ platformKey.textContent = '⌘';
79
+ openBtn.setAttribute('aria-keyshortcuts', 'Meta+K');
80
+ }
81
+ updateShortcutDisplay();
82
+ matchMedia('(min-width: 40rem)').addEventListener('change', updateShortcutDisplay);
83
+ })();
84
+ </script>
85
+
86
+ <script>
87
+ import { pagefindUserConfig } from 'virtual:starlight/pagefind-config';
88
+
89
+ class SiteSearch extends HTMLElement {
90
+ constructor() {
91
+ super();
92
+ const openBtn = this.querySelector<HTMLButtonElement>('button[data-open-modal]')!;
93
+ const closeBtn = this.querySelector<HTMLButtonElement>('button[data-close-modal]')!;
94
+ const dialog = this.querySelector('dialog')!;
95
+ const dialogFrame = this.querySelector('.dialog-frame')!;
96
+
97
+ /** Close the modal if a user clicks on a link or outside of the modal. */
98
+ const onClick = (event: MouseEvent) => {
99
+ const isLink = 'href' in (event.target || {});
100
+ if (
101
+ isLink ||
102
+ (document.body.contains(event.target as Node) &&
103
+ !dialogFrame.contains(event.target as Node))
104
+ ) {
105
+ closeModal();
106
+ }
107
+ };
108
+
109
+ const openModal = (event?: MouseEvent) => {
110
+ dialog.showModal();
111
+ document.body.toggleAttribute('data-search-modal-open', true);
112
+ this.querySelector('input')?.focus();
113
+ event?.stopPropagation();
114
+ window.addEventListener('click', onClick);
115
+ };
116
+
117
+ const closeModal = () => dialog.close();
118
+
119
+ openBtn.addEventListener('click', openModal);
120
+ openBtn.disabled = false;
121
+ closeBtn.addEventListener('click', closeModal);
122
+
123
+ dialog.addEventListener('close', () => {
124
+ document.body.toggleAttribute('data-search-modal-open', false);
125
+ window.removeEventListener('click', onClick);
126
+ });
127
+
128
+ // Listen for `ctrl + k` and `cmd + k` keyboard shortcuts.
129
+ window.addEventListener('keydown', (e) => {
130
+ if ((e.metaKey === true || e.ctrlKey === true) && e.key === 'k') {
131
+ dialog.open ? closeModal() : openModal();
132
+ e.preventDefault();
133
+ }
134
+ });
135
+
136
+ let translations = {};
137
+ try {
138
+ translations = JSON.parse(this.dataset.translations || '{}');
139
+ } catch {}
140
+
141
+ const shouldStrip = this.dataset.stripTrailingSlash !== undefined;
142
+ const stripTrailingSlash = (path: string) => path.replace(/(.)\/(#.*)?$/, '$1$2');
143
+ const formatURL = shouldStrip ? stripTrailingSlash : (path: string) => path;
144
+
145
+ window.addEventListener('DOMContentLoaded', () => {
146
+ if (import.meta.env.DEV) return;
147
+ const onIdle = window.requestIdleCallback || ((cb) => setTimeout(cb, 1));
148
+ onIdle(async () => {
149
+ // @ts-expect-error — Missing types for @pagefind/default-ui package.
150
+ const { PagefindUI } = await import('@pagefind/default-ui');
151
+ new PagefindUI({
152
+ ...pagefindUserConfig,
153
+ element: '#starlight__search',
154
+ baseUrl: import.meta.env.BASE_URL,
155
+ bundlePath: `${import.meta.env.BASE_URL.replace(/\/$/, '')}/pagefind/`,
156
+ showImages: false,
157
+ translations,
158
+ showSubResults: true,
159
+ processResult: (result: {
160
+ url: string;
161
+ sub_results: Array<{ url: string }>;
162
+ }) => {
163
+ result.url = formatURL(result.url);
164
+ result.sub_results = result.sub_results.map((sub_result) => {
165
+ sub_result.url = formatURL(sub_result.url);
166
+ return sub_result;
167
+ });
168
+ },
169
+ });
170
+ });
171
+ });
172
+ }
173
+ }
174
+ customElements.define('site-search', SiteSearch);
175
+ </script>
176
+
177
+ <style>
178
+ site-search {
179
+ flex: 1 1 0%;
180
+ width: 100%;
181
+ }
182
+
183
+ @media (min-width: 768px) {
184
+ site-search {
185
+ flex: none;
186
+ width: auto;
187
+ }
188
+ }
189
+
190
+ button[data-open-modal] {
191
+ transition-property:
192
+ color, background-color, border-color, text-decoration-color, fill, stroke;
193
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
194
+ transition-duration: 0.15s;
195
+ color: color-mix(in oklab, var(--foreground) 88%, var(--muted-foreground));
196
+ font-weight: 400;
197
+ font-size: 0.875rem;
198
+ line-height: 1.25rem;
199
+ padding-top: calc(var(--spacing) * 2);
200
+ padding-bottom: calc(var(--spacing) * 2);
201
+ padding-left: calc(var(--spacing) * 4);
202
+ padding-right: calc(var(--spacing) * 4);
203
+ background-color: color-mix(in oklab, var(--background) 92%, var(--card));
204
+ border-color: color-mix(in oklab, var(--foreground) 15%, transparent);
205
+ border-width: 1px;
206
+ border-style: solid;
207
+ border-radius: var(--radius);
208
+ white-space: nowrap;
209
+ gap: calc(var(--spacing) * 2);
210
+ justify-content: flex-start;
211
+ align-items: center;
212
+ width: 100%;
213
+ height: 2rem;
214
+ display: inline-flex;
215
+ position: relative;
216
+ cursor: pointer;
217
+
218
+ background-image: none;
219
+ -webkit-appearance: button;
220
+ font-family: inherit;
221
+ font-feature-settings: inherit;
222
+ font-variation-settings: inherit;
223
+ letter-spacing: inherit;
224
+ margin: 0;
225
+ }
226
+
227
+ button[data-open-modal]:hover {
228
+ color: var(--foreground);
229
+ border-color: color-mix(in oklab, var(--foreground) 30%, transparent);
230
+ background-color: color-mix(in oklab, var(--muted) 45%, var(--background));
231
+ }
232
+
233
+ @media (min-width: 640px) {
234
+ button[data-open-modal] {
235
+ padding-right: calc(var(--spacing) * 12);
236
+ }
237
+ }
238
+
239
+ @media (min-width: 768px) {
240
+ button[data-open-modal] {
241
+ width: 12rem;
242
+ }
243
+ }
244
+
245
+ @media (min-width: 1024px) {
246
+ button[data-open-modal] {
247
+ width: 16rem;
248
+ }
249
+ }
250
+
251
+ button[data-open-modal] > span {
252
+ display: inline-flex;
253
+ }
254
+
255
+ button[data-open-modal] > kbd {
256
+ transition-property: color, background-color, border-color;
257
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
258
+ transition-duration: 0.15s;
259
+ opacity: 1;
260
+ font-weight: 500;
261
+ font-size: 10px;
262
+ padding-left: calc(var(--spacing) * 1.5);
263
+ padding-right: calc(var(--spacing) * 1.5);
264
+ background-color: color-mix(in oklab, var(--muted) 78%, var(--background));
265
+ border-width: 1px;
266
+ border-style: solid;
267
+ border-color: transparent;
268
+ border-radius: 0.25rem;
269
+ color: var(--muted-foreground);
270
+ gap: 0.25rem;
271
+ align-items: center;
272
+ height: 1.25rem;
273
+ display: none;
274
+ top: 0.3rem;
275
+ right: 0.3rem;
276
+ position: absolute;
277
+ pointer-events: none;
278
+ display: none !important;
279
+ }
280
+
281
+ @media (min-width: 640px) {
282
+ button > kbd {
283
+ display: flex !important;
284
+ }
285
+ }
286
+
287
+ button[data-open-modal] kbd {
288
+ font-family: var(--__sl-font-mono);
289
+ }
290
+
291
+ button[data-open-modal]:hover > kbd {
292
+ color: var(--foreground);
293
+ background-color: color-mix(in oklab, var(--accent) 92%, var(--background));
294
+ }
295
+
296
+ dialog {
297
+ margin: 0;
298
+ background-color: var(--sl-color-gray-6);
299
+ border: 1px solid var(--sl-color-gray-5);
300
+ width: 100%;
301
+ max-width: 100%;
302
+ height: 100%;
303
+ max-height: 100%;
304
+ box-shadow: var(--sl-shadow-lg);
305
+ }
306
+ dialog[open] {
307
+ display: flex;
308
+ }
309
+
310
+ dialog::backdrop {
311
+ background-color: var(--sl-color-backdrop-overlay);
312
+ -webkit-backdrop-filter: blur(0.25rem);
313
+ backdrop-filter: blur(0.25rem);
314
+ }
315
+
316
+ .dialog-frame {
317
+ position: relative;
318
+ overflow: auto;
319
+ flex-direction: column;
320
+ flex-grow: 1;
321
+ gap: 1rem;
322
+ padding: 1rem;
323
+ }
324
+
325
+ button[data-close-modal] {
326
+ position: absolute;
327
+ z-index: 1;
328
+ align-items: center;
329
+ align-self: flex-end;
330
+ height: calc(64px * var(--pagefind-ui-scale));
331
+ padding: 0.25rem;
332
+ border: 0;
333
+ background: transparent;
334
+ cursor: pointer;
335
+ color: var(--sl-color-text-accent);
336
+ }
337
+
338
+ #starlight__search {
339
+ --pagefind-ui-primary: var(--sl-color-accent-light);
340
+ --pagefind-ui-text: var(--sl-color-gray-2);
341
+ --pagefind-ui-font: var(--__sl-font);
342
+ --pagefind-ui-background: var(--sl-color-black);
343
+ --pagefind-ui-border: var(--sl-color-gray-5);
344
+ --pagefind-ui-border-width: 1px;
345
+ --sl-search-cancel-space: 5rem;
346
+ }
347
+
348
+ @media (min-width: 50rem) {
349
+ #starlight__search {
350
+ --sl-search-cancel-space: 0px;
351
+ }
352
+
353
+ dialog {
354
+ margin: 4rem auto auto;
355
+ border-radius: 0.5rem;
356
+ width: 90%;
357
+ max-width: 40rem;
358
+ height: max-content;
359
+ min-height: 15rem;
360
+ max-height: calc(100% - 8rem);
361
+ }
362
+
363
+ .dialog-frame {
364
+ padding: 1.5rem;
365
+ }
366
+ }
367
+ </style>
368
+
369
+ <style is:global>
370
+ [data-search-modal-open] {
371
+ overflow: hidden;
372
+ }
373
+
374
+ #starlight__search {
375
+ --sl-search-result-spacing: calc(1.25rem * var(--pagefind-ui-scale));
376
+ --sl-search-result-pad-inline-start: calc(3.75rem * var(--pagefind-ui-scale));
377
+ --sl-search-result-pad-inline-end: calc(1.25rem * var(--pagefind-ui-scale));
378
+ --sl-search-result-pad-block: calc(0.9375rem * var(--pagefind-ui-scale));
379
+ --sl-search-result-nested-pad-block: calc(0.625rem * var(--pagefind-ui-scale));
380
+ --sl-search-corners: calc(0.3125rem * var(--pagefind-ui-scale));
381
+ --sl-search-page-icon-size: calc(1.875rem * var(--pagefind-ui-scale));
382
+ --sl-search-page-icon-inline-start: calc(
383
+ (var(--sl-search-result-pad-inline-start) - var(--sl-search-page-icon-size)) / 2
384
+ );
385
+ --sl-search-tree-diagram-size: calc(2.5rem * var(--pagefind-ui-scale));
386
+ --sl-search-tree-diagram-inline-start: calc(
387
+ (var(--sl-search-result-pad-inline-start) - var(--sl-search-tree-diagram-size)) / 2
388
+ );
389
+ }
390
+
391
+ #starlight__search .pagefind-ui__form::before {
392
+ --pagefind-ui-text: var(--sl-color-gray-1);
393
+ opacity: 1;
394
+ }
395
+
396
+ #starlight__search .pagefind-ui__search-input {
397
+ color: var(--sl-color-white);
398
+ font-weight: 400;
399
+ width: calc(100% - var(--sl-search-cancel-space));
400
+ }
401
+
402
+ #starlight__search input:focus {
403
+ --pagefind-ui-border: var(--sl-color-accent);
404
+ }
405
+
406
+ #starlight__search .pagefind-ui__search-clear {
407
+ inset-inline-end: var(--sl-search-cancel-space);
408
+ width: calc(60px * var(--pagefind-ui-scale));
409
+ padding: 0;
410
+ background-color: transparent;
411
+ overflow: hidden;
412
+ }
413
+ #starlight__search .pagefind-ui__search-clear:focus {
414
+ outline: 1px solid var(--sl-color-accent);
415
+ }
416
+ #starlight__search .pagefind-ui__search-clear::before {
417
+ content: '';
418
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m13.41 12 6.3-6.29a1 1 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1 1 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 .33 1.64 1 1 0 0 0 1.09-.22l6.29-6.3 6.29 6.3a1 1 0 0 0 1.64-.33 1 1 0 0 0-.22-1.09L13.41 12Z'/%3E%3C/svg%3E")
419
+ center / 50% no-repeat;
420
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m13.41 12 6.3-6.29a1 1 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1 1 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 .33 1.64 1 1 0 0 0 1.09-.22l6.29-6.3 6.29 6.3a1 1 0 0 0 1.64-.33 1 1 0 0 0-.22-1.09L13.41 12Z'/%3E%3C/svg%3E")
421
+ center / 50% no-repeat;
422
+ background-color: var(--sl-color-text-accent);
423
+ display: block;
424
+ width: 100%;
425
+ height: 100%;
426
+ }
427
+
428
+ #starlight__search .pagefind-ui__results > * + * {
429
+ margin-top: var(--sl-search-result-spacing);
430
+ }
431
+ #starlight__search .pagefind-ui__result {
432
+ border: 0;
433
+ padding: 0;
434
+ }
435
+
436
+ #starlight__search .pagefind-ui__result-nested {
437
+ position: relative;
438
+ padding: var(--sl-search-result-nested-pad-block) var(--sl-search-result-pad-inline-end);
439
+ padding-inline-start: var(--sl-search-result-pad-inline-start);
440
+ }
441
+
442
+ #starlight__search .pagefind-ui__result-title:not(:where(.pagefind-ui__result-nested *)),
443
+ #starlight__search .pagefind-ui__result-nested {
444
+ position: relative;
445
+ background-color: var(--sl-color-black);
446
+ }
447
+
448
+ #starlight__search .pagefind-ui__result-title:not(:where(.pagefind-ui__result-nested *)):hover,
449
+ #starlight__search
450
+ .pagefind-ui__result-title:not(:where(.pagefind-ui__result-nested *)):focus-within,
451
+ #starlight__search .pagefind-ui__result-nested:hover,
452
+ #starlight__search .pagefind-ui__result-nested:focus-within {
453
+ outline: 1px solid var(--sl-color-accent-high);
454
+ }
455
+
456
+ #starlight__search
457
+ .pagefind-ui__result-title:not(:where(.pagefind-ui__result-nested *)):focus-within,
458
+ #starlight__search .pagefind-ui__result-nested:focus-within {
459
+ background-color: var(--sl-color-accent-low);
460
+ }
461
+
462
+ #starlight__search .pagefind-ui__result-thumb,
463
+ #starlight__search .pagefind-ui__result-inner {
464
+ margin-top: 0;
465
+ }
466
+
467
+ #starlight__search .pagefind-ui__result-inner > :first-child {
468
+ border-radius: var(--sl-search-corners) var(--sl-search-corners) 0 0;
469
+ }
470
+ #starlight__search .pagefind-ui__result-inner > :last-child {
471
+ border-radius: 0 0 var(--sl-search-corners) var(--sl-search-corners);
472
+ }
473
+
474
+ #starlight__search .pagefind-ui__result-inner > .pagefind-ui__result-title {
475
+ padding: var(--sl-search-result-pad-block) var(--sl-search-result-pad-inline-end);
476
+ padding-inline-start: var(--sl-search-result-pad-inline-start);
477
+ }
478
+ #starlight__search .pagefind-ui__result-inner > .pagefind-ui__result-title::before {
479
+ content: '';
480
+ position: absolute;
481
+ inset-block: 0;
482
+ inset-inline-start: var(--sl-search-page-icon-inline-start);
483
+ width: var(--sl-search-page-icon-size);
484
+ background: var(--sl-color-gray-3);
485
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='currentColor' viewBox='0 0 24 24'%3E%3Cpath d='M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3V8l-6-6a1 1 0 0 0-1 0H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V9Zm-6-4 3 3h-2a1 1 0 0 1-1-1V5Zm4 14a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z'/%3E%3C/svg%3E")
486
+ center no-repeat;
487
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='currentColor' viewBox='0 0 24 24'%3E%3Cpath d='M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3V8l-6-6a1 1 0 0 0-1 0H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V9Zm-6-4 3 3h-2a1 1 0 0 1-1-1V5Zm4 14a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z'/%3E%3C/svg%3E")
488
+ center no-repeat;
489
+ }
490
+
491
+ #starlight__search .pagefind-ui__result-inner {
492
+ align-items: stretch;
493
+ gap: 1px;
494
+ }
495
+
496
+ #starlight__search .pagefind-ui__result-link {
497
+ position: unset;
498
+ --pagefind-ui-text: var(--sl-color-white);
499
+ font-weight: 600;
500
+ }
501
+
502
+ #starlight__search .pagefind-ui__result-link:hover {
503
+ text-decoration: none;
504
+ }
505
+
506
+ #starlight__search .pagefind-ui__result-nested .pagefind-ui__result-link::before {
507
+ content: unset;
508
+ }
509
+
510
+ #starlight__search .pagefind-ui__result-nested::before {
511
+ content: '';
512
+ position: absolute;
513
+ inset-block: 0;
514
+ inset-inline-start: var(--sl-search-tree-diagram-inline-start);
515
+ width: var(--sl-search-tree-diagram-size);
516
+ background: var(--sl-color-gray-4);
517
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' viewBox='0 0 16 1000' preserveAspectRatio='xMinYMin slice'%3E%3Cpath d='M8 0v1000m6-988H8'/%3E%3C/svg%3E")
518
+ 0% 0% / 100% no-repeat;
519
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' viewBox='0 0 16 1000' preserveAspectRatio='xMinYMin slice'%3E%3Cpath d='M8 0v1000m6-988H8'/%3E%3C/svg%3E")
520
+ 0% 0% / 100% no-repeat;
521
+ }
522
+ #starlight__search .pagefind-ui__result-nested:last-child::before {
523
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' viewBox='0 0 16 16'%3E%3Cpath d='M8 0v12m6 0H8'/%3E%3C/svg%3E");
524
+ mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' viewBox='0 0 16 16'%3E%3Cpath d='M8 0v12m6 0H8'/%3E%3C/svg%3E");
525
+ }
526
+
527
+ /* Flip page and tree icons around the vertical axis when in an RTL layout. */
528
+ [dir='rtl'] .pagefind-ui__result-title::before,
529
+ [dir='rtl'] .pagefind-ui__result-nested::before {
530
+ transform: matrix(-1, 0, 0, 1, 0, 0);
531
+ }
532
+
533
+ #starlight__search .pagefind-ui__result-link::after {
534
+ content: '';
535
+ position: absolute;
536
+ inset: 0;
537
+ }
538
+
539
+ #starlight__search .pagefind-ui__result-excerpt {
540
+ font-size: calc(1rem * var(--pagefind-ui-scale));
541
+ overflow-wrap: anywhere;
542
+ }
543
+
544
+ #starlight__search mark {
545
+ color: var(--sl-color-gray-2);
546
+ background-color: transparent;
547
+ font-weight: 600;
548
+ }
549
+ </style>
@@ -0,0 +1,111 @@
1
+ ---
2
+ import SidebarSublist from './parts/SidebarSublist.astro';
3
+
4
+ const { sidebar } = Astro.locals.starlightRoute;
5
+ ---
6
+
7
+ <div class="sidebar">
8
+ <div class="sidebar-border-gradient"></div>
9
+ <div class="sidebar-spacer"></div>
10
+ <div class="sidebar-fade-top"></div>
11
+ <div class="container-sidebar">
12
+ <div class="sidebar-entries">
13
+ <SidebarSublist sublist={sidebar} />
14
+ </div>
15
+ <div class="sidebar-fade-bottom"></div>
16
+ </div>
17
+ </div>
18
+
19
+ <style>
20
+ .sidebar {
21
+ scrollbar-width: none;
22
+ overflow: hidden;
23
+ height: 100%;
24
+ position: relative;
25
+ display: flex;
26
+ flex-direction: column;
27
+ }
28
+
29
+ .sidebar-spacer {
30
+ height: 2.25rem;
31
+ flex-shrink: 0;
32
+ }
33
+
34
+ .sidebar-border-gradient {
35
+ position: absolute;
36
+ top: 0rem;
37
+ right: 0.5rem;
38
+ bottom: 0;
39
+ width: 1px;
40
+ background: linear-gradient(to bottom, transparent 0%, var(--border) 50%, transparent 100%);
41
+ display: none;
42
+ z-index: 1;
43
+ }
44
+
45
+ @media (min-width: 1024px) {
46
+ .sidebar-border-gradient {
47
+ display: flex;
48
+ }
49
+ }
50
+
51
+ .sidebar-fade-top {
52
+ position: absolute;
53
+ top: 2rem;
54
+ left: 0;
55
+ z-index: 10;
56
+ height: 2rem;
57
+ width: calc(100% - 1rem);
58
+ flex-shrink: 0;
59
+ pointer-events: none;
60
+ background-image: linear-gradient(
61
+ to bottom,
62
+ var(--background) 0%,
63
+ color-mix(in srgb, var(--background) 80%, transparent) 50%,
64
+ color-mix(in srgb, var(--background) 50%, transparent) 100%
65
+ );
66
+ filter: blur(2px);
67
+ }
68
+
69
+ .sidebar-fade-bottom {
70
+ position: sticky;
71
+ bottom: -2px;
72
+ z-index: 10;
73
+ height: 4rem;
74
+ flex-shrink: 0;
75
+ margin-top: calc(var(--spacing) * -16);
76
+ pointer-events: none;
77
+ background-image: linear-gradient(
78
+ to top,
79
+ var(--background) 0%,
80
+ color-mix(in srgb, var(--background) 80%, transparent) 50%,
81
+ color-mix(in srgb, var(--background) 50%, transparent) 100%
82
+ );
83
+ filter: blur(2px);
84
+ }
85
+
86
+ .container-sidebar {
87
+ flex-direction: column;
88
+ display: flex;
89
+ overflow: auto;
90
+ scrollbar-width: none;
91
+ flex: 1;
92
+ min-height: 0;
93
+ padding-top: calc(var(--spacing) * 6);
94
+ padding-right: calc(var(--spacing) * 6);
95
+ padding-left: calc(var(--spacing) * 2);
96
+ margin: 0 2rem;
97
+ }
98
+
99
+ .sidebar-entries {
100
+ display: flex;
101
+ flex-direction: column;
102
+ gap: calc(var(--spacing) * 6);
103
+ padding-bottom: calc(var(--spacing) * 16);
104
+ }
105
+
106
+ @media (min-width: 1024px) {
107
+ .container-sidebar {
108
+ max-height: calc(100svh - 10rem - 2.25rem);
109
+ }
110
+ }
111
+ </style>