"use client"; import Image from "next/image"; import type { CSSProperties } from "react"; import { useEffect, useMemo, useState } from "react"; import { toast } from "sonner"; import { PanelView } from "@/components/editor/panels/assets/views/base-view"; import { DraggableItem } from "@/components/editor/panels/assets/draggable-item"; import { Button } from "@/components/ui/button"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { resolveStickerId, type StickerItem as StickerData, } from "@/lib/stickers"; import { useStickersStore } from "@/stores/stickers-store"; import { cn } from "@/utils/ui"; import { HappyIcon, ClockIcon, MultiplicationSignIcon, Search01Icon, } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; import { Spinner } from "@/components/ui/spinner"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { OcSlidersVerticalIcon } from "@opencut/ui/icons"; import type { StickerCategory } from "@/types/stickers"; import { STICKER_CATEGORIES } from "@/constants/sticker-constants"; import { parseStickerId } from "@/lib/stickers/sticker-id"; export function StickersView() { const { selectedCategory, setSelectedCategory } = useStickersStore(); return ( } > ); } function StickerGrid({ items, shouldCapSize = false, }: { items: StickerData[]; shouldCapSize?: boolean; }) { const gridStyle: CSSProperties & { "--sticker-min": string; "--sticker-max"?: string; } = { gridTemplateColumns: shouldCapSize ? "repeat(auto-fill, minmax(var(--sticker-min, 96px), var(--sticker-max, 160px)))" : "repeat(auto-fit, minmax(var(--sticker-min, 96px), 1fr))", "--sticker-min": "96px", ...(shouldCapSize ? { "--sticker-max": "160px" } : {}), }; return (
{items.map((item) => ( ))}
); } function EmptyView({ message }: { message: string }) { return (

No stickers found

{message}

); } function StickersContentView() { const { searchQuery, viewMode, searchResults, recentStickers, isSearching, clearRecentStickers, } = useStickersStore(); const itemsToDisplay = useMemo(() => { if (viewMode === "search" && searchResults) { return searchResults.items; } return []; }, [viewMode, searchResults]); const recentStickerItems = useMemo(() => { const items: StickerData[] = []; for (const stickerId of recentStickers) { const recentStickerItem = toRecentStickerItem({ stickerId }); if (recentStickerItem) { items.push(recentStickerItem); } } return items; }, [recentStickers]); return (
{recentStickerItems.length > 0 && viewMode === "browse" && (
Recent

Clear recent stickers

)} {viewMode === "search" && (
{isSearching ? (
) : searchResults?.items.length ? (
{searchResults.total} results
) : searchQuery ? ( ) : null}
)}
); } interface StickerItemProps { item: StickerData; shouldCapSize?: boolean; } function StickerItem({ item, shouldCapSize = false }: StickerItemProps) { const { addingSticker, addStickerToTimeline } = useStickersStore(); const isAdding = addingSticker === item.id; const [hasImageError, setHasImageError] = useState(false); useEffect(() => { if (!item.id) { return; } setHasImageError(false); }, [item.id]); const displayName = item.name; const handleAdd = async () => { try { await addStickerToTimeline({ stickerId: item.id, name: item.name, }); } catch (error) { console.error("Failed to add sticker:", error); toast.error("Failed to add sticker to timeline"); } }; const preview = hasImageError ? (
{displayName}
) : (
{displayName} { setHasImageError(true); }} loading="lazy" unoptimized />
); return (
{isAdding && (
)}
); } function getStickerNameFromId({ stickerId }: { stickerId: string }): string { const stickerIdParts = stickerId.split(":"); if (stickerIdParts.length <= 1) { return stickerId; } return ( stickerIdParts.slice(1).join(":").split(":").pop()?.replaceAll("-", " ") ?? stickerId ); } function toRecentStickerItem({ stickerId, }: { stickerId: string; }): StickerData | null { try { const { providerId } = parseStickerId({ stickerId }); return { id: stickerId, provider: providerId, name: getStickerNameFromId({ stickerId }), previewUrl: resolveStickerId({ stickerId, options: { width: 64, height: 64 }, }), metadata: {}, }; } catch { return null; } }