@decido/shell 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/.turbo/turbo-build.log +13 -0
  2. package/package.json +65 -0
  3. package/src/AgentPlayer.tsx +105 -0
  4. package/src/DecidoPlayer.tsx +117 -0
  5. package/src/bridge/BridgeAgent.ts +443 -0
  6. package/src/components/DecidoIcon.tsx +56 -0
  7. package/src/components/JsonTreeEditor.tsx +117 -0
  8. package/src/components/PanelSplitter.tsx +71 -0
  9. package/src/components/PluginErrorBoundary.tsx +69 -0
  10. package/src/components/SafeLiquidUI.tsx +114 -0
  11. package/src/components/TransientLayer.tsx +92 -0
  12. package/src/components/agent/AgentChat.tsx +134 -0
  13. package/src/components/chat-extensions/IntentCatalogPanel.tsx +81 -0
  14. package/src/components/chat-extensions/chatSlashCommands.ts +101 -0
  15. package/src/components/controls/CreatorInputBar.tsx +144 -0
  16. package/src/components/controls/OSToolbar.tsx +90 -0
  17. package/src/components/controls/TimelineTape.tsx +43 -0
  18. package/src/components/debug/ActionTimelineTab.tsx +111 -0
  19. package/src/components/debug/CSSInspectorTab.tsx +436 -0
  20. package/src/components/debug/ExportTab.tsx +192 -0
  21. package/src/components/debug/FlowHealthTab.tsx +86 -0
  22. package/src/components/debug/LogsTab.tsx +110 -0
  23. package/src/components/debug/MorphStackTab.tsx +241 -0
  24. package/src/components/debug/NetworkTab.tsx +173 -0
  25. package/src/components/debug/PerformanceTab.tsx +171 -0
  26. package/src/components/debug/ProfilesTab.tsx +238 -0
  27. package/src/components/debug/ReplayTab.tsx +70 -0
  28. package/src/components/debug/StoresTab.tsx +255 -0
  29. package/src/components/debug/TopologyTab.tsx +59 -0
  30. package/src/components/debug/debugConfig.tsx +66 -0
  31. package/src/components/playground/DebugPanel.tsx +112 -0
  32. package/src/components/playground/HeaderCenterControls.tsx +92 -0
  33. package/src/components/playground/KeyframeListItem.tsx +70 -0
  34. package/src/components/playground/PlaygroundAppSidebar.tsx +171 -0
  35. package/src/components/playground/PlaygroundBottomControls.tsx +132 -0
  36. package/src/components/playground/PlaygroundCanvas.tsx +87 -0
  37. package/src/components/playground/PlaygroundChat.tsx +236 -0
  38. package/src/components/playground/PlaygroundErrorBoundary.tsx +63 -0
  39. package/src/components/playground/PlaygroundFloatingInput.tsx +352 -0
  40. package/src/components/playground/PlaygroundHeader.tsx +222 -0
  41. package/src/components/playground/PlaygroundSidebar.tsx +136 -0
  42. package/src/components/playground/PlaygroundTerminal.tsx +44 -0
  43. package/src/components/playground/SuggestionCards.tsx +29 -0
  44. package/src/components/playground/demos/ClinicaAINode.tsx +221 -0
  45. package/src/components/playground/demos/FinanceAINode.tsx +226 -0
  46. package/src/components/playground/demos/KiaAcademyNode.tsx +250 -0
  47. package/src/components/playground/demos/KiaBotNode.tsx +207 -0
  48. package/src/components/playground/demos/KiaCampaignNode.tsx +191 -0
  49. package/src/components/playground/demos/KiaComplianceNode.tsx +140 -0
  50. package/src/components/playground/demos/KiaCustomerJourneyNode.tsx +220 -0
  51. package/src/components/playground/demos/KiaCyberNode.tsx +203 -0
  52. package/src/components/playground/demos/KiaDashboardNode.tsx +399 -0
  53. package/src/components/playground/demos/KiaEmbudoOverviewNode.tsx +168 -0
  54. package/src/components/playground/demos/KiaExecutiveNode.tsx +169 -0
  55. package/src/components/playground/demos/KiaGamificationNode.tsx +229 -0
  56. package/src/components/playground/demos/KiaIntelligenceHubNode.tsx +165 -0
  57. package/src/components/playground/demos/KiaInventoryNode.tsx +183 -0
  58. package/src/components/playground/demos/KiaLeadScoringNode.tsx +226 -0
  59. package/src/components/playground/demos/KiaLiveSimulationNode.tsx +177 -0
  60. package/src/components/playground/demos/KiaMultiDealerNode.tsx +223 -0
  61. package/src/components/playground/demos/KiaNPSVoiceNode.tsx +214 -0
  62. package/src/components/playground/demos/KiaOmnichannelNode.tsx +162 -0
  63. package/src/components/playground/demos/KiaPBIBudgetNode.tsx +152 -0
  64. package/src/components/playground/demos/KiaPBIConversionNode.tsx +206 -0
  65. package/src/components/playground/demos/KiaPBIFunnelNode.tsx +184 -0
  66. package/src/components/playground/demos/KiaPBIOwnershipNode.tsx +113 -0
  67. package/src/components/playground/demos/KiaPBIPartnerNode.tsx +143 -0
  68. package/src/components/playground/demos/KiaPBIPreciosNode.tsx +120 -0
  69. package/src/components/playground/demos/KiaPBIRuntNode.tsx +205 -0
  70. package/src/components/playground/demos/KiaPartnerScoreNode.tsx +206 -0
  71. package/src/components/playground/demos/KiaPredictiveNode.tsx +226 -0
  72. package/src/components/playground/demos/KiaShowroomNode.tsx +194 -0
  73. package/src/components/playground/demos/KiaStoreNode.tsx +215 -0
  74. package/src/components/playground/demos/KiaSustainabilityNode.tsx +173 -0
  75. package/src/components/playground/demos/KiaUsedVehiclesNode.tsx +163 -0
  76. package/src/components/playground/demos/KiaWorkshopNode.tsx +221 -0
  77. package/src/components/playground/demos/SmartCityNode.tsx +205 -0
  78. package/src/components/playground/demos/kia_campaign_manifest.json +112 -0
  79. package/src/components/playground/input-parts/AIModelSelector.tsx +156 -0
  80. package/src/components/playground/input-parts/InputActions.tsx +80 -0
  81. package/src/components/playground/input-parts/InputToolbar.tsx +245 -0
  82. package/src/components/playground/input-parts/ResourceLibraryPanel.tsx +287 -0
  83. package/src/components/playground/sidebarDsdIO.ts +82 -0
  84. package/src/components/settings/SettingsPanel.tsx +267 -0
  85. package/src/components/shell/AppHeader.tsx +9 -0
  86. package/src/components/shell/AppShell.tsx +139 -0
  87. package/src/components/shell/ArtifactBar.tsx +97 -0
  88. package/src/components/shell/BootScreen.tsx +19 -0
  89. package/src/components/shell/CenterComposite.tsx +87 -0
  90. package/src/components/shell/CodeEditorPanel.tsx +88 -0
  91. package/src/components/shell/GlobalOverlays.tsx +228 -0
  92. package/src/components/shell/LayoutConfigurator.tsx +209 -0
  93. package/src/components/shell/LayoutGrid.tsx +178 -0
  94. package/src/components/shell/MorphShell.tsx +368 -0
  95. package/src/components/shell/PluginViewer.tsx +147 -0
  96. package/src/components/shell/ShellNexusPreview.tsx +458 -0
  97. package/src/components/shell/SlotRenderer.tsx +115 -0
  98. package/src/components/shell/TabBar.tsx +94 -0
  99. package/src/components/shell/TemplateLibrary.tsx +195 -0
  100. package/src/components/shell/layoutConstants.ts +35 -0
  101. package/src/components/shell/morphStageMeta.ts +15 -0
  102. package/src/components/shell/shells/BuiltInShells.tsx +443 -0
  103. package/src/components/shell/shells/DatawayChatShell.tsx +42 -0
  104. package/src/components/shell/shells/TokenPreview.tsx +339 -0
  105. package/src/components/shell/shells/bootShells.ts +31 -0
  106. package/src/components/shells/CreatorShell.tsx +37 -0
  107. package/src/components/shells/DecidoShell.tsx +447 -0
  108. package/src/components/shells/ExperimentalChatShell.tsx +245 -0
  109. package/src/components/shells/UserCanvas.tsx +44 -0
  110. package/src/components/studio/BlueprintManagerPanel.tsx +137 -0
  111. package/src/components/studio/DependencyTreePanel.tsx +192 -0
  112. package/src/components/studio/NodePalette.tsx +92 -0
  113. package/src/components/studio/NodePropertiesPanel.tsx +81 -0
  114. package/src/components/studio/ReactFlowEditor.tsx +242 -0
  115. package/src/components/studio/TimelineEditor.tsx +122 -0
  116. package/src/components/studio/TimelineKeyframeCard.tsx +99 -0
  117. package/src/components/studio/VariablePanel.tsx +181 -0
  118. package/src/components/studio/blueprint/BlueprintCard.tsx +82 -0
  119. package/src/components/studio/editor/CanvasContextMenu.tsx +107 -0
  120. package/src/components/studio/editor/EditorToolbar.tsx +80 -0
  121. package/src/components/studio/editor/StageContentRenderer.tsx +134 -0
  122. package/src/components/studio/editor/TrackPropertyEditors.tsx +133 -0
  123. package/src/components/studio/editor/TreeNodeItem.tsx +91 -0
  124. package/src/components/studio/editor/edgeStyles.ts +43 -0
  125. package/src/components/studio/editor/editorKeyHandler.ts +95 -0
  126. package/src/components/studio/editor/nodeTypeRegistry.ts +137 -0
  127. package/src/components/studio/editor/paletteCatalog.tsx +84 -0
  128. package/src/components/studio/nodes/shell/InteractionNodes.tsx +82 -0
  129. package/src/components/studio/nodes/shell/LayoutControlNodes.tsx +69 -0
  130. package/src/components/studio/nodes/shell/RegisterActionNode.tsx +20 -0
  131. package/src/components/studio/nodes/shell/RegisterButtonNode.tsx +22 -0
  132. package/src/components/studio/nodes/shell/RegisterPanelNode.tsx +19 -0
  133. package/src/components/studio/nodes/shell/RegisterSidebarNode.tsx +19 -0
  134. package/src/components/studio/nodes/shell/RegisterStatusBarNode.tsx +22 -0
  135. package/src/components/studio/nodes/shell/RegisterTabNode.tsx +21 -0
  136. package/src/components/studio/nodes/shell/RegisterTopBarNode.tsx +22 -0
  137. package/src/components/studio/nodes/shell/ShellConfigNode.tsx +51 -0
  138. package/src/components/studio/nodes/shell/ShellNodeBase.tsx +100 -0
  139. package/src/components/studio/nodes/shell/ThemeNodes.tsx +51 -0
  140. package/src/components/studio/nodes/shell/index.ts +12 -0
  141. package/src/components/widgets/BroadcastWidget.tsx +93 -0
  142. package/src/components/widgets/MarketplaceWidget.tsx +298 -0
  143. package/src/components/widgets/McpToolsWidget.tsx +231 -0
  144. package/src/components/widgets/OpsDashboard.tsx +59 -0
  145. package/src/components/widgets/QuickActionsWidget.tsx +60 -0
  146. package/src/components/widgets/UsageWidget.tsx +112 -0
  147. package/src/components/widgets/WidgetRenderer.tsx +892 -0
  148. package/src/components/widgets/WidgetSlotPanel.tsx +213 -0
  149. package/src/config/IconRegistry.ts +126 -0
  150. package/src/contexts/NetworkProvider.tsx +162 -0
  151. package/src/core/AIDirector.ts +71 -0
  152. package/src/core/EventBus.ts +37 -0
  153. package/src/core/PluginContext.tsx +141 -0
  154. package/src/hooks/listeners/useUIStateListener.ts +59 -0
  155. package/src/hooks/listeners/useWhatsAppListener.ts +110 -0
  156. package/src/hooks/morphBridge.ts +82 -0
  157. package/src/hooks/useAIModelSelector.ts +144 -0
  158. package/src/hooks/useAgentStream.ts +220 -0
  159. package/src/hooks/useAutoUpdater.ts +89 -0
  160. package/src/hooks/useBootSequence.ts +20 -0
  161. package/src/hooks/useExportDSD.ts +53 -0
  162. package/src/hooks/useFullscreen.ts +35 -0
  163. package/src/hooks/useGeminiStream.ts +282 -0
  164. package/src/hooks/useIntentLens.ts +224 -0
  165. package/src/hooks/useKeyboardShortcuts.ts +69 -0
  166. package/src/hooks/useLoggerBridge.ts +32 -0
  167. package/src/hooks/useMcpClient.ts +112 -0
  168. package/src/hooks/useNexusaiDeploy.ts +118 -0
  169. package/src/hooks/usePlaybackEngine.ts +21 -0
  170. package/src/hooks/usePlaygroundCommander.ts +475 -0
  171. package/src/hooks/usePluginEngine.ts +165 -0
  172. package/src/hooks/useScreenRecorder.ts +73 -0
  173. package/src/hooks/useShellKeyboard.ts +40 -0
  174. package/src/hooks/useShellShortcuts.ts +118 -0
  175. package/src/hooks/useSoundEffects.ts +35 -0
  176. package/src/hooks/useStudioConfig.ts +72 -0
  177. package/src/hooks/useSystemBoot.ts +84 -0
  178. package/src/hooks/useSystemTelemetry.ts +62 -0
  179. package/src/index.ts +97 -0
  180. package/src/lib/debugLogger.ts +80 -0
  181. package/src/lib/networkInterceptor.ts +100 -0
  182. package/src/mocks/decido.tsx +41 -0
  183. package/src/plugins/pluginAPI.ts +190 -0
  184. package/src/store/McpStore.ts +69 -0
  185. package/src/store/UpdaterStore.ts +60 -0
  186. package/src/store/engine.ts +392 -0
  187. package/src/store/index.ts +4 -0
  188. package/src/store/layoutPresets.ts +66 -0
  189. package/src/store/playgroundTypes.ts +98 -0
  190. package/src/store/useActionTimelineStore.ts +48 -0
  191. package/src/store/useDebugPanelStore.ts +98 -0
  192. package/src/store/useDebugProfileStore.ts +130 -0
  193. package/src/store/useLayoutStore.ts +205 -0
  194. package/src/store/useMorphInstanceStore.ts +289 -0
  195. package/src/store/useMorphologyStore.ts +103 -0
  196. package/src/store/usePlaygroundStore.ts +236 -0
  197. package/src/store/useShellRegistry.ts +123 -0
  198. package/src/store/useSuggestionsStore.ts +57 -0
  199. package/src/store/useThemeStore.ts +399 -0
  200. package/src/store/useUIComponentStore.ts +179 -0
  201. package/src/types/DecidoStoryDefinition.ts +43 -0
  202. package/src/utils/ai/ai-architect.ts +92 -0
  203. package/src/utils/ai/ai-code.ts +187 -0
  204. package/src/utils/ai/ai-core.ts +50 -0
  205. package/src/utils/ai/ai-media.ts +292 -0
  206. package/src/utils/layoutGraph.ts +67 -0
  207. package/tsconfig.json +17 -0
  208. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,123 @@
