@astrojs/starlight 0.5.6 → 0.6.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/404.astro +17 -17
- package/CHANGELOG.md +40 -2
- package/components/CallToAction.astro +32 -35
- package/components/ContentPanel.astro +18 -18
- package/components/EditLink.astro +23 -23
- package/components/FallbackContentNotice.astro +16 -18
- package/components/Footer.astro +28 -34
- package/components/HeadSEO.astro +69 -75
- package/components/Header.astro +47 -51
- package/components/Hero.astro +108 -121
- package/components/Icons.ts +73 -71
- package/components/LanguageSelect.astro +31 -31
- package/components/LastUpdated.astro +16 -18
- package/components/MarkdownContent.astro +105 -117
- package/components/MobileMenuToggle.astro +80 -80
- package/components/PrevNextLinks.astro +60 -60
- package/components/RightSidebar.astro +17 -17
- package/components/RightSidebarPanel.astro +41 -41
- package/components/Search.astro +293 -306
- package/components/Select.astro +64 -65
- package/components/Sidebar.astro +23 -23
- package/components/SidebarSublist.astro +96 -95
- package/components/SiteTitle.astro +65 -63
- package/components/SkipLink.astro +17 -17
- package/components/SocialIcons.astro +36 -34
- package/components/TableOfContents/MobileTableOfContents.astro +124 -124
- package/components/TableOfContents/TableOfContentsList.astro +64 -69
- package/components/TableOfContents/generateToC.ts +41 -43
- package/components/TableOfContents/starlight-toc.ts +84 -90
- package/components/TableOfContents.astro +8 -8
- package/components/ThemeProvider.astro +28 -32
- package/components/ThemeSelect.astro +66 -71
- package/global.d.ts +3 -3
- package/index.astro +1 -1
- package/index.ts +52 -59
- package/integrations/asides.ts +109 -111
- package/integrations/sitemap.ts +10 -13
- package/integrations/virtual-user-config.ts +37 -37
- package/layout/Page.astro +84 -72
- package/layout/PageFrame.astro +67 -69
- package/layout/TwoColumnContent.astro +40 -42
- package/package.json +2 -2
- package/schema.ts +126 -113
- package/schemas/favicon.ts +40 -0
- package/schemas/head.ts +12 -23
- package/schemas/i18n.ts +146 -160
- package/schemas/logo.ts +22 -22
- package/schemas/prevNextLink.ts +14 -14
- package/schemas/tableOfContents.ts +14 -18
- package/style/asides.css +27 -27
- package/style/props.css +168 -172
- package/style/reset.css +13 -13
- package/style/shiki.css +11 -11
- package/style/util.css +30 -30
- package/translations/fr.json +21 -21
- package/translations/index.ts +4 -4
- package/translations/it.json +20 -20
- package/translations/tr.json +1 -1
- package/translations/zh.json +0 -1
- package/user-components/Card.astro +50 -54
- package/user-components/CardGrid.astro +21 -21
- package/user-components/Icon.astro +19 -21
- package/user-components/TabItem.astro +3 -3
- package/user-components/Tabs.astro +113 -117
- package/user-components/rehype-tabs.ts +72 -72
- package/utils/base.ts +6 -6
- package/utils/git.ts +55 -55
- package/utils/head.ts +56 -54
- package/utils/i18n.ts +3 -3
- package/utils/localizedUrl.ts +25 -25
- package/utils/navigation.ts +225 -203
- package/utils/routing.ts +74 -85
- package/utils/slugs.ts +41 -51
- package/utils/translations.ts +26 -32
- package/utils/user-config.ts +278 -278
- package/virtual.d.ts +8 -8
package/layout/PageFrame.astro
CHANGED
|
@@ -3,8 +3,8 @@ import MobileMenuToggle from '../components/MobileMenuToggle.astro';
|
|
|
3
3
|
import { useTranslations } from '../utils/translations';
|
|
4
4
|
|
|
5
5
|
interface Props {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
hasSidebar: boolean;
|
|
7
|
+
locale: string | undefined;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
const { hasSidebar, locale } = Astro.props;
|
|
@@ -12,81 +12,79 @@ const t = useTranslations(locale);
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
<div class="page flex">
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
15
|
+
<header class="header"><slot name="header" /></header>
|
|
16
|
+
{
|
|
17
|
+
hasSidebar && (
|
|
18
|
+
<nav class="sidebar" aria-label={t('sidebarNav.accessibleLabel')}>
|
|
19
|
+
<MobileMenuToggle {locale} />
|
|
20
|
+
<div id="starlight__sidebar" class="sidebar-pane">
|
|
21
|
+
<div class="sidebar-content">
|
|
22
|
+
<slot name="sidebar" />
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</nav>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
<div class="main-frame"><slot /></div>
|
|
29
29
|
</div>
|
|
30
30
|
|
|
31
31
|
<style>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
.page {
|
|
33
|
+
flex-direction: column;
|
|
34
|
+
min-height: 100vh;
|
|
35
|
+
}
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
37
|
+
.header {
|
|
38
|
+
z-index: var(--sl-z-index-navbar);
|
|
39
|
+
position: fixed;
|
|
40
|
+
inset-inline-start: 0;
|
|
41
|
+
inset-block-start: 0;
|
|
42
|
+
width: 100%;
|
|
43
|
+
height: var(--sl-nav-height);
|
|
44
|
+
border-bottom: 1px solid var(--sl-color-hairline-shade);
|
|
45
|
+
padding: var(--sl-nav-pad-y) var(--sl-nav-pad-x);
|
|
46
|
+
padding-inline-end: var(--sl-nav-pad-x);
|
|
47
|
+
background-color: var(--sl-color-bg-nav);
|
|
48
|
+
}
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
);
|
|
54
|
-
}
|
|
50
|
+
:global([data-has-sidebar]) .header {
|
|
51
|
+
padding-inline-end: calc(var(--sl-nav-gap) + var(--sl-nav-pad-x) + var(--sl-menu-button-size));
|
|
52
|
+
}
|
|
55
53
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
54
|
+
.sidebar-pane {
|
|
55
|
+
visibility: var(--sl-sidebar-visibility, hidden);
|
|
56
|
+
position: fixed;
|
|
57
|
+
z-index: var(--sl-z-index-menu);
|
|
58
|
+
inset-block: 0;
|
|
59
|
+
inset-inline-start: 0;
|
|
60
|
+
padding-top: var(--sl-nav-height);
|
|
61
|
+
width: 100%;
|
|
62
|
+
background-color: var(--sl-color-black);
|
|
63
|
+
}
|
|
66
64
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
:global([aria-expanded='true']) ~ .sidebar-pane {
|
|
66
|
+
--sl-sidebar-visibility: visible;
|
|
67
|
+
}
|
|
70
68
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
.sidebar-content {
|
|
70
|
+
height: 100%;
|
|
71
|
+
overflow-y: auto;
|
|
72
|
+
}
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
.main-frame {
|
|
75
|
+
padding-top: calc(var(--sl-nav-height) + var(--sl-mobile-toc-height));
|
|
76
|
+
padding-inline-start: var(--sl-content-inline-start);
|
|
77
|
+
}
|
|
80
78
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
79
|
+
@media (min-width: 50rem) {
|
|
80
|
+
:global([data-has-sidebar]) .header {
|
|
81
|
+
padding-inline-end: var(--sl-nav-pad-x);
|
|
82
|
+
}
|
|
83
|
+
.sidebar-pane {
|
|
84
|
+
--sl-sidebar-visibility: visible;
|
|
85
|
+
width: var(--sl-sidebar-width);
|
|
86
|
+
background-color: var(--sl-color-bg-sidebar);
|
|
87
|
+
border-inline-end: 1px solid var(--sl-color-hairline-shade);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
92
90
|
</style>
|
|
@@ -1,56 +1,54 @@
|
|
|
1
1
|
---
|
|
2
2
|
interface Props {
|
|
3
|
-
|
|
3
|
+
hasToC: boolean;
|
|
4
4
|
}
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<div class="lg:flex">
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
{
|
|
9
|
+
Astro.props.hasToC && (
|
|
10
|
+
<aside class="right-sidebar-container">
|
|
11
|
+
<div class="right-sidebar">
|
|
12
|
+
<slot name="right-sidebar" />
|
|
13
|
+
</div>
|
|
14
|
+
</aside>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
<div class="main-pane"><slot /></div>
|
|
18
18
|
</div>
|
|
19
19
|
|
|
20
20
|
<style>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
21
|
+
@media (min-width: 72rem) {
|
|
22
|
+
.right-sidebar-container {
|
|
23
|
+
order: 2;
|
|
24
|
+
position: relative;
|
|
25
|
+
width: calc(
|
|
26
|
+
var(--sl-sidebar-width) + (100% - var(--sl-content-width) - var(--sl-sidebar-width)) / 2
|
|
27
|
+
);
|
|
28
|
+
}
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
.right-sidebar {
|
|
31
|
+
position: fixed;
|
|
32
|
+
top: 0;
|
|
33
|
+
border-inline-start: 1px solid var(--sl-color-gray-6);
|
|
34
|
+
padding-top: var(--sl-nav-height);
|
|
35
|
+
width: 100%;
|
|
36
|
+
height: 100vh;
|
|
37
|
+
overflow-y: auto;
|
|
38
|
+
scrollbar-width: none;
|
|
39
|
+
}
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
.main-pane {
|
|
42
|
+
width: 100%;
|
|
43
|
+
}
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
:global([data-has-sidebar]) .main-pane {
|
|
46
|
+
--sl-content-margin-inline: auto 0;
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
48
|
+
order: 1;
|
|
49
|
+
width: calc(
|
|
50
|
+
var(--sl-content-width) + (100% - var(--sl-content-width) - var(--sl-sidebar-width)) / 2
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
56
54
|
</style>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/starlight",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Build beautiful, high-performance documentation websites with Astro",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"docs",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^18.16.19",
|
|
35
35
|
"@vitest/coverage-v8": "^0.33.0",
|
|
36
|
-
"astro": "^2.
|
|
36
|
+
"astro": "^2.9.3",
|
|
37
37
|
"vitest": "^0.33.0"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
package/schema.ts
CHANGED
|
@@ -9,127 +9,140 @@ type IconName = keyof typeof Icons;
|
|
|
9
9
|
const iconNames = Object.keys(Icons) as [IconName, ...IconName[]];
|
|
10
10
|
|
|
11
11
|
type ImageFunction = () => z.ZodObject<{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
12
|
+
src: z.ZodString;
|
|
13
|
+
width: z.ZodNumber;
|
|
14
|
+
height: z.ZodNumber;
|
|
15
|
+
format: z.ZodUnion<
|
|
16
|
+
[
|
|
17
|
+
z.ZodLiteral<'png'>,
|
|
18
|
+
z.ZodLiteral<'jpg'>,
|
|
19
|
+
z.ZodLiteral<'jpeg'>,
|
|
20
|
+
z.ZodLiteral<'tiff'>,
|
|
21
|
+
z.ZodLiteral<'webp'>,
|
|
22
|
+
z.ZodLiteral<'gif'>,
|
|
23
|
+
z.ZodLiteral<'svg'>,
|
|
24
|
+
]
|
|
25
|
+
>;
|
|
26
26
|
}>;
|
|
27
27
|
|
|
28
28
|
export function docsSchema() {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
return ({ image }: { image: ImageFunction }) =>
|
|
30
|
+
z.object({
|
|
31
|
+
/** The title of the current page. Required. */
|
|
32
|
+
title: z.string(),
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
/**
|
|
35
|
+
* A short description of the current page’s content. Optional, but recommended.
|
|
36
|
+
* A good description is 150–160 characters long and outlines the key content
|
|
37
|
+
* of the page in a clear and engaging way.
|
|
38
|
+
*/
|
|
39
|
+
description: z.string().optional(),
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
.union([z.string().url(), z.boolean()])
|
|
49
|
-
.optional()
|
|
50
|
-
.default(true),
|
|
41
|
+
/**
|
|
42
|
+
* Custom URL where a reader can edit this page.
|
|
43
|
+
* Overrides the `editLink.baseUrl` global config if set.
|
|
44
|
+
*
|
|
45
|
+
* Can also be set to `false` to disable showing an edit link on this page.
|
|
46
|
+
*/
|
|
47
|
+
editUrl: z.union([z.string().url(), z.boolean()]).optional().default(true),
|
|
51
48
|
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
/** Set custom `<head>` tags just for this page. */
|
|
50
|
+
head: HeadConfigSchema(),
|
|
54
51
|
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
/** Override global table of contents configuration for this page. */
|
|
53
|
+
tableOfContents: TableOfContentsSchema().optional(),
|
|
57
54
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Set the layout style for this page.
|
|
57
|
+
* Can be `'doc'` (the default) or `'splash'` for a wider layout without any sidebars.
|
|
58
|
+
*/
|
|
59
|
+
template: z.enum(['doc', 'splash']).default('doc'),
|
|
63
60
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
})
|
|
116
|
-
.optional(),
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* The last update date of the current page.
|
|
120
|
-
* Overrides the `lastUpdated` global config or the date generated from the Git history.
|
|
121
|
-
*/
|
|
122
|
-
lastUpdated: z.union([z.date(), z.boolean()]).optional(),
|
|
61
|
+
/** Display a hero section on this page. */
|
|
62
|
+
hero: z
|
|
63
|
+
.object({
|
|
64
|
+
/**
|
|
65
|
+
* The large title text to show. If not provided, will default to the top-level `title`.
|
|
66
|
+
* Can include HTML.
|
|
67
|
+
*/
|
|
68
|
+
title: z.string().optional(),
|
|
69
|
+
/**
|
|
70
|
+
* A short bit of text about your project.
|
|
71
|
+
* Will be displayed in a smaller size below the title.
|
|
72
|
+
*/
|
|
73
|
+
tagline: z.string().optional(),
|
|
74
|
+
/** The image to use in the hero. You can provide either a relative `file` path or raw `html`. */
|
|
75
|
+
image: z
|
|
76
|
+
.object({
|
|
77
|
+
/** Alt text for screenreaders and other assistive technologies describing your hero image. */
|
|
78
|
+
alt: z.string().default(''),
|
|
79
|
+
/** Relative path to an image file in your repo, e.g. `../../assets/hero.png`. */
|
|
80
|
+
file: image().optional(),
|
|
81
|
+
/** Raw HTML string instead of an image file. Useful for inline SVGs or more complex hero content. */
|
|
82
|
+
html: z.string().optional(),
|
|
83
|
+
})
|
|
84
|
+
.optional(),
|
|
85
|
+
/** An array of call-to-action links displayed at the bottom of the hero. */
|
|
86
|
+
actions: z
|
|
87
|
+
.object({
|
|
88
|
+
/** Text label displayed in the link. */
|
|
89
|
+
text: z.string(),
|
|
90
|
+
/** Value for the link’s `href` attribute, e.g. `/page` or `https://mysite.com`. */
|
|
91
|
+
link: z.string(),
|
|
92
|
+
/** Button style to use. One of `primary`, `secondary`, or `minimal` (the default). */
|
|
93
|
+
variant: z.enum(['primary', 'secondary', 'minimal']).default('minimal'),
|
|
94
|
+
/**
|
|
95
|
+
* An optional icon to display alongside the link text.
|
|
96
|
+
* Can be an inline `<svg>` or the name of one of Starlight’s built-in icons.
|
|
97
|
+
*/
|
|
98
|
+
icon: z
|
|
99
|
+
.union([z.enum(iconNames), z.string().startsWith('<svg')])
|
|
100
|
+
.transform((icon) => {
|
|
101
|
+
const parsedIcon = z.enum(iconNames).safeParse(icon);
|
|
102
|
+
return parsedIcon.success
|
|
103
|
+
? ({ type: 'icon', name: parsedIcon.data } as const)
|
|
104
|
+
: ({ type: 'raw', html: icon } as const);
|
|
105
|
+
})
|
|
106
|
+
.optional(),
|
|
107
|
+
})
|
|
108
|
+
.array()
|
|
109
|
+
.default([]),
|
|
110
|
+
})
|
|
111
|
+
.optional(),
|
|
123
112
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
113
|
+
/**
|
|
114
|
+
* The last update date of the current page.
|
|
115
|
+
* Overrides the `lastUpdated` global config or the date generated from the Git history.
|
|
116
|
+
*/
|
|
117
|
+
lastUpdated: z.union([z.date(), z.boolean()]).optional(),
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The previous navigation link configuration.
|
|
121
|
+
* Overrides the `pagination` global config or the link text and/or URL.
|
|
122
|
+
*/
|
|
123
|
+
prev: PrevNextLinkConfigSchema(),
|
|
124
|
+
/**
|
|
125
|
+
* The next navigation link configuration.
|
|
126
|
+
* Overrides the `pagination` global config or the link text and/or URL.
|
|
127
|
+
*/
|
|
128
|
+
next: PrevNextLinkConfigSchema(),
|
|
129
|
+
|
|
130
|
+
sidebar: z
|
|
131
|
+
.object({
|
|
132
|
+
/**
|
|
133
|
+
* The order of this page in the navigation.
|
|
134
|
+
* Pages are sorted by this value in ascending order. Then by slug.
|
|
135
|
+
* If not provided, pages will be sorted alphabetically by slug.
|
|
136
|
+
* If two pages have the same order value, they will be sorted alphabetically by slug.
|
|
137
|
+
*/
|
|
138
|
+
order: z.number().optional(),
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* The label for this page in the navigation.
|
|
142
|
+
* Defaults to the page `title` if not set.
|
|
143
|
+
*/
|
|
144
|
+
label: z.string().optional(),
|
|
145
|
+
})
|
|
146
|
+
.default({}),
|
|
147
|
+
});
|
|
135
148
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { extname } from 'node:path';
|
|
2
|
+
import { z } from 'astro/zod';
|
|
3
|
+
|
|
4
|
+
const faviconTypeMap = {
|
|
5
|
+
'.ico': 'image/x-icon',
|
|
6
|
+
'.gif': 'image/gif',
|
|
7
|
+
'.jpeg': 'image/jpeg',
|
|
8
|
+
'.jpg': 'image/jpeg',
|
|
9
|
+
'.png': 'image/png',
|
|
10
|
+
'.svg': 'image/svg+xml',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const FaviconSchema = () =>
|
|
14
|
+
z
|
|
15
|
+
.string()
|
|
16
|
+
.default('/favicon.svg')
|
|
17
|
+
.transform((favicon, ctx) => {
|
|
18
|
+
const ext = extname(favicon).toLowerCase();
|
|
19
|
+
|
|
20
|
+
if (!isFaviconExt(ext)) {
|
|
21
|
+
ctx.addIssue({
|
|
22
|
+
code: z.ZodIssueCode.custom,
|
|
23
|
+
message: 'favicon must be a .ico, .gif, .jpg, .png, or .svg file',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return z.NEVER;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
href: favicon,
|
|
31
|
+
type: faviconTypeMap[ext],
|
|
32
|
+
};
|
|
33
|
+
})
|
|
34
|
+
.describe(
|
|
35
|
+
'The default favicon for your site which should be a path to an image in the `public/` directory.'
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
function isFaviconExt(ext: string): ext is keyof typeof faviconTypeMap {
|
|
39
|
+
return ext in faviconTypeMap;
|
|
40
|
+
}
|
package/schemas/head.ts
CHANGED
|
@@ -1,29 +1,18 @@
|
|
|
1
1
|
import { z } from 'astro/zod';
|
|
2
2
|
|
|
3
3
|
export const HeadConfigSchema = () =>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
'template',
|
|
17
|
-
]),
|
|
18
|
-
/** Attributes to set on the tag, e.g. `{ rel: 'stylesheet', href: '/custom.css' }`. */
|
|
19
|
-
attrs: z
|
|
20
|
-
.record(z.union([z.string(), z.boolean(), z.undefined()]))
|
|
21
|
-
.default({}),
|
|
22
|
-
/** Content to place inside the tag (optional). */
|
|
23
|
-
content: z.string().default(''),
|
|
24
|
-
})
|
|
25
|
-
)
|
|
26
|
-
.default([]);
|
|
4
|
+
z
|
|
5
|
+
.array(
|
|
6
|
+
z.object({
|
|
7
|
+
/** Name of the HTML tag to add to `<head>`, e.g. `'meta'`, `'link'`, or `'script'`. */
|
|
8
|
+
tag: z.enum(['title', 'base', 'link', 'style', 'meta', 'script', 'noscript', 'template']),
|
|
9
|
+
/** Attributes to set on the tag, e.g. `{ rel: 'stylesheet', href: '/custom.css' }`. */
|
|
10
|
+
attrs: z.record(z.union([z.string(), z.boolean(), z.undefined()])).default({}),
|
|
11
|
+
/** Content to place inside the tag (optional). */
|
|
12
|
+
content: z.string().default(''),
|
|
13
|
+
})
|
|
14
|
+
)
|
|
15
|
+
.default([]);
|
|
27
16
|
|
|
28
17
|
export type HeadUserConfig = z.input<ReturnType<typeof HeadConfigSchema>>;
|
|
29
18
|
export type HeadConfig = z.output<ReturnType<typeof HeadConfigSchema>>;
|