@decido/shell 1.0.0 → 4.0.1

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/README.md +31 -0
  2. package/package.json +17 -14
  3. package/.turbo/turbo-build.log +0 -13
  4. package/src/AgentPlayer.tsx +0 -105
  5. package/src/DecidoPlayer.tsx +0 -117
  6. package/src/bridge/BridgeAgent.ts +0 -443
  7. package/src/components/DecidoIcon.tsx +0 -56
  8. package/src/components/JsonTreeEditor.tsx +0 -117
  9. package/src/components/PanelSplitter.tsx +0 -71
  10. package/src/components/PluginErrorBoundary.tsx +0 -69
  11. package/src/components/SafeLiquidUI.tsx +0 -114
  12. package/src/components/TransientLayer.tsx +0 -92
  13. package/src/components/agent/AgentChat.tsx +0 -134
  14. package/src/components/chat-extensions/IntentCatalogPanel.tsx +0 -81
  15. package/src/components/chat-extensions/chatSlashCommands.ts +0 -101
  16. package/src/components/controls/CreatorInputBar.tsx +0 -144
  17. package/src/components/controls/OSToolbar.tsx +0 -90
  18. package/src/components/controls/TimelineTape.tsx +0 -43
  19. package/src/components/debug/ActionTimelineTab.tsx +0 -111
  20. package/src/components/debug/CSSInspectorTab.tsx +0 -436
  21. package/src/components/debug/ExportTab.tsx +0 -192
  22. package/src/components/debug/FlowHealthTab.tsx +0 -86
  23. package/src/components/debug/LogsTab.tsx +0 -110
  24. package/src/components/debug/MorphStackTab.tsx +0 -241
  25. package/src/components/debug/NetworkTab.tsx +0 -173
  26. package/src/components/debug/PerformanceTab.tsx +0 -171
  27. package/src/components/debug/ProfilesTab.tsx +0 -238
  28. package/src/components/debug/ReplayTab.tsx +0 -70
  29. package/src/components/debug/StoresTab.tsx +0 -255
  30. package/src/components/debug/TopologyTab.tsx +0 -59
  31. package/src/components/debug/debugConfig.tsx +0 -66
  32. package/src/components/playground/DebugPanel.tsx +0 -112
  33. package/src/components/playground/HeaderCenterControls.tsx +0 -92
  34. package/src/components/playground/KeyframeListItem.tsx +0 -70
  35. package/src/components/playground/PlaygroundAppSidebar.tsx +0 -171
  36. package/src/components/playground/PlaygroundBottomControls.tsx +0 -132
  37. package/src/components/playground/PlaygroundCanvas.tsx +0 -87
  38. package/src/components/playground/PlaygroundChat.tsx +0 -236
  39. package/src/components/playground/PlaygroundErrorBoundary.tsx +0 -63
  40. package/src/components/playground/PlaygroundFloatingInput.tsx +0 -352
  41. package/src/components/playground/PlaygroundHeader.tsx +0 -222
  42. package/src/components/playground/PlaygroundSidebar.tsx +0 -136
  43. package/src/components/playground/PlaygroundTerminal.tsx +0 -44
  44. package/src/components/playground/SuggestionCards.tsx +0 -29
  45. package/src/components/playground/demos/ClinicaAINode.tsx +0 -221
  46. package/src/components/playground/demos/FinanceAINode.tsx +0 -226
  47. package/src/components/playground/demos/KiaAcademyNode.tsx +0 -250
  48. package/src/components/playground/demos/KiaBotNode.tsx +0 -207
  49. package/src/components/playground/demos/KiaCampaignNode.tsx +0 -191
  50. package/src/components/playground/demos/KiaComplianceNode.tsx +0 -140
  51. package/src/components/playground/demos/KiaCustomerJourneyNode.tsx +0 -220
  52. package/src/components/playground/demos/KiaCyberNode.tsx +0 -203
  53. package/src/components/playground/demos/KiaDashboardNode.tsx +0 -399
  54. package/src/components/playground/demos/KiaEmbudoOverviewNode.tsx +0 -168
  55. package/src/components/playground/demos/KiaExecutiveNode.tsx +0 -169
  56. package/src/components/playground/demos/KiaGamificationNode.tsx +0 -229
  57. package/src/components/playground/demos/KiaIntelligenceHubNode.tsx +0 -165
  58. package/src/components/playground/demos/KiaInventoryNode.tsx +0 -183
  59. package/src/components/playground/demos/KiaLeadScoringNode.tsx +0 -226
  60. package/src/components/playground/demos/KiaLiveSimulationNode.tsx +0 -177
  61. package/src/components/playground/demos/KiaMultiDealerNode.tsx +0 -223
  62. package/src/components/playground/demos/KiaNPSVoiceNode.tsx +0 -214
  63. package/src/components/playground/demos/KiaOmnichannelNode.tsx +0 -162
  64. package/src/components/playground/demos/KiaPBIBudgetNode.tsx +0 -152
  65. package/src/components/playground/demos/KiaPBIConversionNode.tsx +0 -206
  66. package/src/components/playground/demos/KiaPBIFunnelNode.tsx +0 -184
  67. package/src/components/playground/demos/KiaPBIOwnershipNode.tsx +0 -113
  68. package/src/components/playground/demos/KiaPBIPartnerNode.tsx +0 -143
  69. package/src/components/playground/demos/KiaPBIPreciosNode.tsx +0 -120
  70. package/src/components/playground/demos/KiaPBIRuntNode.tsx +0 -205
  71. package/src/components/playground/demos/KiaPartnerScoreNode.tsx +0 -206
  72. package/src/components/playground/demos/KiaPredictiveNode.tsx +0 -226
  73. package/src/components/playground/demos/KiaShowroomNode.tsx +0 -194
  74. package/src/components/playground/demos/KiaStoreNode.tsx +0 -215
  75. package/src/components/playground/demos/KiaSustainabilityNode.tsx +0 -173
  76. package/src/components/playground/demos/KiaUsedVehiclesNode.tsx +0 -163
  77. package/src/components/playground/demos/KiaWorkshopNode.tsx +0 -221
  78. package/src/components/playground/demos/SmartCityNode.tsx +0 -205
  79. package/src/components/playground/demos/kia_campaign_manifest.json +0 -112
  80. package/src/components/playground/input-parts/AIModelSelector.tsx +0 -156
  81. package/src/components/playground/input-parts/InputActions.tsx +0 -80
  82. package/src/components/playground/input-parts/InputToolbar.tsx +0 -245
  83. package/src/components/playground/input-parts/ResourceLibraryPanel.tsx +0 -287
  84. package/src/components/playground/sidebarDsdIO.ts +0 -82
  85. package/src/components/settings/SettingsPanel.tsx +0 -267
  86. package/src/components/shell/AppHeader.tsx +0 -9
  87. package/src/components/shell/AppShell.tsx +0 -139
  88. package/src/components/shell/ArtifactBar.tsx +0 -97
  89. package/src/components/shell/BootScreen.tsx +0 -19
  90. package/src/components/shell/CenterComposite.tsx +0 -87
  91. package/src/components/shell/CodeEditorPanel.tsx +0 -88
  92. package/src/components/shell/GlobalOverlays.tsx +0 -228
  93. package/src/components/shell/LayoutConfigurator.tsx +0 -209
  94. package/src/components/shell/LayoutGrid.tsx +0 -178
  95. package/src/components/shell/MorphShell.tsx +0 -368
  96. package/src/components/shell/PluginViewer.tsx +0 -147
  97. package/src/components/shell/ShellNexusPreview.tsx +0 -458
  98. package/src/components/shell/SlotRenderer.tsx +0 -115
  99. package/src/components/shell/TabBar.tsx +0 -94
  100. package/src/components/shell/TemplateLibrary.tsx +0 -195
  101. package/src/components/shell/layoutConstants.ts +0 -35
  102. package/src/components/shell/morphStageMeta.ts +0 -15
  103. package/src/components/shell/shells/BuiltInShells.tsx +0 -443
  104. package/src/components/shell/shells/DatawayChatShell.tsx +0 -42
  105. package/src/components/shell/shells/TokenPreview.tsx +0 -339
  106. package/src/components/shell/shells/bootShells.ts +0 -31
  107. package/src/components/shells/CreatorShell.tsx +0 -37
  108. package/src/components/shells/DecidoShell.tsx +0 -447
  109. package/src/components/shells/ExperimentalChatShell.tsx +0 -245
  110. package/src/components/shells/UserCanvas.tsx +0 -44
  111. package/src/components/studio/BlueprintManagerPanel.tsx +0 -137
  112. package/src/components/studio/DependencyTreePanel.tsx +0 -192
  113. package/src/components/studio/NodePalette.tsx +0 -92
  114. package/src/components/studio/NodePropertiesPanel.tsx +0 -81
  115. package/src/components/studio/ReactFlowEditor.tsx +0 -242
  116. package/src/components/studio/TimelineEditor.tsx +0 -122
  117. package/src/components/studio/TimelineKeyframeCard.tsx +0 -99
  118. package/src/components/studio/VariablePanel.tsx +0 -181
  119. package/src/components/studio/blueprint/BlueprintCard.tsx +0 -82
  120. package/src/components/studio/editor/CanvasContextMenu.tsx +0 -107
  121. package/src/components/studio/editor/EditorToolbar.tsx +0 -80
  122. package/src/components/studio/editor/StageContentRenderer.tsx +0 -134
  123. package/src/components/studio/editor/TrackPropertyEditors.tsx +0 -133
  124. package/src/components/studio/editor/TreeNodeItem.tsx +0 -91
  125. package/src/components/studio/editor/edgeStyles.ts +0 -43
  126. package/src/components/studio/editor/editorKeyHandler.ts +0 -95
  127. package/src/components/studio/editor/nodeTypeRegistry.ts +0 -137
  128. package/src/components/studio/editor/paletteCatalog.tsx +0 -84
  129. package/src/components/studio/nodes/shell/InteractionNodes.tsx +0 -82
  130. package/src/components/studio/nodes/shell/LayoutControlNodes.tsx +0 -69
  131. package/src/components/studio/nodes/shell/RegisterActionNode.tsx +0 -20
  132. package/src/components/studio/nodes/shell/RegisterButtonNode.tsx +0 -22
  133. package/src/components/studio/nodes/shell/RegisterPanelNode.tsx +0 -19
  134. package/src/components/studio/nodes/shell/RegisterSidebarNode.tsx +0 -19
  135. package/src/components/studio/nodes/shell/RegisterStatusBarNode.tsx +0 -22
  136. package/src/components/studio/nodes/shell/RegisterTabNode.tsx +0 -21
  137. package/src/components/studio/nodes/shell/RegisterTopBarNode.tsx +0 -22
  138. package/src/components/studio/nodes/shell/ShellConfigNode.tsx +0 -51
  139. package/src/components/studio/nodes/shell/ShellNodeBase.tsx +0 -100
  140. package/src/components/studio/nodes/shell/ThemeNodes.tsx +0 -51
  141. package/src/components/studio/nodes/shell/index.ts +0 -12
  142. package/src/components/widgets/BroadcastWidget.tsx +0 -93
  143. package/src/components/widgets/MarketplaceWidget.tsx +0 -298
  144. package/src/components/widgets/McpToolsWidget.tsx +0 -231
  145. package/src/components/widgets/OpsDashboard.tsx +0 -59
  146. package/src/components/widgets/QuickActionsWidget.tsx +0 -60
  147. package/src/components/widgets/UsageWidget.tsx +0 -112
  148. package/src/components/widgets/WidgetRenderer.tsx +0 -892
  149. package/src/components/widgets/WidgetSlotPanel.tsx +0 -213
  150. package/src/config/IconRegistry.ts +0 -126
  151. package/src/contexts/NetworkProvider.tsx +0 -162
  152. package/src/core/AIDirector.ts +0 -71
  153. package/src/core/EventBus.ts +0 -37
  154. package/src/core/PluginContext.tsx +0 -141
  155. package/src/hooks/listeners/useUIStateListener.ts +0 -59
  156. package/src/hooks/listeners/useWhatsAppListener.ts +0 -110
  157. package/src/hooks/morphBridge.ts +0 -82
  158. package/src/hooks/useAIModelSelector.ts +0 -144
  159. package/src/hooks/useAgentStream.ts +0 -220
  160. package/src/hooks/useAutoUpdater.ts +0 -89
  161. package/src/hooks/useBootSequence.ts +0 -20
  162. package/src/hooks/useExportDSD.ts +0 -53
  163. package/src/hooks/useFullscreen.ts +0 -35
  164. package/src/hooks/useGeminiStream.ts +0 -282
  165. package/src/hooks/useIntentLens.ts +0 -224
  166. package/src/hooks/useKeyboardShortcuts.ts +0 -69
  167. package/src/hooks/useLoggerBridge.ts +0 -32
  168. package/src/hooks/useMcpClient.ts +0 -112
  169. package/src/hooks/useNexusaiDeploy.ts +0 -118
  170. package/src/hooks/usePlaybackEngine.ts +0 -21
  171. package/src/hooks/usePlaygroundCommander.ts +0 -475
  172. package/src/hooks/usePluginEngine.ts +0 -165
  173. package/src/hooks/useScreenRecorder.ts +0 -73
  174. package/src/hooks/useShellKeyboard.ts +0 -40
  175. package/src/hooks/useShellShortcuts.ts +0 -118
  176. package/src/hooks/useSoundEffects.ts +0 -35
  177. package/src/hooks/useStudioConfig.ts +0 -72
  178. package/src/hooks/useSystemBoot.ts +0 -84
  179. package/src/hooks/useSystemTelemetry.ts +0 -62
  180. package/src/lib/debugLogger.ts +0 -80
  181. package/src/lib/networkInterceptor.ts +0 -100
  182. package/src/mocks/decido.tsx +0 -41
  183. package/src/plugins/pluginAPI.ts +0 -190
  184. package/src/store/McpStore.ts +0 -69
  185. package/src/store/UpdaterStore.ts +0 -60
  186. package/src/store/engine.ts +0 -392
  187. package/src/store/index.ts +0 -4
  188. package/src/store/layoutPresets.ts +0 -66
  189. package/src/store/playgroundTypes.ts +0 -98
  190. package/src/store/useActionTimelineStore.ts +0 -48
  191. package/src/store/useDebugPanelStore.ts +0 -98
  192. package/src/store/useDebugProfileStore.ts +0 -130
  193. package/src/store/useLayoutStore.ts +0 -205
  194. package/src/store/useMorphInstanceStore.ts +0 -289
  195. package/src/store/useMorphologyStore.ts +0 -103
  196. package/src/store/usePlaygroundStore.ts +0 -236
  197. package/src/store/useShellRegistry.ts +0 -123
  198. package/src/store/useSuggestionsStore.ts +0 -57
  199. package/src/store/useThemeStore.ts +0 -399
  200. package/src/store/useUIComponentStore.ts +0 -179
  201. package/src/types/DecidoStoryDefinition.ts +0 -43
  202. package/src/utils/ai/ai-architect.ts +0 -92
  203. package/src/utils/ai/ai-code.ts +0 -187
  204. package/src/utils/ai/ai-core.ts +0 -50
  205. package/src/utils/ai/ai-media.ts +0 -292
  206. package/src/utils/layoutGraph.ts +0 -67
  207. package/tsconfig.json +0 -17
  208. package/tsconfig.tsbuildinfo +0 -1
