232 lines · 7.1 KB · TypeScript
RawDownload
import {  ArrowLeftIcon,  ChartNoAxesColumnIcon,  GitPullRequestIcon,  SettingsIcon,} from "lucide-react";import type { ReactNode } from "react";import { memo, useCallback } from "react";import { Link, useCanGoBack, useLocation, useNavigate } from "@tanstack/react-router"; import { useEnvironmentIdentificationMode } from "../../hooks/useSettings";import { cn } from "../../lib/utils";import { useEnvironments } from "../../state/environments";import { T3Wordmark } from "../T3Wordmark";import {  resolveEnvironmentIdentificationPillLabel,  resolveSidebarStageBackdropVariant,  resolveSidebarStageFocusRingOffsetClass,  SidebarStageBackdrop,  useEnvironmentStageLabel,} from "../SidebarStageBackdrop";import { Badge } from "../ui/badge";import {  SidebarFooter,  SidebarHeader,  SidebarMenu,  SidebarMenuButton,  SidebarMenuItem,  SidebarTrigger,  useSidebar,} from "../ui/sidebar";import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";import { readPullRequestListPreferences } from "../pullRequest/pullRequestListPreferences";import { SidebarProviderUpdatePill } from "./SidebarProviderUpdatePill";import { SidebarUpdateArchitectureWarning, SidebarUpdatePill } from "./SidebarUpdatePill"; export const SidebarChromeHeader = memo(function SidebarChromeHeader({  isElectron,}: {  isElectron: boolean;}) {  const stageLabel = useEnvironmentStageLabel();  const environmentIdentificationMode = useEnvironmentIdentificationMode();  const backdropVariant = resolveSidebarStageBackdropVariant(    stageLabel,    environmentIdentificationMode === "artwork",  );  const pillLabel =    environmentIdentificationMode === "pill"      ? resolveEnvironmentIdentificationPillLabel(stageLabel)      : null;   return (    <SidebarHeader      className={cn(        "@container/sidebar-header relative h-[var(--workspace-topbar-height)] shrink-0 flex-row items-center px-3 py-0 md:px-0",        isElectron && "drag-region",      )}    >      {backdropVariant ? <SidebarStageBackdrop variant={backdropVariant} /> : null}      <SidebarTrigger        className={cn(          "relative z-10 md:hidden",          backdropVariant &&            "focus-visible:ring-white/90 [&_svg]:stroke-white/90! [&_svg]:opacity-100! [&_svg]:hover:stroke-white! [:hover,[data-pressed]]:bg-white/15",          backdropVariant && resolveSidebarStageFocusRingOffsetClass(backdropVariant),        )}      />      <SidebarBrand onBackdrop={backdropVariant !== null} />      {pillLabel ? (        <Badge          className="relative z-10 ml-1 hidden rounded-full px-1.5 text-muted-foreground @[15rem]/sidebar-header:inline-flex"          data-environment-identification="pill"          size="sm"          variant="secondary"        >          {pillLabel}        </Badge>      ) : null}    </SidebarHeader>  );}); function SidebarBrand({ onBackdrop }: { onBackdrop: boolean }) {  return (    <Link      aria-label="Go to threads"      className={cn(        "relative z-10 ml-[var(--workspace-titlebar-content-left)] hidden h-7 w-fit min-w-0 shrink-0 items-center overflow-hidden rounded-md outline-hidden ring-ring focus-visible:ring-2 md:flex",        onBackdrop ? "text-white" : "text-foreground",      )}      to="/"    >      <span className="inline-flex min-w-0 items-baseline gap-1">        <T3Wordmark aria-label="T3" className="h-2.5 w-auto shrink-0" />        <span          className={cn(            "truncate text-sm font-medium tracking-tight",            onBackdrop ? "text-white/70" : "text-muted-foreground",          )}        >          Code        </span>      </span>    </Link>  );} function SidebarUtilityItem({  icon,  label,  onClick,}: {  icon: ReactNode;  label: string;  onClick: () => void;}) {  return (    <SidebarMenuItem className="shrink-0">      <Tooltip>        <TooltipTrigger          render={            <SidebarMenuButton aria-label={label} onClick={onClick} size="icon">              {icon}            </SidebarMenuButton>          }        />        <TooltipPopup side="top">{label}</TooltipPopup>      </Tooltip>    </SidebarMenuItem>  );} export const SidebarUtilityMenu = memo(function SidebarUtilityMenu() {  const navigate = useNavigate();  const canGoBack = useCanGoBack();  const { isMobile, setOpenMobile } = useSidebar();  const currentFooterPage = useLocation({    select: (location) =>      /^\/settings(?:\/|$)/.test(location.pathname)        ? "settings"        : /^\/projects\/[^/]+\/?$/.test(location.pathname)          ? "project-settings"          : location.pathname === "/usage"            ? "usage"            : location.pathname === "/pull-requests"              ? "pull-requests"              : null,  });  const { environments } = useEnvironments();  // The page reads every connected server, so one of them offering pull requests is enough for  // the link to lead somewhere.  const pullRequestsSupported = environments.some(    (environment) => environment.serverConfig?.environment.capabilities.pullRequests === true,  );  const closeMobileSidebar = useCallback(() => {    if (isMobile) {      setOpenMobile(false);    }  }, [isMobile, setOpenMobile]);  const handlePullRequestsClick = useCallback(() => {    closeMobileSidebar();    void navigate({      to: "/pull-requests",      search: readPullRequestListPreferences(),    });  }, [closeMobileSidebar, navigate]);  const handleSettingsClick = useCallback(() => {    closeMobileSidebar();    void navigate({ to: "/settings" });  }, [closeMobileSidebar, navigate]);   const handleUsageClick = useCallback(() => {    if (isMobile) {      setOpenMobile(false);    }    void navigate({ to: "/usage" });  }, [isMobile, navigate, setOpenMobile]);   const handleBackClick = useCallback(() => {    closeMobileSidebar();    if (canGoBack) {      window.history.back();      return;    }    void navigate({ to: "/" });  }, [canGoBack, closeMobileSidebar, navigate]);   return (    <SidebarMenu className="flex-row items-center">      {currentFooterPage ? (        <SidebarMenuItem className="min-w-0 flex-1">          <SidebarMenuButton onClick={handleBackClick}>            <ArrowLeftIcon />            <span>Back</span>          </SidebarMenuButton>        </SidebarMenuItem>      ) : (        <>          <SidebarUtilityItem            icon={<SettingsIcon />}            label="Settings"            onClick={handleSettingsClick}          />          {pullRequestsSupported ? (            <SidebarUtilityItem              icon={<GitPullRequestIcon />}              label="Pull Requests"              onClick={handlePullRequestsClick}            />          ) : null}          <SidebarUtilityItem            icon={<ChartNoAxesColumnIcon />}            label="Usage"            onClick={handleUsageClick}          />        </>      )}      <SidebarUpdatePill />    </SidebarMenu>  );}); export const SidebarChromeFooter = memo(function SidebarChromeFooter() {  return (    <SidebarFooter className="p-[var(--sidebar-content-inset)]">      <SidebarProviderUpdatePill />      <SidebarUpdateArchitectureWarning />      <SidebarUtilityMenu />    </SidebarFooter>  );});