@grove-dev/starlight 0.6.1 → 0.8.0
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.
- package/LICENSE +21 -0
- package/README.md +77 -78
- package/components/custom/ContainerSection.astro +1 -1
- package/components/custom/LinkButton.astro +134 -89
- package/components/custom/dropdown/Dropdown.astro +5 -5
- package/components/custom/dropdown/DropdownContent.astro +66 -66
- package/components/custom/dropdown/DropdownItem.astro +14 -9
- package/components/custom/dropdown/DropdownLabel.astro +4 -4
- package/components/custom/dropdown/DropdownTrigger.astro +13 -13
- package/components/custom/dropdown/index.ts +14 -14
- package/components/overrides/Footer.astro +3 -3
- package/components/overrides/Header.astro +5 -6
- package/components/overrides/Hero.astro +20 -12
- package/components/overrides/PageFrame.astro +25 -9
- package/components/overrides/PageSidebar.astro +1 -0
- package/components/overrides/PageTitle.astro +3 -3
- package/components/overrides/Search.astro +6 -6
- package/components/overrides/Sidebar.astro +38 -1
- package/components/overrides/SocialIcons.astro +3 -1
- package/components/overrides/ThemeSelect.astro +4 -4
- package/components/overrides/TwoColumnContent.astro +1 -1
- package/components/overrides/parts/Drawer.astro +13 -7
- package/components/overrides/parts/NavBar.astro +12 -31
- package/components/overrides/parts/SidebarSublist.astro +75 -4
- package/components/overrides/parts/toc/TableOfContentsList.astro +4 -4
- package/components/overrides/parts/toc/starlight-toc.ts +96 -98
- package/core/config/docs-schema.ts +58 -0
- package/core/config/expresive-code.ts +49 -51
- package/core/config/override.ts +37 -33
- package/core/config/schemas.ts +62 -41
- package/core/config/vite.ts +14 -14
- package/core/i18n.ts +175 -0
- package/core/plugin.ts +45 -43
- package/core/sidebar.ts +22 -0
- package/global.d.ts +3 -3
- package/package.json +3 -19
- package/schema.ts +44 -13
- package/styles/base.css +883 -896
- package/styles/layers.css +1 -1
- package/styles/theme.css +62 -62
- package/user-components.ts +1 -2
- package/virtual.d.ts +28 -28
- package/THIRD_PARTY_LICENSES.md +0 -68
- package/components/custom/Card.astro +0 -118
|
@@ -2,35 +2,35 @@
|
|
|
2
2
|
import type { HTMLAttributes } from 'astro/types';
|
|
3
3
|
|
|
4
4
|
type Props = HTMLAttributes<'div'> & {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
25
|
};
|
|
26
26
|
|
|
27
27
|
const {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
class: className,
|
|
29
|
+
side = 'bottom',
|
|
30
|
+
align = 'start',
|
|
31
|
+
sideOffset = 4,
|
|
32
|
+
animationDuration = 150,
|
|
33
|
+
...rest
|
|
34
34
|
} = Astro.props;
|
|
35
35
|
---
|
|
36
36
|
|
|
@@ -59,7 +59,7 @@ const {
|
|
|
59
59
|
<style>
|
|
60
60
|
div[data-slot='dropdown-content'] {
|
|
61
61
|
background-color: var(--popover-background, var(--muted));
|
|
62
|
-
color: var(
|
|
62
|
+
color: var(--popover-foreground, var(--foreground));
|
|
63
63
|
z-index: 50;
|
|
64
64
|
min-width: 9rem;
|
|
65
65
|
overflow-x: hidden;
|
|
@@ -134,46 +134,46 @@ const {
|
|
|
134
134
|
&[data-side='right'][data-align='end'] {
|
|
135
135
|
bottom: 0;
|
|
136
136
|
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* animations */
|
|
140
|
+
@keyframes fade-in {
|
|
141
|
+
from {
|
|
142
|
+
opacity: 0;
|
|
143
|
+
}
|
|
144
|
+
to {
|
|
145
|
+
opacity: 1;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@keyframes fade-out {
|
|
150
|
+
from {
|
|
151
|
+
opacity: 1;
|
|
152
|
+
}
|
|
153
|
+
to {
|
|
154
|
+
opacity: 0;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
137
157
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
}
|
|
158
|
+
@keyframes zoom-in-95 {
|
|
159
|
+
from {
|
|
160
|
+
opacity: 0;
|
|
161
|
+
transform: scale(0.95);
|
|
162
|
+
}
|
|
163
|
+
to {
|
|
164
|
+
opacity: 1;
|
|
165
|
+
transform: scale(1);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@keyframes zoom-out-95 {
|
|
170
|
+
from {
|
|
171
|
+
opacity: 1;
|
|
172
|
+
transform: scale(1);
|
|
173
|
+
}
|
|
174
|
+
to {
|
|
175
|
+
opacity: 0;
|
|
176
|
+
transform: scale(0.95);
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
</style>
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import type { HTMLTag, Polymorphic } from 'astro/types';
|
|
3
3
|
|
|
4
4
|
type Props<Tag extends HTMLTag> = Polymorphic<{ as: Tag }> & {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
13
|
};
|
|
14
14
|
|
|
15
15
|
const { class: className, inset = false, disabled = false, as: Tag = 'div', ...rest } = Astro.props;
|
|
@@ -53,7 +53,12 @@ const { class: className, inset = false, disabled = false, as: Tag = 'div', ...r
|
|
|
53
53
|
color: var(--accent-foreground);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
/*
|
|
57
|
+
* `:global` because the icon is slotted in by the consumer, so it carries that component's
|
|
58
|
+
* scope class rather than this one's. Astro 7 scopes descendant selectors that Astro 6 left
|
|
59
|
+
* alone, which would otherwise leave slotted icons unsized.
|
|
60
|
+
*/
|
|
61
|
+
> :global(svg) {
|
|
57
62
|
width: 1rem;
|
|
58
63
|
height: 1rem;
|
|
59
64
|
flex-shrink: 0;
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import type { HTMLAttributes } from 'astro/types';
|
|
3
3
|
|
|
4
4
|
type Props = HTMLAttributes<'div'> & {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Whether the label is inset (has left padding)
|
|
7
|
+
*/
|
|
8
|
+
inset?: boolean;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
const { class: className, inset = false, ...rest } = Astro.props;
|
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { HTMLAttributes } from 'astro/types';
|
|
3
|
-
import LinkButton from '../LinkButton.astro';
|
|
3
|
+
import LinkButton, { type ButtonVariant, type LegacyButtonVariant } from '../LinkButton.astro';
|
|
4
4
|
|
|
5
5
|
type Props = Omit<HTMLAttributes<'button'>, 'role' | 'type'> & {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
variant?: ButtonVariant | LegacyButtonVariant;
|
|
12
|
+
size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'icon-sm' | 'icon-md' | 'icon-lg';
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
const {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
class: className,
|
|
17
|
+
variant = 'secondary',
|
|
18
|
+
size = 'sm',
|
|
19
|
+
asChild = false,
|
|
20
|
+
...rest
|
|
21
21
|
} = Astro.props;
|
|
22
22
|
|
|
23
23
|
// Get the first child element if asChild is true
|
|
24
24
|
let hasChildren = false;
|
|
25
25
|
if (Astro.slots.has('default')) {
|
|
26
|
-
|
|
26
|
+
hasChildren = true;
|
|
27
27
|
}
|
|
28
28
|
---
|
|
29
29
|
|
|
@@ -9,21 +9,21 @@ import DropdownShortcut from './DropdownShortcut.astro';
|
|
|
9
9
|
import DropdownTrigger from './DropdownTrigger.astro';
|
|
10
10
|
|
|
11
11
|
export {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
Dropdown,
|
|
13
|
+
DropdownContent,
|
|
14
|
+
DropdownItem,
|
|
15
|
+
DropdownLabel,
|
|
16
|
+
DropdownSeparator,
|
|
17
|
+
DropdownShortcut,
|
|
18
|
+
DropdownTrigger,
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
export default {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
Root: Dropdown,
|
|
23
|
+
Trigger: DropdownTrigger,
|
|
24
|
+
Content: DropdownContent,
|
|
25
|
+
Item: DropdownItem,
|
|
26
|
+
Label: DropdownLabel,
|
|
27
|
+
Separator: DropdownSeparator,
|
|
28
|
+
Shortcut: DropdownShortcut,
|
|
29
29
|
};
|
|
@@ -5,9 +5,9 @@ import Pagination from 'virtual:starlight/components/Pagination';
|
|
|
5
5
|
import config from 'virtual:starlight/user-config';
|
|
6
6
|
|
|
7
7
|
const {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
entry: {
|
|
9
|
+
data: { template },
|
|
10
|
+
},
|
|
11
11
|
} = Astro.locals.starlightRoute;
|
|
12
12
|
|
|
13
13
|
const { lastUpdated: showLastUpdated, editLink } = config;
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
import config from 'virtual:starlight/user-config';
|
|
3
|
+
import LanguageSelect from '@astrojs/starlight/components/LanguageSelect.astro';
|
|
4
|
+
import MobileMenuToggle from './parts/MobileMenuToggle.astro';
|
|
5
|
+
import NavBar from './parts/NavBar.astro';
|
|
3
6
|
import Search from './Search.astro';
|
|
7
|
+
import SiteTitle from './SiteTitle.astro';
|
|
4
8
|
import SocialIcons from './SocialIcons.astro';
|
|
5
|
-
import LanguageSelect from '@astrojs/starlight/components/LanguageSelect.astro';
|
|
6
|
-
|
|
7
9
|
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
10
|
|
|
12
11
|
/** render the `Search` component if Pagefind is enabled or the default search component has been overridden. */
|
|
13
12
|
const shouldRenderSearch =
|
|
14
|
-
|
|
13
|
+
config.pagefind || config.components.Search !== '@astrojs/starlight/components/Search.astro';
|
|
15
14
|
---
|
|
16
15
|
|
|
17
16
|
<MobileMenuToggle />
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { Icon } from '@astrojs/starlight/components';
|
|
3
2
|
import { Image } from 'astro:assets';
|
|
3
|
+
import { Icon } from '@astrojs/starlight/components';
|
|
4
4
|
import { PAGE_TITLE_ID } from '../../core/config/constants';
|
|
5
|
-
import
|
|
5
|
+
import { warnAboutMissingDocsSchemaOnce } from '../../core/config/docs-schema';
|
|
6
6
|
import ContainerSection from '../custom/ContainerSection.astro';
|
|
7
7
|
import LinkButton from '../custom/LinkButton.astro';
|
|
8
8
|
|
|
9
9
|
const { data } = Astro.locals.starlightRoute.entry;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
|
|
11
|
+
warnAboutMissingDocsSchemaOnce(data.hero);
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
title = data.title,
|
|
15
|
+
tagline: heroTagline,
|
|
16
|
+
image,
|
|
17
|
+
announcement,
|
|
18
|
+
actions = [],
|
|
19
|
+
} = data.hero || {};
|
|
20
|
+
|
|
21
|
+
// Falls back on an empty tagline too, not just a missing one.
|
|
15
22
|
const tagline = heroTagline || data.description;
|
|
16
23
|
|
|
24
|
+
const hasImage = !!image;
|
|
17
25
|
const imageAttrs = {
|
|
18
26
|
loading: 'eager' as const,
|
|
19
27
|
decoding: 'async' as const,
|
|
@@ -37,7 +45,7 @@ if (image) {
|
|
|
37
45
|
---
|
|
38
46
|
|
|
39
47
|
<ContainerSection>
|
|
40
|
-
<div class="hero" data-layout={
|
|
48
|
+
<div class="hero" data-layout={data.hero?.layout} data-has-image={hasImage ? '' : undefined}>
|
|
41
49
|
{
|
|
42
50
|
hasImage && (
|
|
43
51
|
<div class="hero-image">
|
|
@@ -67,12 +75,11 @@ if (image) {
|
|
|
67
75
|
)
|
|
68
76
|
}
|
|
69
77
|
|
|
70
|
-
<h1 id={PAGE_TITLE_ID} data-page-title
|
|
78
|
+
<h1 id={PAGE_TITLE_ID} data-page-title set:html={title} />
|
|
71
79
|
</div>
|
|
72
80
|
|
|
73
81
|
<div class="hero-content-container">
|
|
74
|
-
{tagline && <div class="tagline"
|
|
75
|
-
|
|
82
|
+
{tagline && <div class="tagline" set:html={tagline} />}
|
|
76
83
|
{
|
|
77
84
|
actions.length > 0 && (
|
|
78
85
|
<div class="actions">
|
|
@@ -91,7 +98,8 @@ if (image) {
|
|
|
91
98
|
{...attrs}
|
|
92
99
|
>
|
|
93
100
|
{text}
|
|
94
|
-
{icon?.
|
|
101
|
+
{icon?.type === 'icon' && <Icon name={icon.name} />}
|
|
102
|
+
{icon?.type === 'raw' && <Fragment set:html={icon.html} />}
|
|
95
103
|
</LinkButton>
|
|
96
104
|
)
|
|
97
105
|
)}
|
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
---
|
|
2
|
-
import userConfig from 'virtual:
|
|
2
|
+
import userConfig from 'virtual:grove-starlight-config';
|
|
3
|
+
import starlightConfig from 'virtual:starlight/user-config';
|
|
4
|
+
import { AstroError } from 'astro/errors';
|
|
5
|
+
import { marked } from 'marked';
|
|
6
|
+
import { createLocaleLookup, resolveLocalizedString } from '../../core/i18n';
|
|
3
7
|
import Drawer from './parts/Drawer.astro';
|
|
4
8
|
|
|
5
|
-
const { hasSidebar } = Astro.locals.starlightRoute;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const { hasSidebar, lang, locale } = Astro.locals.starlightRoute;
|
|
10
|
+
|
|
11
|
+
const localeKeys = createLocaleLookup({
|
|
12
|
+
lang,
|
|
13
|
+
locale: Astro.currentLocale ?? locale,
|
|
14
|
+
defaultLang: starlightConfig.defaultLocale?.lang,
|
|
15
|
+
defaultLocale: starlightConfig.defaultLocale?.locale,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
let footerText: string;
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
footerText = resolveLocalizedString(userConfig.footerText, localeKeys);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
throw new AstroError(
|
|
24
|
+
error instanceof Error ? error.message : 'Invalid footerText localization.',
|
|
25
|
+
'Update the Grove config so footerText includes a key for the default language.',
|
|
26
|
+
);
|
|
27
|
+
}
|
|
12
28
|
---
|
|
13
29
|
|
|
14
30
|
<div data-slot="layout">
|
|
@@ -39,7 +55,7 @@ const { hasSidebar } = Astro.locals.starlightRoute;
|
|
|
39
55
|
</main>
|
|
40
56
|
|
|
41
57
|
<footer>
|
|
42
|
-
<div data-slot="footer-text"
|
|
58
|
+
<div data-slot="footer-text" set:html={marked.parseInline(footerText)} />
|
|
43
59
|
</footer>
|
|
44
60
|
</div>
|
|
45
61
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
|
+
import userConfig from 'virtual:grove-starlight-config';
|
|
2
3
|
import { Icon } from '@astrojs/starlight/components';
|
|
3
4
|
import { PAGE_TITLE_ID } from '../../core/config/constants';
|
|
4
|
-
import userConfig from 'virtual:lucode-starlight-config';
|
|
5
5
|
import { Dropdown, DropdownContent, DropdownItem, DropdownTrigger } from '../custom/dropdown';
|
|
6
6
|
import LinkButton from '../custom/LinkButton.astro';
|
|
7
7
|
|
|
8
8
|
const {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
entry: { data },
|
|
10
|
+
pagination: { prev, next },
|
|
11
11
|
} = Astro.locals.starlightRoute;
|
|
12
12
|
|
|
13
13
|
const { title, description } = data;
|
|
@@ -3,12 +3,12 @@ import '@pagefind/default-ui/css/ui.css';
|
|
|
3
3
|
import project from 'virtual:starlight/project-context';
|
|
4
4
|
|
|
5
5
|
const pagefindTranslations = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
12
|
};
|
|
13
13
|
|
|
14
14
|
const dataAttributes: DOMStringMap = { 'data-translations': JSON.stringify(pagefindTranslations) };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
import SidebarPersister from '@astrojs/starlight/components/SidebarPersister.astro';
|
|
2
3
|
import SidebarSublist from './parts/SidebarSublist.astro';
|
|
3
4
|
|
|
4
5
|
const { sidebar } = Astro.locals.starlightRoute;
|
|
@@ -10,12 +11,48 @@ const { sidebar } = Astro.locals.starlightRoute;
|
|
|
10
11
|
<div class="sidebar-fade-top"></div>
|
|
11
12
|
<div class="container-sidebar">
|
|
12
13
|
<div class="sidebar-entries">
|
|
13
|
-
|
|
14
|
+
{/* Keeps collapsed groups open and the scroll position across navigations. */}
|
|
15
|
+
<SidebarPersister>
|
|
16
|
+
<SidebarSublist sublist={sidebar} />
|
|
17
|
+
</SidebarPersister>
|
|
14
18
|
</div>
|
|
15
19
|
<div class="sidebar-fade-bottom"></div>
|
|
16
20
|
</div>
|
|
17
21
|
</div>
|
|
18
22
|
|
|
23
|
+
{/*
|
|
24
|
+
Bring the current page's entry into view inside the sidebar's own scroll
|
|
25
|
+
container. SidebarPersister keeps the scroll position across navigations, but
|
|
26
|
+
on a fresh load (or the first visit to a deep page) the sidebar starts at the
|
|
27
|
+
top, so an entry far down the list renders off-screen with no hint that it is
|
|
28
|
+
selected. Only the container is scrolled -- never the page -- and only when
|
|
29
|
+
the entry is actually outside the visible band.
|
|
30
|
+
*/}
|
|
31
|
+
<script is:inline data-astro-rerun>
|
|
32
|
+
(() => {
|
|
33
|
+
const reveal = () => {
|
|
34
|
+
const container = document.querySelector('.container-sidebar');
|
|
35
|
+
const current = container?.querySelector('[aria-current="page"]');
|
|
36
|
+
if (!container || !current) return;
|
|
37
|
+
|
|
38
|
+
const view = container.getBoundingClientRect();
|
|
39
|
+
const entry = current.getBoundingClientRect();
|
|
40
|
+
if (entry.top >= view.top && entry.bottom <= view.bottom) return;
|
|
41
|
+
|
|
42
|
+
const offset =
|
|
43
|
+
entry.top - view.top - container.clientHeight / 2 + entry.height / 2;
|
|
44
|
+
// Instant, not smooth: this positions the sidebar for the page
|
|
45
|
+
// being loaded, so it should already be correct on first paint
|
|
46
|
+
// rather than animating into place while the reader looks at it.
|
|
47
|
+
container.scrollTop += offset;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Runs after SidebarPersister has restored any stored scroll position.
|
|
51
|
+
requestAnimationFrame(reveal);
|
|
52
|
+
document.addEventListener('astro:page-load', () => requestAnimationFrame(reveal));
|
|
53
|
+
})();
|
|
54
|
+
</script>
|
|
55
|
+
|
|
19
56
|
<style>
|
|
20
57
|
.sidebar {
|
|
21
58
|
scrollbar-width: none;
|
|
@@ -32,7 +32,9 @@ const links = config.social || [];
|
|
|
32
32
|
cursor: pointer;
|
|
33
33
|
color: color-mix(in oklab, var(--foreground) 76%, var(--muted-foreground));
|
|
34
34
|
background-color: transparent;
|
|
35
|
-
transition:
|
|
35
|
+
transition:
|
|
36
|
+
color 0.15s,
|
|
37
|
+
background-color 0.15s;
|
|
36
38
|
text-decoration: none;
|
|
37
39
|
}
|
|
38
40
|
a:hover {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
<starlight-theme-
|
|
5
|
+
<starlight-theme-grove-select>
|
|
6
6
|
<button
|
|
7
7
|
aria-label={Astro.locals.t('themeSelect.accessibleLabel')}
|
|
8
8
|
aria-live="polite"
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
|
|
50
50
|
<span class="sr-only">Toggle theme</span>
|
|
51
51
|
</button>
|
|
52
|
-
</starlight-theme-
|
|
52
|
+
</starlight-theme-grove-select>
|
|
53
53
|
|
|
54
54
|
<style>
|
|
55
55
|
button {
|
|
@@ -137,8 +137,8 @@
|
|
|
137
137
|
});
|
|
138
138
|
|
|
139
139
|
customElements.define(
|
|
140
|
-
'starlight-theme-
|
|
141
|
-
class
|
|
140
|
+
'starlight-theme-grove-select',
|
|
141
|
+
class StarlightThemeGroveSelect extends HTMLElement {
|
|
142
142
|
constructor() {
|
|
143
143
|
super();
|
|
144
144
|
onThemeChange(loadTheme());
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
---
|
|
2
|
-
import userConfig from 'virtual:lucode-starlight-config';
|
|
3
|
-
import { getTranslation } from './NavBar.astro';
|
|
4
2
|
import { getRelativeLocaleUrl } from 'astro:i18n';
|
|
5
|
-
|
|
3
|
+
import userConfig from 'virtual:grove-starlight-config';
|
|
4
|
+
import starlightConfig from 'virtual:starlight/user-config';
|
|
5
|
+
import { createLocaleLookup, resolveNavLabel } from '../../../core/i18n';
|
|
6
|
+
|
|
7
|
+
const { sidebar, lang, locale } = Astro.locals.starlightRoute;
|
|
6
8
|
|
|
7
9
|
const currentPath = Astro.url.pathname;
|
|
10
|
+
|
|
11
|
+
const localeKeys = createLocaleLookup({
|
|
12
|
+
lang,
|
|
13
|
+
locale: Astro.currentLocale ?? locale,
|
|
14
|
+
defaultLang: starlightConfig.defaultLocale?.lang,
|
|
15
|
+
defaultLocale: starlightConfig.defaultLocale?.locale,
|
|
16
|
+
});
|
|
8
17
|
---
|
|
9
18
|
|
|
10
19
|
<div popover="auto" id="drawer">
|
|
@@ -25,10 +34,7 @@ const currentPath = Astro.url.pathname;
|
|
|
25
34
|
!absoluteLinkRegex.test(nav.link) && Astro.currentLocale
|
|
26
35
|
? getRelativeLocaleUrl(Astro.currentLocale, nav.link)
|
|
27
36
|
: nav.link;
|
|
28
|
-
const label =
|
|
29
|
-
typeof nav.label === 'string'
|
|
30
|
-
? nav.label
|
|
31
|
-
: getTranslation(nav.label, nav.link, 'label');
|
|
37
|
+
const label = resolveNavLabel(nav.label, nav.translations, localeKeys);
|
|
32
38
|
|
|
33
39
|
return (
|
|
34
40
|
<a href={link} {...nav.attrs}>
|