@tldiagram/core-ui 1.87.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 (272) hide show
  1. package/dist/App.d.ts +1 -0
  2. package/dist/api/client.d.ts +143 -0
  3. package/dist/api/transport-vscode.d.ts +8 -0
  4. package/dist/api/transport.d.ts +1 -0
  5. package/dist/components/CodePreviewPanel-vscode.d.ts +7 -0
  6. package/dist/components/CodePreviewPanel.d.ts +9 -0
  7. package/dist/components/ConfirmDialog.d.ts +12 -0
  8. package/dist/components/ConnectorPanel.d.ts +21 -0
  9. package/dist/components/ContextBoundaryElement.d.ts +11 -0
  10. package/dist/components/ContextNeighborElement.d.ts +29 -0
  11. package/dist/components/ContextStraightConnector.d.ts +4 -0
  12. package/dist/components/CrossBranchControls.d.ts +9 -0
  13. package/dist/components/DependenciesOnboarding.d.ts +5 -0
  14. package/dist/components/DrawingCanvas.d.ts +39 -0
  15. package/dist/components/ElementLibrary-vscode.d.ts +7 -0
  16. package/dist/components/ElementLibrary.d.ts +22 -0
  17. package/dist/components/ElementNode.d.ts +36 -0
  18. package/dist/components/ElementPanel.d.ts +25 -0
  19. package/dist/components/ExploreOnboarding.d.ts +5 -0
  20. package/dist/components/ExplorePageOnboarding.d.ts +5 -0
  21. package/dist/components/ExportModal.d.ts +16 -0
  22. package/dist/components/FloatingEdge.d.ts +9 -0
  23. package/dist/components/GitSourceLinker.d.ts +8 -0
  24. package/dist/components/HeaderContext.d.ts +16 -0
  25. package/dist/components/Icons.d.ts +95 -0
  26. package/dist/components/ImportModal.d.ts +10 -0
  27. package/dist/components/InlineElementAdder.d.ts +17 -0
  28. package/dist/components/LayoutSection.d.ts +7 -0
  29. package/dist/components/LocalSourceLinker.d.ts +8 -0
  30. package/dist/components/MiniZoomOnboarding.d.ts +5 -0
  31. package/dist/components/NavBreadcrumb.d.ts +6 -0
  32. package/dist/components/NodeBody.d.ts +12 -0
  33. package/dist/components/NodeContainer.d.ts +8 -0
  34. package/dist/components/NodeHoverCard.d.ts +10 -0
  35. package/dist/components/PanelHeader.d.ts +8 -0
  36. package/dist/components/PanelUI.d.ts +3 -0
  37. package/dist/components/ProxyConnectorEdge.d.ts +4 -0
  38. package/dist/components/ProxyConnectorPanel.d.ts +9 -0
  39. package/dist/components/SafeBackground.d.ts +13 -0
  40. package/dist/components/ScrollIndicatorWrapper.d.ts +8 -0
  41. package/dist/components/SetChildModal.d.ts +10 -0
  42. package/dist/components/SetParentModal.d.ts +10 -0
  43. package/dist/components/SlidingPanel.d.ts +16 -0
  44. package/dist/components/TagUpsert.d.ts +8 -0
  45. package/dist/components/TopMenuBar.d.ts +8 -0
  46. package/dist/components/ViewBezierConnector.d.ts +4 -0
  47. package/dist/components/ViewDrawMenu.d.ts +22 -0
  48. package/dist/components/ViewEditorEdgeLabelLayout.d.ts +16 -0
  49. package/dist/components/ViewEditorOnboarding.d.ts +5 -0
  50. package/dist/components/ViewExplorer/TagManager/ColorPicker.d.ts +7 -0
  51. package/dist/components/ViewExplorer/TagManager/GroupNamingPopover.d.ts +10 -0
  52. package/dist/components/ViewExplorer/TagManager/LayerItem.d.ts +27 -0
  53. package/dist/components/ViewExplorer/TagManager/TagItem.d.ts +25 -0
  54. package/dist/components/ViewExplorer/TagManager/index.d.ts +21 -0
  55. package/dist/components/ViewExplorer/ViewNavigator.d.ts +11 -0
  56. package/dist/components/ViewExplorer/ViewSearch.d.ts +8 -0
  57. package/dist/components/ViewExplorer/ViewTree.d.ts +18 -0
  58. package/dist/components/ViewExplorer/index.d.ts +31 -0
  59. package/dist/components/ViewExplorer/types.d.ts +11 -0
  60. package/dist/components/ViewExplorer/utils.d.ts +6 -0
  61. package/dist/components/ViewExplorer-vscode.d.ts +6 -0
  62. package/dist/components/ViewFloatingMenu-vscode.d.ts +27 -0
  63. package/dist/components/ViewFloatingMenu.d.ts +39 -0
  64. package/dist/components/ViewGridNode.d.ts +29 -0
  65. package/dist/components/ViewHeaderButton.d.ts +11 -0
  66. package/dist/components/ViewPanel.d.ts +18 -0
  67. package/dist/components/ViewsGridOnboarding.d.ts +5 -0
  68. package/dist/components/ZUI/ZUICanvas.d.ts +18 -0
  69. package/dist/components/ZUI/index.d.ts +2 -0
  70. package/dist/components/ZUI/layout.d.ts +18 -0
  71. package/dist/components/ZUI/proxy.d.ts +25 -0
  72. package/dist/components/ZUI/renderer.d.ts +30 -0
  73. package/dist/components/ZUI/types.d.ts +140 -0
  74. package/dist/components/ZUI/useZUIInteraction.d.ts +21 -0
  75. package/dist/config/runtime-vscode.d.ts +22 -0
  76. package/dist/config/runtime.d.ts +5 -0
  77. package/dist/constants/colors.d.ts +27 -0
  78. package/dist/constants/diagramColors.d.ts +1 -0
  79. package/dist/context/ThemeContext.d.ts +27 -0
  80. package/dist/crossBranch/graph.d.ts +13 -0
  81. package/dist/crossBranch/resolve.d.ts +22 -0
  82. package/dist/crossBranch/settings.d.ts +6 -0
  83. package/dist/crossBranch/store.d.ts +11 -0
  84. package/dist/crossBranch/types.d.ts +96 -0
  85. package/dist/demo/DemoPage.d.ts +9 -0
  86. package/dist/demo/seed.d.ts +9 -0
  87. package/dist/demo/store.d.ts +137 -0
  88. package/dist/demo/viewEditor.d.ts +26 -0
  89. package/dist/favicon.svg +35 -0
  90. package/dist/hooks/useSafeFitView.d.ts +16 -0
  91. package/dist/index.css +1 -0
  92. package/dist/index.d.ts +115 -0
  93. package/dist/index.js +19966 -0
  94. package/dist/lib/vscodeBridge-vscode.d.ts +13 -0
  95. package/dist/lib/vscodeBridge.d.ts +5 -0
  96. package/dist/logo-120.png +0 -0
  97. package/dist/logo-bw.png +0 -0
  98. package/dist/logo-bw.svg +15 -0
  99. package/dist/logo-text.svg +51 -0
  100. package/dist/logo.svg +35 -0
  101. package/dist/pages/AppearanceSettings.d.ts +3 -0
  102. package/dist/pages/Dependencies.d.ts +1 -0
  103. package/dist/pages/InfiniteZoom.d.ts +7 -0
  104. package/dist/pages/Settings.d.ts +7 -0
  105. package/dist/pages/ViewEditor/components/EditorMenus.d.ts +24 -0
  106. package/dist/pages/ViewEditor/components/EditorOverlays.d.ts +30 -0
  107. package/dist/pages/ViewEditor/components/EmptyCanvasState.d.ts +7 -0
  108. package/dist/pages/ViewEditor/context.d.ts +13 -0
  109. package/dist/pages/ViewEditor/hooks/useCanvasInteractions.d.ts +201 -0
  110. package/dist/pages/ViewEditor/hooks/useDrawingEngine.d.ts +40 -0
  111. package/dist/pages/ViewEditor/hooks/useViewContextNeighbours.d.ts +20 -0
  112. package/dist/pages/ViewEditor/hooks/useViewData.d.ts +74 -0
  113. package/dist/pages/ViewEditor/index.d.ts +8 -0
  114. package/dist/pages/ViewEditor/utils.d.ts +14 -0
  115. package/dist/pages/Views.d.ts +6 -0
  116. package/dist/pages/ViewsGrid.d.ts +6 -0
  117. package/dist/pkg/importer/mermaid.d.ts +7 -0
  118. package/dist/pkg/importer/mermaid.test.d.ts +1 -0
  119. package/dist/platform/PlatformContext.d.ts +6 -0
  120. package/dist/platform/context.d.ts +3 -0
  121. package/dist/platform/local.d.ts +2 -0
  122. package/dist/platform/types.d.ts +17 -0
  123. package/dist/slots.d.ts +67 -0
  124. package/dist/theme.d.ts +2 -0
  125. package/dist/types/index.d.ts +193 -0
  126. package/dist/types/vscode-messages.d.ts +60 -0
  127. package/dist/utils/edgeDistribution.d.ts +34 -0
  128. package/dist/utils/githubApi.d.ts +4 -0
  129. package/dist/utils/githubCache.d.ts +17 -0
  130. package/dist/utils/ids.d.ts +2 -0
  131. package/dist/utils/technologyCatalog.d.ts +15 -0
  132. package/dist/utils/toast.d.ts +15 -0
  133. package/dist/utils/treesitter.d.ts +13 -0
  134. package/dist/utils/url.d.ts +12 -0
  135. package/package.json +159 -0
  136. package/src/App.tsx +141 -0
  137. package/src/api/client.ts +618 -0
  138. package/src/api/transport-vscode.ts +28 -0
  139. package/src/api/transport.ts +7 -0
  140. package/src/assets/logo-mark.svg +31 -0
  141. package/src/assets/logo-wordmark.svg +22 -0
  142. package/src/assets/logo.svg +35 -0
  143. package/src/components/CodePreviewPanel-vscode.tsx +85 -0
  144. package/src/components/CodePreviewPanel.tsx +384 -0
  145. package/src/components/ConfirmDialog.tsx +66 -0
  146. package/src/components/ConnectorPanel.tsx +403 -0
  147. package/src/components/ContextBoundaryElement.tsx +35 -0
  148. package/src/components/ContextNeighborElement.tsx +282 -0
  149. package/src/components/ContextStraightConnector.tsx +144 -0
  150. package/src/components/CrossBranchControls.tsx +105 -0
  151. package/src/components/DependenciesOnboarding.tsx +427 -0
  152. package/src/components/DrawingCanvas.tsx +391 -0
  153. package/src/components/ElementLibrary-vscode.tsx +9 -0
  154. package/src/components/ElementLibrary.tsx +512 -0
  155. package/src/components/ElementNode.tsx +1033 -0
  156. package/src/components/ElementPanel.tsx +928 -0
  157. package/src/components/ExploreOnboarding.tsx +347 -0
  158. package/src/components/ExplorePageOnboarding.tsx +383 -0
  159. package/src/components/ExportModal.tsx +132 -0
  160. package/src/components/FloatingEdge.tsx +115 -0
  161. package/src/components/GitSourceLinker.tsx +1053 -0
  162. package/src/components/HeaderContext.tsx +30 -0
  163. package/src/components/Icons.tsx +245 -0
  164. package/src/components/ImportModal.tsx +219 -0
  165. package/src/components/InlineElementAdder.tsx +216 -0
  166. package/src/components/LayoutSection.tsx +624 -0
  167. package/src/components/LocalSourceLinker.tsx +330 -0
  168. package/src/components/MiniZoomOnboarding.tsx +78 -0
  169. package/src/components/NavBreadcrumb.tsx +24 -0
  170. package/src/components/NodeBody.tsx +89 -0
  171. package/src/components/NodeContainer.tsx +58 -0
  172. package/src/components/NodeHoverCard.tsx +135 -0
  173. package/src/components/PanelHeader.tsx +36 -0
  174. package/src/components/PanelUI.tsx +24 -0
  175. package/src/components/ProxyConnectorEdge.tsx +169 -0
  176. package/src/components/ProxyConnectorPanel.tsx +130 -0
  177. package/src/components/SafeBackground.tsx +19 -0
  178. package/src/components/ScrollIndicatorWrapper.tsx +117 -0
  179. package/src/components/SetChildModal.tsx +191 -0
  180. package/src/components/SetParentModal.tsx +187 -0
  181. package/src/components/SlidingPanel.tsx +114 -0
  182. package/src/components/TagUpsert.tsx +142 -0
  183. package/src/components/TopMenuBar.tsx +380 -0
  184. package/src/components/ViewBezierConnector.tsx +143 -0
  185. package/src/components/ViewDrawMenu.tsx +270 -0
  186. package/src/components/ViewEditorEdgeLabelLayout.ts +189 -0
  187. package/src/components/ViewEditorOnboarding.tsx +445 -0
  188. package/src/components/ViewExplorer/TagManager/ColorPicker.tsx +49 -0
  189. package/src/components/ViewExplorer/TagManager/GroupNamingPopover.tsx +96 -0
  190. package/src/components/ViewExplorer/TagManager/LayerItem.tsx +228 -0
  191. package/src/components/ViewExplorer/TagManager/TagItem.tsx +242 -0
  192. package/src/components/ViewExplorer/TagManager/index.tsx +418 -0
  193. package/src/components/ViewExplorer/ViewNavigator.tsx +121 -0
  194. package/src/components/ViewExplorer/ViewSearch.tsx +33 -0
  195. package/src/components/ViewExplorer/ViewTree.tsx +98 -0
  196. package/src/components/ViewExplorer/index.tsx +384 -0
  197. package/src/components/ViewExplorer/types.ts +13 -0
  198. package/src/components/ViewExplorer/utils.ts +56 -0
  199. package/src/components/ViewExplorer-vscode.tsx +8 -0
  200. package/src/components/ViewFloatingMenu-vscode.tsx +248 -0
  201. package/src/components/ViewFloatingMenu.tsx +379 -0
  202. package/src/components/ViewGridNode.tsx +451 -0
  203. package/src/components/ViewHeaderButton.tsx +60 -0
  204. package/src/components/ViewPanel.tsx +162 -0
  205. package/src/components/ViewsGridOnboarding.tsx +400 -0
  206. package/src/components/ZUI/ZUICanvas.tsx +853 -0
  207. package/src/components/ZUI/index.ts +3 -0
  208. package/src/components/ZUI/layout.ts +323 -0
  209. package/src/components/ZUI/proxy.ts +278 -0
  210. package/src/components/ZUI/renderer.ts +1189 -0
  211. package/src/components/ZUI/types.ts +150 -0
  212. package/src/components/ZUI/useZUIInteraction.ts +720 -0
  213. package/src/config/runtime-vscode.ts +46 -0
  214. package/src/config/runtime.ts +30 -0
  215. package/src/constants/colors.ts +80 -0
  216. package/src/constants/diagramColors.ts +9 -0
  217. package/src/context/ThemeContext.tsx +158 -0
  218. package/src/crossBranch/graph.ts +207 -0
  219. package/src/crossBranch/resolve.ts +643 -0
  220. package/src/crossBranch/settings.ts +59 -0
  221. package/src/crossBranch/store.ts +71 -0
  222. package/src/crossBranch/types.ts +102 -0
  223. package/src/demo/DemoPage.tsx +184 -0
  224. package/src/demo/seed.ts +67 -0
  225. package/src/demo/store.ts +536 -0
  226. package/src/demo/viewEditor.ts +110 -0
  227. package/src/hooks/useSafeFitView.ts +60 -0
  228. package/src/index.css +309 -0
  229. package/src/index.ts +184 -0
  230. package/src/kafka-ss.png +0 -0
  231. package/src/lib/vscodeBridge-vscode.ts +27 -0
  232. package/src/lib/vscodeBridge.ts +7 -0
  233. package/src/main.tsx +46 -0
  234. package/src/pages/AppearanceSettings.tsx +135 -0
  235. package/src/pages/Dependencies.tsx +926 -0
  236. package/src/pages/InfiniteZoom.tsx +404 -0
  237. package/src/pages/Settings.tsx +91 -0
  238. package/src/pages/ViewEditor/EDGE_DISTRIBUTION.md +64 -0
  239. package/src/pages/ViewEditor/components/EditorMenus.tsx +112 -0
  240. package/src/pages/ViewEditor/components/EditorOverlays.tsx +172 -0
  241. package/src/pages/ViewEditor/components/EmptyCanvasState.tsx +42 -0
  242. package/src/pages/ViewEditor/context.tsx +21 -0
  243. package/src/pages/ViewEditor/hooks/useCanvasInteractions.ts +1349 -0
  244. package/src/pages/ViewEditor/hooks/useDrawingEngine.ts +127 -0
  245. package/src/pages/ViewEditor/hooks/useViewContextNeighbours.ts +501 -0
  246. package/src/pages/ViewEditor/hooks/useViewData.ts +491 -0
  247. package/src/pages/ViewEditor/index.tsx +1366 -0
  248. package/src/pages/ViewEditor/utils.ts +88 -0
  249. package/src/pages/Views.tsx +171 -0
  250. package/src/pages/ViewsGrid.tsx +1310 -0
  251. package/src/pkg/importer/mermaid.test.ts +141 -0
  252. package/src/pkg/importer/mermaid.ts +76 -0
  253. package/src/platform/PlatformContext.tsx +17 -0
  254. package/src/platform/context.ts +9 -0
  255. package/src/platform/local.tsx +15 -0
  256. package/src/platform/types.ts +19 -0
  257. package/src/slots.ts +92 -0
  258. package/src/styles/editor-panels.css +66 -0
  259. package/src/styles/theme.css +56 -0
  260. package/src/theme.ts +336 -0
  261. package/src/types/index.ts +234 -0
  262. package/src/types/offline-ambient.d.ts +14 -0
  263. package/src/types/vscode-messages.ts +32 -0
  264. package/src/utils/edgeDistribution.ts +103 -0
  265. package/src/utils/githubApi.ts +121 -0
  266. package/src/utils/githubCache.ts +108 -0
  267. package/src/utils/ids.ts +9 -0
  268. package/src/utils/technologyCatalog.ts +143 -0
  269. package/src/utils/toast.ts +100 -0
  270. package/src/utils/treesitter.ts +147 -0
  271. package/src/utils/url.ts +72 -0
  272. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,445 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { Box, Button, HStack, Text, VStack } from '@chakra-ui/react'
