Files
cobble/src/utils/parse-install-icon.ts
T
tbenandClaude Opus 5.5 e462806438 Let each install pick its app icon
Settings > General gets an App icon (super admin): one of the seven
stones, or an uploaded image with the picked stone as a top-left corner
mark (inside a round launcher's crop, clear of the browser's badge),
previewed in both launcher crops before saving.

Uploads are decoded and cropped to a stored square (no SVG); the set is
drawn into DATA_DIR/install-icon/<version>/ and served publicly and
immutable. The manifest, head icon links and push notifications point at
it; the ember stone keeps the stock icons. The generator shares the icon
renderer.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 10:38:25 +01:00

41 lines
1.2 KiB
TypeScript

import { BotHues, type BotHue } from "@/src/dict/bot-dict";
import {
PwaDefaultInstallIcon,
PwaInstallIconModes,
type PwaInstallIcon,
} from "@/src/data/pwa-data";
type Params = {
/**
* The `install_icon` app setting, as saved.
*/
saved?: string | null;
};
/**
* The install's icon from its saved JSON, field by field: anything missing
* or unknown falls back to the stock ember icon's value.
*/
export default function parseInstallIcon({ saved }: Params): PwaInstallIcon {
let raw: Record<string, unknown> = {};
try {
const parsed = saved ? JSON.parse(saved) : null;
if (parsed && typeof parsed == "object") raw = parsed;
} catch {
raw = {};
}
const mode = PwaInstallIconModes.find((value) => value == raw.mode);
const stone = BotHues.find((hue) => hue.value == raw.stone)?.value as BotHue | undefined;
const version =
typeof raw.version == "string" && /^[a-f0-9]{12}$/.test(raw.version) ? raw.version : null;
return {
mode: mode || PwaDefaultInstallIcon.mode,
stone: stone || PwaDefaultInstallIcon.stone,
mark: typeof raw.mark == "boolean" ? raw.mark : PwaDefaultInstallIcon.mark,
version,
};
}