@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,443 +0,0 @@
1
- /**
2
- * Built-in Shell Components — Registered at boot time.
3
- *
4
- * Only shells that DON'T depend on external workspace packages:
5
- * - markdown: Renders markdown content
6
- * - iframe: Renders HTML in a sandboxed iframe (with TW Editor support)
7
- *
8
- * shell-vscode and shell-canvas must be registered by the HOST app
9
- * that has @decido/react-shell and @decido/node-engine as dependencies.
10
- */
11
- import React, { useMemo, useRef, useEffect, useState, useCallback } from 'react';
12
- import type { ShellProps } from '../../../store/useShellRegistry';
13
- import {
14
- Paintbrush, X, Plus, Copy, RotateCcw, Search, MousePointer,
15
- ChevronDown, ChevronRight,
16
- Layout, Type, Palette, Box, Maximize, Layers, Sparkles,
17
- } from 'lucide-react';
18
-
19
- // ═══════════════════════════════════════════
20
- // MARKDOWN SHELL
21
- // ═══════════════════════════════════════════
22
- export const MarkdownShell: React.FC<ShellProps> = ({ data }) => {
23
- const content = data?.content || data?.markdown || '';
24
- return (
25
- <div className="w-full h-full overflow-auto bg-surface-primary p-8 custom-scrollbar">
26
- <div className="max-w-3xl mx-auto prose prose-invert prose-sm prose-zinc">
27
- <div className="whitespace-pre-wrap text-text-primary font-sans leading-relaxed text-sm">
28
- {content}
29
- </div>
30
- </div>
31
- </div>
32
- );
33
- };
34
-
35
- // ═══════════════════════════════════════════
36
- // TW INSPECTOR BRIDGE SCRIPT (injected into iframe blob HTML)
37
- // ═══════════════════════════════════════════
38
- const TW_BRIDGE_SCRIPT = `
39
- <script>
40
- (function() {
41
- var inspectorActive = false;
42
- var selectedEl = null;
43
- var hoveredEl = null;
44
-
45
- function generateSelector(el) {
46
- var parts = [];
47
- var cur = el;
48
- while (cur && cur !== document.body && cur !== document.documentElement) {
49
- var part = cur.tagName.toLowerCase();
50
- if (cur.id) { parts.unshift('#' + cur.id); break; }
51
- var parent = cur.parentElement;
52
- if (parent) {
53
- var sibs = Array.from(parent.children).filter(function(c) { return c.tagName === cur.tagName; });
54
- if (sibs.length > 1) {
55
- part += ':nth-of-type(' + (sibs.indexOf(cur) + 1) + ')';
56
- }
57
- }
58
- parts.unshift(part);
59
- cur = cur.parentElement;
60
- }
61
- return parts.join(' > ');
62
- }
63
-
64
- window.addEventListener('message', function(e) {
65
- if (e.data && e.data.type === 'tw-bridge:toggle') {
66
- inspectorActive = !!e.data.enabled;
67
- document.body.style.cursor = inspectorActive ? 'crosshair' : '';
68
- if (!inspectorActive) {
69
- if (hoveredEl) { hoveredEl.style.outline = ''; hoveredEl.style.outlineOffset = ''; hoveredEl = null; }
70
- if (selectedEl) { selectedEl.style.outline = ''; selectedEl.style.outlineOffset = ''; selectedEl = null; }
71
- }
72
- }
73
- if (e.data && e.data.type === 'tw-bridge:apply') {
74
- var el = document.querySelector(e.data.selector);
75
- if (el) el.className = e.data.classes.join(' ');
76
- }
77
- });
78
-
79
- document.addEventListener('mouseover', function(e) {
80
- if (!inspectorActive) return;
81
- var t = e.target;
82
- if (hoveredEl && hoveredEl !== selectedEl) {
83
- hoveredEl.style.outline = '';
84
- hoveredEl.style.outlineOffset = '';
85
- }
86
- t.style.outline = '2px dashed rgba(139, 92, 246, 0.6)';
87
- t.style.outlineOffset = '2px';
88
- hoveredEl = t;
89
- });
90
-
91
- document.addEventListener('mouseout', function(e) {
92
- if (!inspectorActive) return;
93
- if (e.target !== selectedEl) {
94
- e.target.style.outline = '';
95
- e.target.style.outlineOffset = '';
96
- }
97
- });
98
-
99
- document.addEventListener('click', function(e) {
100
- if (!inspectorActive) return;
101
- e.preventDefault();
102
- e.stopPropagation();
103
- var t = e.target;
104
- if (selectedEl) { selectedEl.style.outline = ''; selectedEl.style.outlineOffset = ''; }
105
- t.style.outline = '2px solid rgba(139, 92, 246, 0.9)';
106
- t.style.outlineOffset = '2px';
107
- selectedEl = t;
108
- var classes = t.className ? t.className.split(/\\s+/).filter(Boolean) : [];
109
- var rect = t.getBoundingClientRect();
110
- window.parent.postMessage({
111
- type: 'tw-bridge:select',
112
- selector: generateSelector(t),
113
- tagName: t.tagName,
114
- classes: classes,
115
- originalClasses: classes,
116
- rect: { width: rect.width, height: rect.height }
117
- }, '*');
118
- }, true);
119
- })();
120
- </script>`;
121
-
122
- // ═══════════════════════════════════════════
123
- // INLINE TW EDITOR — Compact panel for IframeShell
124
- // ═══════════════════════════════════════════
125
-
126
- const TW_CATS = [
127
- { id: 'layout', label: 'Layout', classes: ['flex','inline-flex','grid','block','hidden','flex-row','flex-col','items-center','items-start','items-end','justify-center','justify-between','justify-start','justify-end','relative','absolute','fixed','overflow-hidden','overflow-auto'] },
128
- { id: 'spacing', label: 'Spacing', classes: ['p-0','p-1','p-2','p-3','p-4','p-6','p-8','px-2','px-4','px-6','py-1','py-2','py-3','py-4','m-0','m-1','m-2','m-4','mx-auto','my-2','my-4','gap-1','gap-2','gap-3','gap-4','gap-6'] },
129
- { id: 'sizing', label: 'Sizing', classes: ['w-full','w-auto','w-1/2','w-1/3','h-full','h-auto','h-screen','min-w-0','max-w-sm','max-w-md','max-w-lg'] },
130
- { id: 'typography', label: 'Type', classes: ['text-xs','text-sm','text-base','text-lg','text-xl','text-2xl','font-light','font-normal','font-medium','font-semibold','font-bold','text-left','text-center','text-right','truncate'] },
131
- { id: 'colors', label: 'Colors', classes: ['text-white','text-black','text-gray-500','bg-white','bg-black','bg-transparent','bg-gray-100','bg-gray-800','bg-gray-900','bg-blue-500','bg-green-500','bg-red-500','bg-purple-500','bg-cyan-500'] },
132
- { id: 'borders', label: 'Borders', classes: ['border','border-0','border-2','rounded-none','rounded-sm','rounded','rounded-md','rounded-lg','rounded-xl','rounded-2xl','rounded-full'] },
133
- { id: 'effects', label: 'Effects', classes: ['shadow-sm','shadow','shadow-md','shadow-lg','shadow-xl','opacity-0','opacity-50','opacity-100','transition-all','transition-colors','cursor-pointer'] },
134
- ];
135
-
136
- interface TwSelection {
137
- selector: string;
138
- tagName: string;
139
- classes: string[];
140
- originalClasses: string[];
141
- rect: { width: number; height: number };
142
- }
143
-
144
- function InlineTwEditor({ iframeRef, isOpen, onClose }: {
145
- iframeRef: React.RefObject<HTMLIFrameElement>;
146
- isOpen: boolean;
147
- onClose: () => void;
148
- }) {
149
- const [selected, setSelected] = useState<TwSelection | null>(null);
150
- const [inspectorOn, setInspectorOn] = useState(true);
151
- const [addInput, setAddInput] = useState('');
152
- const [expandedCat, setExpandedCat] = useState<string | null>('layout');
153
- const [filter, setFilter] = useState('');
154
-
155
- useEffect(() => {
156
- if (!isOpen) return;
157
- const handler = (e: MessageEvent) => {
158
- if (e.data?.type === 'tw-bridge:select') {
159
- setSelected({
160
- selector: e.data.selector,
161
- tagName: e.data.tagName,
162
- classes: e.data.classes || [],
163
- originalClasses: e.data.originalClasses || e.data.classes || [],
164
- rect: e.data.rect || { width: 0, height: 0 },
165
- });
166
- }
167
- };
168
- window.addEventListener('message', handler);
169
- return () => window.removeEventListener('message', handler);
170
- }, [isOpen]);
171
-
172
- useEffect(() => {
173
- if (!isOpen) return;
174
- iframeRef.current?.contentWindow?.postMessage({ type: 'tw-bridge:toggle', enabled: inspectorOn }, '*');
175
- }, [inspectorOn, isOpen, iframeRef]);
176
-
177
- useEffect(() => {
178
- if (isOpen) {
179
- setInspectorOn(true);
180
- iframeRef.current?.contentWindow?.postMessage({ type: 'tw-bridge:toggle', enabled: true }, '*');
181
- } else {
182
- iframeRef.current?.contentWindow?.postMessage({ type: 'tw-bridge:toggle', enabled: false }, '*');
183
- }
184
- }, [isOpen, iframeRef]);
185
-
186
- const applyClasses = useCallback((newClasses: string[]) => {
187
- if (!selected) return;
188
- setSelected(prev => prev ? { ...prev, classes: newClasses } : null);
189
- iframeRef.current?.contentWindow?.postMessage({
190
- type: 'tw-bridge:apply',
191
- selector: selected.selector,
192
- classes: newClasses,
193
- }, '*');
194
- }, [selected, iframeRef]);
195
-
196
- const removeClass = useCallback((cls: string) => {
197
- if (!selected) return;
198
- applyClasses(selected.classes.filter(c => c !== cls));
199
- }, [selected, applyClasses]);
200
-
201
- const addClass = useCallback((cls: string) => {
202
- if (!selected) return;
203
- const t = cls.trim();
204
- if (!t || selected.classes.includes(t)) return;
205
- applyClasses([...selected.classes, t]);
206
- setAddInput('');
207
- }, [selected, applyClasses]);
208
-
209
- const resetClasses = useCallback(() => {
210
- if (!selected) return;
211
- applyClasses([...selected.originalClasses]);
212
- }, [selected, applyClasses]);
213
-
214
- const copyClasses = useCallback(() => {
215
- if (!selected) return;
216
- navigator.clipboard.writeText(selected.classes.join(' '));
217
- }, [selected]);
218
-
219
- const hasChanges = selected && JSON.stringify(selected.classes) !== JSON.stringify(selected.originalClasses);
220
-
221
- if (!isOpen) return null;
222
-
223
- return (
224
- <div className="w-[280px] shrink-0 flex flex-col bg-surface-primary border-l border-border-subtle h-full text-text-primary">
225
- {/* Header */}
226
- <div className="px-3 py-2 border-b border-border-subtle shrink-0">
227
- <div className="flex items-center justify-between mb-1.5">
228
- <div className="flex items-center gap-1.5">
229
- <Paintbrush size={12} className="text-accent-purple" />
230
- <span className="text-[11px] font-bold">TW Editor</span>
231
- <span className="text-[7px] px-1 py-0.5 rounded-full bg-accent-purple/15 text-accent-purple font-mono font-bold">LIVE</span>
232
- </div>
233
- <button onClick={onClose} className="text-text-muted hover:text-text-primary transition-colors">
234
- <X size={12} />
235
- </button>
236
- </div>
237
- <button
238
- onClick={() => setInspectorOn(!inspectorOn)}
239
- className={`w-full flex items-center gap-1.5 px-2 py-1 rounded text-[10px] font-medium transition-all cursor-pointer ${
240
- inspectorOn ? 'bg-accent-purple/15 text-accent-purple border border-accent-purple/30' : 'bg-surface-glass text-text-muted border border-border-subtle'
241
- }`}
242
- >
243
- <MousePointer size={10} />
244
- {inspectorOn ? 'Click un elemento' : 'Inspector off'}
245
- <span className={`ml-auto w-1.5 h-1.5 rounded-full ${inspectorOn ? 'bg-accent-green animate-pulse' : 'bg-text-muted/30'}`} />
246
- </button>
247
- </div>
248
-
249
- {selected ? (
250
- <div className="flex-1 flex flex-col overflow-hidden">
251
- {/* Element info */}
252
- <div className="px-3 py-1.5 border-b border-border-subtle/50 shrink-0">
253
- <div className="flex items-center gap-1.5">
254
- <span className="text-[9px] font-mono px-1 py-0.5 rounded bg-surface-glass text-text-muted">&lt;{selected.tagName.toLowerCase()}&gt;</span>
255
- <span className="text-[8px] font-mono text-text-muted/40 ml-auto">{Math.round(selected.rect.width)}×{Math.round(selected.rect.height)}</span>
256
- </div>
257
- </div>
258
-
259
- {/* Current classes */}
260
- <div className="px-3 py-1.5 border-b border-border-subtle/50 shrink-0">
261
- <div className="flex items-center justify-between mb-1">
262
- <span className="text-[8px] font-mono text-text-muted/60 uppercase tracking-wider">Clases ({selected.classes.length})</span>
263
- <div className="flex gap-1">
264
- {hasChanges && (
265
- <button onClick={resetClasses} className="text-[7px] text-accent-amber flex items-center gap-0.5 cursor-pointer"><RotateCcw size={7} /> Undo</button>
266
- )}
267
- <button onClick={copyClasses} className="text-[7px] text-text-muted/40 hover:text-accent-cyan flex items-center gap-0.5 cursor-pointer"><Copy size={7} /> Copy</button>
268
- </div>
269
- </div>
270
- <div className="flex flex-wrap gap-0.5 max-h-[100px] overflow-y-auto custom-scrollbar">
271
- {selected.classes.map(cls => {
272
- const isNew = !selected.originalClasses.includes(cls);
273
- return (
274
- <span key={cls} className={`group inline-flex items-center gap-0.5 px-1 py-0.5 rounded text-[8px] font-mono transition-all ${
275
- isNew ? 'bg-accent-green/15 text-accent-green border border-accent-green/30' : 'bg-surface-glass text-text-secondary border border-border-subtle'
276
- }`}>
277
- {cls}
278
- <button onClick={() => removeClass(cls)} className="opacity-0 group-hover:opacity-100 text-red-400 cursor-pointer"><X size={7} /></button>
279
- </span>
280
- );
281
- })}
282
- </div>
283
- {hasChanges && (
284
- <div className="mt-1 flex flex-wrap gap-0.5">
285
- {selected.originalClasses.filter(c => !selected.classes.includes(c)).map(cls => (
286
- <button key={`rm-${cls}`} onClick={() => addClass(cls)} className="px-1 py-0.5 rounded text-[8px] font-mono bg-red-500/10 text-red-400/60 border border-red-500/20 line-through hover:no-underline cursor-pointer">{cls}</button>
287
- ))}
288
- </div>
289
- )}
290
- </div>
291
-
292
- {/* Add input */}
293
- <div className="px-3 py-1.5 border-b border-border-subtle/50 shrink-0 flex gap-1">
294
- <div className="flex-1 relative">
295
- <Plus size={9} className="absolute left-1.5 top-1/2 -translate-y-1/2 text-text-muted/40" />
296
- <input
297
- type="text" value={addInput}
298
- onChange={e => setAddInput(e.target.value)}
299
- onKeyDown={e => { if (e.key === 'Enter' && addInput.trim()) addClass(addInput); }}
300
- placeholder="Agregar clase..."
301
- className="w-full pl-5 pr-1 py-1 text-[10px] font-mono bg-surface-glass border border-border-subtle rounded text-text-primary placeholder:text-text-muted/30 focus:outline-none focus:border-accent-purple/40"
302
- />
303
- </div>
304
- <button onClick={() => addClass(addInput)} disabled={!addInput.trim()} className="px-2 py-1 rounded bg-accent-purple/15 text-accent-purple text-[9px] font-bold disabled:opacity-30 cursor-pointer">+</button>
305
- </div>
306
-
307
- {/* Quick-add */}
308
- <div className="flex-1 overflow-y-auto custom-scrollbar">
309
- <div className="px-3 py-1 border-b border-border-subtle/30 sticky top-0 bg-surface-primary z-10">
310
- <div className="relative">
311
- <Search size={9} className="absolute left-1.5 top-1/2 -translate-y-1/2 text-text-muted/30" />
312
- <input type="text" value={filter} onChange={e => setFilter(e.target.value)} placeholder="Filtrar..."
313
- className="w-full pl-5 pr-1 py-0.5 text-[9px] font-mono bg-surface-glass border border-border-subtle/50 rounded text-text-primary placeholder:text-text-muted/20 focus:outline-none" />
314
- </div>
315
- </div>
316
- {TW_CATS.map(cat => {
317
- const filtered = filter ? cat.classes.filter(c => c.includes(filter.toLowerCase())) : cat.classes;
318
- if (filtered.length === 0) return null;
319
- const isOpen = expandedCat === cat.id;
320
- return (
321
- <div key={cat.id} className="border-b border-border-subtle/20">
322
- <button onClick={() => setExpandedCat(isOpen ? null : cat.id)} className="w-full flex items-center gap-1.5 px-3 py-1 hover:bg-surface-glass text-left cursor-pointer">
323
- {isOpen ? <ChevronDown size={8} /> : <ChevronRight size={8} />}
324
- <span className="text-[9px] font-semibold text-text-primary flex-1">{cat.label}</span>
325
- <span className="text-[7px] font-mono text-text-muted/40">{filtered.length}</span>
326
- </button>
327
- {isOpen && (
328
- <div className="px-3 pb-1.5 flex flex-wrap gap-0.5">
329
- {filtered.map(cls => {
330
- const active = selected.classes.includes(cls);
331
- return (
332
- <button key={cls} onClick={() => active ? removeClass(cls) : addClass(cls)}
333
- className={`px-1 py-0.5 rounded text-[8px] font-mono cursor-pointer transition-all ${
334
- active ? 'bg-accent-green/15 text-accent-green border border-accent-green/30' : 'bg-surface-glass text-text-muted border border-border-subtle/50 hover:border-accent-purple/30'
335
- }`}>
336
- {active ? '✓ ' : ''}{cls}
337
- </button>
338
- );
339
- })}
340
- </div>
341
- )}
342
- </div>
343
- );
344
- })}
345
- </div>
346
-
347
- {/* Footer */}
348
- {hasChanges && (
349
- <div className="px-3 py-1.5 border-t border-border-subtle bg-surface-secondary/50 shrink-0">
350
- <div className="flex items-center justify-between mb-0.5">
351
- <span className="text-[7px] font-mono text-accent-green/60 uppercase">className</span>
352
- <button onClick={copyClasses} className="text-[7px] text-text-muted/40 hover:text-accent-cyan flex items-center gap-0.5 cursor-pointer"><Copy size={7} /> Copy</button>
353
- </div>
354
- <div className="text-[8px] font-mono text-text-secondary bg-surface-primary p-1.5 rounded border border-border-subtle max-h-[48px] overflow-y-auto break-all">
355
- {selected.classes.join(' ')}
356
- </div>
357
- </div>
358
- )}
359
- </div>
360
- ) : (
361
- <div className="flex-1 flex flex-col items-center justify-center p-4 text-center">
362
- <MousePointer size={20} className="text-accent-purple/30 mb-2" />
363
- <p className="text-[10px] text-text-muted">Click un elemento del preview</p>
364
- <p className="text-[8px] text-text-muted/40 mt-0.5">para editar sus clases Tailwind</p>
365
- </div>
366
- )}
367
- </div>
368
- );
369
- }
370
-
371
- // ═══════════════════════════════════════════
372
- // IFRAME SHELL (with TW Editor support)
373
- // ═══════════════════════════════════════════
374
- export const IframeShell: React.FC<ShellProps> = ({ data, instanceId }) => {
375
- const iframeRef = useRef<HTMLIFrameElement>(null!);
376
- const content = data?.content || data?.html || '';
377
- const url = data?.url || '';
378
- const [twEditorOpen, setTwEditorOpen] = useState(false);
379
-
380
- // Inject TW bridge script + Tailwind CDN into HTML content
381
- const blobUrl = useMemo(() => {
382
- if (url) return url;
383
- if (!content) return 'about:blank';
384
-
385
- // Inject Tailwind CDN + bridge script at the end of the HTML
386
- const twCdn = '<script src="https://cdn.tailwindcss.com"><\/script>';
387
- let enrichedContent = content;
388
-
389
- // Insert before </body> or </html> or at the end
390
- if (enrichedContent.includes('</body>')) {
391
- enrichedContent = enrichedContent.replace('</body>', `${twCdn}${TW_BRIDGE_SCRIPT}</body>`);
392
- } else if (enrichedContent.includes('</html>')) {
393
- enrichedContent = enrichedContent.replace('</html>', `${twCdn}${TW_BRIDGE_SCRIPT}</html>`);
394
- } else {
395
- enrichedContent += `${twCdn}${TW_BRIDGE_SCRIPT}`;
396
- }
397
-
398
- const blob = new Blob([enrichedContent], { type: 'text/html' });
399
- return URL.createObjectURL(blob);
400
- }, [content, url]);
401
-
402
- useEffect(() => {
403
- return () => {
404
- if (!url && blobUrl !== 'about:blank') {
405
- URL.revokeObjectURL(blobUrl);
406
- }
407
- };
408
- }, [blobUrl, url]);
409
-
410
- return (
411
- <div className="w-full h-full bg-surface-secondary rounded-lg overflow-hidden flex">
412
- {/* Iframe preview */}
413
- <div className="flex-1 relative">
414
- <iframe
415
- ref={iframeRef}
416
- src={blobUrl}
417
- title={`sandbox-${instanceId}`}
418
- sandbox="allow-scripts allow-same-origin allow-forms"
419
- className="w-full h-full border-none"
420
- />
421
- {/* TW Editor toggle button */}
422
- <button
423
- onClick={() => setTwEditorOpen(!twEditorOpen)}
424
- className={`absolute top-2 right-2 z-10 flex items-center gap-1 px-2 py-1 rounded-lg text-[10px] font-semibold transition-all shadow-lg cursor-pointer ${
425
- twEditorOpen
426
- ? 'bg-accent-purple text-white'
427
- : 'bg-black/60 text-white/80 hover:bg-accent-purple/80 hover:text-white backdrop-blur-sm'
428
- }`}
429
- title="Tailwind Editor"
430
- >
431
- <Paintbrush size={11} /> TW
432
- </button>
433
- </div>
434
-
435
- {/* Inline TW Editor Panel */}
436
- <InlineTwEditor
437
- iframeRef={iframeRef}
438
- isOpen={twEditorOpen}
439
- onClose={() => setTwEditorOpen(false)}
440
- />
441
- </div>
442
- );
443
- };
@@ -1,42 +0,0 @@
1
- import React, { useEffect } from 'react';
2
- import { Database } from 'lucide-react';
3
-
4
- export const DatawayChatShell: React.FC<any> = ({ artifacts, activeArtifactIndex }) => {
5
- const artifact = artifacts?.[activeArtifactIndex];
6
-
7
- useEffect(() => {
8
- if (!artifact) return;
9
-
10
- let script = '';
11
- if (typeof artifact.content === 'string') {
12
- script = artifact.content;
13
- } else if (artifact.data && typeof artifact.data.content === 'string') {
14
- script = artifact.data.content;
15
- }
16
-
17
- if (script) {
18
- // Limpiar tags de markdown si el LLM los incluye
19
- script = script.replace(/```[a-zA-Z-]*\n/gi, '').replace(/```/g, '').trim();
20
- window.dispatchEvent(new CustomEvent('intent:dataway-generate-script', { detail: { script } }));
21
- }
22
- }, [artifact]);
23
-
24
- if (!artifact) return null;
25
-
26
- let displayScript = typeof artifact.content === 'string' ? artifact.content : (artifact.data?.content || '');
27
- displayScript = displayScript.replace(/```[a-zA-Z-]*\n/gi, '').replace(/```/g, '').trim();
28
-
29
- return (
30
- <div className="w-full flex tracking-tight flex-col border border-teal-500/20 bg-teal-500/5 rounded-xl overflow-hidden mt-2">
31
- <div className="bg-teal-500/10 px-3 py-2 flex items-center gap-2 border-b border-teal-500/10">
32
- <Database className="w-4 h-4 text-teal-600 dark:text-teal-400" />
33
- <span className="text-[11px] font-bold text-teal-800 dark:text-teal-300 uppercase tracking-widest">M-Script Aplicado</span>
34
- </div>
35
- <div className="p-3">
36
- <pre className="text-[13px] font-mono text-teal-900/80 dark:text-teal-100/80 whitespace-pre-wrap break-all">
37
- {displayScript}
38
- </pre>
39
- </div>
40
- </div>
41
- );
42
- };