@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.
- package/LICENSE +178 -0
- package/NOTICE +4 -0
- package/README.md +180 -0
- package/bin/paint.js +266 -0
- package/next-env.d.ts +6 -0
- package/next.config.ts +19 -0
- package/package.json +81 -0
- package/postcss.config.mjs +8 -0
- package/public/dev-editor-inspector.js +1872 -0
- package/src/app/api/claude/analyze/route.ts +319 -0
- package/src/app/api/claude/apply/route.ts +185 -0
- package/src/app/api/claude/pick-folder/route.ts +64 -0
- package/src/app/api/claude/scan/route.ts +221 -0
- package/src/app/api/claude/status/route.ts +55 -0
- package/src/app/api/project/scan/route.ts +634 -0
- package/src/app/api/project-scan/css-variables/route.ts +238 -0
- package/src/app/api/project-scan/route.ts +40 -0
- package/src/app/api/project-scan/tailwind-config/route.ts +172 -0
- package/src/app/api/proxy/[[...path]]/route.ts +2400 -0
- package/src/app/docs/DocsClient.tsx +322 -0
- package/src/app/docs/layout.tsx +7 -0
- package/src/app/docs/page.tsx +855 -0
- package/src/app/globals.css +176 -0
- package/src/app/layout.tsx +19 -0
- package/src/app/page.tsx +46 -0
- package/src/bridge/api-handlers.ts +885 -0
- package/src/bridge/proxy-handler.ts +329 -0
- package/src/bridge/server.ts +113 -0
- package/src/components/BreakpointTabs.tsx +72 -0
- package/src/components/ChangeSummaryModal.tsx +267 -0
- package/src/components/ConnectModal.tsx +994 -0
- package/src/components/Editor.tsx +90 -0
- package/src/components/PageSelector.tsx +208 -0
- package/src/components/PreviewFrame.tsx +299 -0
- package/src/components/ProjectFolderBanner.tsx +91 -0
- package/src/components/ResponsiveToolbar.tsx +222 -0
- package/src/components/TargetSelector.tsx +243 -0
- package/src/components/TopBar.tsx +315 -0
- package/src/components/common/CollapsibleSection.tsx +36 -0
- package/src/components/common/ColorPicker.tsx +920 -0
- package/src/components/common/EditablePre.tsx +136 -0
- package/src/components/common/ErrorBoundary.tsx +65 -0
- package/src/components/common/ResizablePanel.tsx +83 -0
- package/src/components/common/ScanAnimation.tsx +76 -0
- package/src/components/common/ToastContainer.tsx +97 -0
- package/src/components/common/UnitInput.tsx +77 -0
- package/src/components/common/VariableColorPicker.tsx +622 -0
- package/src/components/left-panel/AddElementPanel.tsx +237 -0
- package/src/components/left-panel/ComponentsPanel.tsx +609 -0
- package/src/components/left-panel/IconSidebar.tsx +99 -0
- package/src/components/left-panel/LayerNode.tsx +874 -0
- package/src/components/left-panel/LayerSearch.tsx +23 -0
- package/src/components/left-panel/LayersPanel.tsx +52 -0
- package/src/components/left-panel/LeftPanel.tsx +122 -0
- package/src/components/left-panel/PagesPanel.tsx +114 -0
- package/src/components/left-panel/icons.tsx +162 -0
- package/src/components/left-panel/terminal/ScanOverlay.tsx +66 -0
- package/src/components/left-panel/terminal/TerminalPanel.tsx +217 -0
- package/src/components/right-panel/ElementLogBox.tsx +248 -0
- package/src/components/right-panel/PanelTabs.tsx +83 -0
- package/src/components/right-panel/RightPanel.tsx +41 -0
- package/src/components/right-panel/changes/AiScanResultPanel.tsx +285 -0
- package/src/components/right-panel/changes/ChangeEntry.tsx +59 -0
- package/src/components/right-panel/changes/ChangelogActions.tsx +105 -0
- package/src/components/right-panel/changes/ChangesPanel.tsx +1474 -0
- package/src/components/right-panel/claude/ApplyConfirmModal.tsx +376 -0
- package/src/components/right-panel/claude/ClaudeErrorState.tsx +125 -0
- package/src/components/right-panel/claude/ClaudeIntegrationPanel.tsx +482 -0
- package/src/components/right-panel/claude/ClaudeProgressIndicator.tsx +76 -0
- package/src/components/right-panel/claude/DiffCard.tsx +130 -0
- package/src/components/right-panel/claude/DiffViewer.tsx +54 -0
- package/src/components/right-panel/claude/ProjectRootSelector.tsx +275 -0
- package/src/components/right-panel/claude/ResultsSummary.tsx +119 -0
- package/src/components/right-panel/claude/SetupFlow.tsx +315 -0
- package/src/components/right-panel/console/ConsolePanel.tsx +209 -0
- package/src/components/right-panel/design/AppearanceSection.tsx +703 -0
- package/src/components/right-panel/design/BackgroundSection.tsx +516 -0
- package/src/components/right-panel/design/BorderSection.tsx +161 -0
- package/src/components/right-panel/design/CSSRawView.tsx +412 -0
- package/src/components/right-panel/design/DesignCSSTabToggle.tsx +51 -0
- package/src/components/right-panel/design/DesignPanel.tsx +275 -0
- package/src/components/right-panel/design/ElementBreadcrumb.tsx +51 -0
- package/src/components/right-panel/design/GradientEditor.tsx +726 -0
- package/src/components/right-panel/design/LayoutSection.tsx +1948 -0
- package/src/components/right-panel/design/PositionSection.tsx +865 -0
- package/src/components/right-panel/design/PropertiesSection.tsx +86 -0
- package/src/components/right-panel/design/SVGSection.tsx +361 -0
- package/src/components/right-panel/design/ShadowBlurSection.tsx +227 -0
- package/src/components/right-panel/design/SizeSection.tsx +183 -0
- package/src/components/right-panel/design/TextSection.tsx +719 -0
- package/src/components/right-panel/design/icons.tsx +948 -0
- package/src/components/right-panel/design/inputs/BoxModelPreview.tsx +467 -0
- package/src/components/right-panel/design/inputs/ColorInput.tsx +43 -0
- package/src/components/right-panel/design/inputs/CompactInput.tsx +333 -0
- package/src/components/right-panel/design/inputs/DraggableLabel.tsx +118 -0
- package/src/components/right-panel/design/inputs/IconToggleGroup.tsx +54 -0
- package/src/components/right-panel/design/inputs/LinkedInputPair.tsx +174 -0
- package/src/components/right-panel/design/inputs/SectionHeader.tsx +79 -0
- package/src/components/right-panel/variables/VariablesPanel.tsx +388 -0
- package/src/hooks/useBridge.ts +95 -0
- package/src/hooks/useChangeTracker.ts +563 -0
- package/src/hooks/useClaudeAPI.ts +118 -0
- package/src/hooks/useDOMTree.ts +25 -0
- package/src/hooks/useKeyboardShortcuts.ts +76 -0
- package/src/hooks/usePostMessage.ts +589 -0
- package/src/hooks/useProjectScan.ts +204 -0
- package/src/hooks/useResizable.ts +20 -0
- package/src/hooks/useSelectedElement.ts +51 -0
- package/src/hooks/useTargetUrl.ts +81 -0
- package/src/inspector/DOMTraverser.ts +71 -0
- package/src/inspector/ElementSelector.ts +23 -0
- package/src/inspector/HoverHighlighter.ts +54 -0
- package/src/inspector/SelectionHighlighter.ts +27 -0
- package/src/inspector/StyleExtractor.ts +19 -0
- package/src/inspector/inspector.ts +17 -0
- package/src/inspector/messaging.ts +30 -0
- package/src/lib/apiBase.ts +15 -0
- package/src/lib/classifyElement.ts +430 -0
- package/src/lib/claude-bin.ts +197 -0
- package/src/lib/claude-stream.ts +158 -0
- package/src/lib/clientProjectScanner.ts +344 -0
- package/src/lib/componentMatcher.ts +156 -0
- package/src/lib/constants.ts +573 -0
- package/src/lib/cssVariableUtils.ts +409 -0
- package/src/lib/diffParser.ts +206 -0
- package/src/lib/folderPicker.ts +84 -0
- package/src/lib/gradientParser.ts +160 -0
- package/src/lib/projectScanner.ts +355 -0
- package/src/lib/promptBuilder.ts +402 -0
- package/src/lib/shadowParser.ts +124 -0
- package/src/lib/tailwindClassParser.ts +248 -0
- package/src/lib/textShadowUtils.ts +106 -0
- package/src/lib/utils.ts +299 -0
- package/src/lib/validatePath.ts +40 -0
- package/src/proxy.ts +92 -0
- package/src/server/terminal-server.ts +104 -0
- package/src/store/changeSlice.ts +288 -0
- package/src/store/claudeSlice.ts +222 -0
- package/src/store/componentSlice.ts +90 -0
- package/src/store/consoleSlice.ts +51 -0
- package/src/store/cssVariableSlice.ts +94 -0
- package/src/store/elementSlice.ts +78 -0
- package/src/store/index.ts +35 -0
- package/src/store/terminalSlice.ts +30 -0
- package/src/store/treeSlice.ts +69 -0
- package/src/store/uiSlice.ts +327 -0
- package/src/types/changelog.ts +49 -0
- package/src/types/claude.ts +131 -0
- package/src/types/component.ts +49 -0
- package/src/types/cssVariables.ts +18 -0
- package/src/types/element.ts +21 -0
- package/src/types/file-system-access.d.ts +27 -0
- package/src/types/gradient.ts +12 -0
- package/src/types/messages.ts +392 -0
- package/src/types/shadow.ts +8 -0
- package/src/types/tree.ts +9 -0
- package/tsconfig.json +42 -0
- package/tsconfig.server.json +12 -0
|
@@ -0,0 +1,855 @@
|
|
|
1
|
+
import type { Metadata } from 'next'
|
|
2
|
+
import Link from 'next/link'
|
|
3
|
+
import {
|
|
4
|
+
CodeBlock,
|
|
5
|
+
CopyButton,
|
|
6
|
+
FaqAccordion,
|
|
7
|
+
FaqSection,
|
|
8
|
+
FrameworkAccordion,
|
|
9
|
+
FrameworkSection,
|
|
10
|
+
Sidebar,
|
|
11
|
+
} from './DocsClient'
|
|
12
|
+
|
|
13
|
+
export const metadata: Metadata = {
|
|
14
|
+
title: 'pAInt — Setup Guide',
|
|
15
|
+
description:
|
|
16
|
+
'Framework-specific setup instructions for connecting pAInt to your localhost project.',
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const SCRIPT_TAG =
|
|
20
|
+
'<script src="https://dev-editor-flow.vercel.app/dev-editor-inspector.js"></script>'
|
|
21
|
+
|
|
22
|
+
export default function DocsPage() {
|
|
23
|
+
return (
|
|
24
|
+
<div
|
|
25
|
+
className="min-h-screen"
|
|
26
|
+
style={{ background: 'var(--bg-primary)', color: 'var(--text-primary)' }}
|
|
27
|
+
>
|
|
28
|
+
<div className="mx-auto px-6 py-12" style={{ maxWidth: '1024px' }}>
|
|
29
|
+
{/* Header */}
|
|
30
|
+
<header className="mb-12">
|
|
31
|
+
<Link
|
|
32
|
+
href="/"
|
|
33
|
+
className="inline-flex items-center gap-1 text-sm mb-6 no-underline transition-colors"
|
|
34
|
+
style={{ color: 'var(--accent)' }}
|
|
35
|
+
>
|
|
36
|
+
← Back to Editor
|
|
37
|
+
</Link>
|
|
38
|
+
<h1
|
|
39
|
+
className="text-3xl font-semibold mb-3"
|
|
40
|
+
style={{ color: 'var(--text-primary)' }}
|
|
41
|
+
>
|
|
42
|
+
pAInt — Setup Guide
|
|
43
|
+
</h1>
|
|
44
|
+
<p
|
|
45
|
+
style={{
|
|
46
|
+
color: 'var(--text-secondary)',
|
|
47
|
+
fontSize: '1rem',
|
|
48
|
+
lineHeight: 1.6,
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
Connect the visual editor to your localhost project in seconds.
|
|
52
|
+
</p>
|
|
53
|
+
</header>
|
|
54
|
+
|
|
55
|
+
<div className="flex gap-10">
|
|
56
|
+
{/* Sidebar */}
|
|
57
|
+
<Sidebar />
|
|
58
|
+
|
|
59
|
+
{/* Main content */}
|
|
60
|
+
<div className="flex-1 min-w-0">
|
|
61
|
+
{/* How It Works */}
|
|
62
|
+
<Section id="how-it-works" title="How It Works">
|
|
63
|
+
<p style={bodyText}>
|
|
64
|
+
pAInt is a visual design tool that sits alongside your localhost
|
|
65
|
+
dev server. It gives you a visual-editor-style interface for
|
|
66
|
+
inspecting elements, editing CSS, and repositioning components —
|
|
67
|
+
all without touching your source files directly.
|
|
68
|
+
</p>
|
|
69
|
+
<p style={{ ...bodyText, marginTop: '0.75rem' }}>
|
|
70
|
+
When you click{' '}
|
|
71
|
+
<strong style={{ color: 'var(--text-primary)' }}>
|
|
72
|
+
Connect
|
|
73
|
+
</strong>
|
|
74
|
+
, the editor loads your page through a{' '}
|
|
75
|
+
<strong style={{ color: 'var(--text-primary)' }}>
|
|
76
|
+
built-in reverse proxy
|
|
77
|
+
</strong>
|
|
78
|
+
. The proxy fetches your HTML, strips client-side scripts (to
|
|
79
|
+
prevent routing conflicts), and injects a lightweight inspector
|
|
80
|
+
script. This inspector communicates with the editor via{' '}
|
|
81
|
+
<code style={inlineCodeStyle}>postMessage</code> — reporting
|
|
82
|
+
element metadata when you hover or click, and applying style
|
|
83
|
+
previews in real time.
|
|
84
|
+
</p>
|
|
85
|
+
<p style={{ ...bodyText, marginTop: '0.75rem' }}>
|
|
86
|
+
Every change you make is tracked as a changelog entry with
|
|
87
|
+
original and new values. When you're done, export the
|
|
88
|
+
changelog and paste it into Claude Code (or use the built-in
|
|
89
|
+
Send to Claude Code feature) to have the changes applied to your
|
|
90
|
+
actual source files.
|
|
91
|
+
</p>
|
|
92
|
+
<p style={{ ...bodyText, marginTop: '0.75rem' }}>
|
|
93
|
+
If automatic injection fails (e.g., non-standard HTML
|
|
94
|
+
responses), a banner will prompt you to add the script tag
|
|
95
|
+
manually. The framework guides below show exactly where to place
|
|
96
|
+
it.
|
|
97
|
+
</p>
|
|
98
|
+
</Section>
|
|
99
|
+
|
|
100
|
+
{/* Use Cases */}
|
|
101
|
+
<Section id="use-cases" title="Use Cases">
|
|
102
|
+
<div className="flex flex-col gap-4">
|
|
103
|
+
<UseCaseItem
|
|
104
|
+
title="Visual Style Tweaking"
|
|
105
|
+
description="Select any element on your page, then adjust colors, spacing, typography, borders, and layout from the right panel. Changes preview instantly in the iframe."
|
|
106
|
+
/>
|
|
107
|
+
<UseCaseItem
|
|
108
|
+
title="Responsive Design Testing"
|
|
109
|
+
description="Switch between Mobile (375px), Tablet (768px), and Desktop (1280px) breakpoints in the top bar. Make per-breakpoint style adjustments and export them all at once."
|
|
110
|
+
/>
|
|
111
|
+
<UseCaseItem
|
|
112
|
+
title="Layout Debugging"
|
|
113
|
+
description="Use the left panel DOM tree (Layers) to navigate the page structure. Click any node to highlight it in the preview. Inspect flexbox and grid properties, then adjust layout in the right panel."
|
|
114
|
+
/>
|
|
115
|
+
<UseCaseItem
|
|
116
|
+
title="Drag-and-Drop Repositioning"
|
|
117
|
+
description="Toggle Free Position mode to drag elements to new positions, or Reorder mode to rearrange siblings within flex and grid containers."
|
|
118
|
+
/>
|
|
119
|
+
<UseCaseItem
|
|
120
|
+
title="Change Tracking & Export"
|
|
121
|
+
description="Every style edit is tracked with original and new values. Review all changes in the Changes tab, undo individual edits, or export a structured changelog."
|
|
122
|
+
/>
|
|
123
|
+
<UseCaseItem
|
|
124
|
+
title="Claude Code Integration"
|
|
125
|
+
description="Click Copy Changelog to get a formatted log you can paste into Claude Code, which reads it and applies the CSS changes to your actual source files. Or use Send to Claude Code for direct CLI integration."
|
|
126
|
+
/>
|
|
127
|
+
<UseCaseItem
|
|
128
|
+
title="Multi-Page Editing"
|
|
129
|
+
description="Navigate between pages using the PageSelector dropdown without leaving the editor. Changes are persisted per-page and included in a combined changelog export."
|
|
130
|
+
/>
|
|
131
|
+
</div>
|
|
132
|
+
</Section>
|
|
133
|
+
|
|
134
|
+
{/* Quick Start */}
|
|
135
|
+
<Section id="quick-start" title="Quick Start">
|
|
136
|
+
<ol className="list-none p-0 m-0 flex flex-col gap-5">
|
|
137
|
+
<Step number={1}>
|
|
138
|
+
<strong
|
|
139
|
+
style={{ color: 'var(--text-primary)', fontSize: '1rem' }}
|
|
140
|
+
>
|
|
141
|
+
Open pAInt
|
|
142
|
+
</strong>
|
|
143
|
+
<p style={{ ...bodyText, marginTop: '0.25rem' }}>
|
|
144
|
+
Go to{' '}
|
|
145
|
+
<a
|
|
146
|
+
href="https://dev-editor-flow.vercel.app/"
|
|
147
|
+
target="_blank"
|
|
148
|
+
rel="noopener noreferrer"
|
|
149
|
+
style={{ color: 'var(--accent)' }}
|
|
150
|
+
>
|
|
151
|
+
dev-editor-flow.vercel.app
|
|
152
|
+
</a>
|
|
153
|
+
</p>
|
|
154
|
+
<p style={{ ...mutedText, marginTop: '0.25rem' }}>
|
|
155
|
+
Running locally? Start with{' '}
|
|
156
|
+
<code style={inlineCodeStyle}>bun dev</code> (defaults to{' '}
|
|
157
|
+
<code style={inlineCodeStyle}>http://localhost:4000</code>).
|
|
158
|
+
</p>
|
|
159
|
+
</Step>
|
|
160
|
+
<Step number={2}>
|
|
161
|
+
<strong
|
|
162
|
+
style={{ color: 'var(--text-primary)', fontSize: '1rem' }}
|
|
163
|
+
>
|
|
164
|
+
Start your target project
|
|
165
|
+
</strong>
|
|
166
|
+
<p style={{ ...bodyText, marginTop: '0.25rem' }}>
|
|
167
|
+
Run your project's dev server as usual (e.g.,{' '}
|
|
168
|
+
<code style={inlineCodeStyle}>npm run dev</code> on port
|
|
169
|
+
3000).
|
|
170
|
+
</p>
|
|
171
|
+
</Step>
|
|
172
|
+
<Step number={3}>
|
|
173
|
+
<strong
|
|
174
|
+
style={{ color: 'var(--text-primary)', fontSize: '1rem' }}
|
|
175
|
+
>
|
|
176
|
+
Connect
|
|
177
|
+
</strong>
|
|
178
|
+
<p style={{ ...bodyText, marginTop: '0.25rem' }}>
|
|
179
|
+
Open pAInt in your browser, select your project's port
|
|
180
|
+
from the dropdown, and click{' '}
|
|
181
|
+
<strong style={{ color: 'var(--text-primary)' }}>
|
|
182
|
+
Connect
|
|
183
|
+
</strong>
|
|
184
|
+
. The inspector activates automatically.
|
|
185
|
+
</p>
|
|
186
|
+
</Step>
|
|
187
|
+
</ol>
|
|
188
|
+
</Section>
|
|
189
|
+
|
|
190
|
+
{/* Framework Guides */}
|
|
191
|
+
<Section id="framework-guides" title="Framework Guides">
|
|
192
|
+
<p style={{ ...bodyText, marginBottom: '1rem' }}>
|
|
193
|
+
If the automatic connection doesn't detect the inspector
|
|
194
|
+
within 5 seconds, add the script tag manually to your project.
|
|
195
|
+
Select your framework below for the exact file and placement.
|
|
196
|
+
</p>
|
|
197
|
+
<div
|
|
198
|
+
className="flex items-center gap-2 px-4 py-3 rounded-md mb-4 text-sm"
|
|
199
|
+
style={{
|
|
200
|
+
background: 'var(--accent-bg)',
|
|
201
|
+
border: '1px solid var(--accent)',
|
|
202
|
+
color: 'var(--text-secondary)',
|
|
203
|
+
}}
|
|
204
|
+
>
|
|
205
|
+
<span style={{ color: 'var(--accent)' }}>Note:</span>
|
|
206
|
+
<span>
|
|
207
|
+
The snippets below use the hosted URL. If running pAInt
|
|
208
|
+
locally, replace{' '}
|
|
209
|
+
<code style={{ ...inlineCodeStyle, fontSize: '0.8em' }}>
|
|
210
|
+
https://dev-editor-flow.vercel.app
|
|
211
|
+
</code>{' '}
|
|
212
|
+
with{' '}
|
|
213
|
+
<code style={{ ...inlineCodeStyle, fontSize: '0.8em' }}>
|
|
214
|
+
http://localhost:4000
|
|
215
|
+
</code>{' '}
|
|
216
|
+
(or your custom port).
|
|
217
|
+
</span>
|
|
218
|
+
</div>
|
|
219
|
+
<FrameworkAccordion>
|
|
220
|
+
{/* Next.js */}
|
|
221
|
+
<FrameworkSection id="nextjs" title="Next.js" icon="▲">
|
|
222
|
+
<div>
|
|
223
|
+
<h4
|
|
224
|
+
className="text-base font-medium mb-1"
|
|
225
|
+
style={{ color: 'var(--text-primary)' }}
|
|
226
|
+
>
|
|
227
|
+
App Router
|
|
228
|
+
</h4>
|
|
229
|
+
<p style={{ ...mutedText, marginBottom: '0.5rem' }}>
|
|
230
|
+
Add to <code style={inlineCodeStyle}>app/layout.tsx</code>
|
|
231
|
+
</p>
|
|
232
|
+
<CodeBlock
|
|
233
|
+
language="tsx"
|
|
234
|
+
copyText={SCRIPT_TAG}
|
|
235
|
+
code={`// app/layout.tsx
|
|
236
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
237
|
+
return (
|
|
238
|
+
<html lang="en">
|
|
239
|
+
<body>
|
|
240
|
+
{children}
|
|
241
|
+
<script src="https://dev-editor-flow.vercel.app/dev-editor-inspector.js"></script>
|
|
242
|
+
</body>
|
|
243
|
+
</html>
|
|
244
|
+
);
|
|
245
|
+
}`}
|
|
246
|
+
/>
|
|
247
|
+
</div>
|
|
248
|
+
<div>
|
|
249
|
+
<h4
|
|
250
|
+
className="text-base font-medium mb-1"
|
|
251
|
+
style={{ color: 'var(--text-primary)' }}
|
|
252
|
+
>
|
|
253
|
+
Pages Router
|
|
254
|
+
</h4>
|
|
255
|
+
<p style={{ ...mutedText, marginBottom: '0.5rem' }}>
|
|
256
|
+
Add to{' '}
|
|
257
|
+
<code style={inlineCodeStyle}>pages/_document.tsx</code>
|
|
258
|
+
</p>
|
|
259
|
+
<CodeBlock
|
|
260
|
+
language="tsx"
|
|
261
|
+
copyText={SCRIPT_TAG}
|
|
262
|
+
code={`// pages/_document.tsx
|
|
263
|
+
import { Html, Head, Main, NextScript } from 'next/document';
|
|
264
|
+
|
|
265
|
+
export default function Document() {
|
|
266
|
+
return (
|
|
267
|
+
<Html>
|
|
268
|
+
<Head />
|
|
269
|
+
<body>
|
|
270
|
+
<Main />
|
|
271
|
+
<NextScript />
|
|
272
|
+
<script src="https://dev-editor-flow.vercel.app/dev-editor-inspector.js"></script>
|
|
273
|
+
</body>
|
|
274
|
+
</Html>
|
|
275
|
+
);
|
|
276
|
+
}`}
|
|
277
|
+
/>
|
|
278
|
+
</div>
|
|
279
|
+
</FrameworkSection>
|
|
280
|
+
|
|
281
|
+
{/* Vite + React */}
|
|
282
|
+
<FrameworkSection
|
|
283
|
+
id="vite-react"
|
|
284
|
+
title="Vite + React"
|
|
285
|
+
icon="⚡"
|
|
286
|
+
>
|
|
287
|
+
<p style={{ ...mutedText, marginBottom: '0.5rem' }}>
|
|
288
|
+
Add to <code style={inlineCodeStyle}>index.html</code>{' '}
|
|
289
|
+
(project root)
|
|
290
|
+
</p>
|
|
291
|
+
<CodeBlock
|
|
292
|
+
language="html"
|
|
293
|
+
copyText={SCRIPT_TAG}
|
|
294
|
+
code={`<!-- index.html -->
|
|
295
|
+
<!DOCTYPE html>
|
|
296
|
+
<html lang="en">
|
|
297
|
+
<head>
|
|
298
|
+
<meta charset="UTF-8" />
|
|
299
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
300
|
+
<title>My App</title>
|
|
301
|
+
</head>
|
|
302
|
+
<body>
|
|
303
|
+
<div id="root"></div>
|
|
304
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
305
|
+
<script src="https://dev-editor-flow.vercel.app/dev-editor-inspector.js"></script>
|
|
306
|
+
</body>
|
|
307
|
+
</html>`}
|
|
308
|
+
/>
|
|
309
|
+
</FrameworkSection>
|
|
310
|
+
|
|
311
|
+
{/* Create React App */}
|
|
312
|
+
<FrameworkSection
|
|
313
|
+
id="create-react-app"
|
|
314
|
+
title="Create React App"
|
|
315
|
+
icon="⚛"
|
|
316
|
+
>
|
|
317
|
+
<p style={{ ...mutedText, marginBottom: '0.5rem' }}>
|
|
318
|
+
Add to{' '}
|
|
319
|
+
<code style={inlineCodeStyle}>public/index.html</code>
|
|
320
|
+
</p>
|
|
321
|
+
<CodeBlock
|
|
322
|
+
language="html"
|
|
323
|
+
copyText={SCRIPT_TAG}
|
|
324
|
+
code={`<!-- public/index.html -->
|
|
325
|
+
<!DOCTYPE html>
|
|
326
|
+
<html lang="en">
|
|
327
|
+
<head>
|
|
328
|
+
<meta charset="utf-8" />
|
|
329
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
330
|
+
<title>My App</title>
|
|
331
|
+
</head>
|
|
332
|
+
<body>
|
|
333
|
+
<div id="root"></div>
|
|
334
|
+
<script src="https://dev-editor-flow.vercel.app/dev-editor-inspector.js"></script>
|
|
335
|
+
</body>
|
|
336
|
+
</html>`}
|
|
337
|
+
/>
|
|
338
|
+
</FrameworkSection>
|
|
339
|
+
|
|
340
|
+
{/* Plain HTML */}
|
|
341
|
+
<FrameworkSection
|
|
342
|
+
id="plain-html"
|
|
343
|
+
title="Plain HTML"
|
|
344
|
+
icon="📄"
|
|
345
|
+
>
|
|
346
|
+
<p style={{ ...mutedText, marginBottom: '0.5rem' }}>
|
|
347
|
+
Add before{' '}
|
|
348
|
+
<code style={inlineCodeStyle}></body></code> in any{' '}
|
|
349
|
+
<code style={inlineCodeStyle}>.html</code> file
|
|
350
|
+
</p>
|
|
351
|
+
<CodeBlock
|
|
352
|
+
language="html"
|
|
353
|
+
copyText={SCRIPT_TAG}
|
|
354
|
+
code={`<!DOCTYPE html>
|
|
355
|
+
<html>
|
|
356
|
+
<head>
|
|
357
|
+
<title>My Page</title>
|
|
358
|
+
</head>
|
|
359
|
+
<body>
|
|
360
|
+
<h1>Hello</h1>
|
|
361
|
+
<script src="https://dev-editor-flow.vercel.app/dev-editor-inspector.js"></script>
|
|
362
|
+
</body>
|
|
363
|
+
</html>`}
|
|
364
|
+
/>
|
|
365
|
+
</FrameworkSection>
|
|
366
|
+
|
|
367
|
+
{/* React Native / Expo Web */}
|
|
368
|
+
<FrameworkSection
|
|
369
|
+
id="react-native-expo"
|
|
370
|
+
title="React Native / Expo Web"
|
|
371
|
+
icon="📱"
|
|
372
|
+
>
|
|
373
|
+
<div>
|
|
374
|
+
<h4
|
|
375
|
+
className="text-base font-medium mb-1"
|
|
376
|
+
style={{ color: 'var(--text-primary)' }}
|
|
377
|
+
>
|
|
378
|
+
Expo Router
|
|
379
|
+
</h4>
|
|
380
|
+
<p style={{ ...mutedText, marginBottom: '0.5rem' }}>
|
|
381
|
+
Add to{' '}
|
|
382
|
+
<code style={inlineCodeStyle}>app/_layout.tsx</code> using{' '}
|
|
383
|
+
a <code style={inlineCodeStyle}><Script></code>{' '}
|
|
384
|
+
component or the web{' '}
|
|
385
|
+
<code style={inlineCodeStyle}>index.html</code>
|
|
386
|
+
</p>
|
|
387
|
+
<CodeBlock
|
|
388
|
+
language="tsx"
|
|
389
|
+
copyText={SCRIPT_TAG}
|
|
390
|
+
code={`// app/_layout.tsx
|
|
391
|
+
import { Slot } from 'expo-router';
|
|
392
|
+
import { Platform } from 'react-native';
|
|
393
|
+
import { useEffect } from 'react';
|
|
394
|
+
|
|
395
|
+
export default function RootLayout() {
|
|
396
|
+
useEffect(() => {
|
|
397
|
+
if (Platform.OS === 'web') {
|
|
398
|
+
const script = document.createElement('script');
|
|
399
|
+
script.src = 'https://dev-editor-flow.vercel.app/dev-editor-inspector.js';
|
|
400
|
+
document.body.appendChild(script);
|
|
401
|
+
}
|
|
402
|
+
}, []);
|
|
403
|
+
|
|
404
|
+
return <Slot />;
|
|
405
|
+
}`}
|
|
406
|
+
/>
|
|
407
|
+
</div>
|
|
408
|
+
<div>
|
|
409
|
+
<h4
|
|
410
|
+
className="text-base font-medium mb-1"
|
|
411
|
+
style={{ color: 'var(--text-primary)' }}
|
|
412
|
+
>
|
|
413
|
+
Custom <code style={inlineCodeStyle}>web/index.html</code>
|
|
414
|
+
</h4>
|
|
415
|
+
<p style={{ ...mutedText, marginBottom: '0.5rem' }}>
|
|
416
|
+
If your Expo project has a custom web entry point
|
|
417
|
+
</p>
|
|
418
|
+
<CodeBlock
|
|
419
|
+
language="html"
|
|
420
|
+
copyText={SCRIPT_TAG}
|
|
421
|
+
code={`<!-- web/index.html -->
|
|
422
|
+
<!DOCTYPE html>
|
|
423
|
+
<html>
|
|
424
|
+
<head>
|
|
425
|
+
<meta charset="utf-8" />
|
|
426
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
427
|
+
</head>
|
|
428
|
+
<body>
|
|
429
|
+
<div id="root"></div>
|
|
430
|
+
<script src="https://dev-editor-flow.vercel.app/dev-editor-inspector.js"></script>
|
|
431
|
+
</body>
|
|
432
|
+
</html>`}
|
|
433
|
+
/>
|
|
434
|
+
</div>
|
|
435
|
+
</FrameworkSection>
|
|
436
|
+
|
|
437
|
+
{/* Vue / Nuxt */}
|
|
438
|
+
<FrameworkSection
|
|
439
|
+
id="vue-nuxt"
|
|
440
|
+
title="Vue / Nuxt"
|
|
441
|
+
icon="⚫"
|
|
442
|
+
>
|
|
443
|
+
<div>
|
|
444
|
+
<h4
|
|
445
|
+
className="text-base font-medium mb-1"
|
|
446
|
+
style={{ color: 'var(--text-primary)' }}
|
|
447
|
+
>
|
|
448
|
+
Vue (Vite)
|
|
449
|
+
</h4>
|
|
450
|
+
<p style={{ ...mutedText, marginBottom: '0.5rem' }}>
|
|
451
|
+
Add to <code style={inlineCodeStyle}>index.html</code>{' '}
|
|
452
|
+
(project root)
|
|
453
|
+
</p>
|
|
454
|
+
<CodeBlock
|
|
455
|
+
language="html"
|
|
456
|
+
copyText={SCRIPT_TAG}
|
|
457
|
+
code={`<!-- index.html -->
|
|
458
|
+
<!DOCTYPE html>
|
|
459
|
+
<html lang="en">
|
|
460
|
+
<head>
|
|
461
|
+
<meta charset="UTF-8" />
|
|
462
|
+
<title>My Vue App</title>
|
|
463
|
+
</head>
|
|
464
|
+
<body>
|
|
465
|
+
<div id="app"></div>
|
|
466
|
+
<script type="module" src="/src/main.ts"></script>
|
|
467
|
+
<script src="https://dev-editor-flow.vercel.app/dev-editor-inspector.js"></script>
|
|
468
|
+
</body>
|
|
469
|
+
</html>`}
|
|
470
|
+
/>
|
|
471
|
+
</div>
|
|
472
|
+
<div>
|
|
473
|
+
<h4
|
|
474
|
+
className="text-base font-medium mb-1"
|
|
475
|
+
style={{ color: 'var(--text-primary)' }}
|
|
476
|
+
>
|
|
477
|
+
Nuxt 3
|
|
478
|
+
</h4>
|
|
479
|
+
<p style={{ ...mutedText, marginBottom: '0.5rem' }}>
|
|
480
|
+
Add via{' '}
|
|
481
|
+
<code style={inlineCodeStyle}>nuxt.config.ts</code> or{' '}
|
|
482
|
+
<code style={inlineCodeStyle}>app.html</code>
|
|
483
|
+
</p>
|
|
484
|
+
<CodeBlock
|
|
485
|
+
language="ts"
|
|
486
|
+
copyText={`app: {\n head: {\n script: [{ src: 'https://dev-editor-flow.vercel.app/dev-editor-inspector.js' }]\n }\n}`}
|
|
487
|
+
code={`// nuxt.config.ts
|
|
488
|
+
export default defineNuxtConfig({
|
|
489
|
+
app: {
|
|
490
|
+
head: {
|
|
491
|
+
script: [
|
|
492
|
+
{ src: 'https://dev-editor-flow.vercel.app/dev-editor-inspector.js' }
|
|
493
|
+
]
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
});`}
|
|
497
|
+
/>
|
|
498
|
+
</div>
|
|
499
|
+
</FrameworkSection>
|
|
500
|
+
|
|
501
|
+
{/* Svelte / SvelteKit */}
|
|
502
|
+
<FrameworkSection
|
|
503
|
+
id="svelte-sveltekit"
|
|
504
|
+
title="Svelte / SvelteKit"
|
|
505
|
+
icon="🌱"
|
|
506
|
+
>
|
|
507
|
+
<p style={{ ...mutedText, marginBottom: '0.5rem' }}>
|
|
508
|
+
Add to <code style={inlineCodeStyle}>src/app.html</code>
|
|
509
|
+
</p>
|
|
510
|
+
<CodeBlock
|
|
511
|
+
language="html"
|
|
512
|
+
copyText={SCRIPT_TAG}
|
|
513
|
+
code={`<!-- src/app.html -->
|
|
514
|
+
<!DOCTYPE html>
|
|
515
|
+
<html lang="en">
|
|
516
|
+
<head>
|
|
517
|
+
<meta charset="utf-8" />
|
|
518
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
519
|
+
%sveltekit.head%
|
|
520
|
+
</head>
|
|
521
|
+
<body data-sveltekit-preload-data="hover">
|
|
522
|
+
<div style="display: contents">%sveltekit.body%</div>
|
|
523
|
+
<script src="https://dev-editor-flow.vercel.app/dev-editor-inspector.js"></script>
|
|
524
|
+
</body>
|
|
525
|
+
</html>`}
|
|
526
|
+
/>
|
|
527
|
+
</FrameworkSection>
|
|
528
|
+
</FrameworkAccordion>
|
|
529
|
+
</Section>
|
|
530
|
+
|
|
531
|
+
{/* Troubleshooting */}
|
|
532
|
+
<Section id="troubleshooting" title="Troubleshooting">
|
|
533
|
+
<div className="flex flex-col gap-4">
|
|
534
|
+
<TroubleshootItem title="Inspector script not detected">
|
|
535
|
+
<p>
|
|
536
|
+
If the banner appears after 5 seconds, the automatic proxy
|
|
537
|
+
injection didn't work for your setup. Add the script
|
|
538
|
+
tag manually using the framework guides above. Make sure
|
|
539
|
+
pAInt is running on the port shown in the script URL.
|
|
540
|
+
</p>
|
|
541
|
+
</TroubleshootItem>
|
|
542
|
+
|
|
543
|
+
<TroubleshootItem title="CORS or Cross-Origin errors">
|
|
544
|
+
<p>
|
|
545
|
+
pAInt proxy runs on a different port than your project. If
|
|
546
|
+
your project sets strict CORS headers, the proxy may be
|
|
547
|
+
blocked. The automatic method handles this by serving
|
|
548
|
+
everything from the same origin. For the manual method,
|
|
549
|
+
ensure your dev server allows requests from{' '}
|
|
550
|
+
<code style={inlineCodeStyle}>localhost:4000</code>.
|
|
551
|
+
</p>
|
|
552
|
+
</TroubleshootItem>
|
|
553
|
+
|
|
554
|
+
<TroubleshootItem title="COEP / COOP headers blocking the iframe">
|
|
555
|
+
<p>
|
|
556
|
+
Some frameworks set{' '}
|
|
557
|
+
<code style={inlineCodeStyle}>
|
|
558
|
+
Cross-Origin-Embedder-Policy
|
|
559
|
+
</code>{' '}
|
|
560
|
+
or{' '}
|
|
561
|
+
<code style={inlineCodeStyle}>
|
|
562
|
+
Cross-Origin-Opener-Policy
|
|
563
|
+
</code>{' '}
|
|
564
|
+
headers that prevent loading in an iframe. Check your server
|
|
565
|
+
config or middleware and relax these headers in development.
|
|
566
|
+
</p>
|
|
567
|
+
</TroubleshootItem>
|
|
568
|
+
|
|
569
|
+
<TroubleshootItem title="Infinite iframe reload">
|
|
570
|
+
<p>
|
|
571
|
+
This happens when the target page's client-side router
|
|
572
|
+
detects the proxy URL and redirects. pAInt's proxy
|
|
573
|
+
strips <code style={inlineCodeStyle}><script></code>{' '}
|
|
574
|
+
tags to prevent this. If you still see reloads, check that
|
|
575
|
+
no inline scripts or meta-refresh tags are causing
|
|
576
|
+
navigation.
|
|
577
|
+
</p>
|
|
578
|
+
</TroubleshootItem>
|
|
579
|
+
|
|
580
|
+
<TroubleshootItem title="Styles look different in the editor">
|
|
581
|
+
<p>
|
|
582
|
+
The proxy serves SSR HTML with CSS intact but strips
|
|
583
|
+
JavaScript. If your styles depend on client-side JS (e.g.,
|
|
584
|
+
CSS-in-JS runtime injection), some styles may be missing.
|
|
585
|
+
Use the manual script method with your full dev server if
|
|
586
|
+
CSS-in-JS is critical.
|
|
587
|
+
</p>
|
|
588
|
+
</TroubleshootItem>
|
|
589
|
+
</div>
|
|
590
|
+
</Section>
|
|
591
|
+
|
|
592
|
+
{/* FAQ */}
|
|
593
|
+
<Section id="faq" title="FAQ">
|
|
594
|
+
<FaqAccordion>
|
|
595
|
+
<FaqSection
|
|
596
|
+
id="faq-safe"
|
|
597
|
+
question="Is it safe to add the inspector script to my project?"
|
|
598
|
+
>
|
|
599
|
+
<p>
|
|
600
|
+
Yes. The inspector script is a lightweight, read-only
|
|
601
|
+
observer that listens for hover/click events and reports
|
|
602
|
+
element metadata (tag name, styles, bounding box) back to
|
|
603
|
+
pAInt via <code style={inlineCodeStyle}>postMessage</code>.
|
|
604
|
+
It does not modify your source code, send data to external
|
|
605
|
+
servers, or execute arbitrary code. It only communicates
|
|
606
|
+
with pAInt origin.
|
|
607
|
+
</p>
|
|
608
|
+
</FaqSection>
|
|
609
|
+
|
|
610
|
+
<FaqSection
|
|
611
|
+
id="faq-source"
|
|
612
|
+
question="Does pAInt have access to my source files?"
|
|
613
|
+
>
|
|
614
|
+
<p>
|
|
615
|
+
Not directly. The editor works with the rendered HTML/CSS in
|
|
616
|
+
the browser — it never reads or writes your project's
|
|
617
|
+
source files on its own. When you use the{' '}
|
|
618
|
+
<strong style={{ color: 'var(--text-primary)' }}>
|
|
619
|
+
Send to Claude Code
|
|
620
|
+
</strong>{' '}
|
|
621
|
+
feature, a changelog of your visual edits is sent to Claude
|
|
622
|
+
Code (running locally on your machine), which then applies
|
|
623
|
+
changes to your files. The editor itself has no filesystem
|
|
624
|
+
access.
|
|
625
|
+
</p>
|
|
626
|
+
</FaqSection>
|
|
627
|
+
|
|
628
|
+
<FaqSection
|
|
629
|
+
id="faq-proxy"
|
|
630
|
+
question="Does the reverse proxy forward requests to external servers?"
|
|
631
|
+
>
|
|
632
|
+
<p>
|
|
633
|
+
No. The proxy enforces{' '}
|
|
634
|
+
<strong style={{ color: 'var(--text-primary)' }}>
|
|
635
|
+
localhost-only
|
|
636
|
+
</strong>{' '}
|
|
637
|
+
validation. It will only connect to{' '}
|
|
638
|
+
<code style={inlineCodeStyle}>127.0.0.1</code> /{' '}
|
|
639
|
+
<code style={inlineCodeStyle}>localhost</code> addresses.
|
|
640
|
+
Any attempt to proxy to an external host is rejected.
|
|
641
|
+
</p>
|
|
642
|
+
</FaqSection>
|
|
643
|
+
|
|
644
|
+
<FaqSection
|
|
645
|
+
id="faq-production"
|
|
646
|
+
question="Should I remove the script tag before deploying to production?"
|
|
647
|
+
>
|
|
648
|
+
<p>
|
|
649
|
+
Yes. The inspector script is intended for local development
|
|
650
|
+
only. Remove it (or wrap it in an environment check) before
|
|
651
|
+
deploying. If you forget, the script will try to connect to
|
|
652
|
+
pAInt origin and silently fail — it won't affect your
|
|
653
|
+
users — but it's best practice to keep it out of
|
|
654
|
+
production builds.
|
|
655
|
+
</p>
|
|
656
|
+
</FaqSection>
|
|
657
|
+
|
|
658
|
+
<FaqSection
|
|
659
|
+
id="faq-network"
|
|
660
|
+
question="Can other people on my network see my project through the editor?"
|
|
661
|
+
>
|
|
662
|
+
<p>
|
|
663
|
+
By default, both pAInt and your dev server run on{' '}
|
|
664
|
+
<code style={inlineCodeStyle}>localhost</code>, which is
|
|
665
|
+
only accessible from your machine. If you've configured
|
|
666
|
+
your dev server to listen on{' '}
|
|
667
|
+
<code style={inlineCodeStyle}>0.0.0.0</code>, other devices
|
|
668
|
+
on your network could access it directly, but the
|
|
669
|
+
pAInt's proxy still only connects to localhost.
|
|
670
|
+
</p>
|
|
671
|
+
</FaqSection>
|
|
672
|
+
|
|
673
|
+
<FaqSection
|
|
674
|
+
id="faq-hosted"
|
|
675
|
+
question="Is my data sent anywhere when using the hosted version?"
|
|
676
|
+
>
|
|
677
|
+
<p>
|
|
678
|
+
The hosted version at{' '}
|
|
679
|
+
<code style={inlineCodeStyle}>
|
|
680
|
+
dev-editor-flow.vercel.app
|
|
681
|
+
</code>{' '}
|
|
682
|
+
serves the editor UI only. Your project's HTML is
|
|
683
|
+
fetched by the proxy running on that server, but no project
|
|
684
|
+
data is stored, logged, or shared. All style edits and
|
|
685
|
+
changelogs are kept in your browser's{' '}
|
|
686
|
+
<code style={inlineCodeStyle}>localStorage</code>.
|
|
687
|
+
</p>
|
|
688
|
+
</FaqSection>
|
|
689
|
+
</FaqAccordion>
|
|
690
|
+
</Section>
|
|
691
|
+
</div>
|
|
692
|
+
{/* end main content */}
|
|
693
|
+
</div>
|
|
694
|
+
{/* end flex row */}
|
|
695
|
+
|
|
696
|
+
{/* Footer */}
|
|
697
|
+
<footer
|
|
698
|
+
className="mt-16 pt-6 text-sm text-center"
|
|
699
|
+
style={{
|
|
700
|
+
borderTop: '1px solid var(--border)',
|
|
701
|
+
color: 'var(--text-muted)',
|
|
702
|
+
}}
|
|
703
|
+
>
|
|
704
|
+
pAInt ·{' '}
|
|
705
|
+
<Link
|
|
706
|
+
href="/"
|
|
707
|
+
className="no-underline"
|
|
708
|
+
style={{ color: 'var(--accent)' }}
|
|
709
|
+
>
|
|
710
|
+
Open Editor
|
|
711
|
+
</Link>
|
|
712
|
+
</footer>
|
|
713
|
+
</div>
|
|
714
|
+
</div>
|
|
715
|
+
)
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/* ─── Helper components (server-rendered) ─── */
|
|
719
|
+
|
|
720
|
+
function Section({
|
|
721
|
+
id,
|
|
722
|
+
title,
|
|
723
|
+
children,
|
|
724
|
+
}: {
|
|
725
|
+
id?: string
|
|
726
|
+
title: string
|
|
727
|
+
children: React.ReactNode
|
|
728
|
+
}) {
|
|
729
|
+
return (
|
|
730
|
+
<section id={id} className="mb-14 scroll-mt-12">
|
|
731
|
+
<h2
|
|
732
|
+
className="text-xl font-semibold mb-5 pb-2"
|
|
733
|
+
style={{
|
|
734
|
+
color: 'var(--text-primary)',
|
|
735
|
+
borderBottom: '1px solid var(--border)',
|
|
736
|
+
}}
|
|
737
|
+
>
|
|
738
|
+
{title}
|
|
739
|
+
</h2>
|
|
740
|
+
{children}
|
|
741
|
+
</section>
|
|
742
|
+
)
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function Step({
|
|
746
|
+
number,
|
|
747
|
+
children,
|
|
748
|
+
}: {
|
|
749
|
+
number: number
|
|
750
|
+
children: React.ReactNode
|
|
751
|
+
}) {
|
|
752
|
+
return (
|
|
753
|
+
<li className="flex gap-4">
|
|
754
|
+
<span
|
|
755
|
+
className="shrink-0 w-7 h-7 rounded-full flex items-center justify-center text-sm font-bold"
|
|
756
|
+
style={{
|
|
757
|
+
background: 'var(--accent)',
|
|
758
|
+
color: '#fff',
|
|
759
|
+
}}
|
|
760
|
+
>
|
|
761
|
+
{number}
|
|
762
|
+
</span>
|
|
763
|
+
<div className="flex-1 flex flex-col gap-2">{children}</div>
|
|
764
|
+
</li>
|
|
765
|
+
)
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
function TroubleshootItem({
|
|
769
|
+
title,
|
|
770
|
+
children,
|
|
771
|
+
}: {
|
|
772
|
+
title: string
|
|
773
|
+
children: React.ReactNode
|
|
774
|
+
}) {
|
|
775
|
+
return (
|
|
776
|
+
<div
|
|
777
|
+
className="rounded-md px-4 py-4"
|
|
778
|
+
style={{
|
|
779
|
+
background: 'var(--bg-secondary)',
|
|
780
|
+
border: '1px solid var(--border)',
|
|
781
|
+
}}
|
|
782
|
+
>
|
|
783
|
+
<h4
|
|
784
|
+
className="text-base font-medium mb-2"
|
|
785
|
+
style={{ color: 'var(--text-primary)' }}
|
|
786
|
+
>
|
|
787
|
+
{title}
|
|
788
|
+
</h4>
|
|
789
|
+
<div
|
|
790
|
+
style={{
|
|
791
|
+
color: 'var(--text-secondary)',
|
|
792
|
+
fontSize: '0.9rem',
|
|
793
|
+
lineHeight: 1.6,
|
|
794
|
+
}}
|
|
795
|
+
>
|
|
796
|
+
{children}
|
|
797
|
+
</div>
|
|
798
|
+
</div>
|
|
799
|
+
)
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function UseCaseItem({
|
|
803
|
+
title,
|
|
804
|
+
description,
|
|
805
|
+
}: {
|
|
806
|
+
title: string
|
|
807
|
+
description: string
|
|
808
|
+
}) {
|
|
809
|
+
return (
|
|
810
|
+
<div
|
|
811
|
+
className="rounded-md px-4 py-4"
|
|
812
|
+
style={{
|
|
813
|
+
background: 'var(--bg-secondary)',
|
|
814
|
+
border: '1px solid var(--border)',
|
|
815
|
+
}}
|
|
816
|
+
>
|
|
817
|
+
<h4
|
|
818
|
+
className="text-base font-medium mb-2"
|
|
819
|
+
style={{ color: 'var(--text-primary)' }}
|
|
820
|
+
>
|
|
821
|
+
{title}
|
|
822
|
+
</h4>
|
|
823
|
+
<p
|
|
824
|
+
style={{
|
|
825
|
+
color: 'var(--text-secondary)',
|
|
826
|
+
fontSize: '0.9rem',
|
|
827
|
+
lineHeight: 1.6,
|
|
828
|
+
margin: 0,
|
|
829
|
+
}}
|
|
830
|
+
>
|
|
831
|
+
{description}
|
|
832
|
+
</p>
|
|
833
|
+
</div>
|
|
834
|
+
)
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const bodyText: React.CSSProperties = {
|
|
838
|
+
color: 'var(--text-secondary)',
|
|
839
|
+
fontSize: '1rem',
|
|
840
|
+
lineHeight: 1.7,
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
const mutedText: React.CSSProperties = {
|
|
844
|
+
color: 'var(--text-muted)',
|
|
845
|
+
fontSize: '0.875rem',
|
|
846
|
+
lineHeight: 1.6,
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
const inlineCodeStyle: React.CSSProperties = {
|
|
850
|
+
background: 'var(--bg-tertiary)',
|
|
851
|
+
padding: '2px 6px',
|
|
852
|
+
borderRadius: '3px',
|
|
853
|
+
fontSize: '0.85em',
|
|
854
|
+
color: 'var(--warning)',
|
|
855
|
+
}
|