export const themeTokens = { appName: "Mecha Game Console", contentMaxWidth: "1180px", accent: "#48e6ff", accentSecondary: "#ff77c8", narrowBreakpoint: 760 } as const; export type ThemePaletteId = "mecha-black" | "magical-girl"; export type ThemeBackgroundId = "mecha-grid" | "magic-stage"; export const themePaletteChangeEvent = "platform-web:theme-palette-change"; export interface ThemePaletteChangeDetail { paletteId: ThemePaletteId; } export interface ThemePalette { id: ThemePaletteId; label: string; summary: string; swatches: string[]; variables: Record; } export interface ThemeBackgroundPreset { id: ThemeBackgroundId; label: string; summary: string; preview: string; variables: Record; } export interface WorkspaceThemeState { paletteId: ThemePaletteId; backgroundPresetId: ThemeBackgroundId; backgroundImage: string | null; } const backgroundStorageKey = "platform-web.theme.background"; const backgroundPresetStorageKey = "platform-web.theme.backgroundPreset"; const paletteStorageKey = "platform-web.theme.palette"; const mechaFrameAccessoryTop = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 132 48'%3E%3Cg fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 31h34l9-12h28l7 8h18' stroke='%2348e6ff' stroke-opacity='.86' stroke-width='2.4'/%3E%3Cpath d='M75 17h16l10 10M25 36h22M100 32h15' stroke='%23ffb84d' stroke-opacity='.68' stroke-width='1.7'/%3E%3Ccircle cx='58' cy='24' r='8' stroke='%239af7ff' stroke-opacity='.58' stroke-width='1.6'/%3E%3Cpath d='M58 15v18M49 24h18' stroke='%239af7ff' stroke-opacity='.34' stroke-width='1.2'/%3E%3Cpath d='M106 10l4 4 6-1-4 4 2 6-6-3-5 4 1-7-5-4 6 1z' stroke='%23ffb84d' stroke-opacity='.58' stroke-width='1.4'/%3E%3C/g%3E%3C/svg%3E\")"; const mechaFrameAccessoryBottom = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 132 56'%3E%3Cg fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 38h30l12-19 15 25h25' stroke='%2348e6ff' stroke-opacity='.78' stroke-width='2.4'/%3E%3Cpath d='M34 38l9-13 8 13M74 37h21' stroke='%23ffb84d' stroke-opacity='.62' stroke-width='1.7'/%3E%3Ccircle cx='100' cy='26' r='15' stroke='%239af7ff' stroke-opacity='.54' stroke-width='1.6'/%3E%3Ccircle cx='100' cy='26' r='7' stroke='%23ffb84d' stroke-opacity='.62' stroke-width='1.4'/%3E%3Cpath d='M84 26h32M100 10v32M89 15l22 22M111 15L89 37' stroke='%239af7ff' stroke-opacity='.28' stroke-width='1.1'/%3E%3Cpath d='M18 20l11-7 16 4-13 9z' stroke='%239af7ff' stroke-opacity='.58' stroke-width='1.5'/%3E%3C/g%3E%3C/svg%3E\")"; const magicalFrameAccessoryHeart = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 48'%3E%3Cg fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M36 38S23 29 23 20c0-7 9-9 13-3 4-6 13-4 13 3 0 9-13 18-13 18z' fill='%23ff77c8' fill-opacity='.12' stroke='%23fff6fb' stroke-width='2'/%3E%3Cpath d='M22 20c-6-4-11-2-15 2 5 0 8 2 11 6-5-1-8 1-10 4 7-1 12 1 17 5M50 20c6-4 11-2 15 2-5 0-8 2-11 6 5-1 8 1 10 4-7-1-12 1-17 5' stroke='%23ffd66d' stroke-opacity='.92' stroke-width='1.7'/%3E%3Cpath d='M36 8l2 4 5 1-4 3 1 5-4-3-4 3 1-5-4-3 5-1z' fill='%23ffd66d' fill-opacity='.22' stroke='%23ffd66d' stroke-width='1.4'/%3E%3C/g%3E%3C/svg%3E\")"; const magicalFrameAccessoryWand = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 48'%3E%3Cg fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 40L45 13' stroke='%23ff77c8' stroke-width='3'/%3E%3Cpath d='M49 5l3 6 7 1-5 5 1 7-6-4-7 4 2-7-6-5 7-1z' fill='%23ffd66d' fill-opacity='.2' stroke='%23ffd66d' stroke-width='1.9'/%3E%3Cpath d='M12 14l1.5 3 3.5.5-2.5 2.5.5 3.5-3-2-3 2 .5-3.5L6 17.5l3.5-.5zM59 29l1.5 3 3.5.5-2.5 2.5.5 3.5-3-2-3 2 .5-3.5-2.5-2.5 3.5-.5z' stroke='%23fff6fb' stroke-opacity='.9' stroke-width='1.3'/%3E%3Cpath d='M15 36l7 7' stroke='%23ffd66d' stroke-opacity='.86' stroke-width='1.6'/%3E%3C/g%3E%3C/svg%3E\")"; const magicalFrameAccessoryMoon = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 48'%3E%3Cg fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M42 8c-9 2-15 10-13 19 2 10 12 15 21 11-6-1-11-6-12-12-2-7 0-13 4-18z' fill='%23ff77c8' fill-opacity='.1' stroke='%23fff6fb' stroke-width='2'/%3E%3Cpath d='M19 19l2.5 5 5.5 1-4 4 1 6-5-3-5 3 1-6-4-4 5.5-1z' fill='%23ffd66d' fill-opacity='.2' stroke='%23ffd66d' stroke-width='1.7'/%3E%3Cpath d='M48 10c5 1 9 4 12 8M50 38c5-2 9-5 12-10' stroke='%23ff77c8' stroke-opacity='.84' stroke-width='1.6'/%3E%3Ccircle cx='59' cy='24' r='2' fill='%23fff6fb'/%3E%3C/g%3E%3C/svg%3E\")"; const magicalFrameAccessoryRibbon = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 48'%3E%3Cg fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M35 22c-7-8-17-9-20-4-3 6 5 12 20 8M37 22c7-8 17-9 20-4 3 6-5 12-20 8' fill='%23ff77c8' fill-opacity='.12' stroke='%23fff6fb' stroke-width='2'/%3E%3Cpath d='M35 25L23 42l13-5 5 5 3-17M37 25l12 17-13-5-5 5-3-17' stroke='%23ff77c8' stroke-width='1.8'/%3E%3Ccircle cx='36' cy='24' r='5' fill='%23ffd66d' fill-opacity='.18' stroke='%23ffd66d' stroke-width='1.6'/%3E%3Cpath d='M10 10l1.5 3 3.5.5-2.5 2.5.5 3.5-3-2-3 2 .5-3.5L4 13.5l3.5-.5zM60 8l1.5 3 3.5.5-2.5 2.5.5 3.5-3-2-3 2 .5-3.5-2.5-2.5 3.5-.5z' stroke='%23ffd66d' stroke-width='1.2'/%3E%3C/g%3E%3C/svg%3E\")"; const magicalFrameAccessoryCrystal = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 48'%3E%3Cg fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M36 5l16 14-6 22H26l-6-22z' fill='%23ff77c8' fill-opacity='.09' stroke='%23fff6fb' stroke-width='2'/%3E%3Cpath d='M20 19h32M36 5l-8 14 8 22 8-22zM26 41l10-22 10 22' stroke='%23ffd66d' stroke-opacity='.88' stroke-width='1.35'/%3E%3Cpath d='M10 16l2 4 4 .5-3 3 .8 4.5-3.8-2.4L6 28l1-4.5-3-3 4-.5zM59 9l1.5 3 3.5.5-2.5 2.5.5 3.5-3-2-3 2 .5-3.5-2.5-2.5 3.5-.5z' stroke='%23ff77c8' stroke-width='1.3'/%3E%3C/g%3E%3C/svg%3E\")"; const magicalFrameAccessoryCircle = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 48'%3E%3Cg fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='36' cy='24' r='18' stroke='%23fff6fb' stroke-width='1.7'/%3E%3Ccircle cx='36' cy='24' r='11' stroke='%23ffd66d' stroke-width='1.4'/%3E%3Cpath d='M36 6v36M18 24h36M23 11l26 26M49 11L23 37' stroke='%23ff77c8' stroke-opacity='.68' stroke-width='1.1'/%3E%3Cpath d='M36 14l3 6 7 1-5 5 1 7-6-4-6 4 1-7-5-5 7-1z' fill='%23ffd66d' fill-opacity='.12' stroke='%23ffd66d' stroke-width='1.2'/%3E%3C/g%3E%3C/svg%3E\")"; const mechaMaterialVariables = { "--surface": "rgba(5, 12, 18, 0.58)", "--surface-solid": "rgba(6, 14, 21, 0.88)", "--surface-raised": "rgba(10, 24, 32, 0.64)", "--glass-wash": "linear-gradient(145deg, rgba(33, 55, 64, 0.46), rgba(5, 12, 18, 0.42) 46%, rgba(72, 230, 255, 0.08))", "--shine-sweep": "linear-gradient(112deg, transparent 0 38%, rgba(132, 243, 255, 0.24) 46%, transparent 56%)", "--glass-tint": "rgba(72, 230, 255, 0.08)", "--crystal-rim": "rgba(137, 239, 255, 0.64)", "--moonbeam": "rgba(60, 176, 255, 0.34)", "--diamond-line": "rgba(119, 237, 255, 0.34)", "--glass-shadow": "rgba(0, 0, 0, 0.56)", "--crystal-spark": "rgba(172, 250, 255, 0.92)", "--sparkle": "rgba(196, 252, 255, 0.96)", "--sparkle-gold": "rgba(255, 184, 77, 0.82)", "--corner-sparkle": "linear-gradient(135deg, rgba(72, 230, 255, 0.72) 0 2px, transparent 2px 100%), linear-gradient(315deg, rgba(255, 184, 77, 0.72) 0 2px, transparent 2px 100%), radial-gradient(circle at 86% 18%, rgba(132, 243, 255, 0.88) 0 1.4px, transparent 2.4px)", "--jelly-highlight": "linear-gradient(145deg, rgba(132, 243, 255, 0.16), transparent 32%), radial-gradient(circle at 82% 16%, rgba(255, 184, 77, 0.16), transparent 24%)", "--sugar-dust": "linear-gradient(90deg, rgba(72, 230, 255, 0.08) 1px, transparent 1px), linear-gradient(180deg, rgba(72, 230, 255, 0.07) 1px, transparent 1px), radial-gradient(circle at 88% 18%, rgba(255, 184, 77, 0.62) 0 1.2px, transparent 2px)", "--crystal-edge-glow": "0 0 0 1px rgba(72, 230, 255, 0.28), 0 0 22px rgba(72, 230, 255, 0.2), 0 0 44px rgba(0, 0, 0, 0.48)", "--jelly-inset": "inset 0 1px 0 rgba(180, 248, 255, 0.22), inset 0 -1px 0 rgba(72, 230, 255, 0.16), inset 0 0 24px rgba(72, 230, 255, 0.08)", "--frosted-edge": "linear-gradient(180deg, rgba(132, 243, 255, 0.18), rgba(7, 12, 18, 0.74) 48%, rgba(255, 184, 77, 0.1))", "--frosted-surface": "linear-gradient(145deg, rgba(14, 28, 38, 0.62), rgba(5, 12, 18, 0.46) 48%, rgba(72, 230, 255, 0.07))", "--frame-corner": "linear-gradient(135deg, rgba(72, 230, 255, 0.9) 0 2px, transparent 2px), linear-gradient(315deg, rgba(255, 184, 77, 0.72) 0 2px, transparent 2px)", "--frame-accent": "linear-gradient(90deg, rgba(72, 230, 255, 0), rgba(72, 230, 255, 0.78), rgba(255, 184, 77, 0.58), rgba(72, 230, 255, 0))", "--frame-accessory-top": mechaFrameAccessoryTop, "--frame-accessory-bottom": mechaFrameAccessoryBottom, "--frame-accessory-opacity": "0.22", "--frame-accessory-size": "44px 16px, 48px 20px", "--menu-item-bg": "linear-gradient(90deg, rgba(72, 230, 255, 0.14) 0 1px, transparent 1px 100%), linear-gradient(135deg, rgba(17, 31, 43, 0.94), rgba(4, 8, 13, 0.82) 58%, rgba(255, 184, 77, 0.08))", "--menu-item-active-bg": "linear-gradient(90deg, rgba(72, 230, 255, 0.44) 0 3px, transparent 3px 100%), linear-gradient(135deg, rgba(20, 51, 64, 0.98), rgba(6, 11, 18, 0.9) 52%, rgba(255, 184, 77, 0.18))", "--menu-glyph-bg": "linear-gradient(135deg, rgba(72, 230, 255, 0.28), rgba(255, 184, 77, 0.14)), repeating-linear-gradient(90deg, rgba(137, 239, 255, 0.18) 0 1px, transparent 1px 6px), rgba(5, 9, 15, 0.9)", "--menu-title-shadow": "0 0 14px rgba(72, 230, 255, 0.5), 0 0 2px rgba(255, 184, 77, 0.8)", "--menu-active-outline": "linear-gradient(90deg, rgba(72, 230, 255, 0.95), rgba(255, 184, 77, 0.72), rgba(72, 230, 255, 0.95))", "--panel-material": "var(--sugar-dust), var(--glass-wash), linear-gradient(135deg, rgba(5, 12, 18, 0.46), rgba(10, 24, 32, 0.38))", "--panel-shadow": "var(--jelly-inset), inset 0 0 0 1px rgba(119, 237, 255, 0.24), inset 9px 0 0 rgba(72, 230, 255, 0.06), 0 18px 42px rgba(0, 0, 0, 0.42), 0 0 28px rgba(72, 230, 255, 0.11)" } as const; const magicalMaterialVariables = { "--surface": "rgba(88, 18, 52, 0.48)", "--surface-solid": "rgba(78, 14, 46, 0.82)", "--surface-raised": "rgba(118, 26, 68, 0.54)", "--glass-wash": "linear-gradient(180deg, rgba(255, 226, 242, 0.2), rgba(120, 24, 68, 0.32) 56%, rgba(72, 12, 42, 0.28))", "--shine-sweep": "radial-gradient(circle at 88% 12%, rgba(255, 255, 255, 0.58) 0 2px, transparent 3px)", "--glass-tint": "rgba(255, 119, 200, 0.1)", "--crystal-rim": "rgba(255, 236, 250, 0.92)", "--moonbeam": "rgba(255, 185, 226, 0.76)", "--diamond-line": "rgba(255, 217, 239, 0.72)", "--glass-shadow": "rgba(72, 0, 34, 0.36)", "--crystal-spark": "rgba(255, 246, 253, 0.98)", "--sparkle": "rgba(255, 255, 255, 0.98)", "--sparkle-gold": "rgba(255, 221, 117, 0.9)", "--corner-sparkle": "radial-gradient(circle at 86% 14%, rgba(255, 255, 255, 0.98) 0 2.4px, transparent 3.2px), radial-gradient(circle at 93% 23%, rgba(255, 221, 117, 0.92) 0 1.8px, transparent 2.8px)", "--jelly-highlight": "radial-gradient(circle at 18% 14%, rgba(255, 255, 255, 0.72), transparent 30%), linear-gradient(145deg, rgba(255, 255, 255, 0.34), transparent 34%)", "--sugar-dust": "radial-gradient(circle at 14% 20%, rgba(255, 255, 255, 0.95) 0 1.4px, transparent 2.2px), radial-gradient(circle at 86% 18%, rgba(255, 221, 117, 0.9) 0 1.6px, transparent 2.6px), radial-gradient(circle at 78% 84%, rgba(255, 119, 200, 0.76) 0 1.8px, transparent 2.8px)", "--crystal-edge-glow": "0 0 0 1px rgba(255, 217, 239, 0.78), 0 0 18px rgba(255, 119, 200, 0.46), 0 0 34px rgba(255, 221, 117, 0.18)", "--jelly-inset": "inset 0 1px 0 rgba(255, 255, 255, 0.52), inset 0 -1px 0 rgba(255, 119, 200, 0.28), inset 0 0 20px rgba(255, 255, 255, 0.18)", "--frosted-edge": "linear-gradient(180deg, rgba(255, 255, 255, 0.58), rgba(255, 119, 200, 0.2) 48%, rgba(255, 221, 117, 0.18))", "--frosted-surface": "linear-gradient(180deg, rgba(255, 226, 242, 0.18), rgba(118, 24, 66, 0.36) 52%, rgba(72, 12, 42, 0.28))", "--frame-corner": "radial-gradient(circle at 0 0, rgba(255, 221, 117, 0.9) 0 4px, transparent 5px), radial-gradient(circle at 100% 100%, rgba(255, 119, 200, 0.9) 0 4px, transparent 5px)", "--frame-accent": "linear-gradient(90deg, rgba(255, 221, 117, 0), rgba(255, 221, 117, 0.86), rgba(255, 119, 200, 0.78), rgba(255, 221, 117, 0))", "--frame-accessory-top": magicalFrameAccessoryWand, "--frame-accessory-bottom": magicalFrameAccessoryCircle, "--frame-accessory-heart": magicalFrameAccessoryHeart, "--frame-accessory-wand": magicalFrameAccessoryWand, "--frame-accessory-moon": magicalFrameAccessoryMoon, "--frame-accessory-ribbon": magicalFrameAccessoryRibbon, "--frame-accessory-crystal": magicalFrameAccessoryCrystal, "--frame-accessory-circle": magicalFrameAccessoryCircle, "--frame-accessory-opacity": "0.78", "--frame-accessory-size": "68px 44px", "--menu-item-bg": "radial-gradient(circle at 92% 12%, rgba(255, 255, 255, 0.52) 0 3px, transparent 4px), linear-gradient(180deg, rgba(255, 185, 226, 0.22), rgba(135, 10, 65, 0.42) 68%, rgba(94, 0, 44, 0.48))", "--menu-item-active-bg": "radial-gradient(circle at 96% 18%, rgba(255, 255, 255, 0.72) 0 3px, transparent 4px), linear-gradient(180deg, rgba(255, 203, 232, 0.34), rgba(177, 22, 86, 0.58) 54%, rgba(105, 0, 48, 0.62))", "--menu-glyph-bg": "radial-gradient(circle at 30% 22%, rgba(255, 255, 255, 0.78), transparent 34%), radial-gradient(circle at 72% 80%, rgba(255, 221, 117, 0.42), transparent 30%), linear-gradient(135deg, rgba(255, 119, 200, 0.82), rgba(255, 221, 117, 0.44))", "--menu-title-shadow": "0 2px 0 rgba(96, 24, 24, 0.86), 1px 0 0 rgba(96, 24, 24, 0.86), -1px 0 0 rgba(96, 24, 24, 0.86), 0 0 12px rgba(255, 221, 117, 0.48)", "--menu-active-outline": "linear-gradient(90deg, rgba(255, 221, 117, 0.96), rgba(255, 246, 253, 0.92), rgba(255, 119, 200, 0.9), rgba(255, 221, 117, 0.96))", "--panel-material": "var(--sugar-dust), var(--glass-wash), linear-gradient(180deg, rgba(106, 22, 60, 0.3), rgba(72, 12, 42, 0.3))", "--panel-shadow": "var(--jelly-inset), inset 0 0 0 1px rgba(255, 217, 239, 0.5), 0 18px 42px rgba(72, 0, 34, 0.28), 0 0 30px rgba(255, 119, 200, 0.2), 0 0 16px rgba(255, 221, 117, 0.1)" } as const; export const themePalettes: ThemePalette[] = [ { id: "mecha-black", label: "黑色机甲", summary: "黑钢面板、青蓝扫描线、琥珀能量灯", swatches: ["#05090f", "#111c28", "#48e6ff", "#ffb84d", "#e7f7ff"], variables: { "--ink": "#e7f7ff", "--ink-soft": "#b9d2dc", "--ink-faint": "#84a1ad", ...mechaMaterialVariables, "--line": "rgba(116, 236, 255, 0.32)", "--line-strong": "rgba(132, 243, 255, 0.7)", "--accent": "#48e6ff", "--accent-deep": "#9af7ff", "--accent-soft": "rgba(72, 230, 255, 0.16)", "--teal": "#4fffd7", "--teal-soft": "rgba(79, 255, 215, 0.14)", "--pink": "#ff4d6d", "--pink-soft": "rgba(255, 77, 109, 0.13)", "--gold": "#ffb84d", "--gold-soft": "rgba(255, 184, 77, 0.18)", "--danger": "#ff5a6e", "--danger-soft": "rgba(255, 90, 110, 0.14)", "--success": "#4fffd7", "--success-soft": "rgba(79, 255, 215, 0.18)", "--background-base": "#05070b", "--background-glow-1": "rgba(72, 230, 255, 0.16)", "--background-glow-2": "rgba(255, 184, 77, 0.11)", "--background-glow-3": "rgba(255, 77, 109, 0.1)", "--rim-light": "rgba(180, 248, 255, 0.64)", "--candy-glow": "rgba(72, 230, 255, 0.32)", "--ultimate-effect-alpha": "0.86", "--custom-background-overlay": "transparent", "--code-surface": "#05090f", "--code-ink": "#dffcff", "--code-muted": "#87afba" } }, { id: "magical-girl", label: "魔法少女", summary: "粉色舞台、金色星框、显眼魔法阵", swatches: ["#8b0a40", "#ff77c8", "#ffd66d", "#fff6fb", "#8cf0ff"], variables: { "--ink": "#fff8fd", "--ink-soft": "#ffe8f5", "--ink-faint": "#ffd0e9", ...magicalMaterialVariables, "--line": "rgba(255, 201, 230, 0.42)", "--line-strong": "rgba(255, 225, 139, 0.76)", "--accent": "#ff77c8", "--accent-deep": "#fff6fb", "--accent-soft": "rgba(255, 119, 200, 0.18)", "--teal": "#8cf0ff", "--teal-soft": "rgba(140, 240, 255, 0.16)", "--pink": "#ff8fd2", "--pink-soft": "rgba(255, 143, 210, 0.22)", "--gold": "#ffd66d", "--gold-soft": "rgba(255, 214, 109, 0.24)", "--danger": "#ff8a9d", "--danger-soft": "rgba(255, 138, 157, 0.18)", "--success": "#8cf0ff", "--success-soft": "rgba(140, 240, 255, 0.2)", "--background-base": "#7a0b39", "--background-glow-1": "rgba(255, 119, 200, 0.42)", "--background-glow-2": "rgba(255, 214, 109, 0.28)", "--background-glow-3": "rgba(140, 240, 255, 0.18)", "--rim-light": "rgba(255, 255, 255, 0.92)", "--candy-glow": "rgba(255, 119, 200, 0.48)", "--ultimate-effect-alpha": "0.96", "--custom-background-overlay": "transparent", "--code-surface": "#4b092a", "--code-ink": "#fff4fb", "--code-muted": "#ffc6e4" } } ]; const themePaletteVariableNames = Array.from(new Set(themePalettes.flatMap((palette) => Object.keys(palette.variables)))); export const defaultThemePaletteId: ThemePaletteId = "mecha-black"; export const defaultThemeBackgroundId: ThemeBackgroundId = "mecha-grid"; export const themeBackgroundPresets: ThemeBackgroundPreset[] = [ { id: "mecha-grid", label: "机甲格纳库", summary: "黑钢格栅、雷达圆环、青蓝扫描光", preview: "radial-gradient(circle at 76% 18%, rgba(72, 230, 255, 0.86), transparent 18%), repeating-linear-gradient(90deg, rgba(72, 230, 255, 0.34) 0 1px, transparent 1px 18px), linear-gradient(135deg, #05090f, #111c28)", variables: { "--workspace-background-pattern-image": "radial-gradient(circle at 76% 18%, transparent 0 68px, rgba(72, 230, 255, 0.3) 69px 71px, transparent 72px), radial-gradient(circle at 76% 18%, transparent 0 34px, rgba(255, 184, 77, 0.24) 35px 36px, transparent 37px), conic-gradient(from 0deg at 76% 18%, transparent 0 8%, rgba(72, 230, 255, 0.24) 8% 9%, transparent 9% 28%, rgba(72, 230, 255, 0.18) 28% 29%, transparent 29% 100%), linear-gradient(90deg, rgba(72, 230, 255, 0.08) 1px, transparent 1px), linear-gradient(180deg, rgba(72, 230, 255, 0.07) 1px, transparent 1px), linear-gradient(135deg, transparent 0 48%, rgba(255, 184, 77, 0.1) 49% 50%, transparent 51% 100%), radial-gradient(circle at 20% 78%, rgba(255, 77, 109, 0.12), transparent 28%)", "--workspace-background-pattern-size": "auto, auto, auto, 42px 42px, 42px 42px, 180px 180px, auto", "--workspace-background-pattern-position": "center, center, center, 0 0, 0 0, 0 0, center", "--workspace-background-pattern-repeat": "no-repeat, no-repeat, no-repeat, repeat, repeat, repeat, no-repeat", "--workspace-background-pattern-opacity": "0.92", "--workspace-background-pattern-filter": "saturate(1.18) contrast(1.08)" } }, { id: "magic-stage", label: "粉月魔法阵", summary: "粉色舞台、星星边框、底部大型魔法阵", preview: "radial-gradient(circle at 86% 86%, transparent 0 28%, rgba(255, 255, 255, 0.72) 29% 30%, transparent 31%), radial-gradient(circle at 25% 22%, #ff77c8, transparent 34%), linear-gradient(180deg, #f08bb4, #8b0a40)", variables: { "--workspace-background-pattern-image": "radial-gradient(circle, rgba(255, 255, 255, 0.9) 0 1.4px, transparent 2.2px), radial-gradient(circle, rgba(255, 221, 117, 0.86) 0 1.8px, transparent 2.8px), radial-gradient(circle at 88% 84%, transparent 0 112px, rgba(255, 255, 255, 0.28) 113px 115px, transparent 116px), radial-gradient(circle at 88% 84%, transparent 0 72px, rgba(255, 119, 200, 0.28) 73px 75px, transparent 76px), conic-gradient(from 30deg at 88% 84%, transparent 0 8%, rgba(255, 221, 117, 0.18) 8% 9%, transparent 9% 24%, rgba(255, 255, 255, 0.18) 24% 25%, transparent 25% 100%), linear-gradient(180deg, rgba(255, 203, 226, 0.26), rgba(122, 11, 57, 0.12)), radial-gradient(circle at 18% 20%, rgba(255, 143, 210, 0.28), transparent 28%)", "--workspace-background-pattern-size": "76px 76px, 118px 118px, auto, auto, auto, auto, auto", "--workspace-background-pattern-position": "12px 18px, 42px 58px, center, center, center, center, center", "--workspace-background-pattern-repeat": "repeat, repeat, no-repeat, no-repeat, no-repeat, no-repeat, no-repeat", "--workspace-background-pattern-opacity": "0.96", "--workspace-background-pattern-filter": "saturate(1.24)" } } ]; export function getThemePalette(id: string | null | undefined): ThemePalette { return themePalettes.find((palette) => palette.id === id) ?? themePalettes[0]; } export function getThemeBackgroundPreset(id: string | null | undefined): ThemeBackgroundPreset { return themeBackgroundPresets.find((preset) => preset.id === id) ?? themeBackgroundPresets[0]; } export function loadThemeState(): WorkspaceThemeState { if (typeof window === "undefined") { return { paletteId: defaultThemePaletteId, backgroundPresetId: defaultThemeBackgroundId, backgroundImage: null }; } try { return { paletteId: getThemePalette(window.localStorage.getItem(paletteStorageKey)).id, backgroundPresetId: getThemeBackgroundPreset(window.localStorage.getItem(backgroundPresetStorageKey)).id, backgroundImage: window.localStorage.getItem(backgroundStorageKey) }; } catch { return { paletteId: defaultThemePaletteId, backgroundPresetId: defaultThemeBackgroundId, backgroundImage: null }; } } export function persistThemePalette(paletteId: ThemePaletteId): void { if (typeof window === "undefined") { return; } try { window.localStorage.setItem(paletteStorageKey, paletteId); } catch { // storage may be unavailable; the palette stays session-only } } export function persistThemeBackgroundPreset(backgroundPresetId: ThemeBackgroundId): void { if (typeof window === "undefined") { return; } try { window.localStorage.setItem(backgroundPresetStorageKey, backgroundPresetId); } catch { // storage may be unavailable; the preset stays session-only } } export function persistBackgroundImage(dataUrl: string | null): void { if (typeof window === "undefined") { return; } try { if (dataUrl) { window.localStorage.setItem(backgroundStorageKey, dataUrl); } else { window.localStorage.removeItem(backgroundStorageKey); } } catch { // storage may be unavailable (private mode); the background stays session-only } } export function applyThemePalette(paletteId: ThemePaletteId): void { if (typeof document === "undefined") { return; } const palette = getThemePalette(paletteId); for (const name of themePaletteVariableNames) { document.documentElement.style.removeProperty(name); } for (const [name, value] of Object.entries(palette.variables)) { document.documentElement.style.setProperty(name, value); } document.documentElement.dataset.themePalette = palette.id; if (typeof window !== "undefined") { window.dispatchEvent(new CustomEvent(themePaletteChangeEvent, { detail: { paletteId: palette.id } })); } } export function applyThemeBackgroundPreset(backgroundPresetId: ThemeBackgroundId): void { if (typeof document === "undefined") { return; } const preset = getThemeBackgroundPreset(backgroundPresetId); for (const [name, value] of Object.entries(preset.variables)) { document.documentElement.style.setProperty(name, value); } document.documentElement.dataset.themeBackground = preset.id; } export function applyBackgroundImage(dataUrl: string | null): void { if (typeof document === "undefined") { return; } if (dataUrl) { document.documentElement.style.setProperty("--workspace-background-image", `url(${JSON.stringify(dataUrl)})`); document.documentElement.dataset.customBackground = "true"; } else { document.documentElement.style.removeProperty("--workspace-background-image"); delete document.documentElement.dataset.customBackground; } }