Head
The Head
component is used to render the <head>
element of the document. It is used to set the title, meta tags, and other elements in the <head>
of the document. Ion’s override is pretty much identical to the default Starlight Head
component, the only difference being that it adds it’s own generator tag.
---import type { z } from 'astro/zod';import config from 'virtual:starlight/user-config';import { version } from 'starlight-ion-theme/package.json';import type { HeadConfigSchema } from 'starlight-ion-theme/schemas/head.js';import { fileWithBase } from 'starlight-ion-theme/utils/base.js';import { createHead } from 'starlight-ion-theme/utils/head.js';import { localizedUrl } from 'starlight-ion-theme/utils/localizedUrl.js';import type { Props } from '@astrojs/starlight/props';
const { entry, lang, siteTitle } = Astro.locals.starlightRoute;const { data } = entry;
const canonical = Astro.site ? new URL(Astro.url.pathname, Astro.site) : undefined;const description = data.description || config.description;
// Remove all icon brackets, their content and any whitespaces surrounding them from the title stringconst titleWithoutIcons = data.title.replaceAll(/\s*\[.+\]\s*/gm, '');
const headDefaults: z.input<ReturnType<typeof HeadConfigSchema>> = [ { tag: 'meta', attrs: { charset: 'utf-8' } }, { tag: 'meta', attrs: { name: 'viewport', content: 'width=device-width, initial-scale=1' }, }, { tag: 'title', content: `${titleWithoutIcons} ${config.titleDelimiter} ${siteTitle}` }, { tag: 'link', attrs: { rel: 'canonical', href: canonical?.href } }, { tag: 'meta', attrs: { name: 'generator', content: Astro.generator } }, { tag: 'meta', attrs: { name: 'generator', content: `Starlight (Ion) v${version}` }, }, // Favicon { tag: 'link', attrs: { rel: 'shortcut icon', href: fileWithBase(config.favicon.href), type: config.favicon.type, }, }, // OpenGraph Tags { tag: 'meta', attrs: { property: 'og:title', content: titleWithoutIcons } }, { tag: 'meta', attrs: { property: 'og:type', content: 'article' } }, { tag: 'meta', attrs: { property: 'og:url', content: canonical?.href } }, { tag: 'meta', attrs: { property: 'og:locale', content: lang } }, { tag: 'meta', attrs: { property: 'og:description', content: description } }, { tag: 'meta', attrs: { property: 'og:site_name', content: siteTitle } }, // Twitter Tags { tag: 'meta', attrs: { name: 'twitter:card', content: 'summary_large_image' }, },];
if (description) headDefaults.push({ tag: 'meta', attrs: { name: 'description', content: description }, });
// Link to language alternates.if (canonical && config.isMultilingual) { for (const locale in config.locales) { const localeOpts = config.locales[locale]; if (!localeOpts) continue; headDefaults.push({ tag: 'link', attrs: { rel: 'alternate', hreflang: localeOpts.lang, href: localizedUrl(canonical, locale).href, }, }); }}
// Link to sitemap, but only when `site` is set.if (Astro.site) { headDefaults.push({ tag: 'link', attrs: { rel: 'sitemap', href: fileWithBase('/sitemap-index.xml'), }, });}
// Link to Twitter account if set in Starlight config.if (config.social?.twitter) { headDefaults.push({ tag: 'meta', attrs: { name: 'twitter:site', content: new URL(config.social.twitter.url).pathname, }, });}
const head = createHead(headDefaults, config.head, data.head);---{head.map(({ tag: Tag, attrs, content }) => <Tag {...attrs} set:html={content} />)}