Files
Jyotisha/frontend/src/components/sidebar-session-row.tsx
T

121 lines
3.9 KiB
TypeScript

"use client";
import {
Archive,
ArchiveRestore,
MoreHorizontal,
Pencil,
Pin,
PinOff,
Share2,
Trash2,
} from "lucide-react";
import { forwardRef } from "react";
import { SidebarMenuButton } from "@/components/ui/sidebar";
export type SidebarSession = {
readonly id: string;
readonly title: string;
readonly messageCount: number;
readonly pinned: boolean;
readonly archived: boolean;
};
export type SidebarSessionControls = {
readonly archivedCount: number;
readonly showingArchived: boolean;
readonly menuSessionId: string | null;
readonly disabled: boolean;
readonly onToggleArchivedView: () => void;
readonly onMenuSessionChange: (sessionId: string | null) => void;
readonly onTogglePinned: (sessionId: string) => void;
readonly onRename: (sessionId: string) => void;
readonly onShare: (sessionId: string) => void;
readonly onToggleArchived: (sessionId: string) => void;
readonly onDelete: (sessionId: string) => void;
};
type SidebarSessionRowProps = {
readonly session: SidebarSession;
readonly active: boolean;
readonly disabled: boolean;
readonly menuOpen: boolean;
readonly onMenuOpenChange: (open: boolean) => void;
readonly onSelect: () => void;
readonly onTogglePinned: () => void;
readonly onRename: () => void;
readonly onShare: () => void;
readonly onToggleArchived: () => void;
readonly onDelete: () => void;
};
export const SidebarSessionRow = forwardRef<HTMLButtonElement, SidebarSessionRowProps>(function SidebarSessionRow({
session,
active,
disabled,
menuOpen,
onMenuOpenChange,
onSelect,
onTogglePinned,
onRename,
onShare,
onToggleArchived,
onDelete,
}, ref) {
function runAction(action: () => void) {
onMenuOpenChange(false);
action();
}
return (
<div
className="session-row"
onContextMenu={(event) => {
event.preventDefault();
if (!disabled) onMenuOpenChange(!menuOpen);
}}
>
<SidebarMenuButton
ref={ref}
className="session-main"
type="button"
isActive={active}
aria-current={active ? "page" : undefined}
disabled={disabled}
onClick={onSelect}
>
<span className="session-title">
{session.pinned ? <Pin aria-label="已置顶" /> : null}
<span className="truncate">{session.title}</span>
</span>
{session.messageCount > 0 ? <small>{session.messageCount} </small> : null}
</SidebarMenuButton>
<button
className="session-menu-trigger"
type="button"
aria-label={`${session.title} 更多操作`}
aria-expanded={menuOpen}
disabled={disabled}
onClick={() => onMenuOpenChange(!menuOpen)}
>
<MoreHorizontal aria-hidden="true" />
</button>
{menuOpen ? (
<div className="session-actions" role="menu" aria-label={`${session.title} 操作`}>
<button type="button" role="menuitem" onClick={() => runAction(onTogglePinned)}>
{session.pinned ? <PinOff aria-hidden="true" /> : <Pin aria-hidden="true" />}
<span>{session.pinned ? "取消置顶" : "置顶"}</span>
</button>
<button type="button" role="menuitem" onClick={() => runAction(onRename)}><Pencil aria-hidden="true" /><span></span></button>
<button type="button" role="menuitem" onClick={() => runAction(onShare)}><Share2 aria-hidden="true" /><span></span></button>
<button type="button" role="menuitem" onClick={() => runAction(onToggleArchived)}>
{session.archived ? <ArchiveRestore aria-hidden="true" /> : <Archive aria-hidden="true" />}
<span>{session.archived ? "恢复" : "归档"}</span>
</button>
<button className="session-action-danger" type="button" role="menuitem" onClick={() => runAction(onDelete)}><Trash2 aria-hidden="true" /><span></span></button>
</div>
) : null}
</div>
);
});