summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin2024-06-05 13:11:15 -0400
committerGitHub2024-06-05 19:11:15 +0200
commitdd64836af45f33df4a99ab864eabb91fc9b8e204 (patch)
tree73e3e6ee7204577fb57773a7891d77a1bde4486c
parent15747325112c9fe43b8dfa4e986b95cf8e66af49 (diff)
downloadIT.starlight-dd64836af45f33df4a99ab864eabb91fc9b8e204.tar.gz
IT.starlight-dd64836af45f33df4a99ab864eabb91fc9b8e204.tar.bz2
IT.starlight-dd64836af45f33df4a99ab864eabb91fc9b8e204.zip
Add `<Badge>` component (#1530)
Co-authored-by: HiDeoo <494699+HiDeoo@users.noreply.github.com> Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> Co-authored-by: Chris Swithinbank <swithinbank@gmail.com> Co-authored-by: trueberryless <99918022+trueberryless@users.noreply.github.com> Co-authored-by: Martin Trapp <94928215+martrapp@users.noreply.github.com>
-rw-r--r--.changeset/wicked-melons-study.md6
-rw-r--r--docs/src/content/docs/guides/components.mdx30
-rw-r--r--docs/src/content/docs/guides/sidebar.mdx8
-rw-r--r--docs/src/content/docs/reference/configuration.mdx3
-rw-r--r--docs/src/content/docs/reference/frontmatter.md2
-rw-r--r--packages/starlight/components.ts1
-rw-r--r--packages/starlight/components/Badge.astro87
-rw-r--r--packages/starlight/components/SidebarSublist.astro23
-rw-r--r--packages/starlight/schemas/badge.ts9
-rw-r--r--packages/starlight/user-components/Badge.astro141
10 files changed, 206 insertions, 104 deletions
diff --git a/.changeset/wicked-melons-study.md b/.changeset/wicked-melons-study.md
new file mode 100644
index 00000000..9de08e60
--- /dev/null
+++ b/.changeset/wicked-melons-study.md
@@ -0,0 +1,6 @@
+---
+'@astrojs/starlight': minor
+---
+
+Adds a new `<Badge>` component
+
diff --git a/docs/src/content/docs/guides/components.mdx b/docs/src/content/docs/guides/components.mdx
index 30178aec..95a5e30f 100644
--- a/docs/src/content/docs/guides/components.mdx
+++ b/docs/src/content/docs/guides/components.mdx
@@ -412,6 +412,36 @@ import { Steps } from '@astrojs/starlight/components';
</Steps>
+### Badges
+
+import { Badge } from '@astrojs/starlight/components';
+
+Use the `<Badge>` component to display small pieces of information, such as status or labels.
+
+Pass the content you want to display to the `text` attribute of the `<Badge>` component.
+
+By default, the badge will use the theme accent color of your site. To use a built-in badge color, set the `variant` attribute to one of the following values: `note` (blue), `tip` (purple), `danger` (red), `caution` (orange), or `success` (green).
+
+The `size` attribute (default: `small`) controls the size of the badge text. `medium` and `large` are also available options for displaying a larger badge.
+
+For further customization, use other `<span>` attributes such as `class` or `style` with custom CSS.
+
+```mdx title="src/content/docs/example.mdx"
+import { Badge } from '@astrojs/starlight/components';
+
+<Badge text="New" variant="tip" size="small" />
+<Badge text="Deprecated" variant="caution" size="medium" />
+<Badge text="Starlight" variant="note" size="large" />
+<Badge text="Custom" variant="success" style={{ fontStyle: 'italic' }} />
+```
+
+The code above generates the following on the page:
+
+<Badge text="New" variant="tip" size="small" />
+<Badge text="Deprecated" variant="caution" size="medium" />
+<Badge text="Starlight" variant="note" size="large" />
+<Badge text="Custom" variant="success" style={{ fontStyle: 'italic' }} />
+
### Icon
import { Icon } from '@astrojs/starlight/components';
diff --git a/docs/src/content/docs/guides/sidebar.mdx b/docs/src/content/docs/guides/sidebar.mdx
index bf9d3605..0632b537 100644
--- a/docs/src/content/docs/guides/sidebar.mdx
+++ b/docs/src/content/docs/guides/sidebar.mdx
@@ -294,12 +294,14 @@ The configuration above generates the following sidebar:
]}
/>
-### Badge variants
+### Badge variants and custom styling
-Customize the badge styling using an object with `text` and `variant` properties.
+Customize the badge styling using an object with `text`, `variant`, and `class` properties.
The `text` represents the content to display (e.g. "New").
-Override the `default` styling, which uses the accent color of your site, by setting the `variant` property to one of the following values: `note`, `tip`, `danger`, `caution` or `success`.
+By default, the badge will use the accent color of your site. To use a built-in badge style, set the `variant` property to one of the following values: `note`, `tip`, `danger`, `caution` or `success`.
+
+Optionally, you can create a custom badge style by setting the `class` property to a CSS class name.
```js {10}
starlight({
diff --git a/docs/src/content/docs/reference/configuration.mdx b/docs/src/content/docs/reference/configuration.mdx
index a940a844..59816e1a 100644
--- a/docs/src/content/docs/reference/configuration.mdx
+++ b/docs/src/content/docs/reference/configuration.mdx
@@ -214,7 +214,8 @@ type SidebarItem = {
```ts
interface BadgeConfig {
text: string;
- variant: 'note' | 'tip' | 'caution' | 'danger' | 'success' | 'default';
+ variant?: 'note' | 'tip' | 'caution' | 'danger' | 'success' | 'default';
+ class?: string;
}
```
diff --git a/docs/src/content/docs/reference/frontmatter.md b/docs/src/content/docs/reference/frontmatter.md
index 32ae46ca..41fc4a5b 100644
--- a/docs/src/content/docs/reference/frontmatter.md
+++ b/docs/src/content/docs/reference/frontmatter.md
@@ -355,7 +355,7 @@ sidebar:
Add a badge to the page in the sidebar when displayed in an autogenerated group of links.
When using a string, the badge will be displayed with a default accent color.
-Optionally, pass a [`BadgeConfig` object](/reference/configuration/#badgeconfig) with `text` and `variant` fields to customize the badge.
+Optionally, pass a [`BadgeConfig` object](/reference/configuration/#badgeconfig) with `text`, `variant`, and `class` fields to customize the badge.
```md
---
diff --git a/packages/starlight/components.ts b/packages/starlight/components.ts
index e564b62b..2935e9ff 100644
--- a/packages/starlight/components.ts
+++ b/packages/starlight/components.ts
@@ -1,4 +1,5 @@
export { default as Aside } from './user-components/Aside.astro';
+export { default as Badge } from './user-components/Badge.astro';
export { default as Card } from './user-components/Card.astro';
export { default as CardGrid } from './user-components/CardGrid.astro';
export { default as Icon } from './user-components/Icon.astro';
diff --git a/packages/starlight/components/Badge.astro b/packages/starlight/components/Badge.astro
deleted file mode 100644
index 7e8c0da2..00000000
--- a/packages/starlight/components/Badge.astro
+++ /dev/null
@@ -1,87 +0,0 @@
----
-import type { Badge } from '../schemas/badge';
-
-interface Props {
- variant?: Badge['variant'] | 'outline';
- text?: string;
-}
-const { variant = 'default', text } = Astro.props;
----
-
-<span class:list={['sl-badge', variant]} set:html={text} />
-
-<style>
- .sl-badge {
- display: inline-block;
- border: 1px solid var(--sl-color-border-badge);
- border-radius: 0.25rem;
- font-family: var(--sl-font-system-mono);
- font-size: var(--sl-text-xs);
- font-weight: 400;
- padding: 0.125rem 0.375rem;
- line-height: 1;
- color: #fff;
- background-color: var(--sl-color-bg-badge);
- overflow-wrap: anywhere;
- }
-
- .outline {
- --sl-color-bg-badge: transparent;
- --sl-color-border-badge: currentColor;
- color: inherit;
- }
-
- .default {
- --sl-color-bg-badge: var(--sl-color-accent-low);
- --sl-color-border-badge: var(--sl-color-accent);
- }
-
- .note {
- --sl-color-bg-badge: var(--sl-color-blue-low);
- --sl-color-border-badge: var(--sl-color-blue);
- }
-
- .danger {
- --sl-color-bg-badge: var(--sl-color-red-low);
- --sl-color-border-badge: var(--sl-color-red);
- }
-
- .success {
- --sl-color-bg-badge: var(--sl-color-green-low);
- --sl-color-border-badge: var(--sl-color-green);
- }
-
- .caution {
- --sl-color-bg-badge: var(--sl-color-orange-low);
- --sl-color-border-badge: var(--sl-color-orange);
- }
-
- .tip {
- --sl-color-bg-badge: var(--sl-color-purple-low);
- --sl-color-border-badge: var(--sl-color-purple);
- }
-
- :global([data-theme='light']) .default {
- --sl-color-bg-badge: var(--sl-color-accent-high);
- }
-
- :global([data-theme='light']) .note {
- --sl-color-bg-badge: var(--sl-color-blue-high);
- }
-
- :global([data-theme='light']) .danger {
- --sl-color-bg-badge: var(--sl-color-red-high);
- }
-
- :global([data-theme='light']) .success {
- --sl-color-bg-badge: var(--sl-color-green-high);
- }
-
- :global([data-theme='light']) .caution {
- --sl-color-bg-badge: var(--sl-color-orange-high);
- }
-
- :global([data-theme='light']) .tip {
- --sl-color-bg-badge: var(--sl-color-purple-high);
- }
-</style>
diff --git a/packages/starlight/components/SidebarSublist.astro b/packages/starlight/components/SidebarSublist.astro
index 399d191f..23252501 100644
--- a/packages/starlight/components/SidebarSublist.astro
+++ b/packages/starlight/components/SidebarSublist.astro
@@ -1,7 +1,7 @@
---
import { flattenSidebar, type SidebarEntry } from '../utils/navigation';
import Icon from '../user-components/Icon.astro';
-import Badge from './Badge.astro';
+import Badge from '../user-components/Badge.astro';
interface Props {
sublist: SidebarEntry[];
@@ -24,13 +24,11 @@ const { sublist, nested } = Astro.props;
>
<span>{entry.label}</span>
{entry.badge && (
- <>
- {' '}
- <Badge
- text={entry.badge.text}
- variant={entry.isCurrent ? 'outline' : entry.badge.variant}
- />
- </>
+ <Badge
+ variant={entry.badge.variant}
+ class={entry.badge.class}
+ text={entry.badge.text}
+ />
)}
</a>
) : (
@@ -41,10 +39,11 @@ const { sublist, nested } = Astro.props;
<div class="group-label">
<span class="large">{entry.label}</span>
{entry.badge && (
- <>
- {' '}
- <Badge text={entry.badge.text} variant={entry.badge.variant} />
- </>
+ <Badge
+ variant={entry.badge.variant}
+ class={entry.badge.class}
+ text={entry.badge.text}
+ />
)}
</div>
<Icon name="right-caret" class="caret" size="1.25rem" />
diff --git a/packages/starlight/schemas/badge.ts b/packages/starlight/schemas/badge.ts
index dc6fdb67..a2cac1b1 100644
--- a/packages/starlight/schemas/badge.ts
+++ b/packages/starlight/schemas/badge.ts
@@ -4,8 +4,17 @@ const badgeSchema = () =>
z.object({
variant: z.enum(['note', 'danger', 'success', 'caution', 'tip', 'default']).default('default'),
text: z.string(),
+ class: z.string().optional(),
});
+export const BadgeComponentSchema = badgeSchema()
+ .extend({
+ size: z.enum(['small', 'medium', 'large']).default('small'),
+ })
+ .passthrough();
+
+export type BadgeComponentProps = z.input<typeof BadgeComponentSchema>;
+
export const BadgeConfigSchema = () =>
z
.union([z.string(), badgeSchema()])
diff --git a/packages/starlight/user-components/Badge.astro b/packages/starlight/user-components/Badge.astro
new file mode 100644
index 00000000..821cd0a3
--- /dev/null
+++ b/packages/starlight/user-components/Badge.astro
@@ -0,0 +1,141 @@
+---
+import { BadgeComponentSchema, type BadgeComponentProps } from '../schemas/badge';
+import { parseWithFriendlyErrors } from '../utils/error-map';
+import type { HTMLAttributes } from 'astro/types';
+
+type Props = BadgeComponentProps & HTMLAttributes<'span'>;
+
+const {
+ text,
+ variant,
+ size,
+ class: customClass,
+ ...attrs
+} = parseWithFriendlyErrors(
+ BadgeComponentSchema,
+ Astro.props,
+ 'Invalid prop passed to the `<Badge/>` component.'
+);
+---
+
+<span class:list={['sl-badge', variant, size, customClass]} {...attrs}>{text}</span>
+
+<style>
+ :global(:root) {
+ --sl-badge-default-border: var(--sl-color-accent);
+ --sl-badge-default-bg: var(--sl-color-accent-low);
+ --sl-badge-default-text: #fff;
+
+ --sl-badge-note-border: var(--sl-color-blue);
+ --sl-badge-note-bg: var(--sl-color-blue-low);
+ --sl-badge-note-text: #fff;
+
+ --sl-badge-danger-border: var(--sl-color-red);
+ --sl-badge-danger-bg: var(--sl-color-red-low);
+ --sl-badge-danger-text: #fff;
+
+ --sl-badge-success-border: var(--sl-color-green);
+ --sl-badge-success-bg: var(--sl-color-green-low);
+ --sl-badge-success-text: #fff;
+
+ --sl-badge-caution-border: var(--sl-color-orange);
+ --sl-badge-caution-bg: var(--sl-color-orange-low);
+ --sl-badge-caution-text: #fff;
+
+ --sl-badge-tip-border: var(--sl-color-purple);
+ --sl-badge-tip-bg: var(--sl-color-purple-low);
+ --sl-badge-tip-text: #fff;
+ }
+
+ :global([data-theme='light']:root) {
+ --sl-badge-default-bg: var(--sl-color-accent-high);
+ --sl-badge-note-bg: var(--sl-color-blue-high);
+ --sl-badge-danger-bg: var(--sl-color-red-high);
+ --sl-badge-success-bg: var(--sl-color-green-high);
+ --sl-badge-caution-bg: var(--sl-color-orange-high);
+ --sl-badge-tip-bg: var(--sl-color-purple-high);
+ }
+
+ .sl-badge {
+ display: inline-block;
+ border: 1px solid var(--sl-color-border-badge);
+ border-radius: 0.25rem;
+ font-family: var(--sl-font-system-mono);
+ line-height: normal;
+ color: var(--sl-color-text-badge);
+ background-color: var(--sl-color-bg-badge);
+ overflow-wrap: anywhere;
+ }
+
+ /* Sidebar overrides */
+ :global(.sidebar-content) .sl-badge {
+ line-height: 1;
+ font-size: var(--sl-text-xs);
+ padding: 0.125rem 0.375rem;
+ }
+
+ /* outline variant */
+ :global(.sidebar-content a[aria-current='page']) > .sl-badge {
+ --sl-color-bg-badge: transparent;
+ --sl-color-border-badge: currentColor;
+ color: inherit;
+ }
+
+ /* Color variants */
+ .default {
+ --sl-color-bg-badge: var(--sl-badge-default-bg);
+ --sl-color-border-badge: var(--sl-badge-default-border);
+ --sl-color-text-badge: var(--sl-badge-default-text);
+ }
+
+ .note {
+ --sl-color-bg-badge: var(--sl-badge-note-bg);
+ --sl-color-border-badge: var(--sl-badge-note-border);
+ --sl-color-text-badge: var(--sl-badge-note-text);
+ }
+
+ .danger {
+ --sl-color-bg-badge: var(--sl-badge-danger-bg);
+ --sl-color-border-badge: var(--sl-badge-danger-border);
+ --sl-color-text-badge: var(--sl-badge-danger-text);
+ }
+
+ .success {
+ --sl-color-bg-badge: var(--sl-badge-success-bg);
+ --sl-color-border-badge: var(--sl-badge-success-border);
+ --sl-color-text-badge: var(--sl-badge-success-text);
+ }
+
+ .tip {
+ --sl-color-bg-badge: var(--sl-badge-tip-bg);
+ --sl-color-border-badge: var(--sl-badge-tip-border);
+ --sl-color-text-badge: var(--sl-badge-tip-text);
+ }
+
+ .caution {
+ --sl-color-bg-badge: var(--sl-badge-caution-bg);
+ --sl-color-border-badge: var(--sl-badge-caution-border);
+ --sl-color-text-badge: var(--sl-badge-caution-text);
+ }
+
+ /* Size variants */
+ .small {
+ font-size: var(--sl-text-xs);
+ padding: 0.125rem 0.25rem;
+ }
+
+ .medium {
+ font-size: var(--sl-text-sm);
+ padding: 0.175rem 0.35rem;
+ }
+
+ .large {
+ font-size: var(--sl-text-base);
+ padding: 0.225rem 0.45rem;
+ }
+
+ /* Badge in headings */
+ :global(.sl-markdown-content :is(h1, h2, h3, h4, h5, h6)) .sl-badge {
+ vertical-align: middle;
+ }
+</style>