diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-27 00:33:25 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-27 00:33:25 +0300 |
| commit | 61bec49572358259f7e98e37c2f8cdfda423ed5d (patch) | |
| tree | 0a1d42cee6c1ff26f72069df77867fda32ef5396 /website/src | |
| parent | cfffe6599e4f82f89af4f9b36487793226f54dfe (diff) | |
feat: refactor website homepage
Diffstat (limited to 'website/src')
| -rw-r--r-- | website/src/components/SiteTitle.astro | 77 | ||||
| -rw-r--r-- | website/src/content/docs/index.mdx | 2 | ||||
| -rw-r--r-- | website/src/pages/compare.astro | 175 | ||||
| -rw-r--r-- | website/src/styles/starlight.css | 149 |
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; } |
