@antigenic-oss/paint 0.1.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 (158) hide show
  1. package/LICENSE +178 -0
  2. package/NOTICE +4 -0
  3. package/README.md +180 -0
  4. package/bin/paint.js +266 -0
  5. package/next-env.d.ts +6 -0
  6. package/next.config.ts +19 -0
  7. package/package.json +81 -0
  8. package/postcss.config.mjs +8 -0
  9. package/public/dev-editor-inspector.js +1872 -0
  10. package/src/app/api/claude/analyze/route.ts +319 -0
  11. package/src/app/api/claude/apply/route.ts +185 -0
  12. package/src/app/api/claude/pick-folder/route.ts +64 -0
  13. package/src/app/api/claude/scan/route.ts +221 -0
  14. package/src/app/api/claude/status/route.ts +55 -0
  15. package/src/app/api/project/scan/route.ts +634 -0
  16. package/src/app/api/project-scan/css-variables/route.ts +238 -0
  17. package/src/app/api/project-scan/route.ts +40 -0
  18. package/src/app/api/project-scan/tailwind-config/route.ts +172 -0
  19. package/src/app/api/proxy/[[...path]]/route.ts +2400 -0
  20. package/src/app/docs/DocsClient.tsx +322 -0
  21. package/src/app/docs/layout.tsx +7 -0
  22. package/src/app/docs/page.tsx +855 -0
  23. package/src/app/globals.css +176 -0
  24. package/src/app/layout.tsx +19 -0
  25. package/src/app/page.tsx +46 -0
  26. package/src/bridge/api-handlers.ts +885 -0
  27. package/src/bridge/proxy-handler.ts +329 -0
  28. package/src/bridge/server.ts +113 -0
  29. package/src/components/BreakpointTabs.tsx +72 -0
  30. package/src/components/ChangeSummaryModal.tsx +267 -0
  31. package/src/components/ConnectModal.tsx +994 -0
  32. package/src/components/Editor.tsx +90 -0
  33. package/src/components/PageSelector.tsx +208 -0
  34. package/src/components/PreviewFrame.tsx +299 -0
  35. package/src/components/ProjectFolderBanner.tsx +91 -0
  36. package/src/components/ResponsiveToolbar.tsx +222 -0
  37. package/src/components/TargetSelector.tsx +243 -0
  38. package/src/components/TopBar.tsx +315 -0
  39. package/src/components/common/CollapsibleSection.tsx +36 -0
  40. package/src/components/common/ColorPicker.tsx +920 -0
  41. package/src/components/common/EditablePre.tsx +136 -0
  42. package/src/components/common/ErrorBoundary.tsx +65 -0
  43. package/src/components/common/ResizablePanel.tsx +83 -0
  44. package/src/components/common/ScanAnimation.tsx +76 -0
  45. package/src/components/common/ToastContainer.tsx +97 -0
  46. package/src/components/common/UnitInput.tsx +77 -0
  47. package/src/components/common/VariableColorPicker.tsx +622 -0
  48. package/src/components/left-panel/AddElementPanel.tsx +237 -0
  49. package/src/components/left-panel/ComponentsPanel.tsx +609 -0
  50. package/src/components/left-panel/IconSidebar.tsx +99 -0
  51. package/src/components/left-panel/LayerNode.tsx +874 -0
  52. package/src/components/left-panel/LayerSearch.tsx +23 -0
  53. package/src/components/left-panel/LayersPanel.tsx +52 -0
  54. package/src/components/left-panel/LeftPanel.tsx +122 -0
  55. package/src/components/left-panel/PagesPanel.tsx +114 -0
  56. package/src/components/left-panel/icons.tsx +162 -0
  57. package/src/components/left-panel/terminal/ScanOverlay.tsx +66 -0
  58. package/src/components/left-panel/terminal/TerminalPanel.tsx +217 -0
  59. package/src/components/right-panel/ElementLogBox.tsx +248 -0
  60. package/src/components/right-panel/PanelTabs.tsx +83 -0
  61. package/src/components/right-panel/RightPanel.tsx +41 -0
  62. package/src/components/right-panel/changes/AiScanResultPanel.tsx +285 -0
  63. package/src/components/right-panel/changes/ChangeEntry.tsx +59 -0
  64. package/src/components/right-panel/changes/ChangelogActions.tsx +105 -0
  65. package/src/components/right-panel/changes/ChangesPanel.tsx +1474 -0
  66. package/src/components/right-panel/claude/ApplyConfirmModal.tsx +376 -0
  67. package/src/components/right-panel/claude/ClaudeErrorState.tsx +125 -0
  68. package/src/components/right-panel/claude/ClaudeIntegrationPanel.tsx +482 -0
  69. package/src/components/right-panel/claude/ClaudeProgressIndicator.tsx +76 -0
  70. package/src/components/right-panel/claude/DiffCard.tsx +130 -0
  71. package/src/components/right-panel/claude/DiffViewer.tsx +54 -0
  72. package/src/components/right-panel/claude/ProjectRootSelector.tsx +275 -0
  73. package/src/components/right-panel/claude/ResultsSummary.tsx +119 -0
  74. package/src/components/right-panel/claude/SetupFlow.tsx +315 -0
  75. package/src/components/right-panel/console/ConsolePanel.tsx +209 -0
  76. package/src/components/right-panel/design/AppearanceSection.tsx +703 -0
  77. package/src/components/right-panel/design/BackgroundSection.tsx +516 -0
  78. package/src/components/right-panel/design/BorderSection.tsx +161 -0
  79. package/src/components/right-panel/design/CSSRawView.tsx +412 -0
  80. package/src/components/right-panel/design/DesignCSSTabToggle.tsx +51 -0
  81. package/src/components/right-panel/design/DesignPanel.tsx +275 -0
  82. package/src/components/right-panel/design/ElementBreadcrumb.tsx +51 -0
  83. package/src/components/right-panel/design/GradientEditor.tsx +726 -0
  84. package/src/components/right-panel/design/LayoutSection.tsx +1948 -0
  85. package/src/components/right-panel/design/PositionSection.tsx +865 -0
  86. package/src/components/right-panel/design/PropertiesSection.tsx +86 -0
  87. package/src/components/right-panel/design/SVGSection.tsx +361 -0
  88. package/src/components/right-panel/design/ShadowBlurSection.tsx +227 -0
  89. package/src/components/right-panel/design/SizeSection.tsx +183 -0
  90. package/src/components/right-panel/design/TextSection.tsx +719 -0
  91. package/src/components/right-panel/design/icons.tsx +948 -0
  92. package/src/components/right-panel/design/inputs/BoxModelPreview.tsx +467 -0
  93. package/src/components/right-panel/design/inputs/ColorInput.tsx +43 -0
  94. package/src/components/right-panel/design/inputs/CompactInput.tsx +333 -0
  95. package/src/components/right-panel/design/inputs/DraggableLabel.tsx +118 -0
  96. package/src/components/right-panel/design/inputs/IconToggleGroup.tsx +54 -0
  97. package/src/components/right-panel/design/inputs/LinkedInputPair.tsx +174 -0
  98. package/src/components/right-panel/design/inputs/SectionHeader.tsx +79 -0
  99. package/src/components/right-panel/variables/VariablesPanel.tsx +388 -0
  100. package/src/hooks/useBridge.ts +95 -0
  101. package/src/hooks/useChangeTracker.ts +563 -0
  102. package/src/hooks/useClaudeAPI.ts +118 -0
  103. package/src/hooks/useDOMTree.ts +25 -0
  104. package/src/hooks/useKeyboardShortcuts.ts +76 -0
  105. package/src/hooks/usePostMessage.ts +589 -0
  106. package/src/hooks/useProjectScan.ts +204 -0
  107. package/src/hooks/useResizable.ts +20 -0
  108. package/src/hooks/useSelectedElement.ts +51 -0
  109. package/src/hooks/useTargetUrl.ts +81 -0
  110. package/src/inspector/DOMTraverser.ts +71 -0
  111. package/src/inspector/ElementSelector.ts +23 -0
  112. package/src/inspector/HoverHighlighter.ts +54 -0
  113. package/src/inspector/SelectionHighlighter.ts +27 -0
  114. package/src/inspector/StyleExtractor.ts +19 -0
  115. package/src/inspector/inspector.ts +17 -0
  116. package/src/inspector/messaging.ts +30 -0
  117. package/src/lib/apiBase.ts +15 -0
  118. package/src/lib/classifyElement.ts +430 -0
  119. package/src/lib/claude-bin.ts +197 -0
  120. package/src/lib/claude-stream.ts +158 -0
  121. package/src/lib/clientProjectScanner.ts +344 -0
  122. package/src/lib/componentMatcher.ts +156 -0
  123. package/src/lib/constants.ts +573 -0
  124. package/src/lib/cssVariableUtils.ts +409 -0
  125. package/src/lib/diffParser.ts +206 -0
  126. package/src/lib/folderPicker.ts +84 -0
  127. package/src/lib/gradientParser.ts +160 -0
  128. package/src/lib/projectScanner.ts +355 -0
  129. package/src/lib/promptBuilder.ts +402 -0
  130. package/src/lib/shadowParser.ts +124 -0
  131. package/src/lib/tailwindClassParser.ts +248 -0
  132. package/src/lib/textShadowUtils.ts +106 -0
  133. package/src/lib/utils.ts +299 -0
  134. package/src/lib/validatePath.ts +40 -0
  135. package/src/proxy.ts +92 -0
  136. package/src/server/terminal-server.ts +104 -0
  137. package/src/store/changeSlice.ts +288 -0
  138. package/src/store/claudeSlice.ts +222 -0
  139. package/src/store/componentSlice.ts +90 -0
  140. package/src/store/consoleSlice.ts +51 -0
  141. package/src/store/cssVariableSlice.ts +94 -0
  142. package/src/store/elementSlice.ts +78 -0
  143. package/src/store/index.ts +35 -0
  144. package/src/store/terminalSlice.ts +30 -0
  145. package/src/store/treeSlice.ts +69 -0
  146. package/src/store/uiSlice.ts +327 -0
  147. package/src/types/changelog.ts +49 -0
  148. package/src/types/claude.ts +131 -0
  149. package/src/types/component.ts +49 -0
  150. package/src/types/cssVariables.ts +18 -0
  151. package/src/types/element.ts +21 -0
  152. package/src/types/file-system-access.d.ts +27 -0
  153. package/src/types/gradient.ts +12 -0
  154. package/src/types/messages.ts +392 -0
  155. package/src/types/shadow.ts +8 -0
  156. package/src/types/tree.ts +9 -0
  157. package/tsconfig.json +42 -0
  158. package/tsconfig.server.json +12 -0
