import { FAVICON_MAX_LENGTH } from "./constants"; export const EMOJI_ICON_PREFIX = "emoji:"; /** Simple colored SVG mark presets (letter / shape) as data URLs */ export function makeMarkIcon( label: string, bg = "#3b82f6", fg = "#ffffff", ): string { const text = (label || "?").slice(0, 2).toUpperCase(); const svg = ` ${escapeXml(text)} `; return `data:image/svg+xml,${encodeURIComponent(svg)}`; } export const COLOR_PRESETS = [ "#3b82f6", "#8b5cf6", "#ec4899", "#ef4444", "#f59e0b", "#10b981", "#06b6d4", "#64748b", "#0f172a", "#14b8a6", ] as const; export function emojiIcon(emoji: string): string { return `${EMOJI_ICON_PREFIX}${emoji}`; } export function isEmojiIcon(value: string | undefined | null): boolean { return Boolean(value?.startsWith(EMOJI_ICON_PREFIX)); } export function emojiFromIcon(value: string): string { return value.slice(EMOJI_ICON_PREFIX.length); } /** Google s2 favicon helper */ export function siteFaviconUrl(pageUrl: string, size = 64): string { try { const domain = new URL(pageUrl).hostname.replace(/^www\./, ""); return `https://www.google.com/s2/favicons?domain=${encodeURIComponent(domain)}&sz=${size}`; } catch { return ""; } } export function isValidFaviconValue(value: string | undefined | null): boolean { if (value == null || value === "") return true; if (value.length > FAVICON_MAX_LENGTH) return false; if (value.startsWith(EMOJI_ICON_PREFIX)) { const e = value.slice(EMOJI_ICON_PREFIX.length); return e.length > 0 && e.length <= 16; } if (value.startsWith("data:image/")) { // data:image/png;base64,... or data:image/svg+xml,... return /^data:image\/(png|jpeg|jpg|gif|webp|svg\+xml|x-icon|vnd\.microsoft\.icon);/i.test( value, ); } // http(s) URL try { const u = new URL(value); return u.protocol === "http:" || u.protocol === "https:"; } catch { return false; } } function escapeXml(s: string): string { return s .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } /** Basic SVG sanitization for uploads (strip scripts / handlers) */ export function sanitizeSvg(svgText: string): string { return svgText .replace(/[\s\S]*?<\/script>/gi, "") .replace(/\son\w+\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi, "") .replace(/javascript:/gi, ""); }