founders card
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
import type { GenerateConfig } from "@/lib/card-gen/id-config";
|
||||
import { savePreset, type CardPreset } from "@/lib/card-gen/local-store";
|
||||
|
||||
export type ServerPresetMeta = {
|
||||
id: string;
|
||||
name: string;
|
||||
config: GenerateConfig;
|
||||
imageName: string;
|
||||
hasImage: boolean;
|
||||
fontName: string | null;
|
||||
hasFont: boolean;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
};
|
||||
|
||||
async function readError(res: Response): Promise<string> {
|
||||
const body = (await res.json().catch(() => null)) as { error?: string } | null;
|
||||
return body?.error || `Request failed (${res.status})`;
|
||||
}
|
||||
|
||||
export async function fetchServerPresetList(): Promise<ServerPresetMeta[]> {
|
||||
const res = await fetch("/api/founders-card/presets", { cache: "no-store" });
|
||||
if (!res.ok) throw new Error(await readError(res));
|
||||
const body = (await res.json()) as { presets?: ServerPresetMeta[] };
|
||||
return Array.isArray(body.presets) ? body.presets : [];
|
||||
}
|
||||
|
||||
async function fileFromEndpoint(
|
||||
url: string,
|
||||
fallbackName: string,
|
||||
): Promise<File | null> {
|
||||
const res = await fetch(url, { cache: "no-store" });
|
||||
if (!res.ok) return null;
|
||||
const blob = await res.blob();
|
||||
if (blob.size === 0) return null;
|
||||
const name =
|
||||
/filename="([^"]+)"/i.exec(res.headers.get("content-disposition") ?? "")?.[1] ??
|
||||
fallbackName;
|
||||
return new File([blob], name, {
|
||||
type: blob.type || "application/octet-stream",
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchServerPresets(): Promise<CardPreset[]> {
|
||||
const list = await fetchServerPresetList();
|
||||
const out: CardPreset[] = [];
|
||||
for (const meta of list) {
|
||||
const image = meta.hasImage
|
||||
? await fileFromEndpoint(
|
||||
`/api/founders-card/presets/${meta.id}/image`,
|
||||
meta.imageName || "base.png",
|
||||
)
|
||||
: null;
|
||||
const font = meta.hasFont
|
||||
? await fileFromEndpoint(
|
||||
`/api/founders-card/presets/${meta.id}/font`,
|
||||
meta.fontName || "custom.ttf",
|
||||
)
|
||||
: null;
|
||||
out.push({
|
||||
id: meta.id,
|
||||
name: meta.name,
|
||||
config: meta.config,
|
||||
image,
|
||||
font,
|
||||
createdAt: meta.createdAt,
|
||||
updatedAt: meta.updatedAt,
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export async function pushPresetToServer(input: {
|
||||
id?: string;
|
||||
name: string;
|
||||
config: GenerateConfig;
|
||||
image: File | null;
|
||||
font: File | null;
|
||||
}): Promise<ServerPresetMeta> {
|
||||
const fd = new FormData();
|
||||
fd.append("name", input.name);
|
||||
fd.append("config", JSON.stringify(input.config));
|
||||
if (input.id) fd.append("id", input.id);
|
||||
if (input.image) fd.append("image", input.image);
|
||||
if (input.font) fd.append("font", input.font);
|
||||
if (!input.font) fd.append("clearFont", "1");
|
||||
const res = await fetch("/api/founders-card/presets", {
|
||||
method: "POST",
|
||||
body: fd,
|
||||
});
|
||||
if (!res.ok) throw new Error(await readError(res));
|
||||
return (await res.json()) as ServerPresetMeta;
|
||||
}
|
||||
|
||||
export async function deleteServerPreset(id: string): Promise<void> {
|
||||
const res = await fetch(`/api/founders-card/presets/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
if (!res.ok && res.status !== 404) throw new Error(await readError(res));
|
||||
}
|
||||
|
||||
export async function cacheServerPresetsLocally(
|
||||
presets: CardPreset[],
|
||||
): Promise<void> {
|
||||
for (const preset of presets) {
|
||||
await savePreset({
|
||||
id: preset.id,
|
||||
name: preset.name,
|
||||
config: preset.config,
|
||||
image: preset.image,
|
||||
font: preset.font,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user