ShellPage's JSX carried the whole sidebar inline, including two near-copies of the group header and of the main header's sidebar toggles, which made the render hard to follow and easy to change in one place only. Move-only: the sidebar header, group header (one component for the conversation and project variants), the team and project roster rows, the archived section, the user menu and the sidebar toggle buttons now live in pages/shell. DOM, classNames, test ids, aria attributes, handlers and messages are unchanged; the catalogs only update their file references, and the desktop source checks for the header toggles now read the file they moved to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
119 lines
3.8 KiB
TypeScript
119 lines
3.8 KiB
TypeScript
import { useLingui } from "@lingui/react/macro";
|
|
import type { Bot } from "@rakazo/contracts";
|
|
import { Popover, PopoverContent, PopoverTrigger, Wordmark } from "@rakazo/ui-web";
|
|
import { Bell } from "lucide-react";
|
|
import { WindowChrome } from "../WindowChrome";
|
|
import { BotCreatePicker } from "./bot-picker";
|
|
|
|
/** Window chrome, wordmark, the activity toggle and the create menu atop the sidebar. */
|
|
export function SidebarHeader({
|
|
activityMode,
|
|
onToggleActivityMode,
|
|
createMenuOpen,
|
|
onCreateMenuOpenChange,
|
|
onCloseMobileSidebar,
|
|
bots,
|
|
onCreateBot,
|
|
onOpenBot,
|
|
onCreateGroup,
|
|
onCreateSpace,
|
|
onShowGroupInfo,
|
|
onShowSpaceInfo,
|
|
}: {
|
|
activityMode: boolean;
|
|
onToggleActivityMode: () => void;
|
|
createMenuOpen: boolean;
|
|
onCreateMenuOpenChange: (open: boolean) => void;
|
|
onCloseMobileSidebar: () => void;
|
|
bots: Bot[];
|
|
onCreateBot: () => void;
|
|
onOpenBot: (id: string) => void;
|
|
onCreateGroup: () => void;
|
|
onCreateSpace: () => void;
|
|
onShowGroupInfo: () => void;
|
|
onShowSpaceInfo: () => void;
|
|
}) {
|
|
const { t } = useLingui();
|
|
return (
|
|
<div className="app-drag flex items-center justify-between px-4 lg:px-6 2xl:px-8 pb-3 pt-4">
|
|
<WindowChrome />
|
|
<div className="flex-1 px-1">
|
|
<Wordmark />
|
|
</div>
|
|
<div className="relative flex items-center gap-2.5">
|
|
<button
|
|
type="button"
|
|
aria-label={t`Activity`}
|
|
aria-pressed={activityMode}
|
|
title={t`Activity`}
|
|
data-activity-mode={activityMode ? "on" : "off"}
|
|
onClick={onToggleActivityMode}
|
|
className={`app-no-drag flex size-control-sm items-center justify-center rounded-full ${
|
|
activityMode
|
|
? "bg-primary text-primary-foreground"
|
|
: "rk-sidebar-muted hover:text-foreground/75"
|
|
}`}
|
|
>
|
|
<Bell
|
|
strokeWidth={1.8}
|
|
fill={activityMode ? "currentColor" : "none"}
|
|
aria-hidden="true"
|
|
className="size-icon-md"
|
|
/>
|
|
</button>
|
|
|
|
<Popover open={createMenuOpen} onOpenChange={onCreateMenuOpenChange}>
|
|
<PopoverTrigger
|
|
className="app-no-drag text-[21px] rk-sidebar-muted hover:text-foreground/75"
|
|
title={t`Create`}
|
|
data-testid="create-menu-trigger"
|
|
>
|
|
+
|
|
</PopoverTrigger>
|
|
{/* Unmount with the state change so the panel it opens never coexists with the menu. */}
|
|
{createMenuOpen ? (
|
|
<PopoverContent
|
|
align="end"
|
|
className="app-no-drag w-auto gap-0 overflow-hidden p-0 data-closed:animate-none"
|
|
>
|
|
<BotCreatePicker
|
|
bots={bots}
|
|
onCreateBot={() => {
|
|
onCreateMenuOpenChange(false);
|
|
onCloseMobileSidebar();
|
|
onCreateBot();
|
|
}}
|
|
onOpenBot={(id) => {
|
|
onCreateMenuOpenChange(false);
|
|
onCloseMobileSidebar();
|
|
onOpenBot(id);
|
|
}}
|
|
onCreateGroup={() => {
|
|
onCreateMenuOpenChange(false);
|
|
onCloseMobileSidebar();
|
|
onCreateGroup();
|
|
}}
|
|
onCreateSpace={() => {
|
|
onCreateMenuOpenChange(false);
|
|
onCloseMobileSidebar();
|
|
onCreateSpace();
|
|
}}
|
|
onShowGroupInfo={() => {
|
|
onCreateMenuOpenChange(false);
|
|
onCloseMobileSidebar();
|
|
onShowGroupInfo();
|
|
}}
|
|
onShowSpaceInfo={() => {
|
|
onCreateMenuOpenChange(false);
|
|
onCloseMobileSidebar();
|
|
onShowSpaceInfo();
|
|
}}
|
|
/>
|
|
</PopoverContent>
|
|
) : null}
|
|
</Popover>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|