aboutsummaryrefslogtreecommitdiff
path: root/website/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-27 00:33:25 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-27 00:33:25 +0300
commit61bec49572358259f7e98e37c2f8cdfda423ed5d (patch)
tree0a1d42cee6c1ff26f72069df77867fda32ef5396 /website/src
parentcfffe6599e4f82f89af4f9b36487793226f54dfe (diff)
feat: refactor website homepage
Diffstat (limited to 'website/src')
-rw-r--r--website/src/components/SiteTitle.astro77
-rw-r--r--website/src/content/docs/index.mdx2
-rw-r--r--website/src/pages/compare.astro175
-rw-r--r--website/src/styles/starlight.css149
4 files changed, 297 insertions, 106 deletions
diff --git a/website/src/components/SiteTitle.astro b/website/src/components/SiteTitle.astro
index 04839c38..ee979e9d 100644
--- a/website/src/components/SiteTitle.astro
+++ b/website/src/components/SiteTitle.astro
@@ -1,37 +1,11 @@
---
-import { logos } from 'virtual:starlight/user-images';
-import config from 'virtual:starlight/user-config';
-
const { siteTitle, siteTitleHref } = Astro.locals.starlightRoute;
---
<div class="title-row sl-flex">
<a href={siteTitleHref} class="site-title sl-flex">
- {
- config.logo && logos.dark && (
- <>
- <img
- class:list={{ 'light:sl-hidden print:hidden': !('src' in config.logo) }}
- alt={config.logo.alt}
- src={logos.dark.src}
- width={logos.dark.width}
- height={logos.dark.height}
- />
- {!('src' in config.logo) && (
- <img
- class="dark:sl-hidden print:block"
- alt={config.logo.alt}
- src={logos.light?.src}
- width={logos.light?.width}
- height={logos.light?.height}
- />
- )}
- </>
- )
- }
- <span class:list={{ 'sr-only': config.logo?.replacesTitle }} translate="no">
- {siteTitle}
- </span>
+ <span class="docs-brand-logo" aria-hidden="true"></span>
+ <span translate="no">{siteTitle}</span>
</a>
<nav class="title-nav" aria-label="Primary">
<a href="/docs/">Docs</a>
@@ -41,32 +15,47 @@ const { siteTitle, siteTitleHref } = Astro.locals.starlightRoute;
<style>
@layer starlight.core {
.title-row {
- align-items: baseline;
+ align-items: center;
gap: 1rem;
min-width: 0;
}
.site-title {
- align-items: baseline;
- gap: var(--sl-nav-gap);
+ align-items: center;
+ gap: 0.55rem;
+ font-family: var(--sl-font-mono);
font-size: var(--sl-text-h4);
- font-weight: 600;
- color: var(--sl-color-text-accent);
+ 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;
}
- span {
- overflow: hidden;
+ .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);
}
- img {
- height: calc(var(--sl-nav-height) - 2 * var(--sl-nav-pad-y));
- width: auto;
- max-width: 100%;
- object-fit: contain;
- object-position: 0 50%;
+ .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 {
@@ -79,15 +68,11 @@ const { siteTitle, siteTitleHref } = Astro.locals.starlightRoute;
}
.title-nav a {
- color: var(--sl-color-text-accent);
+ color: var(--sl-color-white);
text-decoration: none;
transition: color 120ms ease;
}
- .site-title {
- transition: color 120ms ease;
- }
-
.site-title:hover,
.title-nav a:hover {
color: var(--sl-color-accent-high);
diff --git a/website/src/content/docs/index.mdx b/website/src/content/docs/index.mdx
index fd7e9ecb..20ea24af 100644
--- a/website/src/content/docs/index.mdx
+++ b/website/src/content/docs/index.mdx
@@ -5,7 +5,7 @@ template: splash
hero:
tagline: "One terminal for the whole herd: real panes, persistent sessions, SSH attach, state awareness, and CLI/socket orchestration."
image:
- file: ../../../public/assets/logo.svg
+ html: '<span class="docs-hero-logo" aria-hidden="true"></span>'
actions:
- text: Install Herdr
link: /docs/install/
diff --git a/website/src/pages/compare.astro b/website/src/pages/compare.astro
index 531c2c19..2baf7b30 100644
--- a/website/src/pages/compare.astro
+++ b/website/src/pages/compare.astro
@@ -8,7 +8,7 @@
name="description"
content="Compare Herdr with tmux, Zellij, cmux, Warp, Solo, Conductor, Emdash, and Superset. See where terminal multiplexers, agent terminals, process dashboards, and worktree orchestrators differ."
/>
- <meta name="theme-color" content="#f7f3ea" />
+ <meta name="theme-color" content="#f0eee9" />
<link rel="canonical" href="https://herdr.dev/compare/" />
<meta property="og:type" content="website" />
@@ -36,13 +36,22 @@
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon.png?v=14" />
<link rel="apple-touch-icon" href="/assets/logo.png" />
<link rel="preload" href="/assets/jbm.woff2" as="font" type="font/woff2" crossorigin />
- <link rel="stylesheet" href="/css/style.css?v=compare1" />
+ <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=compare2" />
</head>
<body>
<header class="site-header">
<nav class="nav" aria-label="Primary navigation">
<a class="brand" href="/" aria-label="Herdr home">
- <img class="brand-logo" src="/assets/logo.svg" alt="" />
+ <span class="brand-logo" aria-hidden="true"></span>
<span>herdr</span>
</a>
<div class="nav-links">
@@ -250,7 +259,7 @@
<footer class="footer">
<a class="brand" href="/" aria-label="Herdr home">
- <img class="brand-logo" src="/assets/logo.svg" alt="" />
+ <span class="brand-logo" aria-hidden="true"></span>
<span>herdr</span>
</a>
<div>
@@ -262,5 +271,163 @@
<a href="mailto:hey@herdr.dev">hey@herdr.dev</a>
</div>
</footer>
+
+ <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/styles/starlight.css b/website/src/styles/starlight.css
index 1120e31b..0747bcc4 100644
--- a/website/src/styles/starlight.css
+++ b/website/src/styles/starlight.css
@@ -14,88 +14,124 @@
--sl-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
--sl-content-width: 54rem;
--sl-sidebar-width: 18.5rem;
- --sl-color-accent-low: #123c37;
- --sl-color-accent: #42cabb;
- --sl-color-accent-high: #d9fff8;
- --sl-color-white: #f8fbff;
- --sl-color-gray-1: #e8edf2;
- --sl-color-gray-2: #c7d0d9;
- --sl-color-gray-3: #93a0ad;
- --sl-color-gray-4: #62707f;
- --sl-color-gray-5: #34404c;
- --sl-color-gray-6: #202833;
- --sl-color-black: #10151c;
- --sl-color-bg: #10151c;
- --sl-color-bg-nav: #151b23;
- --sl-color-bg-sidebar: #151b23;
- --sl-color-bg-inline-code: #202833;
- --sl-color-hairline: #25303b;
- --sl-color-hairline-light: #34404c;
+}
+
+:root,
+:root[data-theme="dark"] {
+ --sl-color-accent-low: #26314f;
+ --sl-color-accent: #7aa2f7;
+ --sl-color-accent-high: #a9c2ff;
+ --sl-color-white: #d5dcff;
+ --sl-color-gray-1: #c0caf5;
+ --sl-color-gray-2: #a9b1d6;
+ --sl-color-gray-3: #737aa2;
+ --sl-color-gray-4: #565f89;
+ --sl-color-gray-5: #414868;
+ --sl-color-gray-6: #2f3549;
+ --sl-color-gray-7: #24283b;
+ --sl-color-black: #1a1b26;
+ --sl-color-bg: #1a1b26;
+ --sl-color-bg-nav: #202331;
+ --sl-color-bg-sidebar: #202331;
+ --sl-color-bg-inline-code: #24283b;
+ --sl-color-hairline: #2f3549;
+ --sl-color-hairline-light: #414868;
}
:root[data-theme="light"] {
- --sl-color-accent-low: #d7f1ed;
- --sl-color-accent: #1f6f68;
- --sl-color-accent-high: #0f3f3b;
- --sl-color-white: #151a21;
- --sl-color-gray-1: #26313c;
- --sl-color-gray-2: #40505d;
- --sl-color-gray-3: #687381;
- --sl-color-gray-4: #8d989f;
- --sl-color-gray-5: #d4cabd;
- --sl-color-gray-6: #eee7dc;
- --sl-color-gray-7: #f7f3ea;
- --sl-color-black: #fffdf8;
- --sl-color-bg: #f7f3ea;
- --sl-color-bg-nav: #fffdf8;
- --sl-color-bg-sidebar: #fffdf8;
- --sl-color-bg-inline-code: #eee7dc;
- --sl-color-hairline: #ded6c8;
- --sl-color-hairline-light: #c9bdad;
+ --sl-color-accent-low: #c4c8da;
+ --sl-color-accent: #2e7de9;
+ --sl-color-accent-high: #1f2f66;
+ --sl-color-white: #1f2f66;
+ --sl-color-gray-1: #3760bf;
+ --sl-color-gray-2: #68709a;
+ --sl-color-gray-3: #8990b3;
+ --sl-color-gray-4: #a8aecb;
+ --sl-color-gray-5: #b6bbd1;
+ --sl-color-gray-6: #c4c8da;
+ --sl-color-gray-7: #d8d9e0;
+ --sl-color-black: #e1e2e7;
+ --sl-color-bg: #e1e2e7;
+ --sl-color-bg-nav: #d8d9e0;
+ --sl-color-bg-sidebar: #d8d9e0;
+ --sl-color-bg-inline-code: #c4c8da;
+ --sl-color-hairline: #b6bbd1;
+ --sl-color-hairline-light: #a8aecb;
}
.site-title {
font-family: var(--sl-font-mono);
- font-weight: 800;
+ font-weight: 700;
letter-spacing: -0.04em;
}
+.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;
+}
+
+.docs-hero-logo {
+ display: block;
+ width: min(20rem, 62vw);
+ aspect-ratio: 1;
+ 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;
+}
+
.sl-markdown-content {
font-size: 1rem;
- line-height: 1.75;
+ line-height: 1.65;
}
.sl-markdown-content h1,
.hero h1 {
- letter-spacing: -0.055em;
- line-height: 0.98;
- font-size: clamp(2.4rem, 5vw, 4.2rem);
+ letter-spacing: -0.03em;
+ line-height: 1.1;
+ font-weight: 400;
+ font-size: clamp(2rem, 5vw, 3.2rem);
+ font-family: var(--sl-font-mono);
}
.sl-markdown-content h2 {
- margin-top: 2.6rem;
- letter-spacing: -0.035em;
+ margin-top: 2.4rem;
+ letter-spacing: -0.02em;
+ font-family: var(--sl-font-mono);
+ font-weight: 400;
}
.sl-markdown-content h3 {
- letter-spacing: -0.025em;
+ letter-spacing: -0.01em;
+ font-family: var(--sl-font-mono);
+ font-weight: 400;
}
.sl-markdown-content > p:first-child {
- font-size: 1.08rem;
+ font-size: 1.05rem;
color: var(--sl-color-gray-1);
}
#starlight__sidebar a[aria-current="page"] {
- background: color-mix(in srgb, var(--sl-color-accent) 13%, transparent);
+ background: color-mix(in srgb, var(--sl-color-accent) 8%, transparent);
color: var(--sl-color-accent-high);
box-shadow: inset 2px 0 0 var(--sl-color-accent);
}
-:root[data-theme="light"] #starlight__sidebar a[aria-current="page"] {
- color: var(--sl-color-accent-high);
-}
-
.mobile-doc-shots {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
@@ -111,7 +147,7 @@
display: block;
width: 100%;
border: 1px solid var(--sl-color-hairline);
- border-radius: 1rem;
+ border-radius: 4px;
}
.mobile-doc-shots figcaption {
@@ -124,17 +160,19 @@
.sl-markdown-content a:not(:where(.not-content *)) {
text-decoration-thickness: 1px;
text-underline-offset: 0.18em;
+ color: var(--sl-color-accent);
}
.sl-markdown-content code:not(:where(.not-content *)) {
border: 1px solid var(--sl-color-hairline);
- border-radius: 0.35rem;
+ border-radius: 2px;
font-size: 0.88em;
+ background: var(--sl-color-bg-inline-code);
}
.sl-markdown-content pre {
border: 1px solid var(--sl-color-hairline);
- border-radius: 0.85rem;
+ border-radius: 4px;
}
.expressive-code {
@@ -143,7 +181,7 @@
.expressive-code .frame {
border: 1px solid var(--sl-color-hairline) !important;
- border-radius: 0.85rem !important;
+ border-radius: 4px !important;
box-shadow: none !important;
overflow: hidden;
}
@@ -169,8 +207,9 @@
.sl-markdown-content .card {
border-color: var(--sl-color-hairline);
background:
- linear-gradient(180deg, color-mix(in srgb, var(--sl-color-accent) 5%, transparent), transparent 58%),
+ linear-gradient(180deg, color-mix(in srgb, var(--sl-color-accent) 4%, transparent), transparent 58%),
var(--sl-color-black);
+ border-radius: 4px;
}
.sl-markdown-content .card .title {
@@ -179,5 +218,5 @@
.hero img {
image-rendering: auto;
- filter: drop-shadow(0 20px 50px rgb(31 111 104 / 0.18));
+ border-radius: 4px;
}