Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 14 additions & 24 deletions src/components/search/search-trigger.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
"use client";

import { Search } from "lucide-react";
import { useSyncExternalStore } from "react";
import { useSearch } from "@/components/search/search-provider";

const emptySubscribe = () => () => {};

function readIsMac(): boolean {
if (typeof navigator === "undefined") return false;
const p = navigator.platform || navigator.userAgent;
return /Mac|iPhone|iPad|iPod/i.test(p);
}

type Props = {
/**
* - `desktop`: inline pill-ish button next to "GitHub" / theme toggle
* in the desktop nav. Hidden below md.
* - `desktop`: wide input-style pill shown in the desktop nav. Reads
* visually as a real search field (light surface, rounded, full
* width within its container) so users discover the feature without
* needing the keyboard shortcut.
* - `mobile`: 44×44 icon-only square sized to the same min-tap target
* as the hamburger. Hidden at md+.
*/
Expand All @@ -24,38 +17,35 @@ type Props = {

export function SearchTrigger({ variant }: Props) {
const { open } = useSearch();
// Read once on the client. SSR snapshot is `false` so we render the
// Ctrl variant; the client snapshot replaces it on hydration if the
// platform actually is macOS. Avoids the set-state-in-effect lint
// and stays consistent with how ThemeToggle reads the DOM.
const isMac = useSyncExternalStore(emptySubscribe, readIsMac, () => false);

if (variant === "mobile") {
return (
<button
type="button"
onClick={open}
aria-label="Open search"
className="md:hidden inline-flex items-center justify-center min-h-[44px] min-w-[44px] rounded text-ink-muted hover:text-ink transition-colors"
className="md:hidden inline-flex items-center justify-center min-h-[44px] min-w-[44px] rounded-md text-ink-muted hover:text-ink transition-colors"
>
<Search size={20} aria-hidden />
</button>
);
}

const shortcut = isMac ? "⌘K" : "Ctrl K";
// Input-look trigger. Soft surface + rule border so the affordance
// reads as a text field even though it actually opens the cmdk modal.
// No platform-specific shortcut hint: ⌘K is wrong on Windows/Linux,
// Ctrl K is wrong on Mac, and a dynamic swap creates hydration
// flicker for two-character gain. Shortcut still works, just not
// advertised in the chrome.
return (
<button
type="button"
onClick={open}
aria-label="Open search"
className="inline-flex items-center gap-1.5 text-ink-muted hover:text-ink transition-colors"
className="group inline-flex items-center gap-2 w-full max-w-[440px] h-9 px-3 rounded-md border border-rule bg-paper-soft text-left text-sm text-ink-faint hover:border-rule-strong hover:text-ink-muted hover:bg-paper transition-colors"
>
<Search size={15} aria-hidden />
<span>Search</span>
<span className="ml-1 inline-flex items-center rounded border border-rule px-1 py-[1px] text-[10px] font-medium uppercase tracking-[0.12em] text-ink-faint tabular">
{shortcut}
</span>
<Search size={15} aria-hidden className="shrink-0" />
<span className="truncate">Search benchmarks, products…</span>
</button>
);
}
26 changes: 12 additions & 14 deletions src/components/site-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,6 @@ export function SiteHeader() {
return () => mql.removeEventListener("change", onChange);
}, [open]);

// Close the mobile menu on route change so a tap on a nav item collapses
// the drawer without the consumer having to wire onClick on every link.
useEffect(() => {
setOpen(false);
}, [pathname]);

return (
<div
// Sticky everywhere by default. Only iOS in-app WebViews (Telegram,
Expand All @@ -77,8 +71,8 @@ export function SiteHeader() {
className="site-header-root sticky top-0 z-50 flex flex-col font-sans bg-surface/95 backdrop-blur supports-[backdrop-filter]:bg-surface/80"
>
<header className="border-b border-rule px-4 sm:px-6 shrink-0 text-sm relative">
<div className="max-w-[1400px] mx-auto flex items-center justify-between gap-3 h-14 md:h-16">
<div className="flex items-center gap-2">
<div className="max-w-[1400px] mx-auto flex items-center gap-4 lg:gap-6 h-14 md:h-16">
<div className="flex items-center gap-2 shrink-0">
<SiteLogoSwitcher size={22} />
<Link
href="/"
Expand All @@ -91,10 +85,10 @@ export function SiteHeader() {
</Link>
</div>

{/* Center nav - CMC-style: underline under the active section.
{/* Nav links - CMC-style: underline under the active section.
Items keep a constant pb to avoid layout shift between
active / inactive states. */}
<nav className="hidden md:flex items-center h-full gap-7 text-[15px] font-medium">
<nav className="hidden md:flex items-center h-full gap-5 lg:gap-7 text-[14px] lg:text-[15px] font-medium shrink-0">
{NAV.map((item) => {
const active = item.match(pathname);
return (
Expand All @@ -103,7 +97,7 @@ export function SiteHeader() {
href={item.href}
aria-current={active ? "page" : undefined}
className={[
"relative flex items-center h-full transition-colors",
"relative flex items-center h-full transition-colors whitespace-nowrap",
active
? "text-ink"
: "text-ink-muted hover:text-ink",
Expand All @@ -121,10 +115,14 @@ export function SiteHeader() {
})}
</nav>

{/* Right utilities - search + github + theme. No separator pipe;
the gap-based spacing handles visual grouping. */}
<div className="hidden md:flex items-center gap-5 text-ink-muted">
{/* Search takes the remaining horizontal space (flex-1) so it
reads as a real input and discoverable without keyboard. */}
<div className="hidden md:flex flex-1 min-w-0 justify-end lg:justify-center">
<SearchTrigger variant="desktop" />
</div>

{/* Utilities - GitHub + theme, gap-spaced, no pipe. */}
<div className="hidden md:flex items-center gap-4 text-ink-muted shrink-0">
<a
href="https://github.com/ChainBench/OpenChainBench"
className="inline-flex items-center hover:text-ink transition-colors"
Expand Down
Loading