From f87e9acbf5090a31858c1cde568cc798140f1366 Mon Sep 17 00:00:00 2001
From: Chris Swithinbank
Date: Mon, 7 Apr 2025 17:33:51 +0200
Subject: Make `social` icon configuration more flexible (#3025)
Co-authored-by: HiDeoo <494699+HiDeoo@users.noreply.github.com>---
.changeset/gold-sloths-unite.md | 24 ++++
.changeset/swift-hotels-move.md | 5 +
docs/astro.config.mjs | 8 +-
docs/src/components/social-links-type.astro | 11 +-
docs/src/content/docs/guides/customization.mdx | 23 ++--
docs/src/content/docs/reference/configuration.mdx | 29 ++---
docs/src/content/docs/reference/plugins.md | 14 ++-
examples/basics/astro.config.mjs | 4 +-
examples/markdoc/astro.config.mjs | 4 +-
examples/tailwind/astro.config.mjs | 4 +-
.../__tests__/basics/config-errors.test.ts | 6 +-
.../starlight/__tests__/basics/user-config.test.ts | 12 +-
packages/starlight/__tests__/head/head.test.ts | 12 ++
packages/starlight/__tests__/head/vitest.config.ts | 1 +
packages/starlight/components/SocialIcons.astro | 10 +-
packages/starlight/schemas/hero.ts | 8 +-
packages/starlight/schemas/icon.ts | 7 ++
packages/starlight/schemas/social.ts | 125 +++------------------
packages/starlight/utils/head.ts | 5 +-
19 files changed, 137 insertions(+), 175 deletions(-)
create mode 100644 .changeset/gold-sloths-unite.md
create mode 100644 .changeset/swift-hotels-move.md
create mode 100644 packages/starlight/schemas/icon.ts
diff --git a/.changeset/gold-sloths-unite.md b/.changeset/gold-sloths-unite.md
new file mode 100644
index 00000000..d81e7ea1
--- /dev/null
+++ b/.changeset/gold-sloths-unite.md
@@ -0,0 +1,24 @@
+---
+'@astrojs/starlight': minor
+---
+
+Makes `social` configuration more flexible.
+
+⚠️ **BREAKING CHANGE:** The `social` configuration option has changed syntax. You will need to update this in `astro.config.mjs` when upgrading.
+
+Previously, a limited set of platforms were supported using a shorthand syntax with labels built in to Starlight. While convenient, this approach was less flexible and required dedicated code for each social platform added.
+
+Now, you must specify the icon and label for each social link explicitly and you can use any of [Starlight’s built-in icons](https://starlight.astro.build/reference/icons/) for social links.
+
+The following example shows updating the old `social` syntax to the new:
+
+```diff
+- social: {
+- github: 'https://github.com/withastro/starlight',
+- discord: 'https://astro.build/chat',
+- },
++ social: [
++ { icon: 'github', label: 'GitHub', href: 'https://github.com/withastro/starlight' },
++ { icon: 'discord', label: 'Discord', href: 'https://astro.build/chat' },
++ ],
+```
diff --git a/.changeset/swift-hotels-move.md b/.changeset/swift-hotels-move.md
new file mode 100644
index 00000000..78a43e6d
--- /dev/null
+++ b/.changeset/swift-hotels-move.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/starlight': patch
+---
+
+Fixes Starlight’s autogenerated `` tags when a Twitter link is set in `social` config. Previously these incorrectly rendered `content="/username"` and now correctly render `content="@username"`.
diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs
index 9906df38..7923a0e7 100644
--- a/docs/astro.config.mjs
+++ b/docs/astro.config.mjs
@@ -45,10 +45,10 @@ export default defineConfig({
editLink: {
baseUrl: 'https://github.com/withastro/starlight/edit/main/docs/',
},
- social: {
- github: 'https://github.com/withastro/starlight',
- discord: 'https://astro.build/chat',
- },
+ social: [
+ { icon: 'github', label: 'GitHub', href: 'https://github.com/withastro/starlight' },
+ { icon: 'discord', label: 'Discord', href: 'https://astro.build/chat' },
+ ],
head: [
{
tag: 'script',
diff --git a/docs/src/components/social-links-type.astro b/docs/src/components/social-links-type.astro
index fc62630d..d60e2071 100644
--- a/docs/src/components/social-links-type.astro
+++ b/docs/src/components/social-links-type.astro
@@ -1,7 +1,10 @@
---
-import { socialLinks } from '../../../packages/starlight/schemas/social';
-
-const socials = [...socialLinks].sort((a, b) => a.localeCompare(b, 'en'));
+import { getRelativeLocaleUrl } from 'astro:i18n';
+const href = getRelativeLocaleUrl(Astro.currentLocale ?? 'en', '/reference/icons/');
---
-{`Partial `'${social}'`).join(' | ')}, string>>`}
+
+
+ label: string; icon: StarlightIcon; href: string
+
+
diff --git a/docs/src/content/docs/guides/customization.mdx b/docs/src/content/docs/guides/customization.mdx
index c77b0cee..c53fa0ba 100644
--- a/docs/src/content/docs/guides/customization.mdx
+++ b/docs/src/content/docs/guides/customization.mdx
@@ -200,10 +200,15 @@ defineConfig({
Starlight has built-in support for adding links to your social media accounts to the site header via the [`social`](/reference/configuration/#social) option in the Starlight integration.
-You can find a full list of supported link icons in the [Configuration Reference](/reference/configuration/#social).
-Let us know on GitHub or Discord if you need support for another service!
+Each entry in the `social` array must be an object with three properties:
-```js {9-12}
+- `icon`: one of Starlight’s [built-in icons](/reference/icons/), e.g. `"github"`.
+- `label`: an accessible label for the link, e.g. `"GitHub"`.
+- `href`: the URL for the link, e.g. `"https://github.com/withastro/starlight"`.
+
+The following example adds links to the Astro Discord chat and the Starlight GitHub repository:
+
+```js {9-16}
// astro.config.mjs
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
@@ -212,10 +217,14 @@ export default defineConfig({
integrations: [
starlight({
title: 'Docs With Social Links',
- social: {
- discord: 'https://astro.build/chat',
- github: 'https://github.com/withastro/starlight',
- },
+ social: [
+ { icon: 'discord', label: 'Discord', href: 'https://astro.build/chat' },
+ {
+ icon: 'github',
+ label: 'GitHub',
+ href: 'https://github.com/withastro/starlight',
+ },
+ ],
}),
],
});
diff --git a/docs/src/content/docs/reference/configuration.mdx b/docs/src/content/docs/reference/configuration.mdx
index 62107d8c..8a9f2638 100644
--- a/docs/src/content/docs/reference/configuration.mdx
+++ b/docs/src/content/docs/reference/configuration.mdx
@@ -341,28 +341,21 @@ The default locale will be used to provide fallback content where translations a
### `social`
-import SocialLinksType from '~/components/social-links-type.astro';
+**type:** {`Array<{ label: string; icon: `}[StarlightIcon](/reference/icons/){`; href: string }>`}
-**type:**
-
-Optional details about the social media accounts for this site. Adding any of these will display them as icon links in the site header.
+Optional details about the social media accounts for this site.
+Each entry will be displayed as an icon link in the site header.
```js
starlight({
- social: {
- codeberg: 'https://codeberg.org/knut/examples',
- discord: 'https://astro.build/chat',
- github: 'https://github.com/withastro/starlight',
- gitlab: 'https://gitlab.com/delucis',
- linkedin: 'https://www.linkedin.com/company/astroinc',
- mastodon: 'https://m.webtoo.ls/@astro',
- threads: 'https://www.threads.net/@nmoodev',
- twitch: 'https://www.twitch.tv/bholmesdev',
- twitter: 'https://twitter.com/astrodotbuild',
- 'x.com': 'https://x.com/astrodotbuild',
- youtube: 'https://youtube.com/@astrodotbuild',
- },
-});
+ social: [
+ { icon: 'codeberg', label: 'Codeberg', href: 'https://codeberg.org/knut' },
+ { icon: 'discord', label: 'Discord', href: 'https://astro.build/chat' },
+ { icon: 'github', label: 'GitHub', href: 'https://github.com/withastro' },
+ { icon: 'gitlab', label: 'GitLab', href: 'https://gitlab.com/delucis' },
+ { icon: 'mastodon', label: 'Mastodon', href: 'https://m.webtoo.ls/@astro' },
+ ],
+}),
```
### `customCss`
diff --git a/docs/src/content/docs/reference/plugins.md b/docs/src/content/docs/reference/plugins.md
index d170a4fd..1c46004a 100644
--- a/docs/src/content/docs/reference/plugins.md
+++ b/docs/src/content/docs/reference/plugins.md
@@ -163,19 +163,23 @@ Provide the root-level configuration keys you want to override.
To update nested configuration values, you must provide the entire nested object.
To extend an existing config option without overriding it, spread the existing value into your new value.
-In the following example, a new [`social`](/reference/configuration/#social) media account is added to the existing configuration by spreading `config.social` into the new `social` object:
+In the following example, a new [`social`](/reference/configuration/#social) media account is added to the existing configuration by spreading `config.social` into the new `social` array:
-```ts {6-11}
+```ts {6-15}
// plugin.ts
export default {
name: 'add-twitter-plugin',
hooks: {
'config:setup'({ config, updateConfig }) {
updateConfig({
- social: {
+ social: [
...config.social,
- twitter: 'https://twitter.com/astrodotbuild',
- },
+ {
+ icon: 'twitter',
+ label: 'Twitter',
+ href: 'https://twitter.com/astrodotbuild',
+ },
+ ],
});
},
},
diff --git a/examples/basics/astro.config.mjs b/examples/basics/astro.config.mjs
index 1b393646..9a25601b 100644
--- a/examples/basics/astro.config.mjs
+++ b/examples/basics/astro.config.mjs
@@ -7,9 +7,7 @@ export default defineConfig({
integrations: [
starlight({
title: 'My Docs',
- social: {
- github: 'https://github.com/withastro/starlight',
- },
+ social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/withastro/starlight' }],
sidebar: [
{
label: 'Guides',
diff --git a/examples/markdoc/astro.config.mjs b/examples/markdoc/astro.config.mjs
index 7f814cbb..949f3fcc 100644
--- a/examples/markdoc/astro.config.mjs
+++ b/examples/markdoc/astro.config.mjs
@@ -9,9 +9,7 @@ export default defineConfig({
markdoc(),
starlight({
title: 'My Docs',
- social: {
- github: 'https://github.com/withastro/starlight',
- },
+ social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/withastro/starlight' }],
sidebar: [
{
label: 'Guides',
diff --git a/examples/tailwind/astro.config.mjs b/examples/tailwind/astro.config.mjs
index a3a3ba5e..872a2896 100644
--- a/examples/tailwind/astro.config.mjs
+++ b/examples/tailwind/astro.config.mjs
@@ -8,9 +8,7 @@ export default defineConfig({
integrations: [
starlight({
title: 'Docs with Tailwind',
- social: {
- github: 'https://github.com/withastro/starlight',
- },
+ social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/withastro/starlight' }],
sidebar: [
{
label: 'Guides',
diff --git a/packages/starlight/__tests__/basics/config-errors.test.ts b/packages/starlight/__tests__/basics/config-errors.test.ts
index a010015f..6f9dad71 100644
--- a/packages/starlight/__tests__/basics/config-errors.test.ts
+++ b/packages/starlight/__tests__/basics/config-errors.test.ts
@@ -122,8 +122,10 @@ test('errors with bad social icon config', () => {
"[AstroUserError]:
Invalid config passed to starlight integration
Hint:
- **social.unknown**: Invalid enum value. Expected 'twitter' | 'mastodon' | 'github' | 'gitlab' | 'bitbucket' | 'discord' | 'gitter' | 'codeberg' | 'codePen' | 'youtube' | 'threads' | 'linkedin' | 'twitch' | 'azureDevOps' | 'microsoftTeams' | 'instagram' | 'stackOverflow' | 'x.com' | 'telegram' | 'rss' | 'facebook' | 'email' | 'reddit' | 'patreon' | 'signal' | 'slack' | 'matrix' | 'openCollective' | 'hackerOne' | 'blueSky' | 'discourse' | 'zulip' | 'pinterest' | 'tiktok' | 'nostr' | 'backstage' | 'farcaster' | 'confluence' | 'jira' | 'storybook' | 'npm' | 'sourcehut' | 'substack', received 'unknown'
- **social.unknown**: Invalid url"
+ Starlight v0.33.0 changed the \`social\` configuration syntax. Please specify an array of link items instead of an object.
+ See the Starlight changelog for details: https://github.com/withastro/starlight/blob/main/packages/starlight/CHANGELOG.md#0330
+
+ **social**: Expected type \`"array"\`, received \`"object"\`"
`
);
});
diff --git a/packages/starlight/__tests__/basics/user-config.test.ts b/packages/starlight/__tests__/basics/user-config.test.ts
index e3eeb723..c0f115f6 100644
--- a/packages/starlight/__tests__/basics/user-config.test.ts
+++ b/packages/starlight/__tests__/basics/user-config.test.ts
@@ -4,11 +4,11 @@ import { StarlightConfigSchema } from '../../utils/user-config';
test('preserve social config order', () => {
const config = StarlightConfigSchema.parse({
title: 'Test',
- social: {
- twitch: 'https://www.twitch.tv/bholmesdev',
- github: 'https://github.com/withastro/starlight',
- discord: 'https://astro.build/chat',
- },
+ social: [
+ { icon: 'twitch', label: 'Twitch', href: 'https://www.twitch.tv/bholmesdev' },
+ { icon: 'github', label: 'GitHub', href: 'https://github.com/withastro/starlight' },
+ { icon: 'discord', label: 'Discord', href: 'https://astro.build/chat' },
+ ],
});
- expect(Object.keys(config.social || {})).toEqual(['twitch', 'github', 'discord']);
+ expect((config.social || []).map(({ icon }) => icon)).toEqual(['twitch', 'github', 'discord']);
});
diff --git a/packages/starlight/__tests__/head/head.test.ts b/packages/starlight/__tests__/head/head.test.ts
index 966635ef..46205b89 100644
--- a/packages/starlight/__tests__/head/head.test.ts
+++ b/packages/starlight/__tests__/head/head.test.ts
@@ -23,6 +23,18 @@ test('includes custom tags defined in the Starlight configuration', () => {
});
});
+test('includes `twitter:site` based on Starlight `social` configuration', () => {
+ const head = getTestHead();
+ expect(head).toContainEqual({
+ tag: 'meta',
+ attrs: {
+ name: 'twitter:site',
+ content: '@astrodotbuild',
+ },
+ content: '',
+ });
+});
+
test('merges two
tags', () => {
const head = getTestHead([{ tag: 'title', content: 'Override', attrs: {} }]);
expect(head.filter((tag) => tag.tag === 'title')).toEqual([
diff --git a/packages/starlight/__tests__/head/vitest.config.ts b/packages/starlight/__tests__/head/vitest.config.ts
index 889b9dd5..b13fef59 100644
--- a/packages/starlight/__tests__/head/vitest.config.ts
+++ b/packages/starlight/__tests__/head/vitest.config.ts
@@ -17,4 +17,5 @@ export default defineVitestConfig({
},
},
],
+ social: [{ icon: 'twitter', label: 'Twitter', href: 'https://twitter.com/astrodotbuild' }],
});
diff --git a/packages/starlight/components/SocialIcons.astro b/packages/starlight/components/SocialIcons.astro
index ad9056ff..b8c5bd4c 100644
--- a/packages/starlight/components/SocialIcons.astro
+++ b/packages/starlight/components/SocialIcons.astro
@@ -2,18 +2,16 @@
import config from 'virtual:starlight/user-config';
import Icon from '../user-components/Icon.astro';
-type Platform = keyof NonNullable;
-type SocialConfig = NonNullable[Platform]>;
-const links = Object.entries(config.social || {}) as [Platform, SocialConfig][];
+const links = config.social || [];
---
{
links.length > 0 && (
<>
- {links.map(([platform, { label, url }]) => (
-
+ {links.map(({ label, href, icon }) => (
+
{label}
-
+
))}
>
diff --git a/packages/starlight/schemas/hero.ts b/packages/starlight/schemas/hero.ts
index 86105523..e1af1f90 100644
--- a/packages/starlight/schemas/hero.ts
+++ b/packages/starlight/schemas/hero.ts
@@ -1,8 +1,6 @@
import { z } from 'astro/zod';
import type { SchemaContext } from 'astro:content';
-import { Icons, type StarlightIcon } from '../components/Icons';
-
-const iconNames = Object.keys(Icons) as [StarlightIcon, ...StarlightIcon[]];
+import { IconSchema } from './icon';
export const HeroSchema = ({ image }: SchemaContext) =>
z.object({
@@ -55,9 +53,9 @@ export const HeroSchema = ({ image }: SchemaContext) =>
* Can be an inline `