'use client'
import * as React from 'react'
import { cn } from '../../utils/cn'
import {
Chevron02LeftIcon,
Ellipsis01Icon,
ClockHistoryIcon,
Refresh01LeftIcon,
SearchIcon,
} from '../icons-v2-generated'
import { XmarkIcon } from '../icons-v2-generated/signs-and-symbols/xmark-icon'
import { ChatHeaderIconButton } from './chat-header-icon-button'
import { ChatHeaderSearchField } from './chat-header-search-field'
import { ActionsMenuDropdown, type ActionsMenuItem } from '../ui/actions-menu'
import { ChatPanelHeaderMobile } from './chat-panel-header-mobile'
import { SquareAvatar } from '../ui/square-avatar'
export interface ChatPanelHeaderProps {
/** Show the back-chevron + bold (h3) title. When false, the static list
* title (h4) is shown with no back affordance. */
showBack?: boolean
/** Title text (next to the back chevron, or the static list title). */
title: string
/** Optional sub-line under the title (e.g. the signed-in user's name).
* Rendered muted (`h6`) beneath the title in every view that has one. */
subtitle?: React.ReactNode
/** Person identity shown as a 32px round avatar at the right edge of the
* title cell (Figma 113:63273): the dialog OWNER in a conversation, the
* signed-in user on the New Chat compose view. Initials fall back from
* `name` when `avatarUrl` is absent/failing. Omit to hide. */
avatar?: { name?: string | null; avatarUrl?: string | null }
/** Accessible label for the back chevron. */
backAriaLabel?: string
/** The open conversation is an archived chat (read-only). */
isArchivedView?: boolean
/** Back-chevron handler. Required only when `showBack` — the list view has no
* back affordance. */
onBack?: () => void
/** Close the panel. */
onClose: () => void
/** Restore/unarchive — renders the refresh button (archived view only). */
onRestore?: () => void
/** Rename — adds the "Rename chat" item to the ⋯ menu. */
onRename?: () => void
/** Archive — adds the "Archive chat" item to the ⋯ menu. */
onArchive?: () => void
/** Copy a shareable link to the open conversation — adds the "Copy chat link"
* item to the ⋯ menu. The host owns the URL and the copy. */
onCopyLink?: () => void
/** Open the Chat Archive page — renders the clock button (list view only). */
onOpenArchive?: () => void
/** Force the COMPACT (`h-14` desktop-style) bar at every width, skipping the
* full-screen mobile header. For EMBEDDED surfaces (e.g. a small preview
* panel) where the phone-sized full-bleed header (large `text-h2` title) is
* wrong regardless of viewport. Default false = viewport-responsive. */
compact?: boolean
/** Toggle the dialog-list search field — renders a magnifier button (list
* view only), before the archive clock. */
onToggleSearch?: () => void
/** Whether the search field is currently open. When true (and `onSearchChange`
* is wired) the title area is REPLACED in place by the inline search field
* and the magnifier toggle is hidden. */
searchActive?: boolean
/** Seeds the inline search field when it opens (current search term). */
searchQuery?: string
/** Emits the debounced search term from the inline field. Enables the
* in-header search experience (list view only). */
onSearchChange?: (query: string) => void
}
/**
* Chat panel top-navigation (Figma node 7363:205930). One bar across the
* list / active-conversation / archived-conversation / guide views: a
* back-chevron + title (or the static list title), then state-dependent
* right-hand actions (restore, ⋯ rename/archive, archive entry) and close.
*/
export function ChatPanelHeader({
showBack = false,
title,
subtitle,
avatar,
backAriaLabel = 'Back',
isArchivedView = false,
onBack,
onClose,
onRestore,
onRename,
onArchive,
onCopyLink,
onOpenArchive,
compact = false,
onToggleSearch,
searchActive = false,
searchQuery,
onSearchChange,
}: ChatPanelHeaderProps) {
// Search open (with a wired handler) swaps the title for the inline field.
const searchInline = searchActive && !!onSearchChange
// Desktop ⋯ menu (active, non-archived conversation only) — rename / archive.
const menuItems = [
onCopyLink && { id: 'copy-link', label: 'Copy chat link', onClick: onCopyLink },
onRename && { id: 'rename', label: 'Rename chat', onClick: onRename },
onArchive && { id: 'archive', label: 'Archive chat', onClick: onArchive },
].filter(Boolean) as ActionsMenuItem[]
return (
<>
{/* Mobile (
{title}
{subtitle && ({subtitle}
)}