From a8dd2d74228e065fb4572a00ea9b5873edd96a3e Mon Sep 17 00:00:00 2001 From: ashim-hq Date: Sun, 19 Apr 2026 15:50:18 +0800 Subject: [PATCH] feat: add HEIC preview support to collage store --- apps/web/src/stores/collage-store.ts | 37 +++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/apps/web/src/stores/collage-store.ts b/apps/web/src/stores/collage-store.ts index 3ebf9c51..f196bf9b 100644 --- a/apps/web/src/stores/collage-store.ts +++ b/apps/web/src/stores/collage-store.ts @@ -1,5 +1,6 @@ import { create } from "zustand"; import { COLLAGE_TEMPLATES, getDefaultTemplate } from "@/lib/collage-templates"; +import { fetchDecodedPreview, needsServerPreview, revokePreviewUrl } from "@/lib/image-preview"; export type AspectRatio = "free" | "1:1" | "4:3" | "3:2" | "16:9" | "9:16" | "4:5"; export type OutputFormat = "png" | "jpeg" | "webp"; @@ -9,6 +10,8 @@ export interface CollageImage { id: string; file: File; blobUrl: string; + previewBlobUrl?: string; + previewLoading: boolean; } export interface CellTransform { @@ -110,6 +113,7 @@ export const useCollageStore = create((set, get) => ({ id: `img-${++nextImageId}`, file: f, blobUrl: URL.createObjectURL(f), + previewLoading: needsServerPreview(f), })); const state = get(); const allImages = [...state.images, ...newImages]; @@ -127,12 +131,33 @@ export const useCollageStore = create((set, get) => ({ resultSize: null, error: null, }); + + for (const img of newImages) { + if (img.previewLoading) { + const imgId = img.id; + fetchDecodedPreview(img.file).then((url) => { + const current = get(); + const idx = current.images.findIndex((i) => i.id === imgId); + if (idx === -1) return; + const updated = [...current.images]; + updated[idx] = { + ...updated[idx], + previewLoading: false, + ...(url ? { previewBlobUrl: url } : {}), + }; + set({ images: updated }); + }); + } + } }, removeImage: (index) => { const state = get(); const img = state.images[index]; - if (img) URL.revokeObjectURL(img.blobUrl); + if (img) { + URL.revokeObjectURL(img.blobUrl); + if (img.previewBlobUrl) revokePreviewUrl(img.previewBlobUrl); + } const newImages = state.images.filter((_, i) => i !== index); if (newImages.length === 0) { get().reset(); @@ -152,7 +177,10 @@ export const useCollageStore = create((set, get) => ({ clearImages: () => { const state = get(); - for (const img of state.images) URL.revokeObjectURL(img.blobUrl); + for (const img of state.images) { + URL.revokeObjectURL(img.blobUrl); + if (img.previewBlobUrl) revokePreviewUrl(img.previewBlobUrl); + } set({ images: [], cellAssignments: [], @@ -237,7 +265,10 @@ export const useCollageStore = create((set, get) => ({ setError: (e) => set({ error: e, phase: "editing" }), reset: () => { const state = get(); - for (const img of state.images) URL.revokeObjectURL(img.blobUrl); + for (const img of state.images) { + URL.revokeObjectURL(img.blobUrl); + if (img.previewBlobUrl) revokePreviewUrl(img.previewBlobUrl); + } nextImageId = 0; set({ images: [],