126 lines
No EOL
3.5 KiB
TypeScript
126 lines
No EOL
3.5 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect, useRef, useCallback } from "react";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export interface ChatSectionHeaderProps {
|
|
title: string;
|
|
isExpanded: boolean;
|
|
onToggle: () => void;
|
|
onAdd?: () => void;
|
|
onMore?: () => void;
|
|
className?: string;
|
|
}
|
|
|
|
export function ChatSectionHeader({
|
|
title,
|
|
isExpanded,
|
|
onToggle,
|
|
onAdd,
|
|
onMore,
|
|
className = "",
|
|
}: ChatSectionHeaderProps) {
|
|
const disclosureButtonRef = useRef<HTMLButtonElement>(null);
|
|
|
|
const handleDisclosureClick = useCallback(() => {
|
|
onToggle();
|
|
}, [onToggle]);
|
|
|
|
const handleAddClick = useCallback((e: React.MouseEvent) => {
|
|
e.stopPropagation();
|
|
onAdd && onAdd();
|
|
}, [onAdd]);
|
|
|
|
const handleMoreClick = useCallback((e: React.MouseEvent) => {
|
|
e.stopPropagation();
|
|
onMore && onMore();
|
|
}, [onMore]);
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"flex items-center justify-between py-2 px-3 border-b border-sidebar-border bg-background/30",
|
|
"hover:bg-background/5 transition-colors",
|
|
className
|
|
)}
|
|
>
|
|
<div className="flex items-center space-x-2">
|
|
<button
|
|
ref={disclosureButtonRef}
|
|
type="button"
|
|
onClick={handleDisclosureClick}
|
|
className={cn(
|
|
"flex items-center justify-center w-6 h-6 rounded",
|
|
"hover:bg-accent focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500",
|
|
"transition-colors"
|
|
)}
|
|
aria-expanded={isExpanded}
|
|
aria-label={isExpanded ? "Collapse section" : "Expand section"}
|
|
>
|
|
{isExpanded ? (
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
className="h-4 w-4"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="2"
|
|
d="M19 9l-7 7-7-7"
|
|
/>
|
|
</svg>
|
|
) : (
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
className="h-4 w-4"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="2"
|
|
d="M4 6h16M4 12h16M4 18h16"
|
|
/>
|
|
</svg>
|
|
)}
|
|
</button>
|
|
<span className="font-medium text-sm text-foreground">{title}</span>
|
|
</div>
|
|
<div className="flex items-center space-x-1">
|
|
{onAdd && (
|
|
<button
|
|
type="button"
|
|
onClick={handleAddClick}
|
|
className={cn(
|
|
"inline-flex items-center px-2 py-0.5 text-xs font-medium rounded",
|
|
"text-indigo-600 hover:bg-indigo-600 hover:text-white",
|
|
"focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500",
|
|
"transition-colors"
|
|
)}
|
|
>
|
|
Add
|
|
</button>
|
|
)}
|
|
{onMore && (
|
|
<button
|
|
type="button"
|
|
onClick={handleMoreClick}
|
|
className={cn(
|
|
"inline-flex items-center px-2 py-0.5 text-xs font-medium rounded",
|
|
"text-gray-500 hover:bg-accent hover:text-foreground",
|
|
"focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500",
|
|
"transition-colors"
|
|
)}
|
|
>
|
|
⋯
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
} |