| 1 | import type { ReactNode } from "react"; |
| 2 | import { FileText, Folder, MessageSquare, X } from "lucide-react"; |
| 3 | import { Tooltip } from "./Tooltip"; |
| 4 | |
| 5 | type ComposerContextCardVariant = "attachment" | "workspace" | "session" | "selection"; |
| 6 | |
| 7 | export function ComposerContextCard({ |
| 8 | variant, |
| 9 | tooltipLabel, |
| 10 | removeLabel, |
| 11 | onRemove, |
| 12 | removeDisabled = false, |
| 13 | removeIconSize, |
| 14 | previewUrl, |
| 15 | onImageClick, |
| 16 | imageOnly = false, |
| 17 | folder = false, |
| 18 | name, |
| 19 | meta, |
| 20 | label, |
| 21 | icon, |
| 22 | }: { |
| 23 | variant: ComposerContextCardVariant; |
| 24 | tooltipLabel: ReactNode; |
| 25 | removeLabel: string; |
| 26 | onRemove: () => void; |
| 27 | removeDisabled?: boolean; |
| 28 | removeIconSize?: number; |
| 29 | previewUrl?: string; |
| 30 | /** called when the image thumbnail is clicked (only for image attachments with previewUrl) */ |
| 31 | onImageClick?: () => void; |
| 32 | imageOnly?: boolean; |
| 33 | folder?: boolean; |
| 34 | name?: string; |
| 35 | meta?: string; |
| 36 | label?: ReactNode; |
| 37 | icon?: ReactNode; |
| 38 | }) { |
| 39 | const variantClass = previewUrl |
| 40 | ? "composer-context__item--image" |
| 41 | : variant === "workspace" |
| 42 | ? `composer-context__item--workspace composer-context__item--${folder ? "folder" : "file"}` |
| 43 | : variant === "session" |
| 44 | ? "composer-context__item--session" |
| 45 | : variant === "selection" |
| 46 | ? "composer-context__item--selection composer-context__item--attachment" |
| 47 | : "composer-context__item--attachment"; |
| 48 | const iconNode = icon ?? (variant === "session" ? <MessageSquare size={15} /> : folder ? <Folder size={15} /> : <FileText size={15} />); |
| 49 | return ( |
| 50 | <div className={`composer-context__item ${variantClass}${imageOnly ? " composer-context__item--image-only" : ""}`}> |
| 51 | <Tooltip label={tooltipLabel}> |
| 52 | <span className="composer-context__label"> |
| 53 | {previewUrl ? ( |
| 54 | <span |
| 55 | className={`composer-context__thumb${onImageClick ? " composer-context__thumb--interactive" : ""}`} |
| 56 | onClick={onImageClick} |
| 57 | role={onImageClick ? "button" : undefined} |
| 58 | tabIndex={onImageClick ? 0 : undefined} |
| 59 | onKeyDown={onImageClick ? (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onImageClick(); } } : undefined} |
| 60 | > |
| 61 | <img src={previewUrl} alt="" draggable={false} /> |
| 62 | </span> |
| 63 | ) : variant === "attachment" || variant === "selection" ? ( |
| 64 | <> |
| 65 | <span className="composer-context__fileicon"> |
| 66 | {icon ?? <FileText size={20} />} |
| 67 | </span> |
| 68 | <span className="composer-context__main"> |
| 69 | <span className="composer-context__name">{name}</span> |
| 70 | {meta && <span className="composer-context__meta">{meta}</span>} |
| 71 | </span> |
| 72 | </> |
| 73 | ) : ( |
| 74 | <> |
| 75 | {iconNode} |
| 76 | <span>{label}</span> |
| 77 | </> |
| 78 | )} |
| 79 | </span> |
| 80 | </Tooltip> |
| 81 | <Tooltip label={removeLabel} className="composer-context__remove-trigger"> |
| 82 | <button |
| 83 | className="composer-context__remove" |
| 84 | type="button" |
| 85 | aria-label={removeLabel} |
| 86 | disabled={removeDisabled} |
| 87 | onClick={onRemove} |
| 88 | > |
| 89 | <X size={removeIconSize ?? (variant === "attachment" ? 14 : 13)} aria-hidden="true" /> |
| 90 | </button> |
| 91 | </Tooltip> |
| 92 | </div> |
| 93 | ); |
| 94 | } |
| 95 |