aboutsummaryrefslogtreecommitdiff
path: root/website/src/components
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-09-01 14:48:45 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-09-01 14:48:45 +0300
commit8a6d697308162874a236c84aac0b0f8c7ac01f83 (patch)
treeed7dc7e8c6f50d66bde721fae78576aede929f66 /website/src/components
parentb54a78aa510b87d1e3b56c619b72eaeb59e4a2a1 (diff)
refactor: separate website presentation from runtime
Diffstat (limited to 'website/src/components')
-rw-r--r--website/src/components/AuthorCard.astro30
-rw-r--r--website/src/components/Banner.astro75
-rw-r--r--website/src/components/ConfigReference.astro204
-rw-r--r--website/src/components/DocsVersionSelect.astro84
-rw-r--r--website/src/components/Head.astro67
-rw-r--r--website/src/components/Header.astro99
-rw-r--r--website/src/components/MarketingLayout.astro274
-rw-r--r--website/src/components/Search.astro52
-rw-r--r--website/src/components/Sidebar.astro53
-rw-r--r--website/src/components/SiteLayout.astro223
-rw-r--r--website/src/components/SiteTitle.astro95
11 files changed, 0 insertions, 1256 deletions
diff --git a/website/src/components/AuthorCard.astro b/website/src/components/AuthorCard.astro
deleted file mode 100644
index ba3a1014..00000000
--- a/website/src/components/AuthorCard.astro
+++ /dev/null
@@ -1,30 +0,0 @@
----
-const name = 'Can Celik';
-const role = 'Building Herdr';
-const photo = '/assets/author-can.jpeg';
-const x = 'https://x.com/cancelik';
-const email = 'can@herdr.dev';
----
-
-<aside class="author-card" aria-label="About the author">
- <img class="author-photo" src={photo} width="72" height="72" alt={name} loading="lazy" decoding="async" />
- <div class="author-body">
- <p class="author-name">{name}</p>
- <p class="author-role">{role}</p>
- <div class="author-links">
- <a href={x} target="_blank" rel="me noopener" aria-label={`${name} on X`}>
- <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" fill="currentColor">
- <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
- </svg>
- <span>X</span>
- </a>
- <a href={`mailto:${email}`} aria-label={`Email ${name}`}>
- <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
- <rect x="2.5" y="4.5" width="19" height="15" rx="2" />
- <path d="m3 6 9 7 9-7" />
- </svg>
- <span>Email</span>
- </a>
- </div>
- </div>
-</aside>
diff --git a/website/src/components/Banner.astro b/website/src/components/Banner.astro
deleted file mode 100644
index cc6567a6..00000000
--- a/website/src/components/Banner.astro
+++ /dev/null
@@ -1,75 +0,0 @@
----
-import versions from '../data/docs-versions.json';
-import { docsRoute, docsTargetHref } from '../docs-path';
-
-const { entry, locale, isFallback } = Astro.locals.starlightRoute;
-const { banner } = entry.data;
-
-const issuesUrl = 'https://github.com/herdrdev/herdr/issues/new?template=translation.yml';
-const translationNotices = {
- ja: `このページの翻訳は LLM によって生成されています。誤りに気づいた場合は <a href="${issuesUrl}">GitHub で issue を開いて</a>お知らせください。`,
- 'zh-cn': `本页面的翻译由 LLM 生成。如果你发现翻译有误,请<a href="${issuesUrl}">在 GitHub 上提交 issue</a> 告诉我们。`,
-};
-const translationNotice = locale && !isFallback ? translationNotices[locale] : undefined;
-const docs = docsRoute(Astro.url.pathname);
-const archivedVersion =
- docs.target !== 'stable' && docs.target !== 'preview' && docs.target !== versions.current
- ? docs.target
- : undefined;
-const latestHref = docsTargetHref(docs, 'stable', versions.scopes);
-const archivedNotices = {
- root: `This page documents Herdr ${archivedVersion}. <a href="${latestHref}">Switch to the latest release.</a>`,
- ja: `このページは Herdr ${archivedVersion} のドキュメントです。<a href="${latestHref}">最新版に切り替えてください。</a>`,
- 'zh-cn': `本页面是 Herdr ${archivedVersion} 的文档。<a href="${latestHref}">切换到最新版本。</a>`,
-};
-const archivedNotice = archivedVersion ? archivedNotices[locale ?? 'root'] : undefined;
----
-
-{banner && <div class="sl-banner" data-pagefind-ignore set:html={banner.content} />}
-{archivedNotice && (
- <div class="version-notice" data-pagefind-ignore set:html={archivedNotice} />
-)}
-{translationNotice && (
- <div class="translation-notice" data-pagefind-ignore set:html={translationNotice} />
-)}
-
-<style>
- @layer starlight.core {
- .sl-banner {
- --__sl-banner-text: var(--sl-color-banner-text, var(--sl-color-text-invert));
- padding: var(--sl-nav-pad-y) var(--sl-nav-pad-x);
- background-color: var(--sl-color-banner-bg, var(--sl-color-bg-accent));
- color: var(--__sl-banner-text);
- line-height: var(--sl-line-height-headings);
- text-align: center;
- text-wrap: balance;
- box-shadow: var(--sl-shadow-sm);
- }
- .sl-banner :global(a) {
- color: var(--__sl-banner-text);
- }
-
- .translation-notice,
- .version-notice {
- padding: 0.5rem var(--sl-nav-pad-x);
- background-color: var(--sl-color-bg-nav);
- border-bottom: 1px solid var(--sl-color-hairline);
- color: var(--sl-color-gray-2);
- font-size: var(--sl-text-xs);
- line-height: var(--sl-line-height-headings);
- text-align: center;
- text-wrap: balance;
- }
- .version-notice {
- background-color: var(--sl-color-orange-low);
- border-bottom-color: var(--sl-color-orange);
- color: var(--sl-color-orange-high);
- }
- .translation-notice :global(a) {
- color: var(--sl-color-text-accent);
- }
- .version-notice :global(a) {
- color: var(--sl-color-orange-high);
- }
- }
-</style>
diff --git a/website/src/components/ConfigReference.astro b/website/src/components/ConfigReference.astro
deleted file mode 100644
index 33894993..00000000
--- a/website/src/components/ConfigReference.astro
+++ /dev/null
@@ -1,204 +0,0 @@
----
-import stableReference from '../data/config-reference.json';
-import previewReference from '../data/config-reference-preview.json';
-import versionReferences from '../data/config-reference-versions.json';
-import { docsVersion } from '../docs-path';
-
-interface Props {
- placeholder?: string;
- noMatches?: string;
- keyCountLabel?: string;
-}
-
-const {
- placeholder = 'filter keys, e.g. sidebar, prefix, sound…',
- noMatches = 'No keys match this filter.',
- keyCountLabel = 'keys',
-} = Astro.props;
-
-const version = docsVersion(Astro.url.pathname);
-const archivedReferences = versionReferences as Record<string, typeof stableReference>;
-const reference = version === 'preview'
- ? previewReference
- : version === 'stable'
- ? stableReference
- : archivedReferences[version];
-if (!reference) {
- throw new Error(`documentation version ${version} has no archived configuration reference`);
-}
-const totalKeys = reference.sections.reduce((sum, section) => sum + section.keys.length, 0);
----
-
-<div class="config-reference" data-count-label={keyCountLabel}>
- <div class="config-reference-controls">
- <input
- type="search"
- class="config-reference-filter"
- placeholder={placeholder}
- autocomplete="off"
- spellcheck="false"
- aria-label={placeholder}
- />
- <p class="config-reference-meta" aria-live="polite">{totalKeys} {keyCountLabel}</p>
- </div>
-
- {reference.sections.map((section) => (
- <section class="config-reference-section">
- <h2 class="config-reference-title" id={`ref-${section.id}`}>{section.title}</h2>
- <ul class="config-reference-list">
- {section.keys.map((entry) => (
- <li
- class="config-reference-row"
- data-search={`${entry.key} ${entry.description} ${(entry.values ?? []).join(' ')}`.toLowerCase()}
- >
- <div class="config-reference-head">
- <code class="config-reference-key">{entry.key}</code>
- <span class="config-reference-type">{entry.type}</span>
- {entry.default && (
- <span class="config-reference-default">
- default <code>{entry.default}</code>
- </span>
- )}
- </div>
- <p class="config-reference-desc">
- {entry.description}
- {entry.values && (
- <span class="config-reference-values">
- {entry.values.map((value) => (
- <code>{value}</code>
- ))}
- </span>
- )}
- </p>
- </li>
- ))}
- </ul>
- </section>
- ))}
-
- <p class="config-reference-empty" hidden>{noMatches}</p>
-</div>
-
-<style>
- .config-reference-controls {
- display: flex;
- align-items: baseline;
- gap: 1rem;
- margin-top: 1rem;
- }
-
- .config-reference-filter {
- flex: 1;
- font: inherit;
- font-family: var(--sl-font-mono);
- font-size: var(--sl-text-sm);
- color: var(--sl-color-white);
- background: var(--sl-color-bg-inline-code);
- border: 1px solid var(--sl-color-hairline-light);
- border-radius: 0.4rem;
- padding: 0.5rem 0.75rem;
- }
-
- .config-reference-filter:focus {
- outline: 2px solid var(--sl-color-accent);
- outline-offset: -1px;
- }
-
- .config-reference-meta {
- margin: 0;
- font-size: var(--sl-text-xs);
- color: var(--sl-color-gray-3);
- white-space: nowrap;
- }
-
- .config-reference-title {
- margin-top: 2rem;
- }
-
- .config-reference-list {
- list-style: none;
- padding: 0;
- margin: 0.75rem 0 0;
- }
-
- .config-reference-row {
- padding: 0.6rem 0;
- border-bottom: 1px solid var(--sl-color-hairline);
- }
-
- .config-reference-row[hidden] {
- display: none;
- }
-
- .config-reference-head {
- display: flex;
- flex-wrap: wrap;
- align-items: baseline;
- gap: 0.6rem;
- }
-
- .config-reference-key {
- font-weight: 600;
- }
-
- .config-reference-type {
- font-size: var(--sl-text-xs);
- color: var(--sl-color-gray-3);
- border: 1px solid var(--sl-color-hairline-light);
- border-radius: 0.3rem;
- padding: 0 0.35rem;
- }
-
- .config-reference-default {
- font-size: var(--sl-text-xs);
- color: var(--sl-color-gray-3);
- }
-
- .config-reference-desc {
- margin: 0.25rem 0 0;
- font-size: var(--sl-text-sm);
- color: var(--sl-color-gray-2);
- }
-
- .config-reference-values {
- display: inline-flex;
- flex-wrap: wrap;
- gap: 0.3rem;
- margin-inline-start: 0.4rem;
- }
-
- .config-reference-empty {
- margin-top: 1.5rem;
- color: var(--sl-color-gray-3);
- }
-</style>
-
-<script>
- for (const root of document.querySelectorAll('.config-reference')) {
- const filter = root.querySelector('.config-reference-filter');
- const meta = root.querySelector('.config-reference-meta');
- const empty = root.querySelector('.config-reference-empty');
- const sections = [...root.querySelectorAll('.config-reference-section')];
- const rows = [...root.querySelectorAll('.config-reference-row')];
- const countLabel = root.dataset.countLabel;
-
- filter?.addEventListener('input', () => {
- const terms = filter.value.trim().toLowerCase().split(/\s+/).filter(Boolean);
- let visible = 0;
-
- for (const row of rows) {
- const haystack = row.dataset.search ?? '';
- const match = terms.every((term) => haystack.includes(term));
- row.hidden = !match;
- if (match) visible += 1;
- }
-
- for (const section of sections) {
- section.hidden = !section.querySelector('.config-reference-row:not([hidden])');
- }
-
- if (meta) meta.textContent = `${visible} ${countLabel}`;
- if (empty) empty.hidden = visible > 0;
- });
- }
-</script>
diff --git a/website/src/components/DocsVersionSelect.astro b/website/src/components/DocsVersionSelect.astro
deleted file mode 100644
index 5ccd856c..00000000
--- a/website/src/components/DocsVersionSelect.astro
+++ /dev/null
@@ -1,84 +0,0 @@
----
-import versions from '../data/docs-versions.json';
-import { docsRoute, docsTargetHref } from '../docs-path';
-
-const route = docsRoute(Astro.url.pathname);
-const locale = route.locale ?? 'root';
-const labels = {
- root: { accessible: 'Documentation version', latest: 'Latest', preview: 'Preview' },
- ja: { accessible: 'ドキュメントのバージョン', latest: '最新', preview: 'プレビュー' },
- 'zh-cn': { accessible: '文档版本', latest: '最新', preview: '预览版' },
-}[locale];
-const scopes = versions.scopes;
----
-
-{route.isDocs && (
- <label class="docs-version-select">
- <span class="sr-only">{labels.accessible}</span>
- <select autocomplete="off" aria-label={labels.accessible}>
- <option
- value={docsTargetHref(route, 'stable', scopes)}
- selected={route.target === 'stable'}
- >
- {labels.latest}{' '}{versions.current}
- </option>
- <option
- value={docsTargetHref(route, 'preview', scopes)}
- selected={route.target === 'preview'}
- >
- {labels.preview}
- </option>
- {versions.versions
- .filter((entry) => entry.version !== versions.current || route.target === versions.current)
- .map((entry) => (
- <option
- value={docsTargetHref(route, entry.version, scopes)}
- selected={route.target === entry.version}
- >
- {entry.version}
- </option>
- ))}
- </select>
- </label>
-)}
-
-<script>
- for (const select of document.querySelectorAll<HTMLSelectElement>('.docs-version-select select')) {
- select.addEventListener('change', () => {
- globalThis.location.href = select.value;
- });
- }
-</script>
-
-<style>
- .docs-version-select {
- display: flex;
- min-width: 0;
- }
-
- select {
- width: 9.5rem;
- min-width: 0;
- border: 1px solid var(--sl-color-hairline);
- border-radius: 4px;
- padding: 0.4rem 1.6rem 0.4rem 0.55rem;
- background: var(--sl-color-bg-nav);
- color: var(--sl-color-gray-2);
- font: inherit;
- font-size: var(--sl-text-xs);
- font-weight: 700;
- text-overflow: ellipsis;
- }
-
- select:hover,
- select:focus {
- border-color: var(--sl-color-accent);
- color: var(--sl-color-accent-high);
- }
-
- @media (max-width: 38rem) {
- select {
- width: 7.5rem;
- }
- }
-</style>
diff --git a/website/src/components/Head.astro b/website/src/components/Head.astro
deleted file mode 100644
index dac83b81..00000000
--- a/website/src/components/Head.astro
+++ /dev/null
@@ -1,67 +0,0 @@
----
-import { docsVersion } from '../docs-path';
-
-const { head } = Astro.locals.starlightRoute;
-const version = docsVersion(Astro.url.pathname);
----
-
-{head.map(({ tag: Tag, attrs, content }) => <Tag {...attrs} set:html={content} />)}
-<meta data-pagefind-filter="version[content]" content={version} />
-{version !== 'stable' && <meta name="robots" content="noindex, nofollow" />}
-
-<script>
- const labels = (() => {
- const lang = document.documentElement.lang.toLowerCase();
- if (lang.startsWith('ja')) return { copy: 'リンクをコピー', copied: 'コピーしました' };
- if (lang.startsWith('zh')) return { copy: '复制链接', copied: '已复制' };
- return { copy: 'Copy link', copied: 'Copied' };
- })();
-
- function labelHeadingLinks(root: ParentNode = document) {
- for (const link of root.querySelectorAll<HTMLAnchorElement>('.sl-anchor-link')) {
- link.title = labels.copy;
- const section = link.querySelector('.sr-only')?.textContent;
- if (section) link.setAttribute('aria-label', `${labels.copy}: ${section}`);
- }
- }
-
- labelHeadingLinks();
- document.addEventListener('astro:page-load', () => labelHeadingLinks());
- document.addEventListener('click', async (event) => {
- if (
- event instanceof MouseEvent &&
- (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
- ) {
- return;
- }
-
- const target = event.target;
- if (!(target instanceof Element)) return;
- const link = target.closest('.sl-anchor-link');
- if (!(link instanceof HTMLAnchorElement) || !navigator.clipboard?.writeText) return;
-
- try {
- await navigator.clipboard.writeText(link.href);
- } catch {
- return;
- }
-
- link.querySelector('.heading-link-copy-feedback')?.remove();
- const feedback = document.createElement('span');
- feedback.className = 'heading-link-copy-feedback';
- feedback.setAttribute('aria-hidden', 'true');
- feedback.textContent = labels.copied;
- link.append(feedback);
- window.setTimeout(() => feedback.remove(), 1400);
-
- let status = document.querySelector<HTMLElement>('[data-heading-link-copy-status]');
- if (!status) {
- status = document.createElement('span');
- status.className = 'sr-only';
- status.setAttribute('role', 'status');
- status.dataset.headingLinkCopyStatus = '';
- document.body.append(status);
- }
- status.textContent = labels.copied;
- });
-</script>
diff --git a/website/src/components/Header.astro b/website/src/components/Header.astro
deleted file mode 100644
index cfa3d759..00000000
--- a/website/src/components/Header.astro
+++ /dev/null
@@ -1,99 +0,0 @@
----
-import config from 'virtual:starlight/user-config';
-
-import LanguageSelect from 'virtual:starlight/components/LanguageSelect';
-import Search from 'virtual:starlight/components/Search';
-import SiteTitle from 'virtual:starlight/components/SiteTitle';
-import SocialIcons from 'virtual:starlight/components/SocialIcons';
-import ThemeSelect from 'virtual:starlight/components/ThemeSelect';
-import DocsVersionSelect from './DocsVersionSelect.astro';
-import { docsRoute } from '../docs-path';
-
-const shouldRenderSearch =
- config.pagefind || config.components.Search !== '@astrojs/starlight/components/Search.astro';
-const isDocs = docsRoute(Astro.url.pathname).isDocs;
----
-
-<div class="header">
- <div class="title-wrapper sl-flex">
- <SiteTitle />
- </div>
- <div class="sl-flex print:hidden search-wrapper">
- {isDocs && <DocsVersionSelect />}
- {shouldRenderSearch && <Search />}
- </div>
- <div class="sl-hidden md:sl-flex print:hidden right-group">
- <div class="sl-flex social-icons">
- <SocialIcons />
- </div>
- <ThemeSelect />
- <LanguageSelect />
- </div>
-</div>
-
-<style>
- @layer starlight.core {
- .header {
- display: flex;
- gap: var(--sl-nav-gap);
- justify-content: space-between;
- align-items: center;
- height: 100%;
- }
-
- .title-wrapper {
- overflow: clip;
- padding: 0.25rem;
- margin: -0.25rem;
- min-width: 0;
- }
-
- .search-wrapper {
- align-items: center;
- gap: 0.75rem;
- min-width: 0;
- }
-
- .right-group,
- .social-icons {
- gap: 1rem;
- align-items: center;
- }
-
- .social-icons::after {
- content: "";
- height: 2rem;
- border-inline-end: 1px solid var(--sl-color-gray-5);
- }
-
- @media (min-width: 50rem) {
- :global(:root[data-has-sidebar]) {
- --__sidebar-pad: calc(2 * var(--sl-nav-pad-x));
- }
-
- :global(:root:not([data-has-toc])) {
- --__toc-width: 0rem;
- }
-
- .header {
- --__sidebar-width: max(0rem, var(--sl-content-inline-start, 0rem) - var(--sl-nav-pad-x));
- --__main-column-fr: calc(
- (
- 100% + var(--__sidebar-pad, 0rem) - var(--__toc-width, var(--sl-sidebar-width)) -
- (2 * var(--__toc-width, var(--sl-nav-pad-x))) - var(--sl-content-inline-start, 0rem) -
- var(--sl-content-width)
- ) / 2
- );
- display: grid;
- grid-template-columns:
- minmax(
- calc(var(--__sidebar-width) + max(0rem, var(--__main-column-fr) - var(--sl-nav-gap))),
- auto
- )
- 1fr
- auto;
- align-content: center;
- }
- }
- }
-</style>
diff --git a/website/src/components/MarketingLayout.astro b/website/src/components/MarketingLayout.astro
deleted file mode 100644
index 6db7e00d..00000000
--- a/website/src/components/MarketingLayout.astro
+++ /dev/null
@@ -1,274 +0,0 @@
----
-interface Props {
- title: string;
- description: string;
- canonicalPath: string;
- ogType?: 'website' | 'article';
- ogImage?: string;
- ogImageAlt?: string;
-}
-
-const {
- title,
- description,
- canonicalPath,
- ogType = 'website',
- ogImage = '/assets/og-card-v9.png',
- ogImageAlt = 'Herdr — run them anywhere, leave them running.',
-} = Astro.props;
-const canonicalUrl = new URL(canonicalPath, 'https://herdr.dev').toString();
-const ogImageUrl = new URL(ogImage, 'https://herdr.dev').toString();
----
-
-<!doctype html>
-<html lang="en">
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>{title}</title>
- <meta name="description" content={description} />
- <meta name="theme-color" content="#f0eee9" />
- <link rel="canonical" href={canonicalUrl} />
-
- <meta property="og:type" content={ogType} />
- <meta property="og:site_name" content="Herdr" />
- <meta property="og:title" content={title} />
- <meta property="og:description" content={description} />
- <meta property="og:url" content={canonicalUrl} />
- <meta property="og:image" content={ogImageUrl} />
- <meta property="og:image:width" content="1200" />
- <meta property="og:image:height" content="630" />
- <meta property="og:image:alt" content={ogImageAlt} />
-
- <meta name="twitter:card" content="summary_large_image" />
- <meta name="twitter:title" content={title} />
- <meta name="twitter:description" content={description} />
- <meta name="twitter:image" content={ogImageUrl} />
- <meta name="twitter:image:alt" content={ogImageAlt} />
-
- <link rel="icon" href="/favicon.ico" sizes="48x48" />
- <link rel="icon" type="image/png" sizes="192x192" href="/assets/favicon.png" />
- <link rel="apple-touch-icon" href="/assets/logo.png" />
- <link rel="preload" href="/assets/jbm.woff2" as="font" type="font/woff2" crossorigin />
- <script>
- (function () {
- var saved = localStorage.getItem("herdr-palette");
- var system = window.matchMedia("(prefers-color-scheme: dark)").matches
- ? "tokyo-night"
- : "tokyo-night-day";
- document.documentElement.setAttribute("data-palette", saved || system);
- })();
- </script>
- <link rel="stylesheet" href="/css/style.css?v=41" />
- </head>
- <body>
- <header class="site-header">
- <nav class="nav" aria-label="Primary navigation">
- <a class="brand" href="/" aria-label="Herdr home">
- <span class="brand-logo" aria-hidden="true"></span>
- <span>herdr</span>
- </a>
- <details class="nav-menu">
- <summary class="nav-menu-button" aria-label="Open navigation">
- <span></span>
- <span></span>
- <span></span>
- </summary>
- <div class="nav-menu-panel">
- <a href="/">Home</a>
- <a href="/compare/">Compare</a>
- <a href="/plugins/">Plugins</a>
- <a href="/blog/">Blog</a>
- <a href="/docs/quick-start/">Quick start</a>
- <a href="/docs/">Docs</a>
- <a href="/docs/socket-api/">API</a>
- <a href="/docs/install/">Install</a>
- <a href="https://github.com/herdrdev/herdr">GitHub</a>
- </div>
- </details>
- <div class="nav-links">
- <a href="/">Home</a>
- <a href="/compare/">Compare</a>
- <a href="/plugins/">Plugins</a>
- <a href="/blog/">Blog</a>
- <a href="/docs/quick-start/">Quick start</a>
- <a href="/docs/">Docs</a>
- <a href="/docs/socket-api/">API</a>
- </div>
- <div class="nav-tools">
- <a class="nav-icon-link" href="https://github.com/herdrdev/herdr" aria-label="Herdr on GitHub">
- <svg viewBox="0 0 16 16" aria-hidden="true">
- <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82A7.64 7.64 0 0 1 8 3.87c.68 0 1.36.09 2 .26 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z" />
- </svg>
- </a>
- <a class="nav-icon-link" href="https://x.com/herdrdev" aria-label="Herdr on X">
- <svg viewBox="0 0 24 24" aria-hidden="true">
- <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231Zm-1.161 17.52h1.833L7.084 4.126H5.117Z" />
- </svg>
- </a>
- <a class="nav-cta" href="/docs/install/">Install</a>
- </div>
- </nav>
- </header>
-
- <slot />
-
- <div class="theme-hint" id="theme-hint" title="Press / or t to switch theme">
- <span class="theme-hint-dot"></span>
- <span class="theme-hint-label" id="theme-hint-label">light</span>
- <span class="theme-hint-key">[/]</span>
- </div>
-
- <div class="theme-overlay" id="theme-overlay" hidden>
- <div class="theme-overlay-panel" role="dialog" aria-label="Theme switcher" aria-modal="true">
- <div class="theme-overlay-title">settings</div>
- <div class="theme-overlay-tabs"><span class="active">theme</span></div>
- <div class="theme-overlay-list" id="theme-overlay-list" role="listbox" aria-label="Themes">
- <div class="theme-sep"><span>dark</span></div>
- <button type="button" role="option" data-value="catppuccin">catppuccin</button>
- <button type="button" role="option" data-value="terminal">terminal</button>
- <button type="button" role="option" data-value="tokyo-night">tokyo night</button>
- <button type="button" role="option" data-value="dracula">dracula</button>
- <button type="button" role="option" data-value="nord">nord</button>
- <button type="button" role="option" data-value="gruvbox">gruvbox</button>
- <button type="button" role="option" data-value="one-dark">one dark</button>
- <button type="button" role="option" data-value="solarized">solarized</button>
- <button type="button" role="option" data-value="kanagawa">kanagawa</button>
- <button type="button" role="option" data-value="rose-pine">rose pine</button>
- <button type="button" role="option" data-value="vesper">vesper</button>
- <div class="theme-sep"><span>light</span></div>
- <button type="button" role="option" data-value="catppuccin-latte">catppuccin latte</button>
- <button type="button" role="option" data-value="tokyo-night-day">tokyo day</button>
- <button type="button" role="option" data-value="gruvbox-light">gruvbox light</button>
- <button type="button" role="option" data-value="one-light">one light</button>
- <button type="button" role="option" data-value="solarized-light">solarized light</button>
- <button type="button" role="option" data-value="kanagawa-lotus">kanagawa lotus</button>
- <button type="button" role="option" data-value="rose-pine-dawn">rose pine dawn</button>
- </div>
- <div class="theme-overlay-footer">
- <span class="theme-overlay-hints"><span class="key">↑↓</span> select</span>
- <span class="theme-overlay-actions"><span class="theme-apply-btn">↵ apply</span><button class="theme-close-btn" type="button" id="theme-close-btn">esc close</button></span>
- </div>
- </div>
- </div>
-
- <script>
- (function () {
- var overlay = document.getElementById("theme-overlay");
- var list = document.getElementById("theme-overlay-list");
- var hintLabel = document.getElementById("theme-hint-label");
- if (!overlay || !list) return;
- var options = Array.prototype.slice.call(list.querySelectorAll("[role='option']"));
- var media = window.matchMedia("(prefers-color-scheme: dark)");
- var saved = localStorage.getItem("herdr-palette") || "";
- var committed = saved || defaultPalette();
-
- function defaultPalette() {
- return media.matches ? "tokyo-night" : "tokyo-night-day";
- }
-
- function setPalette(value) {
- document.documentElement.setAttribute("data-palette", value || defaultPalette());
- }
-
- function updateUI(value) {
- var activeValue = value || defaultPalette();
- options.forEach(function (opt) {
- opt.setAttribute("aria-selected", String(opt.dataset.value === activeValue));
- });
- var active = options.find(function (opt) { return opt.dataset.value === activeValue; });
- if (hintLabel && active) hintLabel.textContent = active.textContent.trim();
- }
-
- function openOverlay() {
- overlay.hidden = false;
- document.body.style.overflow = "hidden";
- committed = localStorage.getItem("herdr-palette") || defaultPalette();
- updateUI(committed);
- var active = list.querySelector("[aria-selected='true']") || options[0];
- if (active) active.focus();
- }
-
- function closeOverlay() {
- overlay.hidden = true;
- document.body.style.overflow = "";
- }
-
- function toggleOverlay() {
- if (overlay.hidden) openOverlay();
- else closeOverlay();
- }
-
- function preview(index) {
- if (index < 0 || index >= options.length) return;
- setPalette(options[index].dataset.value);
- updateUI(options[index].dataset.value);
- options[index].focus();
- }
-
- function commit(value) {
- setPalette(value);
- localStorage.setItem("herdr-palette", value);
- updateUI(value);
- closeOverlay();
- }
-
- function revert() {
- setPalette(committed);
- updateUI(committed);
- closeOverlay();
- }
-
- media.addEventListener("change", function () {
- if (!localStorage.getItem("herdr-palette")) {
- setPalette("");
- updateUI("");
- }
- });
-
- options.forEach(function (opt, idx) {
- opt.addEventListener("click", function () { commit(opt.dataset.value); });
- opt.addEventListener("mouseenter", function () { preview(idx); });
- });
-
- document.addEventListener("keydown", function (e) {
- if ((e.key === "t" || e.key === "/") && !e.ctrlKey && !e.metaKey && !e.altKey) {
- var tag = document.activeElement && document.activeElement.tagName;
- if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
- e.preventDefault();
- toggleOverlay();
- return;
- }
- if (overlay.hidden) return;
- var idx = options.indexOf(document.activeElement);
- if (e.key === "ArrowDown") {
- e.preventDefault();
- preview(idx >= 0 ? Math.min(options.length - 1, idx + 1) : 0);
- } else if (e.key === "ArrowUp") {
- e.preventDefault();
- preview(idx >= 0 ? Math.max(0, idx - 1) : options.length - 1);
- } else if (e.key === "Enter" && idx >= 0) {
- e.preventDefault();
- commit(options[idx].dataset.value);
- } else if (e.key === "Escape") {
- e.preventDefault();
- revert();
- }
- });
-
- var themeHint = document.getElementById("theme-hint");
- if (localStorage.getItem("herdr-theme-hint-seen") === "1") {
- themeHint.classList.add("is-seen");
- }
- themeHint.addEventListener("mouseenter", function () {
- localStorage.setItem("herdr-theme-hint-seen", "1");
- themeHint.classList.add("is-seen");
- }, { once: true });
- themeHint.addEventListener("click", toggleOverlay);
- document.getElementById("theme-close-btn").addEventListener("click", revert);
- setPalette(saved);
- updateUI(saved);
- })();
- </script>
- </body>
-</html>
diff --git a/website/src/components/Search.astro b/website/src/components/Search.astro
deleted file mode 100644
index cceeed34..00000000
--- a/website/src/components/Search.astro
+++ /dev/null
@@ -1,52 +0,0 @@
----
-import StarlightSearch from '@astrojs/starlight/components/Search.astro';
-import { docsVersion } from '../docs-path';
-
-const version = docsVersion(Astro.url.pathname);
----
-
-<version-search data-version={version}>
- <StarlightSearch />
-</version-search>
-
-<script>
- class VersionSearch extends HTMLElement {
- observer?: MutationObserver;
-
- connectedCallback() {
- const version = this.dataset.version;
- if (!version) return;
-
- const selectVersion = () => {
- const checkbox = this.querySelector<HTMLInputElement>(
- `.pagefind-ui__filter-checkbox[name="version"][value="${version}"]`,
- );
- if (!checkbox) return false;
- if (!checkbox.checked) checkbox.click();
- this.observer?.disconnect();
- return true;
- };
-
- if (selectVersion()) return;
- // Starlight does not expose its PagefindUI instance, so wait for Pagefind's filter control.
- this.observer = new MutationObserver(selectVersion);
- this.observer.observe(this, { childList: true, subtree: true });
- }
-
- disconnectedCallback() {
- this.observer?.disconnect();
- }
- }
-
- customElements.define('version-search', VersionSearch);
-</script>
-
-<style>
- version-search {
- display: contents;
- }
-
- version-search :global(.pagefind-ui__filter-panel) {
- display: none;
- }
-</style>
diff --git a/website/src/components/Sidebar.astro b/website/src/components/Sidebar.astro
deleted file mode 100644
index 08d31f79..00000000
--- a/website/src/components/Sidebar.astro
+++ /dev/null
@@ -1,53 +0,0 @@
----
-import MobileMenuFooter from 'virtual:starlight/components/MobileMenuFooter';
-import SidebarPersister from '@astrojs/starlight/components/SidebarPersister.astro';
-import SidebarSublist from '@astrojs/starlight/components/SidebarSublist.astro';
-import versions from '../data/docs-versions.json';
-import { docsRoute, docsTargetHref } from '../docs-path';
-
-const { sidebar } = Astro.locals.starlightRoute;
-const pathname = Astro.url.pathname;
-const route = docsRoute(pathname);
-const scopedSidebar = route.target === 'stable' ? sidebar : rewriteSidebar(sidebar);
-
-function rewriteSidebar(entries) {
- return entries.flatMap((entry) => {
- if (entry.type === 'link') {
- const linkRoute = docsRoute(entry.href);
- if (!linkRoute.isDocs) return [entry];
- if (linkRoute.target !== 'stable') {
- return linkRoute.target === route.target
- ? [{ ...entry, isCurrent: samePath(entry.href, pathname) }]
- : [];
- }
-
- const localeKey = route.locale ?? 'root';
- const availablePages = versions.scopes[route.target]?.locales[localeKey] ?? [];
- if (!availablePages.includes(linkRoute.page)) return [];
-
- const href = docsTargetHref({ ...linkRoute, locale: route.locale }, route.target, versions.scopes);
- return [{ ...entry, href, isCurrent: samePath(href, pathname) }];
- }
-
- const rewrittenEntries = rewriteSidebar(entry.entries);
- if (rewrittenEntries.length === 0) return [];
- return [{ ...entry, entries: rewrittenEntries }];
- });
-}
-
-function samePath(left, right) {
- return stripTrailingSlash(left) === stripTrailingSlash(right);
-}
-
-function stripTrailingSlash(path) {
- return path.length > 1 ? path.replace(/\/$/, '') : path;
-}
----
-
-<SidebarPersister>
- <SidebarSublist sublist={scopedSidebar} />
-</SidebarPersister>
-
-<div class="md:sl-hidden">
- <MobileMenuFooter />
-</div>
diff --git a/website/src/components/SiteLayout.astro b/website/src/components/SiteLayout.astro
deleted file mode 100644
index f056458c..00000000
--- a/website/src/components/SiteLayout.astro
+++ /dev/null
@@ -1,223 +0,0 @@
----
-/* The chassis every non-docs page shares: one dark ground, the framed grid,
- the same nav and footer as the homepage. Pages supply their own <main>.
- Docs keep Starlight's shell and are themed through src/styles/starlight.css. */
-interface Props {
- title: string;
- description: string;
- canonicalPath: string;
- ogType?: 'website' | 'article';
- ogImage?: string;
- ogImageAlt?: string;
-}
-
-const {
- title,
- description,
- canonicalPath,
- ogType = 'website',
- ogImage = '/assets/og-card-v9.png',
- ogImageAlt = 'Herdr — run them anywhere, leave them running.',
-} = Astro.props;
-
-import { fmt, releaseVersion, siteStats } from '../site-data';
-
-const canonicalUrl = new URL(canonicalPath, 'https://herdr.dev').toString();
-const ogImageUrl = new URL(ogImage, 'https://herdr.dev').toString();
-const year = new Date().getFullYear();
-
-/* Same build-time source the homepage uses, so the nav count and the footer
- version agree across every page without being written down twice. */
-const { starCount } = await siteStats();
-const version = await releaseVersion();
-const facts = version ? `v${version} · Apache 2.0` : 'Apache 2.0';
----
-
-<!doctype html>
-<html lang="en" data-palette="catppuccin" data-mode="ink">
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>{title}</title>
- <meta name="description" content={description} />
- <meta name="theme-color" content="#17171a" />
- <link rel="canonical" href={canonicalUrl} />
-
- <meta property="og:type" content={ogType} />
- <meta property="og:site_name" content="Herdr" />
- <meta property="og:title" content={title} />
- <meta property="og:description" content={description} />
- <meta property="og:url" content={canonicalUrl} />
- <meta property="og:image" content={ogImageUrl} />
- <meta property="og:image:width" content="1200" />
- <meta property="og:image:height" content="630" />
- <meta property="og:image:alt" content={ogImageAlt} />
-
- <meta name="twitter:card" content="summary_large_image" />
- <meta name="twitter:title" content={title} />
- <meta name="twitter:description" content={description} />
- <meta name="twitter:image" content={ogImageUrl} />
- <meta name="twitter:image:alt" content={ogImageAlt} />
-
- <link rel="icon" href="/favicon.ico" sizes="48x48" />
- <link rel="icon" type="image/png" sizes="192x192" href="/assets/favicon.png" />
- <link rel="apple-touch-icon" href="/assets/logo.png" />
- <link rel="preload" href="/assets/jbm.woff2?v=2" as="font" type="font/woff2" crossorigin />
- <link rel="preconnect" href="https://fonts.googleapis.com" />
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
- <link
- href="https://fonts.googleapis.com/css2?family=Archivo:wght@600;800;900&family=Inter:wght@400;500;600&display=swap"
- rel="stylesheet"
- />
- <script is:inline>
- /* Ground selection, shared with the docs — see index.html for the
- reasoning. Starlight's `starlight-theme` key is the source of truth;
- `auto` is treated as dark so the default never follows the OS. */
- window.herdrGround = {
- read: function () {
- try {
- return localStorage.getItem('starlight-theme') === 'light' ? 'paper' : 'ink';
- } catch (e) {
- return 'ink';
- }
- },
- apply: function (mode) {
- var root = document.documentElement;
- root.setAttribute('data-mode', mode);
- root.setAttribute('data-palette', mode === 'paper' ? 'solarized-light' : 'catppuccin');
- return mode;
- },
- save: function (mode) {
- try {
- localStorage.setItem('starlight-theme', mode === 'paper' ? 'light' : 'dark');
- } catch (e) {}
- },
- };
- window.herdrGround.apply(window.herdrGround.read());
- </script>
- <link rel="stylesheet" href="/css/style.css?v=59" />
- <link rel="stylesheet" href="/css/site.css?v=64" />
- </head>
- <body class="site">
- <div class="hd-frame">
- <nav class="hd-nav">
- <a class="lock" href="/"><span class="ram"></span><b>herdr</b></a>
- <div class="sp"></div>
- <a class="lnk" href="/docs/">Docs</a>
- <a class="lnk" href="/plugins/">Plugins</a>
- <a class="lnk" href="/blog/">Blog</a>
- <a class="lnk" href="/compare/">Compare</a>
- <a class="ico wide" href="https://github.com/herdrdev/herdr" aria-label="Herdr on GitHub — star count">
- <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82A7.64 7.64 0 0 1 8 3.87c.68 0 1.36.09 2 .26 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z" /></svg>
- <b data-stars>{fmt(starCount)}</b>
- </a>
- <a class="ico" href="https://x.com/herdrdev" aria-label="Herdr on X">
- <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231Zm-1.161 17.52h1.833L7.084 4.126H5.117Z" /></svg>
- </a>
- <div class="mode">
- <button type="button" data-ground="ink" aria-pressed="true">ink</button>
- <button type="button" data-ground="paper" aria-pressed="false">paper</button>
- </div>
- <a class="btn" href="/docs/install/">Install</a>
- <button type="button" class="menu" id="nav-menu" aria-expanded="false" aria-controls="nav-sheet" aria-label="Menu">
- <span></span><span></span><span></span>
- </button>
- </nav>
-
- <div class="sheet" id="nav-sheet">
- <a href="/docs/">Docs</a>
- <a href="/plugins/">Plugins</a>
- <a href="/blog/">Blog</a>
- <a href="/compare/">Compare</a>
- <a href="https://x.com/herdrdev">@herdrdev</a>
- <div class="sheet-ground">
- <span>Ground</span>
- <div class="mode">
- <button type="button" data-ground="ink" aria-pressed="true">ink</button>
- <button type="button" data-ground="paper" aria-pressed="false">paper</button>
- </div>
- </div>
- </div>
-
- <slot />
-
- <footer class="foot">
- <span class="ram"></span>
- <a href="/docs/">docs</a>
- <a href="/plugins/">plugins</a>
- <a href="/blog/">blog</a>
- <a href="/compare/">compare</a>
- <span>built in the terminal · © {year} Herdr, Inc.</span>
- <span class="fact">{facts}</span>
- <span class="out">
- <a class="ico" href="https://github.com/herdrdev/herdr" aria-label="Herdr on GitHub">
- <svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82A7.64 7.64 0 0 1 8 3.87c.68 0 1.36.09 2 .26 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z" /></svg>
- </a>
- <a class="ico" href="https://x.com/herdrdev" aria-label="Herdr on X">
- <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231Zm-1.161 17.52h1.833L7.084 4.126H5.117Z" /></svg>
- </a>
- <a href="mailto:hey@herdr.dev">hey@herdr.dev</a>
- </span>
- </footer>
- </div>
-
- <script is:inline>
- (function () {
- var buttons = document.querySelectorAll('[data-ground]');
- function paint(mode) {
- window.herdrGround.apply(mode);
- buttons.forEach(function (b) {
- b.setAttribute('aria-pressed', String(b.dataset.ground === mode));
- });
- }
- buttons.forEach(function (b) {
- b.addEventListener('click', function () {
- window.herdrGround.save(b.dataset.ground);
- paint(b.dataset.ground);
- });
- });
- paint(window.herdrGround.read());
- })();
-
- /* nav sheet — the links, the account and the ground toggle that don't
- fit the bar on a phone */
- (function () {
- var btn = document.getElementById('nav-menu');
- var sheet = document.getElementById('nav-sheet');
- if (!btn || !sheet) return;
- function set(open) {
- sheet.classList.toggle('open', open);
- btn.setAttribute('aria-expanded', String(open));
- }
- btn.addEventListener('click', function (event) {
- event.stopPropagation();
- set(!sheet.classList.contains('open'));
- });
- /* the ground buttons live in the sheet, so a tap inside must not close
- it — only taps on the page behind do */
- document.addEventListener('click', function (event) {
- if (!sheet.contains(event.target)) set(false);
- });
- document.addEventListener('keydown', function (event) {
- if (event.key === 'Escape') set(false);
- });
- })();
-
- /* The nav count is baked at build, which can be a deploy behind. Refresh
- it from the same snapshot so the number is current on every page. No
- count-up here — this is chrome, not the argument the homepage makes. */
- fetch('https://assets.herdr.dev/stats/stats.json', { headers: { accept: 'application/json' } })
- .then(function (r) {
- return r.ok ? r.json() : null;
- })
- .then(function (d) {
- if (!d || !d.stars || typeof d.stars.total !== 'number') return;
- var text = d.stars.total.toLocaleString('en-US');
- document.querySelectorAll('[data-stars]').forEach(function (el) {
- el.textContent = text;
- });
- })
- .catch(function () {});
- </script>
- </body>
-</html>
diff --git a/website/src/components/SiteTitle.astro b/website/src/components/SiteTitle.astro
deleted file mode 100644
index 3e5af0a3..00000000
--- a/website/src/components/SiteTitle.astro
+++ /dev/null
@@ -1,95 +0,0 @@
----
-import { docsRoute } from '../docs-path';
-
-const { siteTitle, siteTitleHref, locale } = Astro.locals.starlightRoute;
-const route = docsRoute(Astro.url.pathname);
-const localePrefix = locale ? `/${locale}` : '';
-const targetSegment = route.target === 'stable' ? '' : `/${route.target}`;
-const docsHref = `${localePrefix}/docs${targetSegment}/`;
----
-
-<div class="title-row sl-flex">
- <a href={siteTitleHref} class="site-title sl-flex">
- <span class="docs-brand-logo" aria-hidden="true"></span>
- <span translate="no">{siteTitle}</span>
- </a>
- <nav class="title-nav" aria-label="Primary">
- <a href={docsHref}>Docs</a>
- <a href="/plugins/">Plugins</a>
- <a href="/blog/">Blog</a>
- </nav>
-</div>
-
-<style>
- @layer starlight.core {
- .title-row {
- align-items: center;
- gap: 1rem;
- min-width: 0;
- }
-
- .site-title {
- align-items: center;
- gap: 0.55rem;
- font-family: var(--sl-font-mono);
- font-size: var(--sl-text-h4);
- font-weight: 700;
- letter-spacing: -0.04em;
- color: var(--sl-color-white);
- text-decoration: none;
- white-space: nowrap;
- min-width: 0;
- transition: color 120ms ease;
- }
-
- .docs-brand-logo {
- position: relative;
- display: inline-block;
- width: 32px;
- height: 32px;
- flex: 0 0 auto;
- border: 1px solid var(--sl-color-hairline);
- border-radius: 4px;
- background: var(--sl-color-bg-nav);
- }
-
- .docs-brand-logo::before {
- content: "";
- position: absolute;
- inset: 2px;
- background: var(--sl-color-white);
- -webkit-mask: url("/assets/agent-icons/herdr-mask.svg") center / contain no-repeat;
- mask: url("/assets/agent-icons/herdr-mask.svg") center / contain no-repeat;
- }
-
- span:not(.docs-brand-logo) {
- overflow: hidden;
- }
-
- .title-nav {
- display: flex;
- align-items: baseline;
- gap: 0.75rem;
- font-size: var(--sl-text-sm);
- font-weight: 600;
- line-height: 1;
- }
-
- .title-nav a {
- color: var(--sl-color-white);
- text-decoration: none;
- transition: color 120ms ease;
- }
-
- .site-title:hover,
- .title-nav a:hover {
- color: var(--sl-color-accent-high);
- }
-
- @media (max-width: 35rem) {
- .title-nav {
- display: none;
- }
- }
- }
-</style>