mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
1ef24d3e91
* add initial backend service code for devui * add tests * add frontendcode * ui updates * update readme * ui updates and tweaks * update ui bundle * improve ui, add react flow base * add react flow ui, fix background * update ui, fix introspection bug * update readme * update ui build * add support for multimodal input - both backend and frontend * update ui build * refactor as main framework package * backend and tests refactor * ui build update * ui build update and refactor * update pyproject.toml, update uv.lock * update ui build * ui update to fit oai responses types * add backend updat and readme update * mypy and other fixes * add intial dev guide * update ui and fix workflow bug * update ui build, add thread support * type fixes * update workflow view * update uv.lock * fix workflow iport errors * lint and other fixes * mypy fixes * minor update * update ui build * refactor to use oai dependencies directly, update examples to samples, improve typing * readme update * update ui and ui build * fix workflow pyright error * update ui, fix issues with run workflow placement, miniamp menu, etc * make samples integrate serve --------- Co-authored-by: Chris <66376200+crickman@users.noreply.github.com> Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
115 lines
3.3 KiB
TypeScript
115 lines
3.3 KiB
TypeScript
/**
|
|
* AttachmentGallery - Shows uploaded files with thumbnails and remove options
|
|
*/
|
|
|
|
import { useState } from "react";
|
|
import { FileText, Image, Trash2 } from "lucide-react";
|
|
|
|
export interface AttachmentItem {
|
|
id: string;
|
|
file: File;
|
|
preview?: string; // Data URL for preview
|
|
type: "image" | "pdf" | "other";
|
|
}
|
|
|
|
interface AttachmentGalleryProps {
|
|
attachments: AttachmentItem[];
|
|
onRemoveAttachment: (id: string) => void;
|
|
className?: string;
|
|
}
|
|
|
|
export function AttachmentGallery({
|
|
attachments,
|
|
onRemoveAttachment,
|
|
className = "",
|
|
}: AttachmentGalleryProps) {
|
|
if (attachments.length === 0) return null;
|
|
|
|
return (
|
|
<div className={`flex flex-wrap gap-2 p-2 bg-muted rounded-lg ${className}`}>
|
|
{attachments.map((attachment) => (
|
|
<AttachmentPreview
|
|
key={attachment.id}
|
|
attachment={attachment}
|
|
onRemove={() => onRemoveAttachment(attachment.id)}
|
|
/>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface AttachmentPreviewProps {
|
|
attachment: AttachmentItem;
|
|
onRemove: () => void;
|
|
}
|
|
|
|
function AttachmentPreview({ attachment, onRemove }: AttachmentPreviewProps) {
|
|
const [isHovered, setIsHovered] = useState(false);
|
|
|
|
const renderPreview = () => {
|
|
switch (attachment.type) {
|
|
case "image":
|
|
return attachment.preview ? (
|
|
<img
|
|
src={attachment.preview}
|
|
alt={attachment.file.name}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
) : (
|
|
<div className="flex items-center justify-center w-full h-full bg-gray-200">
|
|
<Image className="h-6 w-6 text-gray-400" />
|
|
</div>
|
|
);
|
|
|
|
case "pdf":
|
|
return (
|
|
<div className="flex flex-col items-center justify-center w-full h-full bg-red-50">
|
|
<FileText className="h-6 w-6 text-red-500 mb-1" />
|
|
<span className="text-xs text-red-600">PDF</span>
|
|
</div>
|
|
);
|
|
|
|
default:
|
|
return (
|
|
<div className="flex flex-col items-center justify-center w-full h-full bg-gray-100">
|
|
<FileText className="h-6 w-6 text-gray-500 mb-1" />
|
|
<span className="text-xs text-gray-600">FILE</span>
|
|
</div>
|
|
);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className="relative w-16 h-16 rounded border overflow-hidden group cursor-pointer"
|
|
onMouseEnter={() => setIsHovered(true)}
|
|
onMouseLeave={() => setIsHovered(false)}
|
|
title={attachment.file.name}
|
|
>
|
|
{renderPreview()}
|
|
|
|
{/* Dark overlay with centered delete icon on hover */}
|
|
<div
|
|
className={`absolute inset-0 bg-black/60 flex items-center justify-center transition-all duration-200 ease-in-out ${
|
|
isHovered
|
|
? 'opacity-100 backdrop-blur-sm'
|
|
: 'opacity-0 pointer-events-none'
|
|
}`}
|
|
onClick={onRemove}
|
|
>
|
|
<div className={`transition-all duration-200 ease-in-out ${
|
|
isHovered
|
|
? 'scale-100 opacity-100'
|
|
: 'scale-75 opacity-0'
|
|
}`}>
|
|
<Trash2 className="h-5 w-5 text-white drop-shadow-lg" />
|
|
</div>
|
|
</div>
|
|
|
|
{/* File name tooltip */}
|
|
<div className="absolute bottom-0 left-0 right-0 bg-black bg-opacity-75 text-white text-xs p-1 truncate opacity-0 group-hover:opacity-100 transition-opacity duration-200">
|
|
{attachment.file.name}
|
|
</div>
|
|
</div>
|
|
);
|
|
} |