@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,179 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types';
3
+
4
+ type Props = HTMLAttributes<'div'> & {
5
+ /**
6
+ * Side of the dropdown
7
+ * @default bottom
8
+ */
9
+ side?: 'top' | 'bottom' | 'left' | 'right';
10
+ /**
11
+ * Alignment of the dropdown
12
+ * @default start
13
+ */
14
+ align?: 'start' | 'center' | 'end';
15
+ /**
16
+ * Offset distance in pixels
17
+ * @default 4
18
+ */
19
+ sideOffset?: number;
20
+ /**
21
+ * Open and close animation duration in milliseconds
22
+ * @default 150
23
+ */
24
+ animationDuration?: number;
25
+ };
26
+
27
+ const {
28
+ class: className,
29
+ side = 'bottom',
30
+ align = 'start',
31
+ sideOffset = 4,
32
+ animationDuration = 150,
33
+ ...rest
34
+ } = Astro.props;
35
+ ---
36
+
37
+ <div
38
+ role="menu"
39
+ data-side={side}
40
+ data-align={align}
41
+ data-state="closed"
42
+ tabindex="-1"
43
+ aria-orientation="vertical"
44
+ class:list={['starwind-dropdown-content', className]}
45
+ style={{
46
+ display: 'none',
47
+ animationDuration: `${animationDuration}ms`,
48
+ marginTop: side === 'bottom' ? `${sideOffset}px` : undefined,
49
+ marginBottom: side === 'top' ? `${sideOffset}px` : undefined,
50
+ marginLeft: side === 'right' ? `${sideOffset}px` : undefined,
51
+ marginRight: side === 'left' ? `${sideOffset}px` : undefined,
52
+ }}
53
+ {...rest}
54
+ data-slot="dropdown-content"
55
+ >
56
+ <slot />
57
+ </div>
58
+
59
+ <style>
60
+ div[data-slot='dropdown-content'] {
61
+ background-color: var(--popover-background, var(--muted));
62
+ color: var(var(--popover-foreground), var(--foreground));
63
+ z-index: 50;
64
+ min-width: 9rem;
65
+ overflow-x: hidden;
66
+ overflow-y: auto;
67
+ border-radius: var(--radius);
68
+ border: 1px solid var(--border);
69
+ padding: calc(var(--spacing) * 0.5);
70
+ box-shadow: var(--shadow-md);
71
+ position: absolute;
72
+ will-change: transform;
73
+ width: max-content;
74
+
75
+ &[data-state='open'] {
76
+ animation-name: fade-in, zoom-in-95;
77
+ animation-duration: var(--animation-duration);
78
+ }
79
+
80
+ &[data-state='closed'] {
81
+ animation-name: fade-out, zoom-out-95;
82
+ animation-duration: var(--animation-duration);
83
+ animation-fill-mode: forwards;
84
+ }
85
+
86
+ &[data-side='bottom'] {
87
+ top: 100%;
88
+ margin-top: var(--side-offset);
89
+ }
90
+
91
+ &[data-side='top'] {
92
+ bottom: 100%;
93
+ margin-bottom: var(--side-offset);
94
+ }
95
+
96
+ &[data-side='right'] {
97
+ left: 100%;
98
+ margin-left: var(--side-offset);
99
+ }
100
+
101
+ &[data-side='left'] {
102
+ right: 100%;
103
+ margin-right: var(--side-offset);
104
+ }
105
+
106
+ &[data-side='top'][data-align='start'],
107
+ &[data-side='bottom'][data-align='start'] {
108
+ left: 0;
109
+ }
110
+
111
+ &[data-side='top'][data-align='center'],
112
+ &[data-side='bottom'][data-align='center'] {
113
+ left: 50%;
114
+ transform: translateX(-50%);
115
+ }
116
+
117
+ &[data-side='top'][data-align='end'],
118
+ &[data-side='bottom'][data-align='end'] {
119
+ right: 0;
120
+ }
121
+
122
+ &[data-side='left'][data-align='start'],
123
+ &[data-side='right'][data-align='start'] {
124
+ top: 0;
125
+ }
126
+
127
+ &[data-side='left'][data-align='center'],
128
+ &[data-side='right'][data-align='center'] {
129
+ top: 50%;
130
+ transform: translateY(-50%);
131
+ }
132
+
133
+ &[data-side='left'][data-align='end'],
134
+ &[data-side='right'][data-align='end'] {
135
+ bottom: 0;
136
+ }
137
+
138
+ /* animations */
139
+ @keyframes fade-in {
140
+ from {
141
+ opacity: 0;
142
+ }
143
+ to {
144
+ opacity: 1;
145
+ }
146
+ }
147
+
148
+ @keyframes fade-out {
149
+ from {
150
+ opacity: 1;
151
+ }
152
+ to {
153
+ opacity: 0;
154
+ }
155
+ }
156
+
157
+ @keyframes zoom-in-95 {
158
+ from {
159
+ opacity: 0;
160
+ transform: scale(0.95);
161
+ }
162
+ to {
163
+ opacity: 1;
164
+ transform: scale(1);
165
+ }
166
+ }
167
+
168
+ @keyframes zoom-out-95 {
169
+ from {
170
+ opacity: 1;
171
+ transform: scale(1);
172
+ }
173
+ to {
174
+ opacity: 0;
175
+ transform: scale(0.95);
176
+ }
177
+ }
178
+ }
179
+ </style>
@@ -0,0 +1,72 @@
1
+ ---
2
+ import type { HTMLTag, Polymorphic } from 'astro/types';
3
+
4
+ type Props<Tag extends HTMLTag> = Polymorphic<{ as: Tag }> & {
5
+ /**
6
+ * Whether the item is inset (has left padding)
7
+ */
8
+ inset?: boolean;
9
+ /**
10
+ * Whether the item is disabled
11
+ */
12
+ disabled?: boolean;
13
+ };
14
+
15
+ const { class: className, inset = false, disabled = false, as: Tag = 'div', ...rest } = Astro.props;
16
+ ---
17
+
18
+ <Tag
19
+ class:list={['starwind-dropdown-item', className]}
20
+ role="menuitem"
21
+ tabindex={disabled ? '-1' : '0'}
22
+ data-disabled={disabled ? 'true' : undefined}
23
+ data-inset={inset ? 'true' : undefined}
24
+ data-slot="dropdown-item"
25
+ clas
26
+ {...rest}
27
+ >
28
+ <slot />
29
+ </Tag>
30
+
31
+ <style>
32
+ .starwind-dropdown-item {
33
+ position: relative;
34
+ display: flex;
35
+ cursor: default;
36
+ align-items: center;
37
+ gap: calc(var(--spacing) * 2);
38
+ border-radius: calc(var(--radius) * 0.75);
39
+ padding-inline: calc(var(--spacing) * 2);
40
+ padding-block: calc(var(--spacing) * 1.5);
41
+ transition-property: background-color, color;
42
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
43
+ transition-duration: 100ms;
44
+ outline: none;
45
+ user-select: none;
46
+ text-decoration: none;
47
+ color: inherit;
48
+ font-size: 0.875rem;
49
+ line-height: 1.25rem;
50
+
51
+ &:focus {
52
+ background-color: var(--accent);
53
+ color: var(--accent-foreground);
54
+ }
55
+
56
+ > svg {
57
+ width: 1rem;
58
+ height: 1rem;
59
+ flex-shrink: 0;
60
+ color: var(--muted-foreground);
61
+ }
62
+
63
+ &[data-disabled='true'] {
64
+ pointer-events: none;
65
+ opacity: 0.5;
66
+ }
67
+
68
+ &[data-inset='true'] {
69
+ padding-left: calc(var(--spacing) * 4);
70
+ }
71
+ }
72
+ </style>
@@ -0,0 +1,31 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types';
3
+
4
+ type Props = HTMLAttributes<'div'> & {
5
+ /**
6
+ * Whether the label is inset (has left padding)
7
+ */
8
+ inset?: boolean;
9
+ };
10
+
11
+ const { class: className, inset = false, ...rest } = Astro.props;
12
+ ---
13
+
14
+ <div {...rest} data-slot="dropdown-label" data-inset={inset ? 'true' : undefined}>
15
+ <slot />
16
+ </div>
17
+
18
+ <style>
19
+ [data-slot='dropdown-label'] {
20
+ color: var(--muted-foreground);
21
+ padding-inline: calc(var(--spacing) * 2);
22
+ padding-block: calc(var(--spacing) * 1.5);
23
+ font-size: 0.875rem;
24
+ line-height: 1.25rem;
25
+ font-weight: 500;
26
+ }
27
+
28
+ [data-slot='dropdown-label'][data-inset='true'] {
29
+ padding-left: calc(var(--spacing) * 8);
30
+ }
31
+ </style>
@@ -0,0 +1,18 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types';
3
+
4
+ type Props = HTMLAttributes<'div'>;
5
+
6
+ const { class: className, ...rest } = Astro.props;
7
+ ---
8
+
9
+ <div role="separator" aria-orientation="horizontal" {...rest} data-slot="dropdown-separator"></div>
10
+
11
+ <style>
12
+ div[data-slot='dropdown-separator'] {
13
+ background-color: var(--border);
14
+ margin-inline: calc(var(--spacing) * -1);
15
+ margin-block: var(--spacing);
16
+ height: 1px;
17
+ }
18
+ </style>
@@ -0,0 +1,24 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types';
3
+
4
+ type Props = HTMLAttributes<'span'>;
5
+
6
+ const { ...props } = Astro.props;
7
+ ---
8
+
9
+ <span {...props}>
10
+ <slot />
11
+ </span>
12
+
13
+ <style>
14
+ span {
15
+ color: var(--muted-foreground);
16
+ margin-left: auto;
17
+ font-size: 0.875rem;
18
+ line-height: 1.25rem;
19
+ letter-spacing: 0.05em;
20
+ transition-property: background-color, color;
21
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
22
+ transition-duration: 100ms;
23
+ }
24
+ </style>
@@ -0,0 +1,54 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types';
3
+ import LinkButton from '../LinkButton.astro';
4
+
5
+ type Props = Omit<HTMLAttributes<'button'>, 'role' | 'type'> & {
6
+ /**
7
+ * When true, the component will render its child element with a simple wrapper instead of a button component
8
+ */
9
+ asChild?: boolean;
10
+
11
+ variant?: 'primary' | 'secondary' | 'minimal';
12
+ size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'icon-sm' | 'icon-md' | 'icon-lg';
13
+ };
14
+
15
+ const {
16
+ class: className,
17
+ variant = 'secondary',
18
+ size = 'sm',
19
+ asChild = false,
20
+ ...rest
21
+ } = Astro.props;
22
+
23
+ // Get the first child element if asChild is true
24
+ let hasChildren = false;
25
+ if (Astro.slots.has('default')) {
26
+ hasChildren = true;
27
+ }
28
+ ---
29
+
30
+ {
31
+ asChild && hasChildren ? (
32
+ <div
33
+ class:list={['starwind-dropdown-trigger', className]}
34
+ data-slot="dropdown-trigger"
35
+ data-as-child
36
+ >
37
+ <slot />
38
+ </div>
39
+ ) : (
40
+ <LinkButton
41
+ type="button"
42
+ aria-haspopup="true"
43
+ aria-expanded="false"
44
+ data-state="closed"
45
+ data-slot="dropdown-trigger"
46
+ class:list={[className]}
47
+ variant={variant}
48
+ size={size}
49
+ {...rest}
50
+ >
51
+ <slot />
52
+ </LinkButton>
53
+ )
54
+ }
@@ -0,0 +1,29 @@
1
+ // partially from https://starwind.dev/docs/components/dropdown/
2
+
3
+ import Dropdown from './Dropdown.astro';
4
+ import DropdownContent from './DropdownContent.astro';
5
+ import DropdownItem from './DropdownItem.astro';
6
+ import DropdownLabel from './DropdownLabel.astro';
7
+ import DropdownSeparator from './DropdownSeparator.astro';
8
+ import DropdownShortcut from './DropdownShortcut.astro';
9
+ import DropdownTrigger from './DropdownTrigger.astro';
10
+
11
+ export {
12
+ Dropdown,
13
+ DropdownContent,
14
+ DropdownItem,
15
+ DropdownLabel,
16
+ DropdownSeparator,
17
+ DropdownShortcut,
18
+ DropdownTrigger,
19
+ };
20
+
21
+ export default {
22
+ Root: Dropdown,
23
+ Trigger: DropdownTrigger,
24
+ Content: DropdownContent,
25
+ Item: DropdownItem,
26
+ Label: DropdownLabel,
27
+ Separator: DropdownSeparator,
28
+ Shortcut: DropdownShortcut,
29
+ };
@@ -0,0 +1 @@
1
+ <slot />
@@ -0,0 +1,54 @@
1
+ ---
2
+ import EditLink from 'virtual:starlight/components/EditLink';
3
+ import LastUpdated from 'virtual:starlight/components/LastUpdated';
4
+ import Pagination from 'virtual:starlight/components/Pagination';
5
+ import config from 'virtual:starlight/user-config';
6
+
7
+ const {
8
+ entry: {
9
+ data: { template },
10
+ },
11
+ } = Astro.locals.starlightRoute;
12
+
13
+ const { lastUpdated: showLastUpdated, editLink } = config;
14
+ const showEditLink = editLink?.baseUrl ? true : false;
15
+ ---
16
+
17
+ <!-- footer -->{
18
+ template === 'doc' && (
19
+ <footer>
20
+ {(showEditLink || showLastUpdated) && (
21
+ <div data-slot="doc-footer-meta">
22
+ <LastUpdated />
23
+ <EditLink />
24
+ </div>
25
+ )}
26
+
27
+ <Pagination />
28
+ </footer>
29
+ )
30
+ }
31
+
32
+ <style>
33
+ .padding-negative {
34
+ margin-bottom: -3vh;
35
+ }
36
+
37
+ [data-slot='doc-footer-meta'] {
38
+ display: flex;
39
+ gap: calc(var(--spacing) * 4);
40
+ align-items: center;
41
+ justify-content: end;
42
+ font-size: 0.875em;
43
+ color: var(--muted-foreground);
44
+ margin-top: calc(var(--spacing) * 8);
45
+ opacity: 0.75;
46
+ }
47
+ </style>
48
+
49
+ <style is:global>
50
+ footer.sl-flex {
51
+ border-top: none !important;
52
+ display: flex !important;
53
+ }
54
+ </style>
@@ -0,0 +1,93 @@
1
+ ---
2
+ import config from 'virtual:starlight/user-config';
3
+ import Search from './Search.astro';
4
+ import SocialIcons from './SocialIcons.astro';
5
+ import LanguageSelect from '@astrojs/starlight/components/LanguageSelect.astro';
6
+
7
+ import ThemeSelect from './ThemeSelect.astro';
8
+ import SiteTitle from './SiteTitle.astro';
9
+ import NavBar from './parts/NavBar.astro';
10
+ import MobileMenuToggle from './parts/MobileMenuToggle.astro';
11
+
12
+ /** render the `Search` component if Pagefind is enabled or the default search component has been overridden. */
13
+ const shouldRenderSearch =
14
+ config.pagefind || config.components.Search !== '@astrojs/starlight/components/Search.astro';
15
+ ---
16
+
17
+ <MobileMenuToggle />
18
+
19
+ <div class="site-title-wrapper">
20
+ <SiteTitle />
21
+ <NavBar />
22
+ </div>
23
+
24
+ <div class="header-right">
25
+ {shouldRenderSearch && <Search />}
26
+
27
+ <nav class="header-nav">
28
+ <div>
29
+ <SocialIcons />
30
+ </div>
31
+ <div>
32
+ <ThemeSelect />
33
+ </div>
34
+ <div>
35
+ <LanguageSelect />
36
+ </div>
37
+ </nav>
38
+ </div>
39
+
40
+ <style>
41
+ .site-title-wrapper {
42
+ display: none;
43
+ margin-right: calc(var(--spacing) * 4);
44
+ }
45
+
46
+ @media (min-width: 768px) {
47
+ .site-title-wrapper {
48
+ display: flex;
49
+ }
50
+ }
51
+
52
+ .header-right {
53
+ gap: 0.5rem;
54
+ justify-content: space-between;
55
+ align-items: center;
56
+ flex: 1 1 0%;
57
+ display: flex;
58
+ }
59
+
60
+ @media (min-width: 768px) {
61
+ .header-right {
62
+ justify-content: flex-end;
63
+ }
64
+ }
65
+
66
+ .header-nav {
67
+ gap: 0.125rem;
68
+ align-items: center;
69
+ display: flex;
70
+ }
71
+
72
+ .header-nav > div:has(> :not(script)) {
73
+ display: flex;
74
+ align-items: center;
75
+ }
76
+
77
+ .header-nav > div:has(> :not(script)) + div:has(> :not(script)) {
78
+ position: relative;
79
+ margin-left: calc(var(--spacing) * 1);
80
+ padding-left: calc(var(--spacing) * 3);
81
+ }
82
+
83
+ .header-nav > div:has(> :not(script)) + div:has(> :not(script))::before {
84
+ content: '';
85
+ position: absolute;
86
+ top: 50%;
87
+ left: 0;
88
+ width: 1px;
89
+ height: 1rem;
90
+ background-color: color-mix(in oklab, var(--border) 85%, transparent);
91
+ transform: translateY(-50%);
92
+ }
93
+ </style>