@astrojs/starlight 0.7.3 → 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/CHANGELOG.md +21 -0
- package/README.md +9 -4
- package/components/Badge.astro +86 -0
- package/components/Banner.astro +23 -0
- package/components/CallToAction.astro +1 -1
- package/components/ContentPanel.astro +4 -4
- package/components/EditLink.astro +1 -1
- package/components/FallbackContentNotice.astro +1 -1
- package/components/Footer.astro +1 -1
- package/components/Header.astro +2 -2
- package/components/Hero.astro +4 -4
- package/components/Icons.ts +2 -0
- package/components/MobileMenuToggle.astro +1 -1
- package/components/PrevNextLinks.astro +1 -1
- package/components/RightSidebarPanel.astro +4 -4
- package/components/Search.astro +4 -4
- package/components/Sidebar.astro +2 -2
- package/components/SidebarSublist.astro +12 -1
- package/components/SiteTitle.astro +1 -1
- package/components/SocialIcons.astro +2 -2
- package/components/TableOfContents/MobileTableOfContents.astro +3 -3
- package/layout/Page.astro +2 -0
- package/layout/PageFrame.astro +1 -1
- package/layout/TwoColumnContent.astro +1 -1
- package/package.json +1 -1
- package/schema.ts +16 -0
- package/schemas/badge.ts +20 -0
- package/style/props.css +2 -0
- package/style/util.css +9 -9
- package/user-components/Card.astro +2 -2
- package/user-components/LinkCard.astro +1 -1
- package/utils/navigation.ts +16 -9
- package/utils/user-config.ts +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @astrojs/starlight
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#529](https://github.com/withastro/starlight/pull/529) [`c2d0e7f`](https://github.com/withastro/starlight/commit/c2d0e7f2699e60a48a3a9074eee6439dee8624a1) Thanks [@delucis](https://github.com/delucis)! - For improved compatibility with Tailwind, some Starlight built-in class names are now prefixed with `"sl-"`.
|
|
8
|
+
|
|
9
|
+
While not likely, if you were relying on one of these internal class names in your own components or custom CSS, you will need to update to use the prefixed version.
|
|
10
|
+
|
|
11
|
+
- **Before:** `flex`, `md:flex`, `lg:flex`, `block`, `md:block`, `lg:block`, `hidden`, `md:hidden`, `lg:hidden`.
|
|
12
|
+
- **After:** `sl-flex`, `md:sl-flex`, `lg:sl-flex`, `sl-block`, `md:sl-block`, `lg:sl-block`, `sl-hidden`, `md:sl-hidden`, `lg:sl-hidden`.
|
|
13
|
+
|
|
14
|
+
- [#593](https://github.com/withastro/starlight/pull/593) [`5b8af95`](https://github.com/withastro/starlight/commit/5b8af95049781954eabc3895027218b3de8ff054) Thanks [@delucis](https://github.com/delucis)! - Add announcement banner feature
|
|
15
|
+
|
|
16
|
+
- [#516](https://github.com/withastro/starlight/pull/516) [`70a32a1`](https://github.com/withastro/starlight/commit/70a32a1736c776febb34cf0ca3014f375ff9fec8) Thanks [@kevinzunigacuellar](https://github.com/kevinzunigacuellar)! - Support adding badges to sidebar links from config file and frontmatter
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- [#569](https://github.com/withastro/starlight/pull/569) [`a7691f8`](https://github.com/withastro/starlight/commit/a7691f82fdabb1c4e6b14bcfa8289aaceb929997) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Use locale when sorting autogenerated sidebar entries
|
|
21
|
+
|
|
22
|
+
- [#559](https://github.com/withastro/starlight/pull/559) [`5726353`](https://github.com/withastro/starlight/commit/5726353f1a4815df9ab5a7acd7aea6af53383adc) Thanks [@delucis](https://github.com/delucis)! - Add Stack Overflow icon
|
|
23
|
+
|
|
3
24
|
## 0.7.3
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
# <img src="https://github.com/withastro/starlight/assets/357379/494fcd83-42aa-4891-87e0-87402fa0b6f3" alt="" align="left" width="40" height="40"> Starlight
|
|
2
2
|
|
|
3
|
-
> **Warning**
|
|
4
|
-
> This tool is an early release and very much still work in progress!
|
|
5
|
-
> [Open an issue on GitHub](https://github.com/withastro/starlight/issues/new/choose) if you find something that’s not working.
|
|
6
|
-
|
|
7
3
|
Starlight is a documentation website framework for [Astro][astro].
|
|
8
4
|
|
|
9
5
|
## Documentation
|
|
10
6
|
|
|
11
7
|
[Read the Starlight docs][docs] (they’re built with Starlight!)
|
|
12
8
|
|
|
9
|
+
## Support
|
|
10
|
+
|
|
11
|
+
Get help in the [Astro Discord](discord). Post questions in our `#support` forum with the “starlight” tag, or visit our dedicated `#starlight` channel to discuss current development and more!
|
|
12
|
+
|
|
13
|
+
You can also submit bug reports and feature requests as [GitHub issues](issues).
|
|
14
|
+
|
|
13
15
|
## Contributing
|
|
14
16
|
|
|
15
17
|
Join us as a Starlight contributor! These links will help you get started:
|
|
@@ -17,6 +19,7 @@ Join us as a Starlight contributor! These links will help you get started:
|
|
|
17
19
|
- [Contributor Manual][contributing]
|
|
18
20
|
- [Code of Conduct][coc]
|
|
19
21
|
- [Community Guide][community]
|
|
22
|
+
- [Join the `#starlight` channel on Discord](discord)
|
|
20
23
|
|
|
21
24
|
## License
|
|
22
25
|
|
|
@@ -30,3 +33,5 @@ Copyright (c) 2023–present [Starlight contributors][contributors]
|
|
|
30
33
|
[coc]: https://github.com/withastro/.github/blob/main/CODE_OF_CONDUCT.md
|
|
31
34
|
[community]: https://github.com/withastro/.github/blob/main/COMMUNITY_GUIDE.md
|
|
32
35
|
[contributors]: https://github.com/withastro/starlight/graphs/contributors
|
|
36
|
+
[discord]: https://astro.build/chat/
|
|
37
|
+
[issues]: https://github.com/withastro/starlight/issues
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Badge } from '../schemas/badge';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
variant?: Badge['variant'] | 'outline';
|
|
6
|
+
text?: string;
|
|
7
|
+
}
|
|
8
|
+
const { variant = 'default', text } = Astro.props;
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<span class:list={['sl-badge', variant]} set:html={text} />
|
|
12
|
+
|
|
13
|
+
<style>
|
|
14
|
+
.sl-badge {
|
|
15
|
+
display: inline-block;
|
|
16
|
+
border: 1px solid var(--sl-color-border-badge);
|
|
17
|
+
border-radius: 0.25rem;
|
|
18
|
+
font-family: var(--sl-font-system-mono);
|
|
19
|
+
font-size: var(--sl-text-xs);
|
|
20
|
+
font-weight: 400;
|
|
21
|
+
padding: 0.125rem 0.375rem;
|
|
22
|
+
line-height: 1;
|
|
23
|
+
color: #fff;
|
|
24
|
+
background-color: var(--sl-color-bg-badge);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.outline {
|
|
28
|
+
--sl-color-bg-badge: transparent;
|
|
29
|
+
--sl-color-border-badge: currentColor;
|
|
30
|
+
color: inherit;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.default {
|
|
34
|
+
--sl-color-bg-badge: var(--sl-color-accent-low);
|
|
35
|
+
--sl-color-border-badge: var(--sl-color-accent);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.note {
|
|
39
|
+
--sl-color-bg-badge: var(--sl-color-blue-low);
|
|
40
|
+
--sl-color-border-badge: var(--sl-color-blue);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.danger {
|
|
44
|
+
--sl-color-bg-badge: var(--sl-color-red-low);
|
|
45
|
+
--sl-color-border-badge: var(--sl-color-red);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.success {
|
|
49
|
+
--sl-color-bg-badge: var(--sl-color-green-low);
|
|
50
|
+
--sl-color-border-badge: var(--sl-color-green);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.caution {
|
|
54
|
+
--sl-color-bg-badge: var(--sl-color-orange-low);
|
|
55
|
+
--sl-color-border-badge: var(--sl-color-orange);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.tip {
|
|
59
|
+
--sl-color-bg-badge: var(--sl-color-purple-low);
|
|
60
|
+
--sl-color-border-badge: var(--sl-color-purple);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
:global([data-theme='light']) .default {
|
|
64
|
+
--sl-color-bg-badge: var(--sl-color-accent-high);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
:global([data-theme='light']) .note {
|
|
68
|
+
--sl-color-bg-badge: var(--sl-color-blue-high);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
:global([data-theme='light']) .danger {
|
|
72
|
+
--sl-color-bg-badge: var(--sl-color-red-high);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
:global([data-theme='light']) .success {
|
|
76
|
+
--sl-color-bg-badge: var(--sl-color-green-high);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
:global([data-theme='light']) .caution {
|
|
80
|
+
--sl-color-bg-badge: var(--sl-color-orange-high);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
:global([data-theme='light']) .tip {
|
|
84
|
+
--sl-color-bg-badge: var(--sl-color-purple-high);
|
|
85
|
+
}
|
|
86
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props {
|
|
3
|
+
content: string;
|
|
4
|
+
}
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<div class="sl-banner" role="banner" set:html={Astro.props.content} />
|
|
8
|
+
|
|
9
|
+
<style>
|
|
10
|
+
.sl-banner {
|
|
11
|
+
--__sl-banner-text: var(--sl-color-banner-text, var(--sl-color-text-invert));
|
|
12
|
+
padding: var(--sl-nav-pad-y) var(--sl-nav-pad-x);
|
|
13
|
+
background-color: var(--sl-color-banner-bg, var(--sl-color-bg-accent));
|
|
14
|
+
color: var(--__sl-banner-text);
|
|
15
|
+
line-height: var(--sl-line-height-headings);
|
|
16
|
+
text-align: center;
|
|
17
|
+
text-wrap: balance;
|
|
18
|
+
box-shadow: var(--sl-shadow-sm);
|
|
19
|
+
}
|
|
20
|
+
.sl-banner :global(a) {
|
|
21
|
+
color: var(--__sl-banner-text);
|
|
22
|
+
}
|
|
23
|
+
</style>
|
|
@@ -11,7 +11,7 @@ interface Props {
|
|
|
11
11
|
const { link, variant, icon } = Astro.props;
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
<a class:list={['flex action', variant]} href={link}>
|
|
14
|
+
<a class:list={['sl-flex action', variant]} href={link}>
|
|
15
15
|
<slot />
|
|
16
16
|
{icon?.type === 'icon' && <Icon name={icon.name} size="1.5rem" />}
|
|
17
17
|
{icon?.type === 'raw' && <Fragment set:html={icon.html} />}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div class="content-panel">
|
|
2
|
-
<div class="container"><slot /></div>
|
|
2
|
+
<div class="sl-container"><slot /></div>
|
|
3
3
|
</div>
|
|
4
4
|
|
|
5
5
|
<style>
|
|
@@ -9,16 +9,16 @@
|
|
|
9
9
|
.content-panel + .content-panel {
|
|
10
10
|
border-top: 1px solid var(--sl-color-hairline);
|
|
11
11
|
}
|
|
12
|
-
.container {
|
|
12
|
+
.sl-container {
|
|
13
13
|
max-width: var(--sl-content-width);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
.container > :global(* + *) {
|
|
16
|
+
.sl-container > :global(* + *) {
|
|
17
17
|
margin-top: 1.5rem;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
@media (min-width: 72rem) {
|
|
21
|
-
.container {
|
|
21
|
+
.sl-container {
|
|
22
22
|
margin-inline: var(--sl-content-margin-inline, auto);
|
|
23
23
|
}
|
|
24
24
|
}
|
package/components/Footer.astro
CHANGED
|
@@ -21,7 +21,7 @@ const prevNextLinks = getPrevNextLinks(sidebar, config.pagination, {
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
23
|
<footer>
|
|
24
|
-
<div class="meta flex">
|
|
24
|
+
<div class="meta sl-flex">
|
|
25
25
|
{config.editLink.baseUrl && <EditLink data={entry.data} id={entry.id} {locale} />}
|
|
26
26
|
{
|
|
27
27
|
(entry.data.lastUpdated ?? config.lastUpdated) && (
|
package/components/Header.astro
CHANGED
|
@@ -12,10 +12,10 @@ interface Props {
|
|
|
12
12
|
const { locale } = Astro.props;
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
<div class="header flex">
|
|
15
|
+
<div class="header sl-flex">
|
|
16
16
|
<SiteTitle {locale} />
|
|
17
17
|
<Search {locale} />
|
|
18
|
-
<div class="hidden md:flex right-group">
|
|
18
|
+
<div class="sl-hidden md:sl-flex right-group">
|
|
19
19
|
<SocialIcons />
|
|
20
20
|
<ThemeSelect {locale} />
|
|
21
21
|
<LanguageSelect {locale} />
|
package/components/Hero.astro
CHANGED
|
@@ -28,17 +28,17 @@ const imageAttrs = {
|
|
|
28
28
|
<Image src={image.file} {...imageAttrs} />
|
|
29
29
|
)
|
|
30
30
|
) : (
|
|
31
|
-
image?.html && <div class="hero-html flex" set:html={image.html} />
|
|
31
|
+
image?.html && <div class="hero-html sl-flex" set:html={image.html} />
|
|
32
32
|
)
|
|
33
33
|
}
|
|
34
|
-
<div class="flex stack">
|
|
35
|
-
<div class="flex copy">
|
|
34
|
+
<div class="sl-flex stack">
|
|
35
|
+
<div class="sl-flex copy">
|
|
36
36
|
<h1 id="_top" data-page-title set:html={title} />
|
|
37
37
|
{tagline && <div class="tagline" set:html={tagline} />}
|
|
38
38
|
</div>
|
|
39
39
|
{
|
|
40
40
|
actions.length > 0 && (
|
|
41
|
-
<div class="flex actions">
|
|
41
|
+
<div class="sl-flex actions">
|
|
42
42
|
{actions.map(({ text, ...attrs }) => (
|
|
43
43
|
<CallToAction {...attrs} set:html={text} />
|
|
44
44
|
))}
|
package/components/Icons.ts
CHANGED
|
@@ -84,4 +84,6 @@ export const Icons = {
|
|
|
84
84
|
'<path d="M13.78 7.2a3.63 3.63 0 1 0-4.3-3.68h1.78a2.52 2.52 0 0 1 2.52 2.53V7.2zM7.34 18.8h3.92a2.52 2.52 0 0 0 2.52-2.52V8.37h4.17c.58.01 1.04.5 1.03 1.07v6.45a6.3 6.3 0 0 1-6.14 6.43 6.3 6.3 0 0 1-5.5-3.52zm16.1-14.06a2.51 2.51 0 1 1-5.02 0 2.51 2.51 0 0 1 5.02 0zm-3.36 14.24h-.17c.4-1 .59-2.05.57-3.11V9.46c0-.38-.07-.75-.23-1.09h2.69c.58 0 1.06.48 1.06 1.06v5.65a3.9 3.9 0 0 1-3.9 3.9h-.02z"/><path d="M1.02 5.02h10.24c.56 0 1.02.46 1.02 1.03v10.23a1.02 1.02 0 0 1-1.02 1.02H1.02A1.02 1.02 0 0 1 0 16.28V6.04c0-.56.46-1.02 1.02-1.02zm7.81 3.9V7.84H3.45v1.08h2.03v5.57h1.3V8.92h2.05z"/>',
|
|
85
85
|
instagram:
|
|
86
86
|
'<path d="M17.3 5.5a1.2 1.2 0 1 0 1.2 1.2 1.2 1.2 0 0 0-1.2-1.2ZM22 7.9a7.6 7.6 0 0 0-.4-2.5 5 5 0 0 0-1.2-1.7 4.7 4.7 0 0 0-1.8-1.2 7.3 7.3 0 0 0-2.4-.4L12 2H7.9a7.3 7.3 0 0 0-2.5.5 4.8 4.8 0 0 0-1.7 1.2 4.7 4.7 0 0 0-1.2 1.8 7.3 7.3 0 0 0-.4 2.4L2 12v4.1a7.3 7.3 0 0 0 .5 2.4 4.7 4.7 0 0 0 1.2 1.8 4.8 4.8 0 0 0 1.8 1.2 7.3 7.3 0 0 0 2.4.4l4.1.1h4.1a7.3 7.3 0 0 0 2.4-.5 4.7 4.7 0 0 0 1.8-1.2 4.8 4.8 0 0 0 1.2-1.7 7.6 7.6 0 0 0 .4-2.5L22 12V7.9ZM20.1 16a5.6 5.6 0 0 1-.3 1.9A3 3 0 0 1 19 19a3.2 3.2 0 0 1-1.1.8 5.6 5.6 0 0 1-1.9.3H8a5.7 5.7 0 0 1-1.9-.3A3.3 3.3 0 0 1 5 19a3 3 0 0 1-.7-1.1 5.5 5.5 0 0 1-.4-1.9l-.1-4V8a5.5 5.5 0 0 1 .4-1.9A3 3 0 0 1 5 5a3.1 3.1 0 0 1 1.1-.8A5.7 5.7 0 0 1 8 3.9l4-.1h4a5.6 5.6 0 0 1 1.9.4A3 3 0 0 1 19 5a3 3 0 0 1 .7 1.1A5.6 5.6 0 0 1 20 8l.1 4v4ZM12 6.9a5.1 5.1 0 1 0 5.1 5.1A5.1 5.1 0 0 0 12 6.9Zm0 8.4a3.3 3.3 0 1 1 3.3-3.3 3.3 3.3 0 0 1-3.3 3.3Z"/>',
|
|
87
|
+
stackOverflow:
|
|
88
|
+
'<path d="M15.72 0 14 1.28l6.4 8.58 1.7-1.26L15.73 0zm-3.94 3.42-1.36 1.64 8.22 6.85 1.37-1.64-8.23-6.85zM8.64 7.88l-.91 1.94 9.7 4.52.9-1.94-9.7-4.52zm-1.86 4.86-.44 2.1 10.48 2.2.44-2.1-10.47-2.2zM1.9 15.47V24h19.19v-8.53h-2.13v6.4H4.02v-6.4H1.9zm4.26 2.13v2.13h10.66V17.6H6.15Z"/>',
|
|
87
89
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
<div class="right-sidebar-panel hidden lg:block">
|
|
2
|
-
<div class="container">
|
|
1
|
+
<div class="right-sidebar-panel sl-hidden lg:sl-block">
|
|
2
|
+
<div class="sl-container">
|
|
3
3
|
<slot />
|
|
4
4
|
</div>
|
|
5
5
|
</div>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
.right-sidebar-panel + .right-sidebar-panel {
|
|
12
12
|
border-top: 1px solid var(--sl-color-hairline);
|
|
13
13
|
}
|
|
14
|
-
.container {
|
|
14
|
+
.sl-container {
|
|
15
15
|
width: calc(var(--sl-sidebar-width) - 2 * var(--sl-sidebar-pad-x));
|
|
16
16
|
}
|
|
17
17
|
.right-sidebar-panel :global(h2) {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
color: var(--sl-color-white);
|
|
33
33
|
}
|
|
34
34
|
@media (min-width: 72rem) {
|
|
35
|
-
.container {
|
|
35
|
+
.sl-container {
|
|
36
36
|
max-width: calc(
|
|
37
37
|
(
|
|
38
38
|
(
|
package/components/Search.astro
CHANGED
|
@@ -22,16 +22,16 @@ const pagefindTranslations = {
|
|
|
22
22
|
/* The span is `aria-hidden` because it is not shown on small screens. Instead, the icon label is used for accessibility purposes. */
|
|
23
23
|
}
|
|
24
24
|
<Icon name="magnifier" label={t('search.label')} />
|
|
25
|
-
<span class="hidden md:block" aria-hidden="true">{t('search.label')}</span>
|
|
26
|
-
<Icon name="forward-slash" class="hidden md:block" label={t('search.shortcutLabel')} />
|
|
25
|
+
<span class="sl-hidden md:sl-block" aria-hidden="true">{t('search.label')}</span>
|
|
26
|
+
<Icon name="forward-slash" class="sl-hidden md:sl-block" label={t('search.shortcutLabel')} />
|
|
27
27
|
</button>
|
|
28
28
|
|
|
29
29
|
<dialog style="padding:0" aria-label={t('search.label')}>
|
|
30
|
-
<div class="dialog-frame flex">
|
|
30
|
+
<div class="dialog-frame sl-flex">
|
|
31
31
|
{
|
|
32
32
|
/* TODO: Make the layout of this button flexible to accommodate different word lengths. Currently hard-coded for English: “Cancel” */
|
|
33
33
|
}
|
|
34
|
-
<button data-close-modal class="flex md:hidden">
|
|
34
|
+
<button data-close-modal class="sl-flex md:sl-hidden">
|
|
35
35
|
{t('search.cancelLabel')}
|
|
36
36
|
</button>
|
|
37
37
|
{
|
package/components/Sidebar.astro
CHANGED
|
@@ -12,9 +12,9 @@ interface Props {
|
|
|
12
12
|
const { sidebar, locale } = Astro.props;
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
<div class="sidebar flex">
|
|
15
|
+
<div class="sidebar sl-flex">
|
|
16
16
|
<SidebarSublist sublist={sidebar} />
|
|
17
|
-
<div class="mobile-preferences flex md:hidden">
|
|
17
|
+
<div class="mobile-preferences sl-flex md:sl-hidden">
|
|
18
18
|
<ThemeSelect {locale} />
|
|
19
19
|
<LanguageSelect {locale} />
|
|
20
20
|
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { flattenSidebar, type SidebarEntry } from '../utils/navigation';
|
|
3
3
|
import Icon from '../user-components/Icon.astro';
|
|
4
|
+
import Badge from './Badge.astro';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
7
|
sublist: SidebarEntry[];
|
|
@@ -18,7 +19,13 @@ interface Props {
|
|
|
18
19
|
aria-current={entry.isCurrent && 'page'}
|
|
19
20
|
class:list={{ large: !Astro.props.nested }}
|
|
20
21
|
>
|
|
21
|
-
{entry.label}
|
|
22
|
+
<span>{entry.label}</span>
|
|
23
|
+
{entry.badge && (
|
|
24
|
+
<Badge
|
|
25
|
+
text={entry.badge.text}
|
|
26
|
+
variant={entry.isCurrent ? 'outline' : entry.badge.variant}
|
|
27
|
+
/>
|
|
28
|
+
)}
|
|
22
29
|
</a>
|
|
23
30
|
) : (
|
|
24
31
|
<details
|
|
@@ -104,6 +111,10 @@ interface Props {
|
|
|
104
111
|
background-color: var(--sl-color-text-accent);
|
|
105
112
|
}
|
|
106
113
|
|
|
114
|
+
a > *:not(:last-child) {
|
|
115
|
+
margin-inline-end: 0.25em;
|
|
116
|
+
}
|
|
117
|
+
|
|
107
118
|
@media (min-width: 50rem) {
|
|
108
119
|
.top-level > li + li {
|
|
109
120
|
margin-top: 0.5rem;
|
|
@@ -20,6 +20,7 @@ const labels: Record<Platform, string> = {
|
|
|
20
20
|
twitch: 'Twitch',
|
|
21
21
|
microsoftTeams: 'Microsoft Teams',
|
|
22
22
|
instagram: 'Instagram',
|
|
23
|
+
stackOverflow: 'Stack Overflow',
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
const links = Object.entries(config.social || {}).filter(([, url]) => Boolean(url)) as [
|
|
@@ -32,7 +33,7 @@ const links = Object.entries(config.social || {}).filter(([, url]) => Boolean(ur
|
|
|
32
33
|
links.length > 0 && (
|
|
33
34
|
<>
|
|
34
35
|
{links.map(([platform, url]) => (
|
|
35
|
-
<a href={url} rel="me">
|
|
36
|
+
<a href={url} rel="me" class="sl-flex">
|
|
36
37
|
<span class="sr-only">{labels[platform]}</span>
|
|
37
38
|
<Icon name={platform} />
|
|
38
39
|
</a>
|
|
@@ -44,7 +45,6 @@ const links = Object.entries(config.social || {}).filter(([, url]) => Boolean(ur
|
|
|
44
45
|
|
|
45
46
|
<style>
|
|
46
47
|
a {
|
|
47
|
-
display: flex;
|
|
48
48
|
color: var(--sl-color-text-accent);
|
|
49
49
|
}
|
|
50
50
|
a:hover {
|
|
@@ -16,10 +16,10 @@ const t = useTranslations(locale);
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
18
|
<mobile-starlight-toc data-min-h={minHeadingLevel} data-max-h={maxHeadingLevel}>
|
|
19
|
-
<nav aria-labelledby="starlight__on-this-page--mobile" class="lg:hidden">
|
|
19
|
+
<nav aria-labelledby="starlight__on-this-page--mobile" class="lg:sl-hidden">
|
|
20
20
|
<details id="starlight__mobile-toc">
|
|
21
|
-
<summary id="starlight__on-this-page--mobile" class="flex">
|
|
22
|
-
<div class="toggle flex">
|
|
21
|
+
<summary id="starlight__on-this-page--mobile" class="sl-flex">
|
|
22
|
+
<div class="toggle sl-flex">
|
|
23
23
|
{t('tableOfContents.onThisPage')}
|
|
24
24
|
<Icon name={'right-caret'} class="caret" size="1rem" />
|
|
25
25
|
</div>
|
package/layout/Page.astro
CHANGED
|
@@ -24,6 +24,7 @@ import SkipLink from '../components/SkipLink.astro';
|
|
|
24
24
|
import ThemeProvider from '../components/ThemeProvider.astro';
|
|
25
25
|
import PageFrame from '../layout/PageFrame.astro';
|
|
26
26
|
import TwoColumnContent from '../layout/TwoColumnContent.astro';
|
|
27
|
+
import Banner from '../components/Banner.astro';
|
|
27
28
|
|
|
28
29
|
// Remark component CSS (needs to override `MarkdownContent.astro`)
|
|
29
30
|
import '../style/asides.css';
|
|
@@ -92,6 +93,7 @@ const hasHero = Boolean(entry.data.hero);
|
|
|
92
93
|
<RightSidebar slot="right-sidebar" {headings} {locale} {tocConfig} />
|
|
93
94
|
<main data-pagefind-body={entry.slug !== '404'} lang={entryMeta.lang} dir={entryMeta.dir}>
|
|
94
95
|
{/* TODO: Revisit how this logic flows. */}
|
|
96
|
+
{entry.data.banner && <Banner {...entry.data.banner} />}
|
|
95
97
|
{
|
|
96
98
|
entry.data.hero ? (
|
|
97
99
|
<ContentPanel>
|
package/layout/PageFrame.astro
CHANGED
package/package.json
CHANGED
package/schema.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { HeadConfigSchema } from './schemas/head';
|
|
|
3
3
|
import { PrevNextLinkConfigSchema } from './schemas/prevNextLink';
|
|
4
4
|
import { TableOfContentsSchema } from './schemas/tableOfContents';
|
|
5
5
|
import { Icons } from './components/Icons';
|
|
6
|
+
import { BadgeConfigSchema } from './schemas/badge';
|
|
6
7
|
export { i18nSchema } from './schemas/i18n';
|
|
7
8
|
|
|
8
9
|
type IconName = keyof typeof Icons;
|
|
@@ -147,7 +148,22 @@ export function docsSchema() {
|
|
|
147
148
|
* Prevents this page from being included in autogenerated sidebar groups.
|
|
148
149
|
*/
|
|
149
150
|
hidden: z.boolean().default(false),
|
|
151
|
+
/**
|
|
152
|
+
* Adds a badge to the sidebar link.
|
|
153
|
+
* Can be a string or an object with a variant and text.
|
|
154
|
+
* Variants include 'note', 'tip', 'caution', 'danger', 'success', and 'default'.
|
|
155
|
+
* Passing only a string defaults to the 'default' variant which uses the site accent color.
|
|
156
|
+
*/
|
|
157
|
+
badge: BadgeConfigSchema(),
|
|
150
158
|
})
|
|
151
159
|
.default({}),
|
|
160
|
+
|
|
161
|
+
/** Display an announcement banner at the top of this page. */
|
|
162
|
+
banner: z
|
|
163
|
+
.object({
|
|
164
|
+
/** The content of the banner. Supports HTML syntax. */
|
|
165
|
+
content: z.string(),
|
|
166
|
+
})
|
|
167
|
+
.optional(),
|
|
152
168
|
});
|
|
153
169
|
}
|
package/schemas/badge.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'astro/zod';
|
|
2
|
+
|
|
3
|
+
const badgeSchema = () =>
|
|
4
|
+
z.object({
|
|
5
|
+
variant: z.enum(['note', 'danger', 'success', 'caution', 'tip', 'default']).default('default'),
|
|
6
|
+
text: z.string(),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export const BadgeConfigSchema = () =>
|
|
10
|
+
z
|
|
11
|
+
.union([z.string(), badgeSchema()])
|
|
12
|
+
.transform((badge) => {
|
|
13
|
+
if (typeof badge === 'string') {
|
|
14
|
+
return { variant: 'default' as const, text: badge };
|
|
15
|
+
}
|
|
16
|
+
return badge;
|
|
17
|
+
})
|
|
18
|
+
.optional();
|
|
19
|
+
|
|
20
|
+
export type Badge = z.output<ReturnType<typeof badgeSchema>>;
|
package/style/props.css
CHANGED
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
--sl-color-bg-nav: var(--sl-color-gray-6);
|
|
43
43
|
--sl-color-bg-sidebar: var(--sl-color-gray-6);
|
|
44
44
|
--sl-color-bg-inline-code: var(--sl-color-gray-5);
|
|
45
|
+
--sl-color-bg-accent: var(--sl-color-accent-high);
|
|
45
46
|
--sl-color-hairline-light: var(--sl-color-gray-5);
|
|
46
47
|
--sl-color-hairline: var(--sl-color-gray-6);
|
|
47
48
|
--sl-color-hairline-shade: var(--sl-color-black);
|
|
@@ -148,6 +149,7 @@
|
|
|
148
149
|
--sl-color-bg-nav: var(--sl-color-gray-7);
|
|
149
150
|
--sl-color-bg-sidebar: var(--sl-color-bg);
|
|
150
151
|
--sl-color-bg-inline-code: var(--sl-color-gray-6);
|
|
152
|
+
--sl-color-bg-accent: var(--sl-color-accent);
|
|
151
153
|
--sl-color-hairline-light: var(--sl-color-gray-6);
|
|
152
154
|
--sl-color-hairline-shade: var(--sl-color-gray-6);
|
|
153
155
|
|
package/style/util.css
CHANGED
|
@@ -10,34 +10,34 @@
|
|
|
10
10
|
border-width: 0;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
.hidden {
|
|
13
|
+
.sl-hidden {
|
|
14
14
|
display: none;
|
|
15
15
|
}
|
|
16
|
-
.flex {
|
|
16
|
+
.sl-flex {
|
|
17
17
|
display: flex;
|
|
18
18
|
}
|
|
19
|
-
.block {
|
|
19
|
+
.sl-block {
|
|
20
20
|
display: block;
|
|
21
21
|
}
|
|
22
22
|
@media (min-width: 50rem) {
|
|
23
|
-
.md\:hidden {
|
|
23
|
+
.md\:sl-hidden {
|
|
24
24
|
display: none;
|
|
25
25
|
}
|
|
26
|
-
.md\:flex {
|
|
26
|
+
.md\:sl-flex {
|
|
27
27
|
display: flex;
|
|
28
28
|
}
|
|
29
|
-
.md\:block {
|
|
29
|
+
.md\:sl-block {
|
|
30
30
|
display: block;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
@media (min-width: 72rem) {
|
|
34
|
-
.lg\:hidden {
|
|
34
|
+
.lg\:sl-hidden {
|
|
35
35
|
display: none;
|
|
36
36
|
}
|
|
37
|
-
.lg\:flex {
|
|
37
|
+
.lg\:sl-flex {
|
|
38
38
|
display: flex;
|
|
39
39
|
}
|
|
40
|
-
.lg\:block {
|
|
40
|
+
.lg\:sl-block {
|
|
41
41
|
display: block;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -10,8 +10,8 @@ interface Props {
|
|
|
10
10
|
const { icon, title } = Astro.props;
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
<article class="card flex">
|
|
14
|
-
<p class="title flex">
|
|
13
|
+
<article class="card sl-flex">
|
|
14
|
+
<p class="title sl-flex">
|
|
15
15
|
{icon && <Icon name={icon} class="icon" size="1.333em" />}
|
|
16
16
|
<span set:html={title} />
|
|
17
17
|
</p>
|
package/utils/navigation.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { getLocaleRoutes, type Route } from './routing';
|
|
|
7
7
|
import { localeToLang, slugToPathname } from './slugs';
|
|
8
8
|
import type { AutoSidebarGroup, SidebarItem, SidebarLinkItem } from './user-config';
|
|
9
9
|
import { ensureLeadingAndTrailingSlashes, ensureTrailingSlash } from './path';
|
|
10
|
+
import type { Badge } from '../schemas/badge';
|
|
10
11
|
|
|
11
12
|
const DirKey = Symbol('DirKey');
|
|
12
13
|
|
|
@@ -15,6 +16,7 @@ export interface Link {
|
|
|
15
16
|
label: string;
|
|
16
17
|
href: string;
|
|
17
18
|
isCurrent: boolean;
|
|
19
|
+
badge: Badge | undefined;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
interface Group {
|
|
@@ -112,14 +114,14 @@ function linkFromConfig(
|
|
|
112
114
|
if (locale) href = '/' + locale + href;
|
|
113
115
|
}
|
|
114
116
|
const label = pickLang(item.translations, localeToLang(locale)) || item.label;
|
|
115
|
-
return makeLink(href, label, currentPathname);
|
|
117
|
+
return makeLink(href, label, currentPathname, item.badge);
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
/** Create a link entry. */
|
|
119
|
-
function makeLink(href: string, label: string, currentPathname: string): Link {
|
|
121
|
+
function makeLink(href: string, label: string, currentPathname: string, badge?: Badge): Link {
|
|
120
122
|
if (!isAbsolute(href)) href = pathWithBase(href);
|
|
121
123
|
const isCurrent = href === ensureTrailingSlash(currentPathname);
|
|
122
|
-
return { type: 'link', label, href, isCurrent };
|
|
124
|
+
return { type: 'link', label, href, isCurrent, badge };
|
|
123
125
|
}
|
|
124
126
|
|
|
125
127
|
/** Get the segments leading to a page. */
|
|
@@ -168,7 +170,8 @@ function linkFromRoute(route: Route, currentPathname: string): Link {
|
|
|
168
170
|
return makeLink(
|
|
169
171
|
slugToPathname(route.slug),
|
|
170
172
|
route.entry.data.sidebar.label || route.entry.data.title,
|
|
171
|
-
currentPathname
|
|
173
|
+
currentPathname,
|
|
174
|
+
route.entry.data.sidebar.badge
|
|
172
175
|
);
|
|
173
176
|
}
|
|
174
177
|
|
|
@@ -184,13 +187,17 @@ function getOrder(routeOrDir: Route | Dir): number {
|
|
|
184
187
|
}
|
|
185
188
|
|
|
186
189
|
/** Sort a directory’s entries by user-specified order or alphabetically if no order specified. */
|
|
187
|
-
function sortDirEntries(
|
|
188
|
-
|
|
190
|
+
function sortDirEntries(
|
|
191
|
+
dir: [string, Dir | Route][],
|
|
192
|
+
locale: string | undefined
|
|
193
|
+
): [string, Dir | Route][] {
|
|
194
|
+
const collator = new Intl.Collator(localeToLang(locale));
|
|
195
|
+
return dir.sort(([keyA, a], [keyB, b]) => {
|
|
189
196
|
const [aOrder, bOrder] = [getOrder(a), getOrder(b)];
|
|
190
197
|
// Pages are sorted by order in ascending order.
|
|
191
198
|
if (aOrder !== bOrder) return aOrder < bOrder ? -1 : 1;
|
|
192
199
|
// If two pages have the same order value they will be sorted by their slug.
|
|
193
|
-
return a
|
|
200
|
+
return collator.compare(isDir(a) ? keyA : a.slug, isDir(b) ? keyB : b.slug);
|
|
194
201
|
});
|
|
195
202
|
}
|
|
196
203
|
|
|
@@ -203,7 +210,7 @@ function groupFromDir(
|
|
|
203
210
|
locale: string | undefined,
|
|
204
211
|
collapsed: boolean
|
|
205
212
|
): Group {
|
|
206
|
-
const entries = sortDirEntries(Object.entries(dir)).map(([key, dirOrRoute]) =>
|
|
213
|
+
const entries = sortDirEntries(Object.entries(dir), locale).map(([key, dirOrRoute]) =>
|
|
207
214
|
dirToItem(dirOrRoute, `${fullPath}/${key}`, key, currentPathname, locale, collapsed)
|
|
208
215
|
);
|
|
209
216
|
return {
|
|
@@ -235,7 +242,7 @@ function sidebarFromDir(
|
|
|
235
242
|
locale: string | undefined,
|
|
236
243
|
collapsed: boolean
|
|
237
244
|
) {
|
|
238
|
-
return sortDirEntries(Object.entries(tree)).map(([key, dirOrRoute]) =>
|
|
245
|
+
return sortDirEntries(Object.entries(tree), locale).map(([key, dirOrRoute]) =>
|
|
239
246
|
dirToItem(dirOrRoute, key, key, currentPathname, locale, collapsed)
|
|
240
247
|
);
|
|
241
248
|
}
|
package/utils/user-config.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { HeadConfigSchema } from '../schemas/head';
|
|
|
4
4
|
import { LogoConfigSchema } from '../schemas/logo';
|
|
5
5
|
import { TableOfContentsSchema } from '../schemas/tableOfContents';
|
|
6
6
|
import { FaviconSchema } from '../schemas/favicon';
|
|
7
|
+
import { BadgeConfigSchema } from '../schemas/badge';
|
|
7
8
|
|
|
8
9
|
const LocaleSchema = z.object({
|
|
9
10
|
/** The label for this language to show in UI, e.g. `"English"`, `"العربية"`, or `"简体中文"`. */
|
|
@@ -42,6 +43,8 @@ const SidebarGroupSchema = SidebarBaseSchema.extend({
|
|
|
42
43
|
const SidebarLinkItemSchema = SidebarBaseSchema.extend({
|
|
43
44
|
/** The link to this item’s content. Can be a relative link to local files or the full URL of an external page. */
|
|
44
45
|
link: z.string(),
|
|
46
|
+
/** Adds a badge to the link item */
|
|
47
|
+
badge: BadgeConfigSchema(),
|
|
45
48
|
});
|
|
46
49
|
export type SidebarLinkItem = z.infer<typeof SidebarLinkItemSchema>;
|
|
47
50
|
|
|
@@ -148,6 +151,7 @@ const UserConfigSchema = z.object({
|
|
|
148
151
|
'twitch',
|
|
149
152
|
'microsoftTeams',
|
|
150
153
|
'instagram',
|
|
154
|
+
'stackOverflow',
|
|
151
155
|
]),
|
|
152
156
|
// Link to the respective social profile for this site
|
|
153
157
|
z.string().url()
|