feat(docs-site): add starlight-plugin-icons, use real Gitea logo in header

The header social link used Starlight's generic `code-branch` icon.
Wires up starlight-plugin-icons + UnoCSS (Iconify) and overrides
SocialIcons to render `pajamas:gitea` for the Gitea link instead, while
falling back to Starlight's default icon set for anything else. Sidebar
and codeblock icon support are enabled but unused for now.
This commit is contained in:
2026-08-17 15:30:42 -04:00
parent 8a937124d3
commit f32e0d0ce5
7 changed files with 1510 additions and 41 deletions
+3
View File
@@ -3,6 +3,9 @@ dist/
# generated types
.astro/
# starlight-plugin-icons safelist cache
.starlight-icons/
# dependencies
node_modules/
+12
View File
@@ -26,6 +26,18 @@ The [`starlight-llms-txt`](https://www.npmjs.com/package/starlight-llms-txt)
plugin emits `llms.txt`, `llms-full.txt`, and `llms-small.txt` alongside the
built pages — no configuration needed, it just walks the generated content.
## Icons
[`starlight-plugin-icons`](https://docs.rettend.me/starlight-plugin-icons)
+ [UnoCSS](https://unocss.dev) (`uno.config.ts`) render icons from any
[Iconify](https://icones.js.org) set as `i-<collection>:<name>` classes.
The Gitea link in the header uses it (see
`src/components/starlight/SocialIcons.astro`) to show the real Gitea logo
instead of Starlight's generic `code-branch` icon. Sidebar (`sidebar:
true`) and codeblock (`codeblock: true`) icon support are wired up in
`astro.config.mjs` but unused so far — see the plugin docs for the
`icon:` sidebar syntax if you want to add them.
## Development
```fish title="local dev server"
+49 -39
View File
@@ -1,5 +1,6 @@
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import UnoCSS from 'unocss/astro';
import Icons from 'starlight-plugin-icons';
import starlightLinksValidator from 'starlight-links-validator';
import starlightCatppuccin from '@catppuccin/starlight';
import starlightLlmsTxt from 'starlight-llms-txt';
@@ -9,45 +10,54 @@ export default defineConfig({
prerenderConflictBehavior: 'ignore',
site: 'https://fish.rootiest.fyi',
integrations: [
starlight({
title: 'Rootiest Fish Config',
description: 'Reference manual for the rootiest fish configuration.',
favicon: '/favicon.svg',
logo: {
src: './src/assets/logo.svg',
UnoCSS(),
...Icons({
sidebar: true,
codeblock: true,
extractSafelist: true,
starlight: {
title: 'Rootiest Fish Config',
description: 'Reference manual for the rootiest fish configuration.',
favicon: '/favicon.svg',
logo: {
src: './src/assets/logo.svg',
},
social: [
{
icon: 'code-branch',
label: 'Gitea',
href: 'https://git.rootiest.dev/rootiest/fish-config',
},
],
components: {
SocialIcons: './src/components/starlight/SocialIcons.astro',
},
head: [
{
tag: 'script',
content: 'document.addEventListener("DOMContentLoaded", () => { document.querySelectorAll("starlight-file-tree").forEach(tree => { tree.querySelectorAll("details").forEach((d, i) => { if (i !== 0) d.removeAttribute("open"); }); }); });',
},
],
plugins: [
starlightLinksValidator(),
starlightCatppuccin({
dark: { flavor: "mocha", accent: "green" },
light: { flavor: "latte", accent: "sky" },
}),
starlightLlmsTxt(),
],
expressiveCode: {
// Shiki ships both Catppuccin flavours; Starlight picks by the
// reader's colour scheme, matching the palette in catppuccin.css.
themes: ['catppuccin-mocha', 'catppuccin-latte'],
styleOverrides: {
borderRadius: '0.4rem',
borderColor: 'var(--sl-color-gray-5)',
codeFontSize: '0.875rem',
},
},
sidebar,
},
social: [
{
icon: 'code-branch',
label: 'Gitea',
href: 'https://git.rootiest.dev/rootiest/fish-config',
},
],
head: [
{
tag: 'script',
content: 'document.addEventListener("DOMContentLoaded", () => { document.querySelectorAll("starlight-file-tree").forEach(tree => { tree.querySelectorAll("details").forEach((d, i) => { if (i !== 0) d.removeAttribute("open"); }); }); });',
},
],
plugins: [
starlightLinksValidator(),
starlightCatppuccin({
dark: { flavor: "mocha", accent: "green" },
light: { flavor: "latte", accent: "sky" },
}),
starlightLlmsTxt(),
],
expressiveCode: {
// Shiki ships both Catppuccin flavours; Starlight picks by the
// reader's colour scheme, matching the palette in catppuccin.css.
themes: ['catppuccin-mocha', 'catppuccin-latte'],
styleOverrides: {
borderRadius: '0.4rem',
borderColor: 'var(--sl-color-gray-5)',
codeFontSize: '0.875rem',
},
},
sidebar,
}),
],
});
+1389 -1
View File
File diff suppressed because it is too large Load Diff
+5 -1
View File
@@ -12,9 +12,13 @@
"dependencies": {
"@astrojs/starlight": "^0.41.4",
"@catppuccin/starlight": "^2.1.0",
"@iconify-json/pajamas": "^1.2.15",
"@unocss/astro": "^66.7.5",
"astro": "^7.0.2",
"sharp": "^0.35.3",
"starlight-links-validator": "^0.25.2",
"starlight-llms-txt": "^0.11.0"
"starlight-llms-txt": "^0.11.0",
"starlight-plugin-icons": "^1.1.6",
"unocss": "^66.7.5"
}
}
@@ -0,0 +1,46 @@
---
import config from 'virtual:starlight/user-config';
import { Icon } from '@astrojs/starlight/components';
// Maps a social link's `label` to a UnoCSS iconify icon class, letting a
// link use an icon outside Starlight's built-in set (e.g. a real Gitea
// logo instead of the generic `code-branch` icon).
const customIcons: Record<string, string> = {
Gitea: 'i-pajamas:gitea',
};
const links = config.social || [];
---
{
links.length > 0 && (
<>
{links.map(({ label, href, icon }) => {
const customIcon = customIcons[label];
return (
<a href={href} rel="me" class="sl-flex">
<span class="sr-only">{label}</span>
{customIcon ? <span class={`social-icon ${customIcon}`} aria-hidden="true" /> : <Icon name={icon} />}
</a>
);
})}
</>
)
}
<style>
@layer starlight.core {
a {
color: var(--sl-color-text-accent);
padding: 0.5em;
margin: -0.5em;
}
a:hover {
color: var(--sl-color-white);
}
.social-icon {
width: 1em;
height: 1em;
}
}
</style>
+6
View File
@@ -0,0 +1,6 @@
import { defineConfig } from 'unocss';
import { presetStarlightIcons } from 'starlight-plugin-icons/uno';
export default defineConfig({
presets: [presetStarlightIcons()],
});