1
+ /**
2
+ * useShellRegistry — Centralized registry for shell types.
3
+ *
4
+ * Replaces the scattered `registerMorphComponent` / `getMorphComponent` pattern
5
+ * with a unified ShellType → Component mapping.
6
+ *
7
+ * Built-in shells: markdown, iframe, shell-vscode, shell-canvas
8
+ * Plugins register custom shells via `registerShell('my-shell', MyComponent)`
9
+ */
10
+ import React from 'react';
11
+
12
+ // ── Shell Types ──
13
+
14
+ export type BuiltInShellType = 'markdown' | 'iframe' | 'shell-vscode' | 'shell-canvas';
15
+ export type ShellType = BuiltInShellType | (string & {});
16
+
17
+ /** Props that every shell component receives */
18
+ export interface ShellProps {
19
+ /** Unique instance ID */
20
+ instanceId: string;
21
+ /** Data payload from the morph instance */
22
+ data: Record<string, any>;
23
+ /** Current artifacts for this instance */
24
+ artifacts: MorphArtifact[];
25
+ /** Index of the active artifact */
26
+ activeArtifactIndex: number;
27
+ /** Callback to update artifact data */
28
+ onArtifactUpdate?: (artifactId: string, data: Record<string, any>) => void;
29
+ }
30
+
31
+ /** Artifact within a morph instance (file/version) */
32
+ export interface MorphArtifact {
33
+ id: string;
34
+ name: string;
35
+ version: number;
36
+ shellType: ShellType;
37
+ data: Record<string, any>;
38
+ updatedAt: number;
39
+ }
40
+
41
+ // ── Shell Metadata ──
42
+
43
+ export interface ShellMeta {
44
+ icon: string;
45
+ color: string;
46
+ label: string;
47
+ }
48
+
49
+ const shellMetaRegistry = new Map<string, ShellMeta>();
50
+
51
+ const DEFAULT_SHELL_META: Record<string, ShellMeta> = {
52
+ 'markdown': { icon: '📝', color: '#10b981', label: 'Markdown' },
53
+ 'iframe': { icon: '🖥️', color: '#6b7280', label: 'iFrame' },
54
+ 'nexusai-preview': { icon: '🌐', color: '#3b82f6', label: 'Web Preview' },
55
+ 'shell-vscode': { icon: '💻', color: '#007acc', label: 'VS Code' },
56
+ 'shell-canvas': { icon: '🖼️', color: '#f59e0b', label: 'Canvas' },
57
+ 'shell-theme-editor': { icon: '🎨', color: '#a855f7', label: 'Theme Editor' },
58
+ };
59
+
60
+ // ── Registry ──
61
+
62
+ const shellRegistry = new Map<string, React.ComponentType<ShellProps>>();
63
+
64
+ /**
65
+ * Register a shell type with optional metadata.
66
+ * Built-in shells are registered at boot. Plugins call this for custom shells.
67
+ * @example registerShell('my-plugin-viewer', MyViewerComponent, { icon: '🔧', color: '#f00', label: 'My Viewer' })
68
+ */
69
+ export function registerShell(type: ShellType, component: React.ComponentType<ShellProps>, meta?: ShellMeta) {
70
+ shellRegistry.set(type, component);
71
+ if (meta) shellMetaRegistry.set(type, meta);
72
+ else if (DEFAULT_SHELL_META[type]) shellMetaRegistry.set(type, DEFAULT_SHELL_META[type]);
73
+ }
74
+
75
+ /**
76
+ * Resolve a shell type to its React component.
77
+ * Returns undefined if the shell type is not registered.
78
+ */
79
+ export function resolveShell(type: ShellType): React.ComponentType<ShellProps> | undefined {
80
+ return shellRegistry.get(type);
81
+ }
82
+
83
+ /**
84
+ * Check if a shell type is registered.
85
+ */
86
+ export function isShellRegistered(type: ShellType): boolean {
87
+ return shellRegistry.has(type);
88
+ }
89
+
90
+ /**
91
+ * Get all registered shell type IDs (for UI dropdowns).
92
+ */
93
+ export function getRegisteredShellTypes(): string[] {
94
+ return Array.from(shellRegistry.keys());
95
+ }
96
+
97
+ /**
98
+ * Get metadata for a shell type.
99
+ */
100
+ export function getShellMeta(type: string): ShellMeta {
101
+ return shellMetaRegistry.get(type) || { icon: '📦', color: '#71717a', label: type };
102
+ }
103
+
104
+ // ── Legacy compatibility ──
105
+ // Bridge to the old registerMorphComponent API during migration
106
+
107
+ /**
108
+ * @deprecated Use registerShell() instead
109
+ */
110
+ export function registerMorphComponentCompat(id: string, component: React.ComponentType<any>) {
111
+ // Wrap legacy components to match ShellProps interface
112
+ const WrappedComponent: React.ComponentType<ShellProps> = (props) => {
113
+ return React.createElement(component, { ...(props.data || {}), ...props });
114
+ };
115
+ shellRegistry.set(id, WrappedComponent);
116
+ }
117
+
118
+ /**
119
+ * @deprecated Use resolveShell() instead
120
+ */
121
+ export function getMorphComponentCompat(id: string): React.ComponentType<any> | undefined {
122
+ return shellRegistry.get(id) as React.ComponentType<any> | undefined;
123
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * useSuggestionsStore — Zustand store for managing chat suggestions.
3
+ *
4
+ * Supports: seed phrases (user CRUD), AI-generated suggestions,
5
+ * and plugin-registered suggestions via SDK.
6
+ */
7
+ import { create } from 'zustand';
8
+ import { persist } from 'zustand/middleware';
9
+
10
+ export interface SuggestionsState {
11
+ seeds: string[];
12
+ generated: string[];
13
+ pluginSuggestions: Record<string, string[]>;
14
+
15
+ addSeed: (seed: string) => void;
16
+ removeSeed: (index: number) => void;
17
+ updateSeed: (index: number, value: string) => void;
18
+ setGenerated: (suggestions: string[]) => void;
19
+ registerPluginSuggestions: (pluginId: string, items: string[]) => void;
20
+ unregisterPluginSuggestions: (pluginId: string) => void;
21
+ getAllSuggestions: () => string[];
22
+ }
23
+
24
+ export const useSuggestionsStore = create<SuggestionsState>()(
25
+ persist(
26
+ (set, get) => ({
27
+ seeds: [
28
+ 'Explícame cómo funciona este flujo',
29
+ 'Crea un grafo de onboarding',
30
+ 'Analiza el rendimiento del sistema',
31
+ ],
32
+ generated: [],
33
+ pluginSuggestions: {},
34
+
35
+ addSeed: (seed) => set(s => ({ seeds: [...s.seeds, seed] })),
36
+ removeSeed: (index) => set(s => ({ seeds: s.seeds.filter((_, i) => i !== index) })),
37
+ updateSeed: (index, value) => set(s => ({
38
+ seeds: s.seeds.map((seed, i) => i === index ? value : seed)
39
+ })),
40
+ setGenerated: (suggestions) => set({ generated: suggestions }),
41
+ registerPluginSuggestions: (pluginId, items) => set(s => ({
42
+ pluginSuggestions: { ...s.pluginSuggestions, [pluginId]: items }
43
+ })),
44
+ unregisterPluginSuggestions: (pluginId) => set(s => {
45
+ const next = { ...s.pluginSuggestions };
46
+ delete next[pluginId];
47
+ return { pluginSuggestions: next };
48
+ }),
49
+ getAllSuggestions: () => {
50
+ const s = get();
51
+ const plugin = Object.values(s.pluginSuggestions).flat();
52
+ return [...s.generated, ...s.seeds, ...plugin];
53
+ },
54
+ }),
55
+ { name: 'decido-suggestions-store' }
56
+ )
57
+ );
@@ -0,0 +1,399 @@
1
+ /**
2
+ * Decido Aura — Theme Store
3
+ *
4
+ * Consolidated Zustand store for runtime theme management.
5
+ * Sets `--ds-*` CSS custom properties on `:root` which are
6
+ * read by the TW4 `@theme` contract in tokens.css.
7
+ *
8
+ * Usage:
9
+ * const { setTheme, currentTheme } = useTheme();
10
+ * setTheme('midnight-blue');
11
+ */
12
+ import { create } from 'zustand';
13
+ import { persist } from 'zustand/middleware';
14
+
15
+ // ── Types ──
16
+
17
+ export interface ThemeTokens {
18
+ /* Surface */
19
+ 'surface-primary': string;
20
+ 'surface-secondary': string;
21
+ 'surface-tertiary': string;
22
+ 'surface-elevated': string;
23
+ 'surface-glass': string;
24
+ 'surface-overlay': string;
25
+ /* Text */
26
+ 'text-primary': string;
27
+ 'text-secondary': string;
28
+ 'text-muted': string;
29
+ 'text-inverse': string;
30
+ /* Accent */
31
+ 'accent-blue': string;
32
+ 'accent-purple': string;
33
+ 'accent-green': string;
34
+ 'accent-red': string;
35
+ 'accent-amber': string;
36
+ 'accent-cyan': string;
37
+ /* Border */
38
+ 'border-subtle': string;
39
+ 'border-default': string;
40
+ 'border-strong': string;
41
+ 'border-glow': string;
42
+ /* Status */
43
+ 'status-ok': string;
44
+ 'status-warn': string;
45
+ 'status-error': string;
46
+ 'status-info': string;
47
+ }
48
+
49
+ export interface ThemeMeta {
50
+ 'radius-xs': string;
51
+ 'radius-sm': string;
52
+ 'radius-md': string;
53
+ 'radius-lg': string;
54
+ 'radius-xl': string;
55
+ 'blur-xs': string;
56
+ 'blur-sm': string;
57
+ 'blur-md': string;
58
+ 'blur-lg': string;
59
+ 'blur-xl': string;
60
+ 'font-sans': string;
61
+ 'font-mono': string;
62
+ }
63
+
64
+ export interface ThemePreset {
65
+ id: string;
66
+ name: string;
67
+ description: string;
68
+ preview: { bg: string; accent: string; text: string };
69
+ tokens: ThemeTokens;
70
+ meta: ThemeMeta;
71
+ }
72
+
73
+ // ── Default Meta ──
74
+
75
+ const DEFAULT_META: ThemeMeta = {
76
+ 'radius-xs': '4px',
77
+ 'radius-sm': '6px',
78
+ 'radius-md': '10px',
79
+ 'radius-lg': '16px',
80
+ 'radius-xl': '24px',
81
+ 'blur-xs': '4px',
82
+ 'blur-sm': '8px',
83
+ 'blur-md': '16px',
84
+ 'blur-lg': '24px',
85
+ 'blur-xl': '40px',
86
+ 'font-sans': "'Inter', 'system-ui', sans-serif",
87
+ 'font-mono': "'JetBrains Mono', 'Fira Code', monospace",
88
+ };
89
+
90
+ // ── Presets ──
91
+
92
+ export const THEME_DECIDO_DARK: ThemePreset = {
93
+ id: 'decido-dark',
94
+ name: 'Decido Dark',
95
+ description: 'Tema por defecto — oscuro con acentos púrpura y cyan',
96
+ preview: { bg: '#0a0a0f', accent: '#a855f7', text: '#e8e8f0' },
97
+ tokens: {
98
+ 'surface-primary': '#0a0a0f',
99
+ 'surface-secondary': '#12121a',
100
+ 'surface-tertiary': '#1a1a26',
101
+ 'surface-elevated': '#22222e',
102
+ 'surface-glass': 'rgba(255, 255, 255, 0.03)',
103
+ 'surface-overlay': 'rgba(0, 0, 0, 0.6)',
104
+ 'text-primary': '#e8e8f0',
105
+ 'text-secondary': '#9898b0',
106
+ 'text-muted': '#5a5a72',
107
+ 'text-inverse': '#0a0a0f',
108
+ 'accent-blue': '#4a9eff',
109
+ 'accent-purple': '#a855f7',
110
+ 'accent-green': '#34d399',
111
+ 'accent-red': '#f87171',
112
+ 'accent-amber': '#fbbf24',
113
+ 'accent-cyan': '#22d3ee',
114
+ 'border-subtle': 'rgba(255, 255, 255, 0.06)',
115
+ 'border-default': 'rgba(255, 255, 255, 0.1)',
116
+ 'border-strong': 'rgba(255, 255, 255, 0.2)',
117
+ 'border-glow': 'rgba(168, 85, 247, 0.5)',
118
+ 'status-ok': '#34d399',
119
+ 'status-warn': '#fbbf24',
120
+ 'status-error': '#f87171',
121
+ 'status-info': '#4a9eff',
122
+ },
123
+ meta: DEFAULT_META,
124
+ };
125
+
126
+ export const THEME_MIDNIGHT_BLUE: ThemePreset = {
127
+ id: 'midnight-blue',
128
+ name: 'Midnight Blue',
129
+ description: 'Azul profundo con tonos slate',
130
+ preview: { bg: '#0b1120', accent: '#3b82f6', text: '#f1f5f9' },
131
+ tokens: {
132
+ 'surface-primary': '#0b1120',
133
+ 'surface-secondary': '#111827',
134
+ 'surface-tertiary': '#1e293b',
135
+ 'surface-elevated': '#273548',
136
+ 'surface-glass': 'rgba(30, 41, 59, 0.5)',
137
+ 'surface-overlay': 'rgba(11, 17, 32, 0.7)',
138
+ 'text-primary': '#f1f5f9',
139
+ 'text-secondary': '#94a3b8',
140
+ 'text-muted': '#64748b',
141
+ 'text-inverse': '#0b1120',
142
+ 'accent-blue': '#3b82f6',
143
+ 'accent-purple': '#8b5cf6',
144
+ 'accent-green': '#22c55e',
145
+ 'accent-red': '#ef4444',
146
+ 'accent-amber': '#f59e0b',
147
+ 'accent-cyan': '#06b6d4',
148
+ 'border-subtle': 'rgba(148, 163, 184, 0.06)',
149
+ 'border-default': 'rgba(148, 163, 184, 0.12)',
150
+ 'border-strong': 'rgba(148, 163, 184, 0.25)',
151
+ 'border-glow': 'rgba(59, 130, 246, 0.5)',
152
+ 'status-ok': '#22c55e',
153
+ 'status-warn': '#f59e0b',
154
+ 'status-error': '#ef4444',
155
+ 'status-info': '#3b82f6',
156
+ },
157
+ meta: DEFAULT_META,
158
+ };
159
+
160
+ export const THEME_EMERALD_NOIR: ThemePreset = {
161
+ id: 'emerald-noir',
162
+ name: 'Emerald Noir',
163
+ description: 'Oscuro con acentos esmeralda',
164
+ preview: { bg: '#0a0f0d', accent: '#34d399', text: '#ecfdf5' },
165
+ tokens: {
166
+ 'surface-primary': '#0a0f0d',
167
+ 'surface-secondary': '#0f1a15',
168
+ 'surface-tertiary': '#162620',
169
+ 'surface-elevated': '#1e332b',
170
+ 'surface-glass': 'rgba(22, 38, 32, 0.5)',
171
+ 'surface-overlay': 'rgba(10, 15, 13, 0.7)',
172
+ 'text-primary': '#ecfdf5',
173
+ 'text-secondary': '#a7f3d0',
174
+ 'text-muted': '#6ee7b7',
175
+ 'text-inverse': '#0a0f0d',
176
+ 'accent-blue': '#2dd4bf',
177
+ 'accent-purple': '#a78bfa',
178
+ 'accent-green': '#34d399',
179
+ 'accent-red': '#fb7185',
180
+ 'accent-amber': '#fbbf24',
181
+ 'accent-cyan': '#2dd4bf',
182
+ 'border-subtle': 'rgba(167, 243, 208, 0.06)',
183
+ 'border-default': 'rgba(167, 243, 208, 0.12)',
184
+ 'border-strong': 'rgba(167, 243, 208, 0.25)',
185
+ 'border-glow': 'rgba(52, 211, 153, 0.5)',
186
+ 'status-ok': '#34d399',
187
+ 'status-warn': '#fbbf24',
188
+ 'status-error': '#fb7185',
189
+ 'status-info': '#2dd4bf',
190
+ },
191
+ meta: DEFAULT_META,
192
+ };
193
+
194
+ export const THEME_ROSE_GOLD: ThemePreset = {
195
+ id: 'rose-gold',
196
+ name: 'Rose Gold',
197
+ description: 'Elegante con tonos rosa y dorado',
198
+ preview: { bg: '#120a0d', accent: '#f472b6', text: '#fdf2f8' },
199
+ tokens: {
200
+ 'surface-primary': '#120a0d',
201
+ 'surface-secondary': '#1a1015',
202
+ 'surface-tertiary': '#26161e',
203
+ 'surface-elevated': '#331c28',
204
+ 'surface-glass': 'rgba(38, 22, 30, 0.5)',
205
+ 'surface-overlay': 'rgba(18, 10, 13, 0.7)',
206
+ 'text-primary': '#fdf2f8',
207
+ 'text-secondary': '#f9a8d4',
208
+ 'text-muted': '#f472b6',
209
+ 'text-inverse': '#120a0d',
210
+ 'accent-blue': '#e879f9',
211
+ 'accent-purple': '#f472b6',
212
+ 'accent-green': '#34d399',
213
+ 'accent-red': '#fb7185',
214
+ 'accent-amber': '#fcd34d',
215
+ 'accent-cyan': '#e879f9',
216
+ 'border-subtle': 'rgba(249, 168, 212, 0.06)',
217
+ 'border-default': 'rgba(249, 168, 212, 0.12)',
218
+ 'border-strong': 'rgba(249, 168, 212, 0.25)',
219
+ 'border-glow': 'rgba(244, 114, 182, 0.5)',
220
+ 'status-ok': '#34d399',
221
+ 'status-warn': '#fcd34d',
222
+ 'status-error': '#fb7185',
223
+ 'status-info': '#e879f9',
224
+ },
225
+ meta: DEFAULT_META,
226
+ };
227
+
228
+ export const THEME_OLED_PURE: ThemePreset = {
229
+ id: 'oled-pure',
230
+ name: 'OLED Pure',
231
+ description: 'Negro absoluto para pantallas OLED',
232
+ preview: { bg: '#000000', accent: '#a855f7', text: '#ffffff' },
233
+ tokens: {
234
+ 'surface-primary': '#000000',
235
+ 'surface-secondary': '#0a0a0a',
236
+ 'surface-tertiary': '#141414',
237
+ 'surface-elevated': '#1e1e1e',
238
+ 'surface-glass': 'rgba(255, 255, 255, 0.02)',
239
+ 'surface-overlay': 'rgba(0, 0, 0, 0.8)',
240
+ 'text-primary': '#ffffff',
241
+ 'text-secondary': '#a0a0a0',
242
+ 'text-muted': '#666666',
243
+ 'text-inverse': '#000000',
244
+ 'accent-blue': '#4a9eff',
245
+ 'accent-purple': '#a855f7',
246
+ 'accent-green': '#34d399',
247
+ 'accent-red': '#f87171',
248
+ 'accent-amber': '#fbbf24',
249
+ 'accent-cyan': '#22d3ee',
250
+ 'border-subtle': 'rgba(255, 255, 255, 0.04)',
251
+ 'border-default': 'rgba(255, 255, 255, 0.08)',
252
+ 'border-strong': 'rgba(255, 255, 255, 0.15)',
253
+ 'border-glow': 'rgba(168, 85, 247, 0.5)',
254
+ 'status-ok': '#4ade80',
255
+ 'status-warn': '#fbbf24',
256
+ 'status-error': '#f87171',
257
+ 'status-info': '#4a9eff',
258
+ },
259
+ meta: DEFAULT_META,
260
+ };
261
+
262
+ // ── Light Theme ──
263
+
264
+ export const THEME_DECIDO_LIGHT: ThemePreset = {
265
+ id: 'decido-light',
266
+ name: 'Decido Light',
267
+ description: 'Tema claro premium — ideal para trabajo diurno',
268
+ preview: { bg: '#f8f9fb', accent: '#6366f1', text: '#1a1a2e' },
269
+ tokens: {
270
+ 'surface-primary': '#f8f9fb',
271
+ 'surface-secondary': '#ffffff',
272
+ 'surface-tertiary': '#eef0f4',
273
+ 'surface-elevated': '#ffffff',
274
+ 'surface-glass': 'rgba(0, 0, 0, 0.03)',
275
+ 'surface-overlay': 'rgba(0, 0, 0, 0.4)',
276
+ 'text-primary': '#1a1a2e',
277
+ 'text-secondary': '#64648c',
278
+ 'text-muted': '#9898b0',
279
+ 'text-inverse': '#ffffff',
280
+ 'accent-blue': '#3b82f6',
281
+ 'accent-purple': '#6366f1',
282
+ 'accent-green': '#10b981',
283
+ 'accent-red': '#ef4444',
284
+ 'accent-amber': '#f59e0b',
285
+ 'accent-cyan': '#06b6d4',
286
+ 'border-subtle': 'rgba(0, 0, 0, 0.06)',
287
+ 'border-default': 'rgba(0, 0, 0, 0.12)',
288
+ 'border-strong': 'rgba(0, 0, 0, 0.2)',
289
+ 'border-glow': 'rgba(99, 102, 241, 0.4)',
290
+ 'status-ok': '#10b981',
291
+ 'status-warn': '#f59e0b',
292
+ 'status-error': '#ef4444',
293
+ 'status-info': '#3b82f6',
294
+ },
295
+ meta: DEFAULT_META,
296
+ };
297
+
298
+ // ── All presets ──
299
+
300
+ export const THEME_PRESETS: ThemePreset[] = [
301
+ THEME_DECIDO_DARK,
302
+ THEME_DECIDO_LIGHT,
303
+ THEME_MIDNIGHT_BLUE,
304
+ THEME_EMERALD_NOIR,
305
+ THEME_ROSE_GOLD,
306
+ THEME_OLED_PURE,
307
+ ];
308
+
309
+ // ── Inject helper ──
310
+
311
+ function injectTokens(tokens: ThemeTokens, meta: ThemeMeta) {
312
+ const root = document.documentElement;
313
+ Object.entries(tokens).forEach(([key, value]) => {
314
+ root.style.setProperty(`--ds-${key}`, value);
315
+ });
316
+ Object.entries(meta).forEach(([key, value]) => {
317
+ root.style.setProperty(`--ds-${key}`, value);
318
+ });
319
+ }
320
+
321
+ // ── Store ──
322
+
323
+ interface ThemeState {
324
+ currentThemeId: string;
325
+ customPresets: ThemePreset[];
326
+ /* Actions */
327
+ setTheme: (themeId: string) => void;
328
+ setToken: (name: keyof ThemeTokens, value: string) => void;
329
+ addPreset: (preset: ThemePreset) => void;
330
+ inject: () => void;
331
+ exportCSS: () => string;
332
+ /* Getters */
333
+ getCurrentPreset: () => ThemePreset;
334
+ getAllPresets: () => ThemePreset[];
335
+ }
336
+
337
+ export const useTheme = create<ThemeState>()(
338
+ persist(
339
+ (set, get) => ({
340
+ currentThemeId: 'decido-dark',
341
+ customPresets: [],
342
+
343
+ setTheme: (themeId) => {
344
+ set({ currentThemeId: themeId });
345
+ const preset = get().getCurrentPreset();
346
+ injectTokens(preset.tokens, preset.meta);
347
+ },
348
+
349
+ setToken: (name, value) => {
350
+ document.documentElement.style.setProperty(`--ds-${name}`, value);
351
+ },
352
+
353
+ addPreset: (preset) => {
354
+ set((s) => ({
355
+ customPresets: [...s.customPresets.filter((p) => p.id !== preset.id), preset],
356
+ }));
357
+ },
358
+
359
+ inject: () => {
360
+ const preset = get().getCurrentPreset();
361
+ injectTokens(preset.tokens, preset.meta);
362
+ },
363
+
364
+ exportCSS: () => {
365
+ const preset = get().getCurrentPreset();
366
+ const lines = [`:root {`];
367
+ Object.entries(preset.tokens).forEach(([k, v]) => {
368
+ lines.push(` --ds-${k}: ${v};`);
369
+ });
370
+ Object.entries(preset.meta).forEach(([k, v]) => {
371
+ lines.push(` --ds-${k}: ${v};`);
372
+ });
373
+ lines.push(`}`);
374
+ return lines.join('\n');
375
+ },
376
+
377
+ getCurrentPreset: () => {
378
+ const { currentThemeId, customPresets } = get();
379
+ return (
380
+ [...THEME_PRESETS, ...customPresets].find((p) => p.id === currentThemeId) ??
381
+ THEME_DECIDO_DARK
382
+ );
383
+ },
384
+
385
+ getAllPresets: () => {
386
+ return [...THEME_PRESETS, ...get().customPresets];
387
+ },
388
+ }),
389
+ {
390
+ name: 'decido-aura-theme',
391
+ onRehydrateStorage: () => (state) => {
392
+ if (state) {
393
+ // Re-inject theme on page load
394
+ setTimeout(() => state.inject(), 0);
395
+ }
396
+ },
397
+ }
398
+ )
399
+ );