"use client"; import * as React from "react"; import { Braces, Download, FileCode2, FileText, Printer, Text } from "lucide-react"; import { Button, type ButtonProps } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; import { ActionSheet, type ActionSheetItem } from "@/components/ui/sheet"; import { Tooltip } from "@/components/ui/tooltip"; import { useIsMobile } from "@/lib/client/hooks"; import { EXPORT_OPTIONS, exportConversation, type ClientExportFormat } from "./export"; export const EXPORT_ICONS: Record = { markdown: , txt: , json: , html: , pdf: , }; export interface ExportMenuProps { conversationId: string; /** Shown as the sheet title on phones. */ title?: string; /** Custom trigger; defaults to a ghost icon button with a tooltip. */ children?: React.ReactNode; align?: "start" | "center" | "end"; side?: "top" | "bottom" | "left" | "right"; size?: ButtonProps["size"]; variant?: ButtonProps["variant"]; className?: string; onExported?: (format: ClientExportFormat) => void; } /** * Export menu for a conversation — dropdown on desktop, ActionSheet on phones. * Used by the command palette; exported for the chat header (workstream A) and the sidebar. * * * */ export function ExportMenu({ conversationId, title, children, align = "end", side, size = "icon-sm", variant = "ghost", className, onExported }: ExportMenuProps) { const isMobile = useIsMobile(); const [open, setOpen] = React.useState(false); const [busy, setBusy] = React.useState(null); const run = async (format: ClientExportFormat) => { setBusy(format); try { await exportConversation(conversationId, format); onExported?.(format); } catch { /* toasted */ } finally { setBusy(null); } }; const trigger = children ?? ( ); if (isMobile) { const items: ActionSheetItem[] = EXPORT_OPTIONS.map((o) => ({ key: o.format, label: o.label, hint: o.hint, icon: EXPORT_ICONS[o.format], onSelect: () => void run(o.format) })); return ( <> {React.isValidElement<{ onClick?: React.MouseEventHandler }>(trigger) ? React.cloneElement(trigger, { onClick: () => setOpen(true) }) : setOpen(true)}>{trigger}} ); } return ( {trigger} Export {EXPORT_OPTIONS.slice(0, 4).map((o) => ( void run(o.format)}> {EXPORT_ICONS[o.format]} {o.label} {o.hint} ))} void run("pdf")}> {EXPORT_ICONS.pdf} PDF (print) Print dialog ); }