marmar-context / web / context / src / clinician / shell / TopBar.tsx
TopBar.tsx
Raw
import { Button, cn, Icon, Kbd, Tip } from "../kit";
import { Link } from "../router";
import { useClinician } from "../session";
import { modKey } from "./nav";

export type Crumb = { label: string; to?: string };

/** Breadcrumbs, search and Lock now; on a phone, the button that opens the sidebar sheet. */
export function TopBar({ crumbs, menuOpen, onMenu, onSearch }: { crumbs: Crumb[]; menuOpen: boolean; onMenu: () => void; onSearch: () => void }) {
  const { lock } = useClinician();
  const mod = modKey();
  return (
    <header className="sticky top-0 z-30 flex h-14 items-center gap-2 bg-page/90 px-4 backdrop-blur-md md:h-[60px] md:rounded-t-[20px] md:px-5">
      <div className="flex min-w-0 flex-1 items-center gap-2">
        <Button variant="ghost" size="icon" className="-ml-1.5 md:hidden" aria-label="Open navigation" aria-expanded={menuOpen} onClick={onMenu}>
          <Icon name="menu-line" size={18} />
        </Button>
        <nav aria-label="Breadcrumb" className="flex min-w-0 items-center gap-2.5 text-[14px] leading-5">
          {crumbs.map((c, i) => {
            const last = i === crumbs.length - 1;
            return (
              <span key={i} className={cn("min-w-0 items-center gap-2.5", last ? "flex" : "hidden shrink-0 sm:flex")}>
                {i > 0 && (
                  <span aria-hidden="true" className={cn("text-line-strong", last && "hidden sm:inline")}>
                    /
                  </span>
                )}
                {c.to && !last ? (
                  <Link to={c.to} className="text-muted no-underline hover:text-ink">
                    {c.label}
                  </Link>
                ) : (
                  <span aria-current={last ? "page" : undefined} className={cn("truncate", last ? "font-medium text-[#27272a]" : "text-muted")}>
                    {c.label}
                  </span>
                )}
              </span>
            );
          })}
        </nav>
      </div>
      <button
        type="button"
        onClick={onSearch}
        aria-keyshortcuts="Meta+K Control+K"
        className="hidden h-9 w-[min(380px,36vw)] shrink-0 cursor-pointer items-center gap-2 rounded-[10px] border-0 bg-quiet px-3 text-left font-sans text-[13.5px] text-subtle transition-colors outline-none hover:bg-quiet-hover focus-visible:shadow-[0_0_0_2px_#fff,0_0_0_4px_var(--color-brand)] sm:flex"
      >
        <Icon name="search-line" size={16} />
        <span className="min-w-0 flex-1 truncate">Search patients and pages</span>
        <Kbd>{mod} K</Kbd>
      </button>
      <div className="flex items-center justify-end gap-1 sm:flex-1">
        <Button variant="ghost" size="icon" className="sm:hidden" aria-label="Search patients and pages" onClick={onSearch}>
          <Icon name="search-line" size={18} />
        </Button>
        <Tip label="Lock now" side="bottom">
          <Button variant="ghost" size="icon" aria-label="Lock Context now" onClick={lock}>
            <Icon name="lock-line" size={18} />
          </Button>
        </Tip>
      </div>
    </header>
  );
}