@@ -1,436 +0,0 @@
1
- /**
2
- * CSSInspectorTab — Integrated Tailwind CSS Inspector for DebugPanel
3
- *
4
- * Features:
5
- * - Element picker with outline overlay
6
- * - Tailwind class viewer/editor (add/remove/toggle)
7
- * - Design token inspector (--ds-* vars affecting element)
8
- * - Box model visualizer
9
- * - Theme switcher
10
- * - "Find hardcoded" detector
11
- */
12
- import React, { useState, useCallback, useEffect, useRef, useMemo } from 'react';
13
- import { Eye, EyeOff, ChevronRight, ChevronDown, Search, Palette, Copy, X, Plus, AlertTriangle, Box, Layers } from 'lucide-react';
14
- import { useTheme, THEME_PRESETS } from '../../store/useThemeStore';
15
-
16
- // ── Outline Overlay (renders outside normal flow) ──
17
-
18
- const OutlineOverlay: React.FC<{ target: HTMLElement | null; color?: string }> = ({ target, color = '#3b82f6' }) => {
19
- const [rect, setRect] = useState<DOMRect | null>(null);
20
- useEffect(() => {
21
- if (!target) { setRect(null); return; }
22
- const update = () => setRect(target.getBoundingClientRect());
23
- update();
24
- const obs = new ResizeObserver(update);
25
- obs.observe(target);
26
- window.addEventListener('scroll', update, true);
27
- return () => { obs.disconnect(); window.removeEventListener('scroll', update, true); };
28
- }, [target]);
29
-
30
- if (!rect) return null;
31
- return (
32
- <div className="fixed pointer-events-none z-99999" style={{
33
- left: rect.left - 2, top: rect.top - 2,
34
- width: rect.width + 4, height: rect.height + 4,
35
- border: `2px solid ${color}`, borderRadius: 4,
36
- background: `${color}11`, transition: 'all 0.15s ease',
37
- }}>
38
- <span className="absolute -top-5 left-0 text-[9px] font-mono px-1.5 py-0.5 rounded" style={{ background: color, color: '#fff' }}>
39
- {target?.tagName.toLowerCase()}{target?.id ? `#${target.id}` : ''}{target?.classList.length ? `.${Array.from(target.classList).slice(0, 2).join('.')}` : ''}
40
- </span>
41
- </div>
42
- );
43
- };
44
-
45
- // ── Important CSS props ──
46
- const KEY_PROPS = [
47
- 'display', 'position', 'z-index', 'opacity',
48
- 'width', 'height', 'max-width', 'max-height',
49
- 'margin', 'padding', 'gap',
50
- 'flex', 'flex-direction', 'align-items', 'justify-content',
51
- 'background-color', 'color', 'font-size', 'font-weight',
52
- 'border', 'border-radius', 'box-shadow', 'backdrop-filter',
53
- 'overflow', 'transform', 'pointer-events',
54
- ];
55
-
56
- // ── Detect if a color value is hardcoded (not using tokens) ──
57
- function isHardcodedColor(value: string): boolean {
58
- if (!value) return false;
59
- return /^#[0-9a-f]{3,8}$/i.test(value) || /^rgb/i.test(value);
60
- }
61
-
62
- // ── Extract --ds-* tokens from computed styles ──
63
- function getActiveTokens(el: HTMLElement): { token: string; value: string }[] {
64
- const style = getComputedStyle(el);
65
- const root = getComputedStyle(document.documentElement);
66
- const tokens: { token: string; value: string }[] = [];
67
- const dsVars = ['surface-primary', 'surface-secondary', 'surface-tertiary', 'surface-elevated',
68
- 'surface-glass', 'text-primary', 'text-secondary', 'text-muted', 'accent-blue', 'accent-purple',
69
- 'accent-green', 'accent-red', 'accent-amber', 'accent-cyan', 'border-subtle', 'border-default',
70
- 'border-strong', 'border-glow'];
71
-
72
- const bgColor = style.backgroundColor;
73
- const textColor = style.color;
74
- const borderColor = style.borderColor;
75
-
76
- for (const v of dsVars) {
77
- const tokenVal = root.getPropertyValue(`--ds-${v}`).trim();
78
- if (!tokenVal) continue;
79
- if (bgColor === tokenVal || textColor === tokenVal || borderColor === tokenVal) {
80
- tokens.push({ token: `--ds-${v}`, value: tokenVal });
81
- }
82
- }
83
- return tokens;
84
- }
85
-
86
- // ── Box Model Component ──
87
- const BoxModelViz: React.FC<{ el: HTMLElement }> = ({ el }) => {
88
- const style = getComputedStyle(el);
89
- const m = { t: style.marginTop, r: style.marginRight, b: style.marginBottom, l: style.marginLeft };
90
- const p = { t: style.paddingTop, r: style.paddingRight, b: style.paddingBottom, l: style.paddingLeft };
91
- const w = el.offsetWidth;
92
- const h = el.offsetHeight;
93
-
94
- return (
95
- <div className="flex justify-center py-3">
96
- <div className="relative text-[8px] font-mono select-none">
97
- {/* Margin */}
98
- <div className="border border-dashed border-accent-amber/40 bg-accent-amber/5 px-6 py-4 rounded">
99
- <span className="absolute top-0.5 left-1 text-accent-amber/60">margin</span>
100
- <span className="absolute top-1 left-1/2 -translate-x-1/2 text-accent-amber">{m.t}</span>
101
- <span className="absolute bottom-1 left-1/2 -translate-x-1/2 text-accent-amber">{m.b}</span>
102
- <span className="absolute left-1 top-1/2 -translate-y-1/2 text-accent-amber">{m.l}</span>
103
- <span className="absolute right-1 top-1/2 -translate-y-1/2 text-accent-amber">{m.r}</span>
104
- {/* Padding */}
105
- <div className="border border-dashed border-accent-green/40 bg-accent-green/5 px-6 py-4 rounded relative">
106
- <span className="absolute top-0.5 left-1 text-accent-green/60">padding</span>
107
- <span className="absolute top-1 left-1/2 -translate-x-1/2 text-accent-green">{p.t}</span>
108
- <span className="absolute bottom-1 left-1/2 -translate-x-1/2 text-accent-green">{p.b}</span>
109
- <span className="absolute left-1 top-1/2 -translate-y-1/2 text-accent-green">{p.l}</span>
110
- <span className="absolute right-1 top-1/2 -translate-y-1/2 text-accent-green">{p.r}</span>
111
- {/* Content */}
112
- <div className="bg-accent-blue/10 border border-accent-blue/30 rounded px-4 py-2 text-center text-accent-blue">
113
- {w} × {h}
114
- </div>
115
- </div>
116
- </div>
117
- </div>
118
- </div>
119
- );
120
- };
121
-
122
- // ── Sub-tabs ──
123
- type SubTab = 'classes' | 'computed' | 'tokens' | 'box';
124
-
125
- // ── Main Component ──
126
- export const CSSInspectorTab: React.FC = () => {
127
- const [selected, setSelected] = useState<HTMLElement | null>(null);
128
- const [hovered, setHovered] = useState<HTMLElement | null>(null);
129
- const [pickMode, setPickMode] = useState(false);
130
- const [subTab, setSubTab] = useState<SubTab>('classes');
131
- const [filter, setFilter] = useState('');
132
- const [showAll, setShowAll] = useState(false);
133
- const [addClass, setAddClass] = useState('');
134
- const [hardcodedEls, setHardcodedEls] = useState<HTMLElement[]>([]);
135
- const setTheme = useTheme(s => s.setTheme);
136
- const currentThemeId = useTheme(s => s.currentThemeId);
137
-
138
- // Pick mode
139
- useEffect(() => {
140
- if (!pickMode) return;
141
- const onClick = (e: MouseEvent) => {
142
- e.preventDefault(); e.stopPropagation();
143
- const t = e.target as HTMLElement;
144
- if (t.closest('[data-debug-panel]')) return;
145
- setSelected(t); setPickMode(false);
146
- };
147
- const onMove = (e: MouseEvent) => {
148
- const t = e.target as HTMLElement;
149
- if (!t.closest('[data-debug-panel]')) setHovered(t);
150
- };
151
- document.addEventListener('click', onClick, true);
152
- document.addEventListener('mousemove', onMove, true);
153
- document.body.style.cursor = 'crosshair';
154
- return () => {
155
- document.removeEventListener('click', onClick, true);
156
- document.removeEventListener('mousemove', onMove, true);
157
- document.body.style.cursor = '';
158
- };
159
- }, [pickMode]);
160
-
161
- // Classes of selected element
162
- const classes = useMemo(() => {
163
- if (!selected) return [];
164
- return Array.from(selected.classList).filter(c => !filter || c.includes(filter));
165
- }, [selected, filter]);
166
-
167
- // Computed CSS
168
- const computedProps = useMemo(() => {
169
- if (!selected) return [];
170
- const computed = getComputedStyle(selected);
171
- const props = showAll
172
- ? Array.from({ length: computed.length }, (_, i) => computed[i])
173
- : KEY_PROPS;
174
- return props
175
- .map(p => ({ prop: p, value: computed.getPropertyValue(p) }))
176
- .filter(p => p.value && p.value !== 'none' && p.value !== 'normal' && p.value !== 'auto' && p.value !== '0px')
177
- .filter(p => !filter || p.prop.includes(filter) || p.value.includes(filter));
178
- }, [selected, filter, showAll]);
179
-
180
- // Active tokens
181
- const tokens = useMemo(() => selected ? getActiveTokens(selected) : [], [selected]);
182
-
183
- // Toggle class
184
- const toggleClass = useCallback((cls: string) => {
185
- if (!selected) return;
186
- selected.classList.toggle(cls);
187
- setSelected(selected); // force re-render
188
- setFilter(f => f); // trigger useMemo
189
- }, [selected]);
190
-
191
- // Add class
192
- const handleAddClass = useCallback(() => {
193
- if (!selected || !addClass.trim()) return;
194
- selected.classList.add(...addClass.trim().split(/\s+/));
195
- setAddClass('');
196
- setFilter(f => f);
197
- }, [selected, addClass]);
198
-
199
- // Find hardcoded colors
200
- const findHardcoded = useCallback(() => {
201
- const root = document.getElementById('root');
202
- if (!root) return;
203
- const els: HTMLElement[] = [];
204
- root.querySelectorAll('*').forEach((el) => {
205
- if (!(el instanceof HTMLElement)) return;
206
- const s = getComputedStyle(el);
207
- const bg = s.backgroundColor;
208
- const color = s.color;
209
- // Check if using non-token colors (not transparent, not inherit)
210
- if (bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent') {
211
- const hasBgToken = Array.from(el.classList).some(c => c.startsWith('bg-surface-') || c.startsWith('bg-accent-'));
212
- if (!hasBgToken && isHardcodedColor(bg)) {
213
- els.push(el);
214
- }
215
- }
216
- });
217
- setHardcodedEls(els);
218
- }, []);
219
-
220
- // Sub-tab buttons
221
- const SUB_TABS: { id: SubTab; label: string; icon: React.ComponentType<any> }[] = [
222
- { id: 'classes', label: 'Classes', icon: Layers },
223
- { id: 'computed', label: 'CSS', icon: Box },
224
- { id: 'tokens', label: 'Tokens', icon: Palette },
225
- { id: 'box', label: 'Box', icon: Box },
226
- ];
227
-
228
- return (
229
- <div className="flex flex-col h-full text-text-primary" data-debug-panel>
230
- {/* Overlays */}
231
- <OutlineOverlay target={pickMode ? hovered : selected} color={pickMode ? '#f59e0b' : '#3b82f6'} />
232
- {hovered && !pickMode && hovered !== selected && <OutlineOverlay target={hovered} color="#22d3ee44" />}
233
-
234
- {/* Toolbar */}
235
- <div className="flex items-center gap-1 px-2 py-1.5 border-b border-border-subtle bg-surface-secondary/50 shrink-0">
236
- {/* Pick button */}
237
- <button
238
- onClick={() => setPickMode(!pickMode)}
239
- className={`flex items-center gap-1 px-2 py-1 rounded text-[10px] font-semibold transition-all ${pickMode ? 'bg-accent-amber/20 text-accent-amber ring-1 ring-accent-amber/40' : 'text-text-muted hover:text-text-primary hover:bg-surface-glass'}`}
240
- title="Pick Element"
241
- >
242
- {pickMode ? <Eye size={11} /> : <EyeOff size={11} />}
243
- Pick
244
- </button>
245
-
246
- <div className="w-px h-4 bg-border-subtle mx-1" />
247
-
248
- {/* Theme switcher */}
249
- <select
250
- value={currentThemeId}
251
- onChange={(e) => setTheme(e.target.value)}
252
- className="bg-surface-tertiary text-text-primary text-[10px] font-mono rounded px-1.5 py-1 border border-border-subtle outline-none cursor-pointer"
253
- >
254
- {THEME_PRESETS.map(t => (
255
- <option key={t.id} value={t.id}>{t.name}</option>
256
- ))}
257
- </select>
258
-
259
- <div className="w-px h-4 bg-border-subtle mx-1" />
260
-
261
- {/* Find hardcoded */}
262
- <button
263
- onClick={findHardcoded}
264
- className="flex items-center gap-1 px-2 py-1 rounded text-[10px] font-semibold text-text-muted hover:text-accent-red hover:bg-accent-red/10 transition-all"
265
- title="Find elements with hardcoded colors"
266
- >
267
- <AlertTriangle size={10} />
268
- Audit
269
- {hardcodedEls.length > 0 && <span className="text-[8px] bg-accent-red/20 text-accent-red px-1 rounded-full">{hardcodedEls.length}</span>}
270
- </button>
271
-
272
- {/* Selected element label */}
273
- {selected && (
274
- <div className="ml-auto text-[9px] font-mono text-text-muted truncate max-w-[180px]">
275
- &lt;{selected.tagName.toLowerCase()}{selected.id ? `#${selected.id}` : ''}&gt;
276
- <span className="text-text-muted/50 ml-1">{selected.offsetWidth}×{selected.offsetHeight}</span>
277
- </div>
278
- )}
279
- </div>
280
-
281
- {selected ? (
282
- <>
283
- {/* Sub-tab bar */}
284
- <div className="flex items-center gap-0.5 px-2 py-1 border-b border-border-subtle shrink-0">
285
- {SUB_TABS.map(t => (
286
- <button
287
- key={t.id}
288
- onClick={() => setSubTab(t.id)}
289
- className={`px-2 py-0.5 rounded text-[10px] font-semibold transition-all ${subTab === t.id ? 'bg-surface-glass text-text-primary' : 'text-text-muted hover:text-text-primary'}`}
290
- >
291
- {t.label}
292
- </button>
293
- ))}
294
-
295
- {/* Search */}
296
- <div className="ml-auto flex items-center gap-1 bg-surface-tertiary rounded px-1.5 py-0.5 border border-border-subtle">
297
- <Search size={9} className="text-text-muted" />
298
- <input
299
- value={filter}
300
- onChange={(e) => setFilter(e.target.value)}
301
- placeholder="Filter..."
302
- className="bg-transparent text-text-primary text-[10px] font-mono outline-none w-20"
303
- />
304
- </div>
305
- </div>
306
-
307
- {/* Content */}
308
- <div className="flex-1 overflow-auto scrollbar-thin">
309
- {/* ── Classes Tab ── */}
310
- {subTab === 'classes' && (
311
- <div className="p-2">
312
- {/* Add class */}
313
- <div className="flex items-center gap-1 mb-2">
314
- <input
315
- value={addClass}
316
- onChange={(e) => setAddClass(e.target.value)}
317
- onKeyDown={(e) => e.key === 'Enter' && handleAddClass()}
318
- placeholder="Add TW class..."
319
- className="flex-1 bg-surface-tertiary text-text-primary text-[10px] font-mono px-2 py-1 rounded border border-border-subtle outline-none focus:border-accent-blue/50"
320
- />
321
- <button onClick={handleAddClass} className="p-1 rounded text-text-muted hover:text-accent-green hover:bg-accent-green/10">
322
- <Plus size={11} />
323
- </button>
324
- </div>
325
- {/* Class list */}
326
- <div className="flex flex-wrap gap-1">
327
- {classes.map((cls) => (
328
- <button
329
- key={cls}
330
- onClick={() => toggleClass(cls)}
331
- className="group flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[9px] font-mono bg-surface-glass border border-border-subtle text-text-secondary hover:text-text-primary hover:border-accent-blue/40 transition-all"
332
- >
333
- {cls}
334
- <X size={8} className="opacity-0 group-hover:opacity-100 text-accent-red" />
335
- </button>
336
- ))}
337
- {classes.length === 0 && (
338
- <span className="text-[10px] text-text-muted italic">No classes match filter</span>
339
- )}
340
- </div>
341
- {/* Copy all */}
342
- <button
343
- onClick={() => selected && navigator.clipboard.writeText(Array.from(selected.classList).join(' '))}
344
- className="mt-2 flex items-center gap-1 text-[9px] text-text-muted hover:text-accent-cyan transition-colors"
345
- >
346
- <Copy size={9} /> Copy all classes
347
- </button>
348
- </div>
349
- )}
350
-
351
- {/* ── Computed CSS Tab ── */}
352
- {subTab === 'computed' && (
353
- <div>
354
- <div className="px-2 py-1 flex justify-end">
355
- <button
356
- onClick={() => setShowAll(!showAll)}
357
- className={`text-[9px] font-mono px-1.5 py-0.5 rounded ${showAll ? 'bg-accent-purple/20 text-accent-purple' : 'text-text-muted hover:text-text-primary'}`}
358
- >
359
- {showAll ? 'ALL' : 'KEY'}
360
- </button>
361
- </div>
362
- {computedProps.map(({ prop, value }) => (
363
- <div key={prop} className="flex items-center gap-1 px-2 py-0.5 text-[10px] font-mono hover:bg-surface-glass group">
364
- <span className="text-accent-purple shrink-0 w-[110px] truncate">{prop}:</span>
365
- <span className="flex-1 text-text-secondary truncate">{value}</span>
366
- {/* Color swatch */}
367
- {(prop.includes('color') || prop === 'background-color') && value !== 'transparent' && value !== 'rgba(0, 0, 0, 0)' && (
368
- <span className="w-3 h-3 rounded-sm border border-border-subtle shrink-0" style={{ backgroundColor: value }} />
369
- )}
370
- <button onClick={() => navigator.clipboard.writeText(`${prop}: ${value}`)} className="opacity-0 group-hover:opacity-100 text-text-muted hover:text-accent-cyan">
371
- <Copy size={9} />
372
- </button>
373
- </div>
374
- ))}
375
- </div>
376
- )}
377
-
378
- {/* ── Tokens Tab ── */}
379
- {subTab === 'tokens' && (
380
- <div className="p-2">
381
- <div className="text-[9px] font-mono text-text-muted uppercase tracking-wider mb-2">Active Design Tokens</div>
382
- {tokens.length > 0 ? tokens.map(({ token, value }) => (
383
- <div key={token} className="flex items-center gap-2 px-2 py-1 rounded hover:bg-surface-glass text-[10px] font-mono">
384
- <span className="w-4 h-4 rounded border border-border-subtle shrink-0" style={{ backgroundColor: value }} />
385
- <span className="text-accent-cyan">{token}</span>
386
- <span className="text-text-muted ml-auto">{value}</span>
387
- </div>
388
- )) : (
389
- <div className="text-text-muted text-[10px] italic">
390
- No `--ds-*` tokens detected on this element.
391
- <br />This might use hardcoded colors.
392
- </div>
393
- )}
394
-
395
- {/* Inline styles */}
396
- {selected?.style.cssText && (
397
- <div className="mt-3">
398
- <div className="text-[9px] font-mono text-text-muted uppercase tracking-wider mb-1">Inline Styles</div>
399
- <div className="text-[10px] font-mono text-accent-amber bg-surface-glass rounded p-2 break-all">{selected.style.cssText}</div>
400
- </div>
401
- )}
402
- </div>
403
- )}
404
-
405
- {/* ── Box Model Tab ── */}
406
- {subTab === 'box' && selected && <BoxModelViz el={selected} />}
407
- </div>
408
- </>
409
- ) : (
410
- <div className="flex-1 flex flex-col items-center justify-center text-text-muted text-xs gap-2 py-8">
411
- <Eye size={24} className="opacity-30" />
412
- <span>Click <strong>"Pick"</strong> to select an element</span>
413
- <span className="text-[9px]">or use <strong>"Audit"</strong> to find hardcoded colors</span>
414
- </div>
415
- )}
416
-
417
- {/* Hardcoded results footer */}
418
- {hardcodedEls.length > 0 && (
419
- <div className="shrink-0 border-t border-border-subtle px-2 py-1 bg-accent-red/5">
420
- <div className="text-[9px] font-mono text-accent-red mb-1">⚠ {hardcodedEls.length} elements with potential hardcoded colors</div>
421
- <div className="flex flex-wrap gap-1 max-h-12 overflow-auto">
422
- {hardcodedEls.slice(0, 20).map((el, i) => (
423
- <button
424
- key={i}
425
- onClick={() => { setSelected(el); setSubTab('computed'); }}
426
- className="text-[8px] font-mono text-text-muted hover:text-accent-red bg-surface-glass rounded px-1 py-0.5"
427
- >
428
- {el.tagName.toLowerCase()}{el.className && typeof el.className === 'string' ? `.${el.className.split(' ')[0]}` : ''}
429
- </button>
430
- ))}
431
- </div>
432
- </div>
433
- )}
434
- </div>
435
- );
436
- };
@@ -1,192 +0,0 @@
1
- import React, { useCallback, useState } from 'react';
2
- import { Download, Upload, Copy, Check, FileJson, FileText } from 'lucide-react';
3
- import { useDebugPanelStore } from '../../store/useDebugPanelStore';
4
- import { useActionTimelineStore } from '../../store/useActionTimelineStore';
5
- import { getNetworkEntries } from '../../lib/networkInterceptor';
6
- import { useMorphologyStore } from '../../store/useMorphologyStore';
7
- import { useLayoutStore } from '../../store/useLayoutStore';
8
- import { useMorphInstanceStore } from '../../store/useMorphInstanceStore';
9
- import { useDebugProfileStore } from '../../store/useDebugProfileStore';
10
-
11
- function generateReport(): object {
12
- const now = new Date();
13
- return {
14
- meta: {
15
- exportedAt: now.toISOString(),
16
- userAgent: navigator.userAgent,
17
- url: window.location.href,
18
- screenSize: `${window.innerWidth}x${window.innerHeight}`,
19
- },
20
- logs: useDebugPanelStore.getState().logEntries.slice(-100),
21
- timeline: useActionTimelineStore.getState().events,
22
- network: getNetworkEntries(),
23
- morphology: {
24
- activeStage: useMorphologyStore.getState().activeStage,
25
- stageHistory: useMorphologyStore.getState().stageHistory,
26
- },
27
- layout: {
28
- activeStage: useLayoutStore.getState().activeStage,
29
- stageHistory: useLayoutStore.getState().stageHistory,
30
- slots: useLayoutStore.getState().slots,
31
- },
32
- instances: (() => {
33
- const inst = useMorphInstanceStore.getState().instances;
34
- const arr: any[] = [];
35
- inst.forEach((v, k) => arr.push({ instanceId: k, ...v }));
36
- return arr;
37
- })(),
38
- profiles: useDebugProfileStore.getState().profiles,
39
- };
40
- }
41
-
42
- function generateMarkdownReport(): string {
43
- const report = generateReport() as any;
44
- const lines: string[] = [];
45
- const ts = new Date().toLocaleString();
46
- lines.push(`# Debug Report — ${ts}\n`);
47
- lines.push(`## Meta`);
48
- lines.push(`- **Screen**: ${report.meta.screenSize}`);
49
- lines.push(`- **URL**: ${report.meta.url}`);
50
- lines.push(`- **UA**: ${report.meta.userAgent}\n`);
51
-
52
- // Morph state
53
- lines.push(`## Morphology State`);
54
- lines.push(`- **Active Stage**: ${report.morphology.activeStage?.type || 'null'} (${report.morphology.activeStage?.label || '–'})`);
55
- lines.push(`- **History Depth**: ${report.morphology.stageHistory.length}`);
56
- const layoutSync = report.morphology.activeStage?.type === report.layout.activeStage?.type ? '✅ Sincronizado' : '⚠️ DESINCRONIZADO';
57
- lines.push(`- **Layout Sync**: ${layoutSync}\n`);
58
-
59
- // Logs summary
60
- const logsByLevel = { info: 0, warn: 0, error: 0, debug: 0 };
61
- report.logs.forEach((l: any) => { logsByLevel[l.level as keyof typeof logsByLevel]++; });
62
- lines.push(`## Logs Summary (${report.logs.length})`);
63
- lines.push(`| Level | Count |\n|-------|-------|\n| info | ${logsByLevel.info} |\n| warn | ${logsByLevel.warn} |\n| error | ${logsByLevel.error} |\n| debug | ${logsByLevel.debug} |\n`);
64
-
65
- // Network summary
66
- const netErrors = report.network.filter((n: any) => n.status >= 400 || n.error).length;
67
- lines.push(`## Network (${report.network.length} requests, ${netErrors} errors)`);
68
- if (report.network.length > 0) {
69
- lines.push(`| Time | Method | Status | URL | Duration |`);
70
- lines.push(`|------|--------|--------|-----|----------|`);
71
- report.network.slice(-20).forEach((n: any) => {
72
- const url = n.url.length > 50 ? n.url.slice(0, 47) + '...' : n.url;
73
- lines.push(`| ${n.timestamp} | ${n.method} | ${n.status || 'ERR'} | ${url} | ${n.duration}ms |`);
74
- });
75
- }
76
- lines.push('');
77
-
78
- // Timeline events
79
- lines.push(`## Timeline Events (${report.timeline.length})`);
80
- report.timeline.slice(-30).forEach((e: any) => {
81
- lines.push(`- \`${e.timestamp}\` **${e.storeName}**.${e.actionName} ${e.level !== 'info' ? `(${e.level})` : ''}`);
82
- });
83
-
84
- return lines.join('\n');
85
- }
86
-
87
- function downloadFile(content: string, filename: string, mimeType: string) {
88
- const blob = new Blob([content], { type: mimeType });
89
- const url = URL.createObjectURL(blob);
90
- const a = document.createElement('a');
91
- a.href = url; a.download = filename; a.click();
92
- URL.revokeObjectURL(url);
93
- }
94
-
95
- export function ExportTab() {
96
- const [copied, setCopied] = useState(false);
97
- const [lastAction, setLastAction] = useState<string | null>(null);
98
-
99
- const handleExportJSON = useCallback(() => {
100
- const report = generateReport();
101
- const ts = new Date().toISOString().replace(/[:.]/g, '-');
102
- downloadFile(JSON.stringify(report, null, 2), `debug-report-${ts}.json`, 'application/json');
103
- setLastAction('📦 JSON exportado');
104
- setTimeout(() => setLastAction(null), 2000);
105
- }, []);
106
-
107
- const handleExportMD = useCallback(() => {
108
- const md = generateMarkdownReport();
109
- const ts = new Date().toISOString().replace(/[:.]/g, '-');
110
- downloadFile(md, `debug-report-${ts}.md`, 'text/markdown');
111
- setLastAction('📝 Markdown exportado');
112
- setTimeout(() => setLastAction(null), 2000);
113
- }, []);
114
-
115
- const handleCopyClipboard = useCallback(async () => {
116
- const md = generateMarkdownReport();
117
- await navigator.clipboard.writeText(md);
118
- setCopied(true);
119
- setLastAction('📋 Copiado al portapapeles');
120
- setTimeout(() => { setCopied(false); setLastAction(null); }, 2000);
121
- }, []);
122
-
123
- const logCount = useDebugPanelStore(s => s.logEntries.length);
124
- const timelineCount = useActionTimelineStore(s => s.events.length);
125
-
126
- return (
127
- <div className="p-4 space-y-4 overflow-y-auto h-full custom-scrollbar">
128
- <div className="text-[10px] font-bold text-text-secondary uppercase tracking-widest flex items-center gap-1">
129
- <Download size={10} /> Exportar Sesión de Debug
130
- </div>
131
-
132
- <div className="grid grid-cols-3 gap-3">
133
- {/* JSON Export */}
134
- <button
135
- onClick={handleExportJSON}
136
- className="rounded-xl bg-blue-500/10 border border-blue-500/20 p-4 hover:bg-blue-500/15 transition-all group"
137
- >
138
- <FileJson size={24} className="text-blue-400 mb-2 group-hover:scale-110 transition-transform" />
139
- <div className="text-[11px] font-bold text-text-primary">JSON Completo</div>
140
- <div className="text-[9px] text-text-muted mt-1">Logs, timeline, network, morph state, profiles</div>
141
- </button>
142
-
143
- {/* Markdown Export */}
144
- <button
145
- onClick={handleExportMD}
146
- className="rounded-xl bg-violet-500/10 border border-violet-500/20 p-4 hover:bg-violet-500/15 transition-all group"
147
- >
148
- <FileText size={24} className="text-violet-400 mb-2 group-hover:scale-110 transition-transform" />
149
- <div className="text-[11px] font-bold text-text-primary">Markdown Report</div>
150
- <div className="text-[9px] text-text-muted mt-1">Resumen legible con tablas y métricas</div>
151
- </button>
152
-
153
- {/* Clipboard */}
154
- <button
155
- onClick={handleCopyClipboard}
156
- className="rounded-xl bg-emerald-500/10 border border-emerald-500/20 p-4 hover:bg-emerald-500/15 transition-all group"
157
- >
158
- {copied ? <Check size={24} className="text-emerald-400 mb-2" /> : <Copy size={24} className="text-emerald-400 mb-2 group-hover:scale-110 transition-transform" />}
159
- <div className="text-[11px] font-bold text-text-primary">Copiar al Clipboard</div>
160
- <div className="text-[9px] text-text-muted mt-1">Pegar en chat, issue, o documento</div>
161
- </button>
162
- </div>
163
-
164
- {/* Stats */}
165
- <div className="rounded-xl bg-surface-secondary/50 border border-border-subtle p-3">
166
- <div className="text-[9px] font-bold text-text-muted uppercase tracking-widest mb-2">Datos a exportar</div>
167
- <div className="grid grid-cols-4 gap-3 text-center">
168
- <div>
169
- <div className="text-[14px] font-bold text-green-400">{logCount}</div>
170
- <div className="text-[8px] text-text-muted">Logs</div>
171
- </div>
172
- <div>
173
- <div className="text-[14px] font-bold text-amber-400">{timelineCount}</div>
174
- <div className="text-[8px] text-text-muted">Timeline</div>
175
- </div>
176
- <div>
177
- <div className="text-[14px] font-bold text-cyan-400">{getNetworkEntries().length}</div>
178
- <div className="text-[8px] text-text-muted">Network</div>
179
- </div>
180
- <div>
181
- <div className="text-[14px] font-bold text-violet-400">{useDebugProfileStore.getState().profiles.length}</div>
182
- <div className="text-[8px] text-text-muted">Profiles</div>
183
- </div>
184
- </div>
185
- </div>
186
-
187
- {lastAction && (
188
- <div className="text-[10px] text-emerald-400 font-mono animate-pulse text-center">{lastAction}</div>
189
- )}
190
- </div>
191
- );
192
- }