addElementAtTime({ asset: item, startTime: currentTime })
}
variant={variant}
isRounded={isRounded}
/>
);
}
function MediaItemWithContextMenu({
item,
children,
onRemove,
}: {
item: MediaAsset;
children: React.ReactNode;
onRemove: ({
event,
ids,
}: {
event: React.MouseEvent;
ids: string[];
}) => void;
}) {
const { isSelected, selectedIds } = useSelection();
const idsToDelete = isSelected(item.id) ? selectedIds : [item.id];
const deleteLabel =
idsToDelete.length > 1 ? `Delete ${idsToDelete.length} items` : "Delete";
return (
{children}
Export clips
) =>
onRemove({ event, ids: idsToDelete })
}
>
{deleteLabel}
);
}
function MediaItemList({
items,
mode,
onRemove,
}: {
items: MediaAsset[];
mode: MediaViewMode;
onRemove: ({
event,
ids,
}: {
event: React.MouseEvent;
ids: string[];
}) => void;
}) {
const isGrid = mode === "grid";
return (
{items.map((item) => (
}
variant={isGrid ? "card" : "compact"}
isRounded={isGrid ? false : undefined}
/>
))}
);
}
function formatDuration({ duration }: { duration: number }) {
const min = Math.floor(duration / 60);
const sec = Math.floor(duration % 60);
return `${min}:${sec.toString().padStart(2, "0")}`;
}
function MediaDurationBadge({ duration }: { duration?: number }) {
if (!duration) return null;
return (
{formatDuration({ duration })}
);
}
function MediaDurationLabel({ duration }: { duration?: number }) {
if (!duration) return null;
return (
{formatDuration({ duration })}
);
}
function MediaTypePlaceholder({
icon,
label,
duration,
variant,
}: {
icon: IconSvgElement;
label: string;
duration?: number;
variant: "muted" | "bordered";
}) {
const iconClassName = cn("size-6", variant === "bordered" && "mb-1");
return (
{label}
);
}
function MediaPreview({
item,
variant = "grid",
}: {
item: MediaAsset;
variant?: "grid" | "compact";
}) {
const shouldShowDurationBadge = variant === "grid";
if (item.type === "image") {
return (
);
}
if (item.type === "video") {
if (item.thumbnailUrl) {
return (
{shouldShowDurationBadge ? (
) : null}
);
}
return (
);
}
if (item.type === "audio") {
return (
);
}
return (
);
}
function MediaActions({
mediaViewMode,
setMediaViewMode,
isProcessing,
sortBy,
sortOrder,
onSort,
onImport,
}: {
mediaViewMode: MediaViewMode;
setMediaViewMode: (mode: MediaViewMode) => void;
isProcessing: boolean;
sortBy: MediaSortKey;
sortOrder: MediaSortOrder;
onSort: ({ key }: { key: MediaSortKey }) => void;
onImport: () => void;
}) {
return (
{mediaViewMode === "grid"
? "Switch to list view"
: "Switch to grid view"}
Sort by {sortBy} (
{sortOrder === "asc" ? "ascending" : "descending"})
);
}
function SortMenuItem({
label,
sortKey,
currentSortBy,
currentSortOrder,
onSort,
}: {
label: string;
sortKey: MediaSortKey;
currentSortBy: MediaSortKey;
currentSortOrder: MediaSortOrder;
onSort: ({ key }: { key: MediaSortKey }) => void;
}) {
const isActive = currentSortBy === sortKey;
const arrow = isActive ? (currentSortOrder === "asc" ? "↑" : "↓") : "";
return (
onSort({ key: sortKey })}>
{label} {arrow}
);
}