mirror of
https://github.com/basketikun/infinite-canvas.git
synced 2026-08-05 17:04:27 +08:00
refactor: remove "use client" directive from multiple files and update project structure to align with Vite and React Router
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import { saveAs } from "file-saver";
|
||||
|
||||
import { createZip, readZip } from "@/lib/zip";
|
||||
import { getMediaBlob, setMediaBlob } from "@/services/file-storage";
|
||||
import { getImageBlob, setImageBlob } from "@/services/image-storage";
|
||||
import type { Asset } from "@/stores/use-asset-store";
|
||||
|
||||
type AssetExportFile = {
|
||||
app: "infinite-canvas";
|
||||
version: 1;
|
||||
exportedAt: string;
|
||||
assets: Asset[];
|
||||
files: AssetExportItem[];
|
||||
};
|
||||
|
||||
type AssetExportItem = {
|
||||
storageKey: string;
|
||||
path: string;
|
||||
mimeType: string;
|
||||
bytes: number;
|
||||
};
|
||||
|
||||
export async function exportAssets(assets: Asset[]) {
|
||||
const files: AssetExportItem[] = [];
|
||||
const zipFiles: { name: string; data: BlobPart }[] = [];
|
||||
|
||||
await Promise.all(
|
||||
assets.map(async (asset) => {
|
||||
if (asset.kind !== "image" && asset.kind !== "video") return;
|
||||
const storageKey = asset.data.storageKey;
|
||||
if (!storageKey) return;
|
||||
const blob = asset.kind === "image" ? await getImageBlob(storageKey) : await getMediaBlob(storageKey);
|
||||
if (!blob) return;
|
||||
const path = `files/${safeFileName(storageKey)}.${fileExtension(blob.type, asset.kind)}`;
|
||||
files.push({ storageKey, path, mimeType: blob.type || asset.data.mimeType, bytes: blob.size });
|
||||
zipFiles.push({ name: path, data: blob });
|
||||
}),
|
||||
);
|
||||
|
||||
const data: AssetExportFile = { app: "infinite-canvas", version: 1, exportedAt: new Date().toISOString(), assets, files };
|
||||
const zip = await createZip([{ name: "assets.json", data: JSON.stringify(data, null, 2) }, ...zipFiles]);
|
||||
saveAs(zip, "我的素材.zip");
|
||||
}
|
||||
|
||||
export async function readAssetPackage(file: File) {
|
||||
const zip = await readZip(file);
|
||||
const assetFile = zip.get("assets.json");
|
||||
if (!assetFile) throw new Error("missing assets.json");
|
||||
const data = JSON.parse(await assetFile.text()) as AssetExportFile;
|
||||
await Promise.all(
|
||||
data.files.map(async (item) => {
|
||||
const blob = zip.get(item.path);
|
||||
if (!blob) return;
|
||||
const typedBlob = blob.type ? blob : blob.slice(0, blob.size, item.mimeType);
|
||||
await (item.storageKey.startsWith("image:") ? setImageBlob(item.storageKey, typedBlob) : setMediaBlob(item.storageKey, typedBlob));
|
||||
}),
|
||||
);
|
||||
return data.assets;
|
||||
}
|
||||
|
||||
function safeFileName(value: string) {
|
||||
return value.replace(/[\\/:*?"<>|]/g, "_");
|
||||
}
|
||||
|
||||
function fileExtension(mimeType: string, kind: Asset["kind"]) {
|
||||
if (mimeType.includes("png")) return "png";
|
||||
if (mimeType.includes("jpeg")) return "jpg";
|
||||
if (mimeType.includes("webp")) return "webp";
|
||||
if (mimeType.includes("gif")) return "gif";
|
||||
if (mimeType.includes("mp4")) return "mp4";
|
||||
if (mimeType.includes("webm")) return "webm";
|
||||
return kind === "image" ? "png" : "bin";
|
||||
}
|
||||
Reference in New Issue
Block a user