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 <LinkButton> component #1784

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
5 changes: 5 additions & 0 deletions .changeset/chilled-pots-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/starlight': minor
---

Adds `<LinkButton>` component for visually distinct and emphasized call to action links
16 changes: 16 additions & 0 deletions .changeset/thirty-students-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
'@astrojs/starlight': minor
---

Changes the hero component action button default [variant](https://starlight.astro.build/reference/frontmatter/#heroconfig) from `minimal` to `primary`.

If you want to preserve the previous behavior, hero component action button previously declared without a `variant` will need to be updated to include the `variant` property with the value `minimal`.

```diff
hero:
actions:
- text: View on GitHub
link: https://github.com/astronaut/my-project
icon: external
+ variant: minimal
```
31 changes: 31 additions & 0 deletions docs/src/content/docs/guides/components.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,37 @@ import { LinkCard } from '@astrojs/starlight/components';
<LinkCard title="Components" href="/guides/components/" />
</CardGrid>

### Link Buttons

Use the `<LinkButton>` component for visually distinct and emphasized call to action links best suited to sparingly direct users to the most relevant or actionable content at the end of a section.

A `<LinkButton>` requires an [`href`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#href) attribute and optionally accepts other link attributes such as `target`.

The `icon` attribute can optionally be set to the name of [one of Starlight's built-in icons](#all-icons) to include an icon next to the text.
The `iconPlacement` attribute can be used to place the icon before the text by setting it to `start` (defaults to `end`).

Customize the appearance of the link button using the `variant` attribute, which can be set to `primary` (the default), `secondary`, or `minimal`.

```mdx
# src/content/docs/example.mdx

import { LinkButton } from '@astrojs/starlight/components';

<LinkButton href="/getting-started/">Get started</LinkButton>
<LinkButton href="https://docs.astro.build" variant="secondary" icon="external">
Related: Astro
</LinkButton>
```

The above code generates the following on the page:

import { LinkButton } from '@astrojs/starlight/components';

<LinkButton href="/getting-started/">Get started</LinkButton>
<LinkButton href="https://docs.astro.build" variant="secondary" icon="external">
Related: Astro
</LinkButton>

### Asides

Asides (also known as “admonitions” or “callouts”) are useful for displaying secondary information alongside a page’s main content.
Expand Down
5 changes: 3 additions & 2 deletions docs/src/content/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ hero:
actions:
- text: Get started
icon: right-arrow
variant: primary
link: /getting-started/
- text: View on GitHub
icon: external
variant: minimal
link: https://github.com/withastro/starlight
---

Expand Down Expand Up @@ -69,8 +69,9 @@ import Testimonial from '~/components/testimonial.astro';
Starlight is our go-to example of a great DX: the speed, convenience, and
attention to details is inspiring. It takes care of the tech and the looks,
so you can focus on your content 👏

StackBlitz team absolutely loves it!

</Testimonial>
<Testimonial
name="Roberto"
Expand Down
6 changes: 3 additions & 3 deletions docs/src/content/docs/reference/frontmatter.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ hero:
- text: Tell me more
link: /getting-started/
icon: right-arrow
variant: primary
- text: View on GitHub
link: https://github.com/astronaut/my-project
icon: external
variant: minimal
attrs:
rel: me
---
Expand Down Expand Up @@ -166,8 +166,8 @@ interface HeroConfig {
actions?: Array<{
text: string;
link: string;
variant: 'primary' | 'secondary' | 'minimal';
icon: string;
variant?: 'primary' | 'secondary' | 'minimal';
icon?: string;
attrs?: Record<string, string | number | boolean>;
}>;
}
Expand Down
1 change: 1 addition & 0 deletions packages/starlight/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export { default as TabItem } from './user-components/TabItem.astro';
export { default as LinkCard } from './user-components/LinkCard.astro';
export { default as Steps } from './user-components/Steps.astro';
export { default as FileTree } from './user-components/FileTree.astro';
export { default as LinkButton } from './user-components/LinkButton.astro';
export { Code } from 'astro-expressive-code/components';
51 changes: 0 additions & 51 deletions packages/starlight/components/CallToAction.astro

This file was deleted.

9 changes: 6 additions & 3 deletions packages/starlight/components/Hero.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { Image } from 'astro:assets';
import { PAGE_TITLE_ID } from '../constants';
import type { Props } from '../props';
import CallToAction from './CallToAction.astro';
import LinkButton from '../user-components/LinkButton.astro';

const { data } = Astro.props.entry;
const { title = data.title, tagline, image, actions = [] } = data.hero || {};
Expand Down Expand Up @@ -50,8 +50,11 @@ if (image) {
{
actions.length > 0 && (
<div class="sl-flex actions">
{actions.map(({ text, ...attrs }) => (
<CallToAction {...attrs} set:html={text} />
{actions.map(({ attrs, icon, link: href, text, variant }) => (
<LinkButton {href} {variant} icon={icon?.name} {...attrs}>
{text}
{icon?.html && <Fragment set:html={icon.html} />}
</LinkButton>
))}
</div>
)
Expand Down
4 changes: 0 additions & 4 deletions packages/starlight/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@
"types": "./components/Sidebar.astro.tsx",
"import": "./components/Sidebar.astro"
},
"./components/CallToAction.astro": {
Copy link
Contributor

Choose a reason for hiding this comment

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

May want to call this out in the changeset as well

"types": "./components/CallToAction.astro.tsx",
"import": "./components/CallToAction.astro"
},
"./components/MarkdownContent.astro": {
"types": "./components/MarkdownContent.astro.tsx",
"import": "./components/MarkdownContent.astro"
Expand Down
4 changes: 2 additions & 2 deletions packages/starlight/schemas/hero.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export const HeroSchema = ({ image }: SchemaContext) =>
text: z.string(),
/** Value for the link’s `href` attribute, e.g. `/page` or `https://mysite.com`. */
link: z.string(),
/** Button style to use. One of `primary`, `secondary`, or `minimal` (the default). */
variant: z.enum(['primary', 'secondary', 'minimal']).default('minimal'),
/** Button style to use. One of `primary` (the default), `secondary`, or `minimal`. */
variant: z.enum(['primary', 'secondary', 'minimal']).default('primary'),
/**
* An optional icon to display alongside the link text.
* Can be an inline `<svg>` or the name of one of Starlight’s built-in icons.
Expand Down
4 changes: 2 additions & 2 deletions packages/starlight/style/markdown.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@
font-size: var(--sl-text-h6);
}

.sl-markdown-content a:not(:where(.not-content *)) {
.sl-markdown-content a:not(:where(:is(.not-content, .not-content *))) {
color: var(--sl-color-text-accent);
}
.sl-markdown-content a:hover:not(:where(.not-content *)) {
.sl-markdown-content a:hover:not(:where(:is(.not-content, .not-content *))) {
Comment on lines +65 to +68
Copy link
Member Author

Choose a reason for hiding this comment

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

These changes are used to avoid <LinkButton> getting Markdown link styles applied to it by specifying the not-content class on the link itself and not a wrapping element.

I'm wondering if this is a change that could be applied to some other places to avoid relying on a wrapping element to avoid Markdown styles 🤔

color: var(--sl-color-white);
}

Expand Down
72 changes: 72 additions & 0 deletions packages/starlight/user-components/LinkButton.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
import type { HTMLAttributes } from 'astro/types';
import { Icons } from '../components/Icons';
import Icon from './Icon.astro';

interface Props extends Omit<HTMLAttributes<'a'>, 'href'> {
href: string | URL;
icon?: keyof typeof Icons | undefined;
iconPlacement?: 'start' | 'end' | undefined;
variant?: 'primary' | 'secondary' | 'minimal';
}

const {
class: className,
icon,
iconPlacement = 'end',
variant = 'primary',
...attrs
} = Astro.props;
---

<a class:list={['sl-link-button not-content', variant, className]} {...attrs}>
{icon && iconPlacement === 'start' && <Icon name={icon} size="1.5rem" />}
<slot />
{icon && iconPlacement === 'end' && <Icon name={icon} size="1.5rem" />}
</a>

<style>
.sl-link-button {
align-items: center;
border-radius: 999rem;
color: var(--sl-color-white);
display: inline-flex;
font-size: var(--sl-text-sm);
gap: 0.5em;
line-height: 1.7145;
padding: 0.5rem 1.125rem;
text-decoration: none;
}

.sl-link-button.primary {
background: var(--sl-color-text-accent);
border: 1px solid var(--sl-color-text-accent);
color: var(--sl-color-black);
}
.sl-link-button.secondary {
border: 1px solid;
}
.sl-link-button.minimal {
outline-offset: 0.25rem;
padding-inline: 0;
}

.sl-link-button :global(svg) {
flex-shrink: 0;
}

@media (min-width: 50rem) {
.sl-link-button {
font-size: var(--sl-text-base);
line-height: 1.5;
padding: 1rem 1.25rem;
}
}

:global(.sl-markdown-content) .sl-link-button {
margin-inline-end: 0.5em;
}
:global(.sl-markdown-content) .sl-link-button:not(:where(p *)) {
margin-block: 1rem;
}
</style>