style: fresh look on media panel

This commit is contained in:
Maze Winther
2025-07-01 00:13:41 +02:00
parent 1fa4c9c72f
commit d11d835c7c

View File

@ -10,6 +10,12 @@ import { toast } from "sonner";
import { AspectRatio } from "../ui/aspect-ratio"; import { AspectRatio } from "../ui/aspect-ratio";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import { DragOverlay } from "../ui/drag-overlay"; import { DragOverlay } from "../ui/drag-overlay";
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
} from "../ui/context-menu";
// MediaPanel lets users add, view, and drag media (images, videos, audio) into the project. // MediaPanel lets users add, view, and drag media (images, videos, audio) into the project.
// You can upload files or drag them from your computer. Dragging from here to the timeline adds them to your video project. // You can upload files or drag them from your computer. Dragging from here to the timeline adds them to your video project.
@ -131,23 +137,22 @@ export function MediaPanel() {
if (item.type === "image") { if (item.type === "image") {
return ( return (
<img <div className="w-full h-full flex items-center justify-center">
src={item.url} <img
alt={item.name} src={item.url}
className="w-full h-full object-contain rounded cursor-grab active:cursor-grabbing" alt={item.name}
loading="lazy" className="max-w-full max-h-full object-contain rounded"
{...baseDragProps} loading="lazy"
/> {...baseDragProps}
/>
</div>
); );
} }
if (item.type === "video") { if (item.type === "video") {
if (item.thumbnailUrl) { if (item.thumbnailUrl) {
return ( return (
<div <div className="relative w-full h-full" {...baseDragProps}>
className="relative w-full h-full cursor-grab active:cursor-grabbing"
{...baseDragProps}
>
<img <img
src={item.thumbnailUrl} src={item.thumbnailUrl}
alt={item.name} alt={item.name}
@ -167,7 +172,7 @@ export function MediaPanel() {
} }
return ( return (
<div <div
className="w-full h-full bg-muted/30 flex flex-col items-center justify-center text-muted-foreground rounded cursor-grab active:cursor-grabbing" className="w-full h-full bg-muted/30 flex flex-col items-center justify-center text-muted-foreground rounded"
{...baseDragProps} {...baseDragProps}
> >
<Video className="h-6 w-6 mb-1" /> <Video className="h-6 w-6 mb-1" />
@ -184,7 +189,7 @@ export function MediaPanel() {
if (item.type === "audio") { if (item.type === "audio") {
return ( return (
<div <div
className="w-full h-full bg-gradient-to-br from-green-500/20 to-emerald-500/20 flex flex-col items-center justify-center text-muted-foreground rounded border border-green-500/20 cursor-grab active:cursor-grabbing" className="w-full h-full bg-gradient-to-br from-green-500/20 to-emerald-500/20 flex flex-col items-center justify-center text-muted-foreground rounded border border-green-500/20"
{...baseDragProps} {...baseDragProps}
> >
<Music className="h-6 w-6 mb-1" /> <Music className="h-6 w-6 mb-1" />
@ -200,7 +205,7 @@ export function MediaPanel() {
return ( return (
<div <div
className="w-full h-full bg-muted/30 flex flex-col items-center justify-center text-muted-foreground rounded cursor-grab active:cursor-grabbing" className="w-full h-full bg-muted/30 flex flex-col items-center justify-center text-muted-foreground rounded"
{...baseDragProps} {...baseDragProps}
> >
<Image className="h-6 w-6" /> <Image className="h-6 w-6" />
@ -290,39 +295,45 @@ export function MediaPanel() {
</p> </p>
</div> </div>
) : ( ) : (
<div className="grid grid-cols-2 gap-2"> <div
className="grid gap-2"
style={{
gridTemplateColumns: "repeat(auto-fill, 160px)",
}}
>
{/* Render each media item as a draggable button */} {/* Render each media item as a draggable button */}
{filteredMediaItems.map((item) => ( {filteredMediaItems.map((item) => (
<div key={item.id} className="relative group"> <div key={item.id} className="relative group">
<Button <ContextMenu>
variant="outline" <ContextMenuTrigger asChild>
className="flex flex-col gap-2 p-2 h-auto w-full relative" <Button
> variant="outline"
<AspectRatio ratio={16 / 9} className="bg-accent"> className="flex flex-col gap-1 p-2 h-auto w-full relative border-none !bg-transparent cursor-default"
{renderPreview(item)} >
</AspectRatio> <AspectRatio ratio={16 / 9} className="bg-accent">
<span {renderPreview(item)}
className="text-xs truncate px-1 max-w-full" </AspectRatio>
aria-label={item.name} <span
title={item.name} className="text-[0.7rem] text-muted-foreground truncate w-full text-left"
> aria-label={item.name}
{item.name.length > 8 title={item.name}
? `${item.name.slice(0, 4)}...${item.name.slice(-3)}` >
: item.name} {item.name.length > 8
</span> ? `${item.name.slice(0, 4)}...${item.name.slice(-3)}`
</Button> : item.name}
</span>
{/* Show remove button on hover */} </Button>
<div className="absolute -top-2 -right-2 opacity-0 group-hover:opacity-100 transition-opacity"> </ContextMenuTrigger>
<Button <ContextMenuContent>
variant="destructive" <ContextMenuItem>Export clips</ContextMenuItem>
size="icon" <ContextMenuItem
className="h-6 w-6" variant="destructive"
onClick={(e) => handleRemove(e, item.id)} onClick={(e) => handleRemove(e, item.id)}
> >
<Trash2 className="h-3 w-3" /> Delete
</Button> </ContextMenuItem>
</div> </ContextMenuContent>
</ContextMenu>
</div> </div>
))} ))}
</div> </div>