Vectrum
Sign In
68 lines · 2.6 KB · TypeScript
import { cache } from "react";
import Link from "next/link";
import { listReposForUser } from "@/lib/repos";
import { SIGNUPS_ENABLED } from "@/lib/signups";
import type { Theme } from "@/lib/theme";
import type { User } from "@/lib/users";
import { BRAND, Logo, LogoMark } from "./brand";
import { PlusIcon } from "./icons";
import { NavLinks } from "./nav-links";
import { SearchBox } from "./search-box";
import { AppSidebar, MobileNav } from "./sidebar-nav";
import { ButtonLink } from "./ui";

// The sidebar and the search box both list them; one query per request.
const sidebarRepos = cache(async (viewerId: string) =>
  (await listReposForUser(viewerId)).map((r) => ({ owner: r.owner, name: r.name, imageVersion: r.imageVersion })),
);

const viewerOf = (viewer: User) => ({ username: viewer.username, name: viewer.name });

/** Left rail for signed-in users: account menu, places and repository shortcuts. */
export async function SiteSidebar({ viewer, theme }: { viewer: User; theme: Theme }) {
  return <AppSidebar viewer={viewerOf(viewer)} repos={await sidebarRepos(viewer.id)} theme={theme} />;
}

/** Thin bar above the sheet for signed-in users. On small screens it also carries the navigation. */
export async function TopBar({ viewer }: { viewer: User }) {
  return (
    <header className="flex h-14 shrink-0 items-center gap-2 px-3 lg:pl-1">
      <div className="flex items-center gap-2 lg:hidden">
        <MobileNav viewer={viewerOf(viewer)} />
        <Link href="/" aria-label={`${BRAND.name} home`} className="rounded-lg transition hover:opacity-80">
          <LogoMark size={22} />
        </Link>
      </div>

      <div className="ml-auto flex items-center gap-2.5">
        <SearchBox repos={await sidebarRepos(viewer.id)} signedIn />
        <ButtonLink href="/new" variant="primary" icon={<PlusIcon />}>
          New
        </ButtonLink>
      </div>
    </header>
  );
}

/** Header for signed-out visitors. */
export function SiteHeader() {
  return (
    <header className="flex h-14 shrink-0 items-center gap-3 px-3 md:px-4">
      <Link href="/" aria-label={`${BRAND.name} home`} className="rounded-lg transition hover:opacity-80">
        <Logo size={22} />
      </Link>
      <div className="ml-auto flex items-center gap-2">
        <SearchBox />
        <NavLinks links={[{ href: "/explore", label: "Explore" }]} />
        <ButtonLink href="/login" variant="invisible">
          Sign In
        </ButtonLink>
        {SIGNUPS_ENABLED && (
          <ButtonLink href="/signup" variant="primary">
            Create Account
          </ButtonLink>
        )}
      </div>
    </header>
  );
}