@@ -0,0 +1,315 @@
1
+ 'use client'
2
+
3
+ import { useState } from 'react'
4
+ import { TargetSelector } from './TargetSelector'
5
+ import { BreakpointTabs } from './BreakpointTabs'
6
+ import { ChangeSummaryModal } from './ChangeSummaryModal'
7
+ import { ProjectFolderBanner } from './ProjectFolderBanner'
8
+ import { useEditorStore } from '@/store'
9
+ import { usePostMessage } from '@/hooks/usePostMessage'
10
+ import {
11
+ performUndo,
12
+ performRedo,
13
+ performRevertAll,
14
+ } from '@/hooks/useChangeTracker'
15
+
16
+ export function TopBar() {
17
+ const toggleLeftPanel = useEditorStore((s) => s.toggleLeftPanel)
18
+ const toggleRightPanel = useEditorStore((s) => s.toggleRightPanel)
19
+ const leftPanelOpen = useEditorStore((s) => s.leftPanelOpen)
20
+ const rightPanelOpen = useEditorStore((s) => s.rightPanelOpen)
21
+ const connectionStatus = useEditorStore((s) => s.connectionStatus)
22
+ const changeCount = useEditorStore((s) => s.styleChanges.length)
23
+ const selectionMode = useEditorStore((s) => s.selectionMode)
24
+ const toggleSelectionMode = useEditorStore((s) => s.toggleSelectionMode)
25
+ const viewMode = useEditorStore((s) => s.viewMode)
26
+ const toggleViewMode = useEditorStore((s) => s.toggleViewMode)
27
+ const canUndo = useEditorStore((s) => s.undoStack.length > 0)
28
+ const canRedo = useEditorStore((s) => s.redoStack.length > 0)
29
+ const [showSummary, setShowSummary] = useState(false)
30
+ const { sendToInspector, iframeRef } = usePostMessage()
31
+
32
+ return (
33
+ <div className="relative flex-shrink-0">
34
+ <div
35
+ className="flex items-center h-10 px-3 gap-3"
36
+ style={{
37
+ background: 'var(--bg-secondary)',
38
+ borderBottom: '1px solid var(--border)',
39
+ }}
40
+ >
41
+ {/* Left panel toggle */}
42
+ <button
43
+ onClick={toggleLeftPanel}
44
+ className="px-2 py-1 text-xs rounded hover:bg-[var(--bg-hover)] transition-colors"
45
+ style={{
46
+ color: leftPanelOpen ? 'var(--accent)' : 'var(--text-secondary)',
47
+ }}
48
+ title="Toggle layers panel"
49
+ >
50
+
51
+ </button>
52
+
53
+ {/* Logo */}
54
+ <span
55
+ className="text-sm font-semibold tracking-tight whitespace-nowrap"
56
+ style={{ color: 'var(--text-primary)' }}
57
+ >
58
+ pAInt
59
+ </span>
60
+
61
+ {/* Separator */}
62
+ <div className="w-px h-5" style={{ background: 'var(--border)' }} />
63
+
64
+ {/* Target URL selector */}
65
+ <TargetSelector />
66
+
67
+ {/* Refresh preview */}
68
+ {connectionStatus === 'connected' && (
69
+ <button
70
+ onClick={() => {
71
+ const iframe = iframeRef.current
72
+ if (iframe?.src) {
73
+ iframe.src = iframe.src
74
+ }
75
+ }}
76
+ className="p-1.5 rounded hover:bg-[var(--bg-hover)] transition-colors"
77
+ style={{ color: 'var(--text-secondary)' }}
78
+ title="Refresh preview"
79
+ >
80
+ <svg
81
+ width="14"
82
+ height="14"
83
+ viewBox="0 0 24 24"
84
+ fill="none"
85
+ stroke="currentColor"
86
+ strokeWidth="2"
87
+ strokeLinecap="round"
88
+ strokeLinejoin="round"
89
+ >
90
+ <polyline points="23 4 23 10 17 10" />
91
+ <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10" />
92
+ </svg>
93
+ </button>
94
+ )}
95
+
96
+ {/* Center area — breakpoints */}
97
+ {connectionStatus === 'connected' && (
98
+ <>
99
+ <div className="w-px h-5" style={{ background: 'var(--border)' }} />
100
+ <BreakpointTabs />
101
+ </>
102
+ )}
103
+
104
+ {/* Select / Preview toggle */}
105
+ {connectionStatus === 'connected' && (
106
+ <>
107
+ <div className="w-px h-5" style={{ background: 'var(--border)' }} />
108
+ <div
109
+ className="flex rounded overflow-hidden"
110
+ style={{ border: '1px solid var(--border)' }}
111
+ >
112
+ <button
113
+ onClick={() => {
114
+ if (!viewMode && selectionMode) return
115
+ if (viewMode) {
116
+ toggleViewMode()
117
+ if (!selectionMode) toggleSelectionMode()
118
+ sendToInspector({
119
+ type: 'SET_SELECTION_MODE',
120
+ payload: { enabled: true },
121
+ })
122
+ } else {
123
+ toggleSelectionMode()
124
+ sendToInspector({
125
+ type: 'SET_SELECTION_MODE',
126
+ payload: { enabled: true },
127
+ })
128
+ }
129
+ }}
130
+ className="flex items-center gap-1.5 px-2.5 py-1 text-xs transition-colors"
131
+ style={{
132
+ background:
133
+ !viewMode && selectionMode
134
+ ? 'var(--accent)'
135
+ : 'var(--bg-tertiary)',
136
+ color:
137
+ !viewMode && selectionMode
138
+ ? '#fff'
139
+ : 'var(--text-secondary)',
140
+ borderRight: '1px solid var(--border)',
141
+ }}
142
+ title={
143
+ selectionMode && !viewMode
144
+ ? 'Selection mode ON — click selects elements'
145
+ : 'Switch to selection mode'
146
+ }
147
+ >
148
+ <svg
149
+ width="14"
150
+ height="14"
151
+ viewBox="0 0 24 24"
152
+ fill="none"
153
+ stroke="currentColor"
154
+ strokeWidth="2"
155
+ strokeLinecap="round"
156
+ strokeLinejoin="round"
157
+ >
158
+ <path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z" />
159
+ <path d="M13 13l6 6" />
160
+ </svg>
161
+ Select
162
+ </button>
163
+ <button
164
+ onClick={() => {
165
+ if (viewMode) return
166
+ toggleViewMode()
167
+ sendToInspector({
168
+ type: 'SET_SELECTION_MODE',
169
+ payload: { enabled: false },
170
+ })
171
+ }}
172
+ className="flex items-center gap-1.5 px-2.5 py-1 text-xs transition-colors"
173
+ style={{
174
+ background: viewMode ? 'var(--accent)' : 'var(--bg-tertiary)',
175
+ color: viewMode ? '#fff' : 'var(--text-secondary)',
176
+ }}
177
+ title={
178
+ viewMode
179
+ ? 'Preview mode — exit to edit'
180
+ : 'Preview — navigate & test the site'
181
+ }
182
+ >
183
+ <svg
184
+ width="14"
185
+ height="14"
186
+ viewBox="0 0 24 24"
187
+ fill="none"
188
+ stroke="currentColor"
189
+ strokeWidth="2"
190
+ strokeLinecap="round"
191
+ strokeLinejoin="round"
192
+ >
193
+ <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
194
+ <circle cx="12" cy="12" r="3" />
195
+ </svg>
196
+ Preview
197
+ </button>
198
+ </div>
199
+ </>
200
+ )}
201
+
202
+ {/* Spacer */}
203
+ <div className="flex-1" />
204
+
205
+ {/* Undo / Redo */}
206
+ {connectionStatus === 'connected' && (
207
+ <>
208
+ <button
209
+ onClick={performUndo}
210
+ disabled={!canUndo}
211
+ className="p-1.5 rounded hover:bg-[var(--bg-hover)] transition-colors"
212
+ style={{
213
+ color: canUndo ? 'var(--text-secondary)' : 'var(--text-muted)',
214
+ opacity: canUndo ? 1 : 0.4,
215
+ cursor: canUndo ? 'pointer' : 'default',
216
+ }}
217
+ title="Undo (Cmd+Z)"
218
+ >
219
+ <svg
220
+ width="14"
221
+ height="14"
222
+ viewBox="0 0 24 24"
223
+ fill="none"
224
+ stroke="currentColor"
225
+ strokeWidth="2"
226
+ strokeLinecap="round"
227
+ strokeLinejoin="round"
228
+ >
229
+ <polyline points="1 4 1 10 7 10" />
230
+ <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10" />
231
+ </svg>
232
+ </button>
233
+ <button
234
+ onClick={performRedo}
235
+ disabled={!canRedo}
236
+ className="p-1.5 rounded hover:bg-[var(--bg-hover)] transition-colors"
237
+ style={{
238
+ color: canRedo ? 'var(--text-secondary)' : 'var(--text-muted)',
239
+ opacity: canRedo ? 1 : 0.4,
240
+ cursor: canRedo ? 'pointer' : 'default',
241
+ }}
242
+ title="Redo (Cmd+Shift+Z)"
243
+ >
244
+ <svg
245
+ width="14"
246
+ height="14"
247
+ viewBox="0 0 24 24"
248
+ fill="none"
249
+ stroke="currentColor"
250
+ strokeWidth="2"
251
+ strokeLinecap="round"
252
+ strokeLinejoin="round"
253
+ >
254
+ <polyline points="23 4 23 10 17 10" />
255
+ <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10" />
256
+ </svg>
257
+ </button>
258
+ </>
259
+ )}
260
+
261
+ {/* Summary + Reset All buttons */}
262
+ {connectionStatus === 'connected' && changeCount > 0 && (
263
+ <>
264
+ <button
265
+ onClick={() => setShowSummary(true)}
266
+ className="px-3 py-1 text-xs font-medium rounded transition-colors"
267
+ style={{
268
+ border: '1px solid var(--accent)',
269
+ color: 'var(--accent)',
270
+ background: 'transparent',
271
+ }}
272
+ >
273
+ Summary ({changeCount})
274
+ </button>
275
+ <button
276
+ onClick={performRevertAll}
277
+ className="px-3 py-1 text-xs font-medium rounded transition-colors"
278
+ style={{ background: '#f87171', color: '#fff' }}
279
+ >
280
+ Reset All
281
+ </button>
282
+ </>
283
+ )}
284
+
285
+ {/* Docs link */}
286
+ <a
287
+ href="/docs"
288
+ target="_blank"
289
+ rel="noopener noreferrer"
290
+ className="px-2 py-1 text-xs rounded hover:bg-[var(--bg-hover)] transition-colors no-underline"
291
+ style={{ color: 'var(--text-secondary)' }}
292
+ title="Setup guide & docs"
293
+ >
294
+ Docs
295
+ </a>
296
+
297
+ {/* Right panel toggle */}
298
+ <button
299
+ onClick={toggleRightPanel}
300
+ className="px-2 py-1 text-xs rounded hover:bg-[var(--bg-hover)] transition-colors"
301
+ style={{
302
+ color: rightPanelOpen ? 'var(--accent)' : 'var(--text-secondary)',
303
+ }}
304
+ title="Toggle design panel"
305
+ >
306
+
307
+ </button>
308
+ </div>
309
+ <ProjectFolderBanner />
310
+ {showSummary && (
311
+ <ChangeSummaryModal onClose={() => setShowSummary(false)} />
312
+ )}
313
+ </div>
314
+ )
315
+ }
@@ -0,0 +1,36 @@
1
+ 'use client'
2
+
3
+ import { useState } from 'react'
4
+
5
+ interface CollapsibleSectionProps {
6
+ title: string
7
+ defaultOpen?: boolean
8
+ children: React.ReactNode
9
+ }
10
+
11
+ export function CollapsibleSection({
12
+ title,
13
+ defaultOpen = true,
14
+ children,
15
+ }: CollapsibleSectionProps) {
16
+ const [isOpen, setIsOpen] = useState(defaultOpen)
17
+
18
+ return (
19
+ <div style={{ borderBottom: '1px solid var(--border)' }}>
20
+ <button
21
+ onClick={() => setIsOpen(!isOpen)}
22
+ className="flex items-center w-full px-3 py-2 text-xs font-medium hover:bg-[var(--bg-hover)] transition-colors"
23
+ style={{ color: 'var(--text-secondary)' }}
24
+ >
25
+ <span
26
+ className="mr-2 text-[10px] transition-transform"
27
+ style={{ transform: isOpen ? 'rotate(0deg)' : 'rotate(-90deg)' }}
28
+ >
29
+
30
+ </span>
31
+ {title}
32
+ </button>
33
+ {isOpen && <div className="px-3 pb-3 space-y-2">{children}</div>}
34
+ </div>
35
+ )
36
+ }