@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,65 @@
1
+ ---
2
+ import config from 'virtual:starlight/user-config';
3
+ import { logos } from 'virtual:starlight/user-images';
4
+
5
+ const { siteTitle, siteTitleHref } = Astro.locals.starlightRoute;
6
+ ---
7
+
8
+ <a href={siteTitleHref} class="site-title">
9
+ {
10
+ config.logo && logos.dark && (
11
+ <>
12
+ <img
13
+ class:list={[{ 'light:sl-hidden': !('src' in config.logo) }, 'logo']}
14
+ alt={config.logo.alt}
15
+ src={logos.dark.src}
16
+ width={logos.dark.width}
17
+ height={logos.dark.height}
18
+ />
19
+ {/* Show light alternate if a user configure both light and dark logos. */}
20
+ {!('src' in config.logo) && (
21
+ <img
22
+ class="dark:sl-hidden logo"
23
+ alt={config.logo.alt}
24
+ src={logos.light?.src}
25
+ width={logos.light?.width}
26
+ height={logos.light?.height}
27
+ />
28
+ )}
29
+ </>
30
+ )
31
+ }
32
+ <span class:list={[{ 'sr-only': config.logo?.replacesTitle }, 'title-text']}>
33
+ {siteTitle}
34
+ </span>
35
+ </a>
36
+
37
+ <style>
38
+ .logo {
39
+ max-height: 32px;
40
+ max-width: 32px;
41
+ }
42
+
43
+ .site-title {
44
+ gap: 0.5rem;
45
+ align-items: center;
46
+ display: flex;
47
+ margin-right: calc(var(--spacing) * 3);
48
+ }
49
+
50
+ .title-text {
51
+ font-weight: 700;
52
+ display: none;
53
+ }
54
+
55
+ @media (min-width: 1024px) {
56
+ .title-text {
57
+ display: inline-block;
58
+ }
59
+ }
60
+
61
+ a {
62
+ color: inherit;
63
+ text-decoration: inherit;
64
+ }
65
+ </style>
@@ -0,0 +1,47 @@
1
+ ---
2
+ import config from 'virtual:starlight/user-config';
3
+
4
+ import { Icon } from '@astrojs/starlight/components';
5
+
6
+ const links = config.social || [];
7
+ ---
8
+
9
+ {
10
+ links.length > 0 && (
11
+ <>
12
+ {links.map(({ label, href, icon }) => (
13
+ <a href={href} rel="me" class="sl-flex button" data-variant="ghost">
14
+ <span class="sr-only">{label}</span>
15
+ <Icon name={icon} />
16
+ </a>
17
+ ))}
18
+ </>
19
+ )
20
+ }
21
+
22
+ <style>
23
+ a {
24
+ all: unset;
25
+ display: inline-flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ width: 2rem;
29
+ height: 2rem;
30
+ padding: 0;
31
+ border-radius: calc(var(--radius) - 2px);
32
+ cursor: pointer;
33
+ color: color-mix(in oklab, var(--foreground) 76%, var(--muted-foreground));
34
+ background-color: transparent;
35
+ transition: color 0.15s, background-color 0.15s;
36
+ text-decoration: none;
37
+ }
38
+ a:hover {
39
+ color: var(--accent-foreground);
40
+ background-color: color-mix(in oklab, var(--accent) 80%, transparent);
41
+ }
42
+
43
+ a :global(svg) {
44
+ width: 1rem;
45
+ height: 1rem;
46
+ }
47
+ </style>
@@ -0,0 +1,36 @@
1
+ ---
2
+ import TableOfContentsList from './parts/toc/TableOfContentsList.astro';
3
+
4
+ const { toc } = Astro.locals.starlightRoute;
5
+ ---
6
+
7
+ {
8
+ toc && (
9
+ <starlight-toc data-min-h={toc.minHeadingLevel} data-max-h={toc.maxHeadingLevel}>
10
+ <nav aria-labelledby="starlight__on-this-page">
11
+ <p id="starlight__on-this-page">{Astro.locals.t('tableOfContents.onThisPage')}</p>
12
+ <TableOfContentsList toc={toc.items} />
13
+ </nav>
14
+ </starlight-toc>
15
+ )
16
+ }
17
+
18
+ <script src="./parts/toc/starlight-toc"></script>
19
+
20
+ <style>
21
+ starlight-toc {
22
+ scrollbar-width: none;
23
+ padding-bottom: calc(var(--spacing) * 10);
24
+ overflow: auto;
25
+ height: 100%;
26
+ }
27
+ nav {
28
+ }
29
+ p {
30
+ font-weight: 400;
31
+ font-size: 0.75rem;
32
+ line-height: 1rem;
33
+ margin-bottom: calc(var(--spacing) * 3.5);
34
+ color: var(--muted-foreground);
35
+ }
36
+ </style>
@@ -0,0 +1,156 @@
1
+ ---
2
+
3
+ ---
4
+
5
+ <starlight-theme-lucode-select>
6
+ <button
7
+ aria-label={Astro.locals.t('themeSelect.accessibleLabel')}
8
+ aria-live="polite"
9
+ class="sl-flex button"
10
+ title={Astro.locals.t('themeSelect.accessibleLabel')}
11
+ data-variant="ghost"
12
+ >
13
+ <svg
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ width="24"
16
+ height="24"
17
+ viewBox="0 0 24 24"
18
+ fill="none"
19
+ stroke="currentColor"
20
+ stroke-width="2"
21
+ stroke-linecap="round"
22
+ stroke-linejoin="round"
23
+ class="sun"
24
+ >
25
+ <circle cx="12" cy="12" r="4"></circle>
26
+ <path d="M12 2v2"></path>
27
+ <path d="M12 20v2"></path>
28
+ <path d="m4.93 4.93 1.41 1.41"></path>
29
+ <path d="m17.66 17.66 1.41 1.41"></path>
30
+ <path d="M2 12h2"></path>
31
+ <path d="M20 12h2"></path>
32
+ <path d="m6.34 17.66-1.41 1.41"></path>
33
+ <path d="m19.07 4.93-1.41 1.41"></path>
34
+ </svg>
35
+
36
+ <svg
37
+ xmlns="http://www.w3.org/2000/svg"
38
+ width="24"
39
+ height="24"
40
+ viewBox="0 0 24 24"
41
+ fill="none"
42
+ stroke="currentColor"
43
+ stroke-width="2"
44
+ stroke-linecap="round"
45
+ stroke-linejoin="round"
46
+ class="moon"
47
+ ><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"> </path>
48
+ </svg>
49
+
50
+ <span class="sr-only">Toggle theme</span>
51
+ </button>
52
+ </starlight-theme-lucode-select>
53
+
54
+ <style>
55
+ button {
56
+ all: unset;
57
+ display: inline-flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ width: 2rem;
61
+ height: 2rem;
62
+ border-radius: calc(var(--radius) - 2px);
63
+ cursor: pointer;
64
+ color: color-mix(in oklab, var(--foreground) 76%, var(--muted-foreground));
65
+ background-color: transparent;
66
+ transition:
67
+ color 0.15s,
68
+ background-color 0.15s;
69
+ }
70
+ button:hover {
71
+ color: var(--accent-foreground);
72
+ background-color: color-mix(in oklab, var(--accent) 80%, transparent);
73
+ }
74
+ svg {
75
+ flex-shrink: 0;
76
+ width: 1rem;
77
+ height: 1rem;
78
+ pointer-events: none;
79
+ }
80
+
81
+ :global([data-theme='light']) svg.sun {
82
+ display: none;
83
+ }
84
+
85
+ :global([data-theme='dark']) svg.moon {
86
+ display: none;
87
+ }
88
+ </style>
89
+
90
+ {/* Inlined to avoid FOUC. Uses global scope from `ThemeProvider.astro` */}
91
+ <script is:inline>
92
+ // eslint-disable-next-line no-undef
93
+ StarlightThemeProvider.updatePickers();
94
+ </script>
95
+
96
+ <script>
97
+ type Theme = 'auto' | 'dark' | 'light';
98
+
99
+ /** Key in `localStorage` to store color theme preference at. */
100
+ const storageKey = 'starlight-theme';
101
+
102
+ /** Get a typesafe theme string from any JS value (unknown values are coerced to `'auto'`). */
103
+ function parseTheme(theme: unknown): Theme {
104
+ return theme === 'auto' || theme === 'dark' || theme === 'light' ? theme : 'auto';
105
+ }
106
+
107
+ /** Load the user’s preference from `localStorage`. */
108
+ function loadTheme(): Theme {
109
+ return parseTheme(typeof localStorage !== 'undefined' && localStorage.getItem(storageKey));
110
+ }
111
+
112
+ /** Store the user’s preference in `localStorage`. */
113
+ function storeTheme(theme: Theme): void {
114
+ if (typeof localStorage !== 'undefined') {
115
+ localStorage.setItem(storageKey, theme === 'light' || theme === 'dark' ? theme : '');
116
+ }
117
+ }
118
+
119
+ /** Get the preferred system color scheme. */
120
+ function getPreferredColorScheme(): Theme {
121
+ return matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
122
+ }
123
+
124
+ /** Update select menu UI, document theme, and local storage state. */
125
+ function onThemeChange(theme: Theme): void {
126
+ StarlightThemeProvider.updatePickers(theme);
127
+ document.documentElement.dataset.theme =
128
+ theme === 'auto' ? getPreferredColorScheme() : theme;
129
+ storeTheme(theme);
130
+ }
131
+
132
+ // React to changes in system color scheme.
133
+ matchMedia(`(prefers-color-scheme: light)`).addEventListener('change', () => {
134
+ if (loadTheme() === 'auto') {
135
+ onThemeChange('auto');
136
+ }
137
+ });
138
+
139
+ customElements.define(
140
+ 'starlight-theme-lucode-select',
141
+ class StarlightThemeLucodeSelect extends HTMLElement {
142
+ constructor() {
143
+ super();
144
+ onThemeChange(loadTheme());
145
+ const button = this.querySelector('button');
146
+ button?.addEventListener('click', () => {
147
+ const theme = parseTheme(document.documentElement.dataset.theme);
148
+ const newTheme =
149
+ theme === 'dark' ? 'light' : theme === 'light' ? 'dark' : 'auto';
150
+ onThemeChange(newTheme);
151
+ button?.setAttribute('aria-label', `${newTheme} theme`);
152
+ });
153
+ }
154
+ }
155
+ );
156
+ </script>
@@ -0,0 +1,75 @@
1
+ ---
2
+ const { toc } = Astro.locals.starlightRoute;
3
+ ---
4
+
5
+ {!toc && <slot />}
6
+
7
+ {
8
+ toc && (
9
+ <main class="container-main" data-slot="docs">
10
+ <div class="main">
11
+ <slot />
12
+ </div>
13
+
14
+ <div class="toc">
15
+ <slot name="right-sidebar" />
16
+ </div>
17
+ </main>
18
+ )
19
+ }
20
+
21
+ <style>
22
+ .container-main {
23
+ padding-top: calc(var(--spacing) * 2);
24
+ padding-bottom: calc(var(--spacing) * 6);
25
+ position: relative;
26
+ }
27
+
28
+ @media (min-width: 1024px) {
29
+ .container-main {
30
+ padding-left: calc(var(--spacing) * 8);
31
+ }
32
+ }
33
+
34
+ @media (min-width: 1280px) {
35
+ .container-main {
36
+ grid-template-columns: 1fr 240px;
37
+ display: grid;
38
+ gap: 2.5rem;
39
+ padding-top: calc(var(--spacing) * 8);
40
+ padding-bottom: calc(var(--spacing) * 8);
41
+ }
42
+ }
43
+
44
+ .main {
45
+ max-width: 40rem;
46
+ min-width: 0;
47
+ width: 100%;
48
+ margin-inline: auto;
49
+ padding-inline: calc(var(--spacing) * 4);
50
+ padding-top: calc(var(--spacing) * 4);
51
+
52
+ main {
53
+ display: flex;
54
+ flex-direction: column;
55
+ gap: calc(var(--spacing) * 6);
56
+ }
57
+ }
58
+
59
+ @media (min-width: 768px) {
60
+ .main {
61
+ padding-inline: 0;
62
+ }
63
+ }
64
+
65
+ .toc {
66
+ font-size: 0.875rem;
67
+ line-height: 1.25rem;
68
+ display: none;
69
+ }
70
+ @media (min-width: 1280px) {
71
+ .toc {
72
+ display: block;
73
+ }
74
+ }
75
+ </style>
@@ -0,0 +1,232 @@
1
+ ---
2
+ import userConfig from 'virtual:lucode-starlight-config';
3
+ import { getTranslation } from './NavBar.astro';
4
+ import { getRelativeLocaleUrl } from 'astro:i18n';
5
+ const { sidebar } = Astro.locals.starlightRoute;
6
+
7
+ const currentPath = Astro.url.pathname;
8
+ ---
9
+
10
+ <div popover="auto" id="drawer">
11
+ <button class="sheet-overlay" popovertarget="drawer" popovertargetaction="hide"></button>
12
+ <div class="content">
13
+ <div class="header">
14
+ <button class="drag-icon" popovertarget="drawer" popovertargetaction="hide">
15
+ <span></span>
16
+ </button>
17
+ </div>
18
+ <div class="body">
19
+ <div class="links-nav">
20
+ {
21
+ userConfig.navLinks?.map((nav) => {
22
+ const absoluteLinkRegex = /^https?:\/\//;
23
+
24
+ const link =
25
+ !absoluteLinkRegex.test(nav.link) && Astro.currentLocale
26
+ ? getRelativeLocaleUrl(Astro.currentLocale, nav.link)
27
+ : nav.link;
28
+ const label =
29
+ typeof nav.label === 'string'
30
+ ? nav.label
31
+ : getTranslation(nav.label, nav.link, 'label');
32
+
33
+ return (
34
+ <a href={link} {...nav.attrs}>
35
+ {label}
36
+ {nav.badge && <span class="badge">{nav.badge}</span>}
37
+ </a>
38
+ );
39
+ })
40
+ }
41
+ </div>
42
+
43
+ <div class="links-docs">
44
+ {
45
+ sidebar.map(
46
+ (entry) =>
47
+ entry.type !== 'link' && (
48
+ <div class="container-sidebar-entry">
49
+ <h4 class="entry-title">{entry.label}</h4>
50
+
51
+ {entry.entries.map(
52
+ (link) =>
53
+ link.type === 'link' && (
54
+ <a
55
+ href={link.href}
56
+ {...link.attrs}
57
+ data-active={currentPath === link.href}
58
+ >
59
+ {link.label}
60
+ </a>
61
+ )
62
+ )}
63
+ </div>
64
+ )
65
+ )
66
+ }
67
+ </div>
68
+ </div>
69
+ </div>
70
+ </div>
71
+
72
+ <style>
73
+ button {
74
+ all: unset;
75
+ }
76
+
77
+ [popover] {
78
+ padding: 0;
79
+ position: fixed;
80
+ top: 0;
81
+ left: 0;
82
+ width: 100vw;
83
+ height: 100vh;
84
+ display: flex;
85
+ opacity: 0;
86
+ pointer-events: none;
87
+ align-items: center;
88
+ flex-direction: column;
89
+ justify-content: flex-end;
90
+ transition: 0.1s linear;
91
+ z-index: 1000;
92
+ background: transparent;
93
+ border: none;
94
+ overflow: hidden;
95
+ }
96
+
97
+ [popover]::backdrop {
98
+ background: color-mix(in oklab, black 80%, transparent);
99
+ backdrop-filter: blur(2px);
100
+ }
101
+
102
+ [popover]:popover-open {
103
+ opacity: 1;
104
+ pointer-events: auto;
105
+ }
106
+
107
+ [popover]:popover-open .content {
108
+ transform: translateY(0%);
109
+ }
110
+
111
+ .sheet-overlay {
112
+ position: fixed;
113
+ top: 0;
114
+ left: 0;
115
+ z-index: -1;
116
+ width: 100vw;
117
+ height: 100vh;
118
+ opacity: 0.1;
119
+ background-color: transparent;
120
+ }
121
+
122
+ .content {
123
+ width: 100%;
124
+ position: relative;
125
+ background: var(--background);
126
+ max-height: 100vh;
127
+ height: 70vh;
128
+ max-width: 1150px;
129
+ transform: translateY(100%);
130
+ border-radius: 12px 12px 0 0;
131
+ box-shadow: 0 10px 20px rgba(0, 0, 0, 0.03);
132
+ transition: 0.3s ease;
133
+ }
134
+
135
+ .header {
136
+ display: flex;
137
+ justify-content: center;
138
+ }
139
+
140
+ .header .drag-icon span {
141
+ height: calc(var(--spacing) * 1);
142
+ width: 100px;
143
+ display: block;
144
+ background-color: color-mix(in oklab, var(--foreground) 20%, transparent);
145
+ border-radius: 9999px;
146
+ margin-top: calc(var(--spacing) * 1);
147
+ }
148
+
149
+ .body {
150
+ height: 100%;
151
+ overflow-y: auto;
152
+ padding: 1.5rem;
153
+ }
154
+
155
+ .body::-webkit-scrollbar {
156
+ width: 0;
157
+ }
158
+
159
+ .links-nav {
160
+ display: flex;
161
+ flex-direction: column;
162
+ gap: 0.75rem;
163
+ }
164
+
165
+ .links-nav a {
166
+ font-size: 1rem;
167
+ line-height: 1.5rem;
168
+ color: inherit;
169
+ text-decoration: inherit;
170
+ }
171
+
172
+ .links-docs {
173
+ display: flex;
174
+ flex-direction: column;
175
+ gap: calc(var(--spacing) * 2);
176
+ }
177
+
178
+ .container-sidebar-entry {
179
+ padding-top: calc(var(--spacing) * 6);
180
+ display: flex;
181
+ flex-direction: column;
182
+ gap: calc(var(--spacing) * 2);
183
+
184
+ &:last-child {
185
+ margin-bottom: calc(var(--spacing) * 4);
186
+ }
187
+ }
188
+
189
+ .entry-title {
190
+ font-weight: 500;
191
+ }
192
+
193
+ .container-sidebar-entry a {
194
+ font-size: 1rem;
195
+ line-height: 1.2rem;
196
+ color: var(--muted-foreground);
197
+ text-decoration: inherit;
198
+
199
+ &[data-active='true'] {
200
+ color: var(--foreground);
201
+ font-weight: 500;
202
+ }
203
+ }
204
+
205
+ .badge {
206
+ padding-top: calc(var(--spacing) * 0.5);
207
+ padding-bottom: calc(var(--spacing) * 0.5);
208
+ padding-left: calc(var(--spacing) * 1.5);
209
+ padding-right: calc(var(--spacing) * 1.5);
210
+ margin-left: calc(var(--spacing) * 2);
211
+ border-radius: 0.375rem;
212
+ font-size: 0.75rem;
213
+ line-height: 1rem;
214
+ font-weight: 400;
215
+ line-height: 1;
216
+ text-decoration: none;
217
+ background: #adfa1d;
218
+ color: #000000;
219
+ }
220
+ </style>
221
+
222
+ <script>
223
+ const drawer = document.getElementById('drawer');
224
+ if (drawer) {
225
+ drawer.addEventListener('toggle', (e) => {
226
+ const event = e as ToggleEvent;
227
+ const isOpen = event.newState === 'open';
228
+ document.documentElement.style.overflow = isOpen ? 'hidden' : '';
229
+ document.body.style.overflow = isOpen ? 'hidden' : '';
230
+ });
231
+ }
232
+ </script>
@@ -0,0 +1,42 @@
1
+ <button class="show-modal" popovertargetaction="toggle" popovertarget="drawer">
2
+ <svg
3
+ xmlns="http://www.w3.org/2000/svg"
4
+ fill="none"
5
+ viewBox="0 0 24 24"
6
+ stroke-width="1.5"
7
+ stroke="currentColor"
8
+ >
9
+ <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 9h16.5m-16.5 6.75h16.5"
10
+ ></path>
11
+ </svg>
12
+ <span class="sr-only">Toggle Menu</span>
13
+ </button>
14
+
15
+ <style>
16
+ button {
17
+ all: unset;
18
+
19
+ display: inline-flex;
20
+ margin-right: calc(var(--spacing) * 2);
21
+ margin-left: calc(var(--spacing) * -2);
22
+ height: 2rem;
23
+ width: 2rem;
24
+ align-items: center;
25
+ justify-content: center;
26
+ padding-bottom: calc(var(--spacing) * 2);
27
+ padding-top: calc(var(--spacing) * 2);
28
+ font-size: 1rem;
29
+ line-height: 1.5rem;
30
+ }
31
+
32
+ @media (min-width: 1024px) {
33
+ button {
34
+ display: none;
35
+ }
36
+ }
37
+
38
+ button > svg {
39
+ width: 1.5rem;
40
+ height: 1.5rem;
41
+ }
42
+ </style>