3
+
4
+ const STORAGE_KEY = `diagrameditor_tutorial_v1_core`
5
+
6
+ interface Props {
7
+
8
+ hasElements: boolean
9
+ }
10
+
11
+ // ── SVG helpers ─────────────────────────────────────────────────────────────
12
+
13
+ function GridDots({ prefix }: { prefix: string }) {
14
+ return (
15
+ <>
16
+ {Array.from({ length: 7 }, (_, r) =>
17
+ Array.from({ length: 14 }, (_, c) => (
18
+ <circle
19
+ key={`${prefix}-${r}-${c}`}
20
+ cx={(c * 20 + 10).toString()}
21
+ cy={(r * 20 + 10).toString()}
22
+ r="0.8"
23
+ fill="#1E2D40"
24
+ />
25
+ )),
26
+ ).flat()}
27
+ </>
28
+ )
29
+ }
30
+
31
+ // Step 0 - click element → panel slides in
32
+ function ClickInspectIllustration() {
33
+ return (
34
+ <svg
35
+ viewBox="0 0 280 150"
36
+ xmlns="http://www.w3.org/2000/svg"
37
+ style={{ width: '100%', height: 'auto', borderRadius: 10, display: 'block', overflow: 'hidden' }}
38
+ >
39
+ <defs>
40
+ <style>{`
41
+ .dei-panel {
42
+ animation: deiPanelSlide 4s ease-in-out infinite;
43
+ }
44
+ @keyframes deiPanelSlide {
45
+ 0%, 20% { transform: translateX(85px); opacity: 0; }
46
+ 40%, 75% { transform: translateX(0); opacity: 1; }
47
+ 90%, 100%{ transform: translateX(85px); opacity: 0; }
48
+ }
49
+ .dei-node-select {
50
+ animation: deiNodeGlow 4s ease-in-out infinite;
51
+ }
52
+ @keyframes deiNodeGlow {
53
+ 0%, 25% { stroke: #4A5568; filter: none; }
54
+ 40%, 75% { stroke: #63B3ED; filter: drop-shadow(0 0 6px rgba(99,179,237,0.5)); }
55
+ 90%, 100%{ stroke: #4A5568; filter: none; }
56
+ }
57
+ .dei-cursor {
58
+ animation: deiCursorClick 4s ease-in-out infinite;
59
+ }
60
+ @keyframes deiCursorClick {
61
+ 0%, 15% { transform: translate(82px, 75px) scale(1); opacity: 0; }
62
+ 22% { transform: translate(82px, 75px) scale(1); opacity: 1; }
63
+ 32% { transform: translate(82px, 75px) scale(0.85); opacity: 1; }
64
+ 42%, 80% { transform: translate(82px, 75px) scale(1); opacity: 0.4; }
65
+ 90%, 100%{ opacity: 0; }
66
+ }
67
+ `}</style>
68
+ </defs>
69
+
70
+ <rect width="280" height="150" fill="#0D1117" rx="8" />
71
+ <GridDots prefix="ci" />
72
+
73
+ {/* Node */}
74
+ <rect
75
+ x="32" y="47" width="100" height="56"
76
+ rx="8" fill="#1C2535"
77
+ stroke="#4A5568" strokeWidth="1.5"
78
+ className="dei-node-select"
79
+ />
80
+ {/* Handles */}
81
+ <circle cx="32" cy="75" r="3.5" fill="#63B3ED" opacity="0.6" />
82
+ <circle cx="132" cy="75" r="3.5" fill="#63B3ED" opacity="0.6" />
83
+ <circle cx="82" cy="47" r="3.5" fill="#63B3ED" opacity="0.6" />
84
+ <circle cx="82" cy="103" r="3.5" fill="#63B3ED" opacity="0.6" />
85
+ <text x="82" y="72" textAnchor="middle" fill="#E2E8F0" fontSize="11" fontFamily="system-ui,sans-serif" fontWeight="700">API Gateway</text>
86
+ <text x="82" y="87" textAnchor="middle" fill="#718096" fontSize="8.5" fontFamily="system-ui,sans-serif">container</text>
87
+
88
+ {/* Cursor */}
89
+ <g className="dei-cursor">
90
+ <path d="M0,0 L0,14 L4,10 L7,17 L9,16 L6,9 L11,9 Z" fill="white" stroke="#0D1117" strokeWidth="0.6" />
91
+ </g>
92
+
93
+ {/* Sliding detail panel */}
94
+ <g className="dei-panel">
95
+ <rect x="148" y="10" width="122" height="130" rx="8" fill="#1A202C" stroke="#2D3748" strokeWidth="1" />
96
+ <rect x="148" y="10" width="122" height="28" rx="8" fill="#212A3A" />
97
+ <rect x="148" y="28" width="122" height="10" rx="0" fill="#212A3A" />
98
+ <text x="160" y="28" fill="#90CDF4" fontSize="9.5" fontFamily="system-ui,sans-serif" fontWeight="700">API Gateway</text>
99
+ <text x="160" y="39" fill="#718096" fontSize="8" fontFamily="system-ui,sans-serif">container</text>
100
+
101
+ <text x="160" y="57" fill="#718096" fontSize="7.5" fontFamily="system-ui,sans-serif" letterSpacing="0.05em">NAME</text>
102
+ <rect x="160" y="62" width="98" height="12" rx="3" fill="#263040" />
103
+ <text x="165" y="72" fill="#CBD5E0" fontSize="8" fontFamily="system-ui,sans-serif">API Gateway</text>
104
+
105
+ <text x="160" y="87" fill="#718096" fontSize="7.5" fontFamily="system-ui,sans-serif" letterSpacing="0.05em">TYPE</text>
106
+ <rect x="160" y="92" width="98" height="12" rx="3" fill="#263040" />
107
+ <text x="165" y="102" fill="#CBD5E0" fontSize="8" fontFamily="system-ui,sans-serif">container</text>
108
+
109
+ <text x="160" y="117" fill="#718096" fontSize="7.5" fontFamily="system-ui,sans-serif" letterSpacing="0.05em">DESCRIPTION</text>
110
+ <rect x="160" y="122" width="98" height="14" rx="3" fill="#263040" />
111
+ </g>
112
+
113
+ <text x="140" y="144" textAnchor="middle" fill="#2D3748" fontSize="8" fontFamily="system-ui,sans-serif">click any element to inspect and edit it</text>
114
+ </svg>
115
+ )
116
+ }
117
+
118
+ // Step 1 - right-click / long-press canvas → context menu
119
+ function CanvasMenuIllustration() {
120
+ return (
121
+ <svg
122
+ viewBox="0 0 280 150"
123
+ xmlns="http://www.w3.org/2000/svg"
124
+ style={{ width: '100%', height: 'auto', borderRadius: 10, display: 'block', overflow: 'hidden' }}
125
+ >
126
+ <defs>
127
+ <style>{`
128
+ .dei-ctx-menu {
129
+ animation: deiCtxPop 5s ease-in-out infinite;
130
+ }
131
+ @keyframes deiCtxPop {
132
+ 0%, 35% { opacity: 0; transform: scale(0.92) translateY(4px); }
133
+ 50%, 80% { opacity: 1; transform: scale(1) translateY(0); }
134
+ 93%, 100%{ opacity: 0; transform: scale(0.92) translateY(4px); }
135
+ }
136
+ .dei-ripple {
137
+ animation: deiRipple 5s ease-in-out infinite;
138
+ }
139
+ @keyframes deiRipple {
140
+ 0%, 25% { opacity: 0; r: 4; }
141
+ 35% { opacity: 0.8; r: 4; }
142
+ 50% { opacity: 0; r: 22; }
143
+ 100% { opacity: 0; r: 22; }
144
+ }
145
+ .dei-ctx-cursor {
146
+ animation: deiCtxCursor 5s ease-in-out infinite;
147
+ }
148
+ @keyframes deiCtxCursor {
149
+ 0%, 20% { transform: translate(130px, 90px); opacity: 0; }
150
+ 30% { opacity: 1; }
151
+ 50%, 90% { transform: translate(130px, 90px); opacity: 0.4; }
152
+ 100% { opacity: 0; }
153
+ }
154
+ `}</style>
155
+ <marker id="dei-arr" markerWidth="7" markerHeight="7" refX="5" refY="3" orient="auto">
156
+ <path d="M0,0 L0,6 L7,3 z" fill="#4A5568" />
157
+ </marker>
158
+ </defs>
159
+
160
+ <rect width="280" height="150" fill="#0D1117" rx="8" />
161
+ <GridDots prefix="cm" />
162
+
163
+ {/* Existing nodes faded */}
164
+ <rect x="18" y="30" width="76" height="46" rx="7" fill="#1C2535" stroke="#2D3748" strokeWidth="1" />
165
+ <text x="56" y="57" textAnchor="middle" fill="#718096" fontSize="9" fontFamily="system-ui,sans-serif">Auth Service</text>
166
+
167
+ <rect x="186" y="30" width="76" height="46" rx="7" fill="#1C2535" stroke="#2D3748" strokeWidth="1" />
168
+ <text x="224" y="57" textAnchor="middle" fill="#718096" fontSize="9" fontFamily="system-ui,sans-serif">Database</text>
169
+
170
+ <line x1="94" y1="53" x2="186" y2="53" stroke="#2D3748" strokeWidth="1.5" markerEnd="url(#dei-arr)" />
171
+
172
+ {/* Right-click ripple on empty canvas */}
173
+ <circle cx="130" cy="90" className="dei-ripple" fill="none" stroke="#63B3ED" strokeWidth="1.5" r="4" />
174
+
175
+ {/* Cursor */}
176
+ <g className="dei-ctx-cursor">
177
+ <path d="M0,0 L0,14 L4,10 L7,17 L9,16 L6,9 L11,9 Z" fill="white" stroke="#0D1117" strokeWidth="0.6" />
178
+ </g>
179
+
180
+ {/* Context menu */}
181
+ <g className="dei-ctx-menu" style={{ transformOrigin: '130px 90px' }}>
182
+ <rect x="90" y="85" width="115" height="32" rx="6" fill="#1A202C" stroke="#2D3748" strokeWidth="1" />
183
+
184
+ {/* Add Element row - highlighted */}
185
+ <rect x="90" y="85" width="115" height="32" rx="6" fill="#172030" />
186
+ <text x="103" y="105" fill="#90CDF4" fontSize="9" fontFamily="system-ui,sans-serif" fontWeight="600">Add Element</text>
187
+ <rect x="178" y="96" width="18" height="11" rx="2" fill="#2D3748" />
188
+ <text x="187" y="105" textAnchor="middle" fill="#A0AEC0" fontSize="7.5" fontFamily="system-ui,sans-serif" fontWeight="700">C</text>
189
+ </g>
190
+
191
+ <text x="140" y="144" textAnchor="middle" fill="#2D3748" fontSize="8" fontFamily="system-ui,sans-serif">right-click (or hold on mobile) on empty canvas</text>
192
+ </svg>
193
+ )
194
+ }
195
+
196
+ // Step 2 - long-press / right-click element → interactive connect mode
197
+ function InteractiveConnectIllustration() {
198
+ return (
199
+ <svg
200
+ viewBox="0 0 280 150"
201
+ xmlns="http://www.w3.org/2000/svg"
202
+ style={{ width: '100%', height: 'auto', borderRadius: 10, display: 'block', overflow: 'hidden' }}
203
+ >
204
+ <defs>
205
+ <style>{`
206
+ .dei-src-glow {
207
+ animation: deiSrcGlow 4.5s ease-in-out infinite;
208
+ }
209
+ @keyframes deiSrcGlow {
210
+ 0%, 15% { stroke: #4A5568; filter: none; }
211
+ 30%, 75% { stroke: #63B3ED; filter: drop-shadow(0 0 10px rgba(99,179,237,0.6)); }
212
+ 90%, 100%{ stroke: #4A5568; filter: none; }
213
+ }
214
+ .dei-tgt-glow {
215
+ animation: deiTgtGlow 4.5s ease-in-out infinite;
216
+ }
217
+ @keyframes deiTgtGlow {
218
+ 0%, 40% { stroke: #4A5568; filter: none; }
219
+ 55%, 75% { stroke: #4FD1C5; filter: drop-shadow(0 0 8px rgba(79,209,197,0.5)); }
220
+ 90%, 100%{ stroke: #4A5568; filter: none; }
221
+ }
222
+ .dei-arc {
223
+ animation: deiArcDraw 4.5s ease-in-out infinite;
224
+ }
225
+ @keyframes deiArcDraw {
226
+ 0%, 45% { stroke-dashoffset: 120; opacity: 0; }
227
+ 60%, 75% { stroke-dashoffset: 0; opacity: 1; }
228
+ 88%, 100%{ stroke-dashoffset: 0; opacity: 0; }
229
+ }
230
+ .dei-src-label {
231
+ animation: deiSrcLabel 4.5s ease-in-out infinite;
232
+ }
233
+ @keyframes deiSrcLabel {
234
+ 0%, 20% { opacity: 0; }
235
+ 32%, 72% { opacity: 1; }
236
+ 85%, 100%{ opacity: 0; }
237
+ }
238
+ .dei-tgt-label {
239
+ animation: deiTgtLabel 4.5s ease-in-out infinite;
240
+ }
241
+ @keyframes deiTgtLabel {
242
+ 0%, 44% { opacity: 0; }
243
+ 56%, 74% { opacity: 1; }
244
+ 86%, 100%{ opacity: 0; }
245
+ }
246
+ .dei-hold-hint {
247
+ animation: deiHoldHint 4.5s ease-in-out infinite;
248
+ }
249
+ @keyframes deiHoldHint {
250
+ 0%, 10% { opacity: 0; }
251
+ 18%, 28% { opacity: 1; }
252
+ 36%, 100%{ opacity: 0; }
253
+ }
254
+ `}</style>
255
+ <marker id="dei-arr2" markerWidth="8" markerHeight="8" refX="6" refY="3" orient="auto">
256
+ <path d="M0,0 L0,6 L8,3 z" fill="#63B3ED" />
257
+ </marker>
258
+ </defs>
259
+
260
+ <rect width="280" height="150" fill="#0D1117" rx="8" />
261
+ <GridDots prefix="ic" />
262
+
263
+ {/* Source node */}
264
+ <rect x="22" y="47" width="96" height="56" rx="8" fill="#1C2535" strokeWidth="2" className="dei-src-glow" stroke="#4A5568" />
265
+ <text x="70" y="72" textAnchor="middle" fill="#E2E8F0" fontSize="10" fontFamily="system-ui,sans-serif" fontWeight="700">Auth Service</text>
266
+ <text x="70" y="86" textAnchor="middle" fill="#718096" fontSize="8" fontFamily="system-ui,sans-serif">container</text>
267
+ {/* Source badge */}
268
+ <rect x="34" y="36" width="42" height="13" rx="6" fill="#1A3A5A" stroke="#63B3ED" strokeWidth="0.8" className="dei-src-label" />
269
+ <text x="55" y="46" textAnchor="middle" fill="#63B3ED" fontSize="7.5" fontFamily="system-ui,sans-serif" fontWeight="700" className="dei-src-label">SOURCE</text>
270
+
271
+ {/* Target node */}
272
+ <rect x="162" y="47" width="96" height="56" rx="8" fill="#1C2535" strokeWidth="2" className="dei-tgt-glow" stroke="#4A5568" />
273
+ <text x="210" y="72" textAnchor="middle" fill="#E2E8F0" fontSize="10" fontFamily="system-ui,sans-serif" fontWeight="700">Database</text>
274
+ <text x="210" y="86" textAnchor="middle" fill="#718096" fontSize="8" fontFamily="system-ui,sans-serif">database</text>
275
+ {/* Target badge */}
276
+ <rect x="174" y="36" width="70" height="13" rx="6" fill="#142A2A" stroke="#4FD1C5" strokeWidth="0.8" className="dei-tgt-label" />
277
+ <text x="209" y="46" textAnchor="middle" fill="#4FD1C5" fontSize="7.5" fontFamily="system-ui,sans-serif" fontWeight="700" className="dei-tgt-label">TAP TO CONNECT</text>
278
+
279
+ {/* Animated arc */}
280
+ <path
281
+ d="M 118 75 C 138 55, 142 55, 162 75"
282
+ fill="none"
283
+ stroke="#63B3ED"
284
+ strokeWidth="1.8"
285
+ strokeDasharray="120"
286
+ strokeDashoffset="120"
287
+ markerEnd="url(#dei-arr2)"
288
+ className="dei-arc"
289
+ />
290
+
291
+ {/* Hold hint */}
292
+ <text x="70" y="120" textAnchor="middle" fill="#4A90D9" fontSize="7.5" fontFamily="system-ui,sans-serif" className="dei-hold-hint">hold to activate</text>
293
+
294
+ <text x="140" y="144" textAnchor="middle" fill="#2D3748" fontSize="8" fontFamily="system-ui,sans-serif">right-click (or hold on mobile) an element to enter connect mode</text>
295
+ </svg>
296
+ )
297
+ }
298
+
299
+ // ── Steps data ───────────────────────────────────────────────────────────────
300
+
301
+ const STEPS = [
302
+ {
303
+ title: 'Click to Inspect',
304
+ body: 'Click any element to open its detail panel. Edit the name, type, technology, description, and more. Click an connector to edit its label and relationship.',
305
+ visual: 'inspect' as const,
306
+ },
307
+ {
308
+ title: 'Canvas Menu',
309
+ body: 'Right-click anywhere on the canvas (or hold on mobile) to open the context menu. Navigate between diagram levels or add a new element at that spot.',
310
+ visual: 'canvasmenu' as const,
311
+ },
312
+ {
313
+ title: 'Connect Mode',
314
+ body: 'Right-click (or hold on mobile) any element to enter connect mode - it glows blue as the source. Then tap any other element to draw an connector between them.',
315
+ visual: 'connect' as const,
316
+ },
317
+ ]
318
+
319
+ // ── Main component ───────────────────────────────────────────────────────────
320
+
321
+ export default function ViewEditorOnboarding({ hasElements }: Props) {
322
+ const [visible, setVisible] = useState(false)
323
+ const [step, setStep] = useState(0)
324
+
325
+ useEffect(() => {
326
+ if (!hasElements) return
327
+ if (!localStorage.getItem(STORAGE_KEY)) {
328
+ setVisible(true)
329
+ }
330
+ }, [ hasElements])
331
+
332
+ const dismiss = () => {
333
+ localStorage.setItem(STORAGE_KEY, '1')
334
+ setVisible(false)
335
+ }
336
+
337
+ if (!visible) return null
338
+
339
+ const current = STEPS[step]
340
+ const isLast = step === STEPS.length - 1
341
+
342
+ return (
343
+ <Box
344
+ position="fixed"
345
+ inset={0}
346
+ zIndex={2000}
347
+ display="flex"
348
+ alignItems="center"
349
+ justifyContent="center"
350
+ pointerEvents="none"
351
+ >
352
+ {/* Backdrop */}
353
+ <Box
354
+ position="absolute"
355
+ inset={0}
356
+ bg="blackAlpha.700"
357
+ pointerEvents="auto"
358
+ onClick={dismiss}
359
+ />
360
+
361
+ {/* Tutorial card */}
362
+ <Box
363
+ position="relative"
364
+ w="380px"
365
+ bg="var(--bg-panel)"
366
+ border="1px solid"
367
+ borderColor="var(--border-main)"
368
+ borderRadius="16px"
369
+ p={6}
370
+ boxShadow="0 24px 60px rgba(0,0,0,0.6), 0 4px 16px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.04)"
371
+ pointerEvents="auto"
372
+ >
373
+ {/* Skip */}
374
+ <Button
375
+ position="absolute"
376
+ top={3}
377
+ right={3}
378
+ size="xs"
379
+ variant="ghost"
380
+ color="gray.500"
381
+ _hover={{ color: 'gray.200', bg: 'whiteAlpha.100' }}
382
+ onClick={dismiss}
383
+ fontWeight="normal"
384
+ >
385
+ Skip Tutorial
386
+ </Button>
387
+
388
+ {/* Step dots */}
389
+ <HStack justify="center" spacing={2} mb={5}>
390
+ {STEPS.map((_, i) => (
391
+ <Box
392
+ key={i}
393
+ w={i === step ? '18px' : '6px'}
394
+ h="6px"
395
+ rounded="full"
396
+ bg={i === step ? 'blue.400' : 'gray.600'}
397
+ transition="all 0.25s ease"
398
+ cursor="pointer"
399
+ onClick={() => setStep(i)}
400
+ _hover={{ bg: i === step ? 'blue.400' : 'gray.500' }}
401
+ />
402
+ ))}
403
+ </HStack>
404
+
405
+ {/* Visual + text */}
406
+ <VStack spacing={4} textAlign="center">
407
+ {current.visual === 'inspect' && <ClickInspectIllustration />}
408
+ {current.visual === 'canvasmenu' && <CanvasMenuIllustration />}
409
+ {current.visual === 'connect' && <InteractiveConnectIllustration />}
410
+
411
+ <VStack spacing={2}>
412
+ <Text fontWeight="bold" fontSize="lg" color="gray.100" lineHeight="short">
413
+ {current.title}
414
+ </Text>
415
+ <Text fontSize="sm" color="gray.400" lineHeight="tall" maxW="300px">
416
+ {current.body}
417
+ </Text>
418
+ </VStack>
419
+ </VStack>
420
+
421
+ {/* Nav */}
422
+ <HStack mt={6} justify="space-between" align="center">
423
+ <Button
424
+ size="sm"
425
+ variant="ghost"
426
+ color="gray.500"
427
+ _hover={{ color: 'gray.300' }}
428
+ onClick={() => setStep(step - 1)}
429
+ visibility={step > 0 ? 'visible' : 'hidden'}
430
+ >
431
+ ← Back
432
+ </Button>
433
+ <Button
434
+ size="sm"
435
+ colorScheme="blue"
436
+ px={5}
437
+ onClick={isLast ? dismiss : () => setStep(step + 1)}
438
+ >
439
+ {isLast ? 'Got it' : 'Next →'}
440
+ </Button>
441
+ </HStack>
442
+ </Box>
443
+ </Box>
444
+ )
445
+ }
@@ -0,0 +1,49 @@
1
+ import React from 'react'
2
+ import {
3
+ Box,
4
+ SimpleGrid,
5
+ PopoverContent,
6
+ PopoverBody,
7
+ PopoverArrow,
8
+ } from '@chakra-ui/react'
9
+ import { SWATCH_COLORS } from '../utils'
10
+
11
+ interface Props {
12
+ onSelect: (color: string) => void
13
+ onClose: () => void
14
+ }
15
+
16
+ export const ColorPicker: React.FC<Props> = ({ onSelect, onClose }) => {
17
+ return (
18
+ <PopoverContent
19
+ bg="gray.800"
20
+ border="1px solid"
21
+ borderColor="whiteAlpha.200"
22
+ shadow="2xl"
23
+ w="160px"
24
+ zIndex={2000}
25
+ >
26
+ <PopoverArrow bg="gray.800" />
27
+ <PopoverBody p={2}>
28
+ <SimpleGrid columns={5} spacing={2}>
29
+ {SWATCH_COLORS.map((c) => (
30
+ <Box
31
+ key={c}
32
+ w="20px"
33
+ h="20px"
34
+ bg={c}
35
+ rounded="full"
36
+ cursor="pointer"
37
+ _hover={{ transform: 'scale(1.1)', boxShadow: '0 0 0 2px white' }}
38
+ onClick={() => {
39
+ onSelect(c)
40
+ onClose()
41
+ }}
42
+ transition="all 0.1s"
43
+ />
44
+ ))}
45
+ </SimpleGrid>
46
+ </PopoverBody>
47
+ </PopoverContent>
48
+ )
49
+ }
@@ -0,0 +1,96 @@
1
+ import React, { useState, useEffect, useRef } from 'react'
2
+ import {
3
+ PopoverContent,
4
+ PopoverBody,
5
+ PopoverArrow,
6
+ Input,
7
+ Button,
8
+ HStack,
9
+ Text,
10
+ VStack,
11
+ } from '@chakra-ui/react'
12
+
13
+ interface Props {
14
+ isOpen: boolean
15
+ onClose: () => void
16
+ onConfirm: (name: string) => void | Promise<void>
17
+ defaultName: string
18
+ anchorEl?: HTMLElement | null
19
+ }
20
+
21
+ export const GroupNamingPopover: React.FC<Props> = ({
22
+ isOpen,
23
+ onClose,
24
+ onConfirm,
25
+ defaultName,
26
+ }) => {
27
+ const [name, setName] = useState(defaultName)
28
+ const inputRef = useRef<HTMLInputElement>(null)
29
+
30
+ useEffect(() => {
31
+ if (isOpen) {
32
+ setName(defaultName)
33
+ // Focus after a short delay to ensure popover is rendered
34
+ setTimeout(() => inputRef.current?.focus(), 100)
35
+ }
36
+ }, [isOpen, defaultName])
37
+
38
+ const handleConfirm = async () => {
39
+ if (name.trim()) {
40
+ await onConfirm(name.trim())
41
+ onClose()
42
+ }
43
+ }
44
+
45
+ const handleKeyDown = (e: React.KeyboardEvent) => {
46
+ if (e.key === 'Enter') {
47
+ e.preventDefault()
48
+ void handleConfirm()
49
+ } else if (e.key === 'Escape') {
50
+ onClose()
51
+ }
52
+ }
53
+
54
+ return (
55
+ <PopoverContent
56
+ bg="gray.800"
57
+ border="1px solid"
58
+ borderColor="whiteAlpha.200"
59
+ shadow="2xl"
60
+ w="240px"
61
+ zIndex={2000}
62
+ onKeyDown={handleKeyDown}
63
+ >
64
+ <PopoverArrow bg="gray.800" />
65
+ <PopoverBody p={3}>
66
+ <VStack align="stretch" spacing={2}>
67
+ <Text fontSize="10px" fontWeight="700" color="var(--accent)" textTransform="uppercase">
68
+ New Tag Group
69
+ </Text>
70
+ <HStack spacing={2}>
71
+ <Input
72
+ ref={inputRef}
73
+ size="xs"
74
+ value={name}
75
+ onChange={(e) => setName(e.target.value)}
76
+ placeholder="Group name..."
77
+ bg="whiteAlpha.50"
78
+ borderColor="whiteAlpha.100"
79
+ color="white"
80
+ _focus={{ borderColor: 'var(--accent)' }}
81
+ />
82
+ <Button
83
+ size="xs"
84
+ colorScheme="blue"
85
+ onClick={handleConfirm}
86
+ bg="var(--accent)"
87
+ _hover={{ bg: 'var(--accent-hover)' }}
88
+ >
89
+ Create
90
+ </Button>
91
+ </HStack>
92
+ </VStack>
93
+ </PopoverBody>
94
+ </PopoverContent>
95
+ )
96
+ }