Files
ttstd-infinite-canvas/web/src/services/api/appearance.ts
2026-10-05 13:41:17 +08:00

145 lines
4.5 KiB
TypeScript

import { http } from "@/services/api/request";
import type { SkinDefinition } from "@/lib/skin-themes";
import type { CanvasAppearance } from "@/lib/canvas/agent-appearance";
import { apiBaseURL } from "@/services/api/request";
import type { UpdateAnnouncement } from "@/lib/update-announcement";
export type PublicAppearance = {
updates?: UpdateAnnouncement;
canvas?: CanvasAppearance;
schemaVersion: number;
brandName: string;
brandSlug: string;
authHeroTitle: string;
authHeroDescription: string;
logoUrl: string;
darkLogoUrl: string;
logoFrameEnabled: boolean;
authVideoUrl: string;
authVideoPosterUrl: string;
authVideoAutoplay: boolean;
skinId: string;
activeSkin: SkinDefinition;
seoTitle: string;
seoDescription: string;
seoKeywords: string;
footerCopyright: string;
icpFilingEnabled: boolean;
icpFilingNumber: string;
redeemPurchaseUrl: string;
logoConfigured: boolean;
darkLogoConfigured: boolean;
authVideoConfigured: boolean;
authVideoPosterConfigured: boolean;
configured: boolean;
revision: string;
updatedAt?: string;
};
export type AdminAppearance = {
updates?: UpdateAnnouncement;
canvas?: CanvasAppearance;
schemaVersion: number;
brandName: string;
brandSlug: string;
authHeroTitle: string;
authHeroDescription: string;
logoResourceId: string;
darkLogoResourceId: string;
logoFrameEnabled: boolean;
authVideoResourceId: string;
authVideoPosterResourceId: string;
authVideoAutoplay: boolean;
skinId: string;
skinThemes: SkinDefinition[];
seoTitle: string;
seoDescription: string;
seoKeywords: string;
footerCopyright: string;
icpFilingEnabled: boolean;
icpFilingNumber: string;
redeemPurchaseUrl: string;
public: PublicAppearance;
configured: boolean;
updatedBy?: string;
createdAt?: string;
updatedAt?: string;
};
export type AppearanceAssetSlot = "logo" | "logo-dark" | "video" | "poster";
export type AppearanceResource = {
id: string;
kind: string;
status: string;
mimeType: string;
size: number;
};
export async function getPublicAppearance(signal?: AbortSignal) {
const result = await http.get<{ appearance: PublicAppearance }>("/public/appearance", { signal });
return result.appearance;
}
export async function getAdminAppearance(signal?: AbortSignal) {
const result = await http.get<{ setting: AdminAppearance }>("/admin/settings/appearance", { signal });
return result.setting;
}
export async function updateAdminAppearance(
input: Pick<
AdminAppearance,
| "brandName"
| "canvas"
| "updates"
| "brandSlug"
| "authHeroTitle"
| "authHeroDescription"
| "logoResourceId"
| "darkLogoResourceId"
| "logoFrameEnabled"
| "authVideoResourceId"
| "authVideoPosterResourceId"
| "authVideoAutoplay"
| "skinId"
| "skinThemes"
| "seoTitle"
| "seoDescription"
| "seoKeywords"
| "footerCopyright"
| "icpFilingEnabled"
| "icpFilingNumber"
| "redeemPurchaseUrl"
>,
) {
const result = await http.patch<{ setting: AdminAppearance }>("/admin/settings/appearance", input);
return result.setting;
}
export async function resetAdminAppearance() {
const result = await http.delete<{ setting: AdminAppearance }>("/admin/settings/appearance");
return result.setting;
}
export async function uploadAppearanceAsset(slot: AppearanceAssetSlot | "update-image" | "update-video", file: File) {
const body = new FormData();
body.append("file", file);
const result = await http.post<{ resource: AppearanceResource }>(`/admin/settings/appearance/assets/${slot}`, body);
return result.resource;
}
export function updateAnnouncementPreviewURL(resourceId: string) {
return `${apiBaseURL.replace(/\/$/, "")}/admin/settings/appearance/updates/${encodeURIComponent(resourceId)}`;
}
export async function uploadLive2D(file: File) {
const body = new FormData();
body.append("file", file);
const result = await http.post<{ model: { resourceId: string; entry: string } }>("/admin/settings/appearance/live2d", body);
return result.model;
}
export function live2DModelURL(resourceId: string, entry: string, preview = false) {
return `${apiBaseURL.replace(/\/$/, "")}/${preview ? "admin/settings" : "public"}/appearance/live2d/${encodeURIComponent(resourceId)}/${entry.split("/").map(encodeURIComponent).join("/")}`;
}