Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add <Badge> component #1530

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c63a6c3
Move <Badge> to user components
kevinzunigacuellar Feb 18, 2024
41dad00
testing page
kevinzunigacuellar Feb 18, 2024
a1761f5
add changeset
kevinzunigacuellar Feb 18, 2024
80ad0ae
copilot bad!
kevinzunigacuellar Feb 18, 2024
cf8a9a6
new light themes, expose css variables, override themes for md content
kevinzunigacuellar Feb 22, 2024
480b08b
more examples
kevinzunigacuellar Feb 22, 2024
9383dce
add `class` for defining custom badges
kevinzunigacuellar Feb 22, 2024
7e726d7
switch set:html for slot
kevinzunigacuellar Feb 22, 2024
22a517e
add class to badge schema and sidebar
kevinzunigacuellar Feb 22, 2024
d915e4f
add docs!
kevinzunigacuellar Feb 26, 2024
14d84cf
Merge branch 'main' into kevin/badge
kevinzunigacuellar Apr 15, 2024
9a64a0f
Wip: badge
kevinzunigacuellar Apr 16, 2024
7c98bad
Update badge component and related schemas
kevinzunigacuellar Apr 16, 2024
94c6d8e
remove unused exports
kevinzunigacuellar Apr 16, 2024
4e9256d
docs: add class override
kevinzunigacuellar Apr 16, 2024
d2e05f1
Merge branch 'main' into kevin/badge
kevinzunigacuellar Apr 16, 2024
ec2afcc
Remove test file
kevinzunigacuellar Apr 16, 2024
a62ead3
move badge docs before icon section
kevinzunigacuellar Apr 16, 2024
263f0cc
feat: tweak badge appearance in headings
HiDeoo Apr 29, 2024
3926ac4
export and use BadgeComponent type for badge component
kevinzunigacuellar May 1, 2024
b77871d
update docs 💜
kevinzunigacuellar May 1, 2024
474395b
rfc: BadgeComponent to support `attrs`
kevinzunigacuellar May 7, 2024
7acfb8e
chore: Update badge component documentation
kevinzunigacuellar May 7, 2024
d1ce134
remove attrs from schema
kevinzunigacuellar May 7, 2024
9bce965
update docs
kevinzunigacuellar May 7, 2024
de49e5c
remove comma
kevinzunigacuellar May 7, 2024
4cbf409
Apply suggestions from code review
kevinzunigacuellar May 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/wicked-melons-study.md
@@ -0,0 +1,6 @@
---
'@astrojs/starlight': minor
---

Adds the `<Badge>` component

29 changes: 29 additions & 0 deletions docs/src/content/docs/guides/components.mdx
Expand Up @@ -368,6 +368,35 @@ 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.
Optionally, you can specify a `variant` attribute with values like `tip`, `note`, `caution`, `danger`, `success` or `default` (the default uses the theme accent color) to adjust the badge's appearance.

To adjust the badge's size, you can specify a `size` attribute with values like `small` (the default), `medium`, or `large`.

You can also include other `<span>` attributes such as `class` or `style` to further customize the badge.

```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';
Expand Down
8 changes: 5 additions & 3 deletions docs/src/content/docs/guides/sidebar.mdx
Expand Up @@ -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`.
Change the appearance, by setting 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({
Expand Down
1 change: 1 addition & 0 deletions docs/src/content/docs/reference/configuration.mdx
Expand Up @@ -203,6 +203,7 @@ type SidebarItem = {
interface BadgeConfig {
text: string;
variant: 'note' | 'tip' | 'caution' | 'danger' | 'success' | 'default';
class?: string;
}
```

Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/reference/frontmatter.md
Expand Up @@ -340,7 +340,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
---
Expand Down
1 change: 1 addition & 0 deletions 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';
Expand Down
87 changes: 0 additions & 87 deletions packages/starlight/components/Badge.astro

This file was deleted.

23 changes: 11 additions & 12 deletions 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[];
Expand All @@ -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>
) : (
Expand All @@ -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" />
Expand Down
14 changes: 9 additions & 5 deletions packages/starlight/schemas/badge.ts
@@ -1,10 +1,14 @@
import { z } from 'astro/zod';

const badgeSchema = () =>
z.object({
variant: z.enum(['note', 'danger', 'success', 'caution', 'tip', 'default']).default('default'),
text: z.string(),
});
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'),
});
kevinzunigacuellar marked this conversation as resolved.
Show resolved Hide resolved

export const BadgeConfigSchema = () =>
z
Expand Down
153 changes: 153 additions & 0 deletions packages/starlight/user-components/Badge.astro
@@ -0,0 +1,153 @@
---
import { BadgeComponentSchema } from '../schemas/badge';
kevinzunigacuellar marked this conversation as resolved.
Show resolved Hide resolved
import { parseWithFriendlyErrors } from '../utils/error-map';
import type { HTMLAttributes } from 'astro/types';

type Props = {
variant?: 'note' | 'danger' | 'success' | 'caution' | 'tip' | 'default';
text: string;
size?: 'small' | 'medium' | 'large';
class?: string | undefined;
} & HTMLAttributes<'span'>;

const {
variant: variantProp,
text: textProp,
size: sizeProp,
class: classProp,
...attrs
} = Astro.props;

const { text, variant, size, class: customClass } = parseWithFriendlyErrors(
BadgeComponentSchema,
{
class: classProp,
variant: variantProp,
text: textProp,
size: sizeProp,
},
'Invalid prop passed to the `<Badge/>` component.'
);
kevinzunigacuellar marked this conversation as resolved.
Show resolved Hide resolved
---

<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;
}
Copy link
Member

@martrapp martrapp Apr 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After having looked into this PR as the perfect solution for #1764 and martrapp/astro-vtbot#77, I would like to suggest to move the sidebar specific styling to

. There it would be a neighbor of the other aria-current='page'-styling, and you would get rid of the references to sidebar-content here.


/* 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>