94 lines
2.8 KiB
TypeScript
94 lines
2.8 KiB
TypeScript
import type { StreamParticle } from "@/api/types";
|
|
import { getParticleData } from "@/api/types";
|
|
import {
|
|
MessageSquare,
|
|
Video,
|
|
Mic,
|
|
ScrollText,
|
|
BookOpen,
|
|
FileIcon,
|
|
FolderIcon,
|
|
} from "lucide-react";
|
|
|
|
interface ParticlePreviewProps {
|
|
particle: StreamParticle;
|
|
}
|
|
|
|
export function ParticlePreview({ particle }: ParticlePreviewProps) {
|
|
switch (particle.type) {
|
|
case "text": {
|
|
const data = getParticleData(particle, "text");
|
|
return (
|
|
<div className="flex items-start gap-2">
|
|
<MessageSquare className="text-muted-foreground mt-0.5 h-3.5 w-3.5 shrink-0" />
|
|
<p className="text-muted-foreground line-clamp-2 text-xs">
|
|
{data.content}
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|
|
case "media": {
|
|
const data = getParticleData(particle, "media");
|
|
const isVideo = data.mime_type.startsWith("video");
|
|
const Icon = isVideo ? Video : Mic;
|
|
const label = isVideo ? "Video" : "Audio";
|
|
const seconds = Math.round(data.duration_ms / 1000);
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<Icon className="text-muted-foreground h-3.5 w-3.5 shrink-0" />
|
|
<span className="text-muted-foreground text-xs">
|
|
{label} · {seconds}s
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|
|
case "quest": {
|
|
const data = getParticleData(particle, "quest");
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<ScrollText className="text-muted-foreground h-3.5 w-3.5 shrink-0" />
|
|
<span className="text-muted-foreground truncate text-xs">
|
|
{data.title}
|
|
{data.status && ` · ${data.status}`}
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|
|
case "paper": {
|
|
const data = getParticleData(particle, "paper");
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<BookOpen className="text-muted-foreground h-3.5 w-3.5 shrink-0" />
|
|
<span className="text-muted-foreground truncate text-xs">
|
|
{data.title}
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|
|
case "file": {
|
|
const data = getParticleData(particle, "file");
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<FileIcon className="text-muted-foreground h-3.5 w-3.5 shrink-0" />
|
|
<span className="text-muted-foreground truncate text-xs">
|
|
{data.filename}
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|
|
case "folder": {
|
|
const data = getParticleData(particle, "folder");
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<FolderIcon className="text-muted-foreground h-3.5 w-3.5 shrink-0" />
|
|
<span className="text-muted-foreground truncate text-xs">
|
|
{data.name}
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|
|
default:
|
|
return null;
|
|
}
|
|
}
|