diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-03-25 16:47:22 +0100 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-03-29 15:48:22 +0200 |
| commit | 8db3bead13441a5882d8689dfc6a9f09c82375d9 (patch) | |
| tree | e9d0cafa93904ffcbec3188c37961bcc16c6422d /apps/web/src/stores/stickers-store.ts | |
| parent | 39ea298a9ccba3104c549c0ca079c231981811f5 (diff) | |
| download | opencut-8db3bead13441a5882d8689dfc6a9f09c82375d9.tar.gz | |
feat: masks, properties refactor, shaders, storage migrations, and more
Diffstat (limited to 'apps/web/src/stores/stickers-store.ts')
| -rw-r--r-- | apps/web/src/stores/stickers-store.ts | 177 |
1 files changed, 98 insertions, 79 deletions
diff --git a/apps/web/src/stores/stickers-store.ts b/apps/web/src/stores/stickers-store.ts index 3f713b3d..7a678084 100644 --- a/apps/web/src/stores/stickers-store.ts +++ b/apps/web/src/stores/stickers-store.ts @@ -1,16 +1,20 @@ import { create } from "zustand"; import { persist } from "zustand/middleware"; -import { EditorCore } from "@/core"; -import { searchStickers as searchStickersFromProviders } from "@/lib/stickers"; -import type { StickerSearchResult } from "@/lib/stickers"; -import { buildStickerElement } from "@/lib/timeline/element-utils"; +import { + browseAll, + browseCategory, + searchAll, + searchStickers as searchStickersFromProviders, +} from "@/lib/stickers"; +import type { StickerBrowseResult, StickerSearchResult } from "@/lib/stickers"; import { STICKER_CATEGORIES } from "@/constants/sticker-constants"; -import type { StickerCategory } from "@/types/stickers"; +import type { StickerCategory } from "@/lib/stickers/types"; import { registerDefaultStickerProviders } from "@/lib/stickers/providers"; -import { hasProvider } from "@/lib/stickers/registry"; +import { stickersRegistry } from "@/lib/stickers/registry"; import { parseStickerId } from "@/lib/stickers/sticker-id"; const MAX_RECENT_STICKERS = 50; +let browseRequestVersion = 0; function isValidStickerId(value: unknown): value is string { if (typeof value !== "string") { @@ -19,7 +23,7 @@ function isValidStickerId(value: unknown): value is string { try { const parsed = parseStickerId({ stickerId: value }); - return hasProvider({ providerId: parsed.providerId }); + return stickersRegistry.has(parsed.providerId); } catch { return false; } @@ -60,20 +64,15 @@ interface StickersStore { selectedCategory: StickerCategory; viewMode: ViewMode; searchResults: StickerSearchResult | null; + browseContent: StickerBrowseResult | null; recentStickers: string[]; isSearching: boolean; - addingSticker: string | null; + isBrowsing: boolean; setSearchQuery: ({ query }: { query: string }) => void; setSelectedCategory: ({ category }: { category: StickerCategory }) => void; searchStickers: ({ query }: { query: string }) => Promise<void>; - addStickerToTimeline: ({ - stickerId, - name, - }: { - stickerId: string; - name?: string; - }) => void; + browseStickers: () => Promise<void>; addToRecentStickers: ({ stickerId }: { stickerId: string }) => void; clearRecentStickers: () => void; } @@ -86,22 +85,34 @@ export const useStickersStore = create<StickersStore>()( viewMode: "browse", searchResults: null, + browseContent: null, recentStickers: [], isSearching: false, - addingSticker: null, + isBrowsing: false, setSearchQuery: ({ query }) => set({ searchQuery: query }), - setSelectedCategory: ({ category }) => - set({ - selectedCategory: category in STICKER_CATEGORIES ? category : "all", - viewMode: "browse", - }), + setSelectedCategory: ({ category }) => { + set({ + selectedCategory: category in STICKER_CATEGORIES ? category : "all", + browseContent: null, + }); + + const query = get().searchQuery.trim(); + if (query) { + void get().searchStickers({ query }); + return; + } + + void get().browseStickers(); + }, searchStickers: async ({ query }: { query: string }) => { - if (!query.trim()) { + const trimmedQuery = query.trim(); + if (!trimmedQuery) { set({ searchResults: null, viewMode: "browse" }); + await get().browseStickers(); return; } @@ -111,12 +122,17 @@ export const useStickersStore = create<StickersStore>()( set({ isSearching: true, viewMode: "search" }); try { - const results = await searchStickersFromProviders({ - query, - category: selectedCategory, - limit: 100, - }); - set({ searchResults: results }); + if (selectedCategory === "all") { + const browseContent = await searchAll({ query: trimmedQuery }); + set({ browseContent, searchResults: null }); + } else { + const results = await searchStickersFromProviders({ + query: trimmedQuery, + category: selectedCategory, + limit: 100, + }); + set({ searchResults: results }); + } } catch (error) { console.error("Search failed:", error); set({ searchResults: null }); @@ -125,67 +141,70 @@ export const useStickersStore = create<StickersStore>()( } }, - addStickerToTimeline: ({ - stickerId, - name, - }: { - stickerId: string; - name?: string; - }) => { - set({ addingSticker: stickerId }); - try { - const editor = EditorCore.getInstance(); - const currentTime = editor.playback.getCurrentTime(); - const tracks = editor.timeline.getTracks(); + browseStickers: async () => { + const version = ++browseRequestVersion; + const category = get().selectedCategory; + const selectedCategory = + category in STICKER_CATEGORIES ? category : "all"; - const stickerTrack = tracks.find((t) => t.type === "sticker"); - let trackId: string; + set({ isBrowsing: true, viewMode: "browse" }); + try { + const browseContent = + selectedCategory === "all" + ? await browseAll({ + recentStickers: get().recentStickers, + }) + : await browseCategory({ + category: selectedCategory, + }); - if (stickerTrack) { - trackId = stickerTrack.id; - } else { - trackId = editor.timeline.addTrack({ type: "sticker" }); - } + if (version !== browseRequestVersion) return; + set({ browseContent }); + } catch (error) { + if (version !== browseRequestVersion) return; + console.error("Browse failed:", error); + set({ browseContent: null }); + } finally { + if (version === browseRequestVersion) { + set({ isBrowsing: false }); + } + } + }, - const element = buildStickerElement({ - stickerId, - name, - startTime: currentTime, - }); - editor.timeline.insertElement({ - placement: { mode: "explicit", trackId }, - element, - }); + addToRecentStickers: ({ stickerId }: { stickerId: string }) => { + const sanitizedStickerIds = sanitizeRecentStickers({ + recentStickers: [stickerId], + }); + if (sanitizedStickerIds.length === 0) { + return; + } - get().addToRecentStickers({ stickerId }); - } finally { - set({ addingSticker: null }); - } - }, + set((state) => { + const recent = [ + sanitizedStickerIds[0], + ...state.recentStickers.filter((s) => s !== sanitizedStickerIds[0]), + ]; + return { + recentStickers: recent.slice(0, MAX_RECENT_STICKERS), + }; + }); - addToRecentStickers: ({ stickerId }: { stickerId: string }) => { - const sanitizedStickerIds = sanitizeRecentStickers({ - recentStickers: [stickerId], - }); - if (sanitizedStickerIds.length === 0) { - return; - } + if (get().viewMode === "browse" && get().selectedCategory === "all") { + void get().browseStickers(); + } + }, - set((state) => { - const recent = [ - sanitizedStickerIds[0], - ...state.recentStickers.filter((s) => s !== sanitizedStickerIds[0]), - ]; - return { - recentStickers: recent.slice(0, MAX_RECENT_STICKERS), - }; - }); - }, + clearRecentStickers: () => { + set({ recentStickers: [] }); - clearRecentStickers: () => set({ recentStickers: [] }), + if (get().viewMode === "browse" && get().selectedCategory === "all") { + void get().browseStickers(); + } + }, }), { name: "stickers-settings", + version: 1, migrate: (persistedState) => { if ( typeof persistedState === "object" && |
