@newtonedev/editor 0.1.5 → 0.1.6
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/dist/Editor.d.ts.map +1 -1
- package/dist/components/CodeBlock.d.ts.map +1 -1
- package/dist/components/PresetSelector.d.ts.map +1 -1
- package/dist/components/PreviewWindow.d.ts +3 -2
- package/dist/components/PreviewWindow.d.ts.map +1 -1
- package/dist/components/RightSidebar.d.ts +4 -1
- package/dist/components/RightSidebar.d.ts.map +1 -1
- package/dist/components/Sidebar.d.ts.map +1 -1
- package/dist/hooks/useEditorState.d.ts.map +1 -1
- package/dist/index.cjs +469 -242
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +470 -243
- package/dist/index.js.map +1 -1
- package/dist/preview/ComponentDetailView.d.ts +3 -2
- package/dist/preview/ComponentDetailView.d.ts.map +1 -1
- package/dist/preview/IconBrowserView.d.ts +7 -0
- package/dist/preview/IconBrowserView.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/Editor.tsx +4 -1
- package/src/components/CodeBlock.tsx +42 -14
- package/src/components/PresetSelector.tsx +8 -33
- package/src/components/PreviewWindow.tsx +6 -3
- package/src/components/RightSidebar.tsx +103 -40
- package/src/components/Sidebar.tsx +12 -92
- package/src/hooks/useEditorState.ts +14 -3
- package/src/preview/ComponentDetailView.tsx +46 -7
- package/src/preview/IconBrowserView.tsx +187 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
interface ComponentDetailViewProps {
|
|
2
2
|
readonly componentId: string;
|
|
3
3
|
readonly selectedVariantId: string | null;
|
|
4
|
-
readonly propOverrides?: Record<string, unknown>;
|
|
5
4
|
readonly onSelectVariant: (variantId: string) => void;
|
|
5
|
+
readonly propOverrides?: Record<string, unknown>;
|
|
6
|
+
readonly onPropOverride?: (name: string, value: unknown) => void;
|
|
6
7
|
}
|
|
7
|
-
export declare function ComponentDetailView({ componentId, selectedVariantId, propOverrides,
|
|
8
|
+
export declare function ComponentDetailView({ componentId, selectedVariantId, onSelectVariant, propOverrides, onPropOverride, }: ComponentDetailViewProps): import("react/jsx-runtime").JSX.Element | null;
|
|
8
9
|
export {};
|
|
9
10
|
//# sourceMappingURL=ComponentDetailView.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentDetailView.d.ts","sourceRoot":"","sources":["../../src/preview/ComponentDetailView.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ComponentDetailView.d.ts","sourceRoot":"","sources":["../../src/preview/ComponentDetailView.tsx"],"names":[],"mappings":"AAOA,UAAU,wBAAwB;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjD,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAClE;AAED,wBAAgB,mBAAmB,CAAC,EAClC,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,cAAc,GACf,EAAE,wBAAwB,kDA+I1B"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface IconBrowserViewProps {
|
|
2
|
+
readonly selectedIconName: string;
|
|
3
|
+
readonly onIconSelect: (name: string) => void;
|
|
4
|
+
}
|
|
5
|
+
export declare function IconBrowserView({ selectedIconName, onIconSelect, }: IconBrowserViewProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=IconBrowserView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconBrowserView.d.ts","sourceRoot":"","sources":["../../src/preview/IconBrowserView.tsx"],"names":[],"mappings":"AAIA,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,eAAe,CAAC,EAC9B,gBAAgB,EAChB,YAAY,GACb,EAAE,oBAAoB,2CA8KtB"}
|
package/package.json
CHANGED
package/src/Editor.tsx
CHANGED
|
@@ -110,9 +110,10 @@ export function Editor({
|
|
|
110
110
|
<PreviewWindow
|
|
111
111
|
view={editor.previewView}
|
|
112
112
|
selectedVariantId={editor.selectedVariantId}
|
|
113
|
-
propOverrides={editor.propOverrides}
|
|
114
113
|
onNavigate={editor.handlePreviewNavigate}
|
|
115
114
|
onSelectVariant={editor.handleSelectVariant}
|
|
115
|
+
propOverrides={editor.propOverrides}
|
|
116
|
+
onPropOverride={editor.handlePropOverride}
|
|
116
117
|
/>
|
|
117
118
|
</div>
|
|
118
119
|
</NewtoneProvider>
|
|
@@ -127,6 +128,8 @@ export function Editor({
|
|
|
127
128
|
onResetOverrides={editor.handleResetOverrides}
|
|
128
129
|
onClose={editor.handleCloseSidebar}
|
|
129
130
|
onScopeToComponent={editor.handleScopeToComponent}
|
|
131
|
+
previewConfig={previewConfig}
|
|
132
|
+
colorMode={editor.colorMode}
|
|
130
133
|
/>
|
|
131
134
|
}
|
|
132
135
|
/>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useState, useCallback } from "react";
|
|
2
|
-
import { useTokens,
|
|
2
|
+
import { useTokens, Icon } from "@newtonedev/components";
|
|
3
3
|
import { srgbToHex } from "newtone";
|
|
4
4
|
|
|
5
5
|
export function CopyButton({ text }: { readonly text: string }) {
|
|
6
|
+
const tokens = useTokens();
|
|
6
7
|
const [copied, setCopied] = useState(false);
|
|
7
8
|
|
|
8
9
|
const handleCopy = useCallback(async () => {
|
|
@@ -12,9 +13,31 @@ export function CopyButton({ text }: { readonly text: string }) {
|
|
|
12
13
|
}, [text]);
|
|
13
14
|
|
|
14
15
|
return (
|
|
15
|
-
<
|
|
16
|
-
{
|
|
17
|
-
|
|
16
|
+
<button
|
|
17
|
+
onClick={handleCopy}
|
|
18
|
+
aria-label={copied ? "Copied" : "Copy code"}
|
|
19
|
+
style={{
|
|
20
|
+
background: "none",
|
|
21
|
+
border: "none",
|
|
22
|
+
cursor: "pointer",
|
|
23
|
+
padding: 4,
|
|
24
|
+
display: "flex",
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
justifyContent: "center",
|
|
27
|
+
color: srgbToHex(
|
|
28
|
+
copied ? tokens.accent.fill.srgb : tokens.textTertiary.srgb,
|
|
29
|
+
),
|
|
30
|
+
transition: "color 150ms ease",
|
|
31
|
+
}}
|
|
32
|
+
>
|
|
33
|
+
<Icon
|
|
34
|
+
name={copied ? "check" : "content_copy"}
|
|
35
|
+
size={16}
|
|
36
|
+
color={srgbToHex(
|
|
37
|
+
copied ? tokens.accent.fill.srgb : tokens.textTertiary.srgb,
|
|
38
|
+
)}
|
|
39
|
+
/>
|
|
40
|
+
</button>
|
|
18
41
|
);
|
|
19
42
|
}
|
|
20
43
|
|
|
@@ -26,24 +49,29 @@ export function CodeBlock({
|
|
|
26
49
|
const tokens = useTokens();
|
|
27
50
|
|
|
28
51
|
return (
|
|
29
|
-
<div
|
|
52
|
+
<div
|
|
53
|
+
style={{
|
|
54
|
+
backgroundColor: srgbToHex(tokens.backgroundSunken.srgb),
|
|
55
|
+
border: `1px solid ${srgbToHex(tokens.border.srgb)}`,
|
|
56
|
+
borderRadius: 8,
|
|
57
|
+
overflow: "hidden",
|
|
58
|
+
}}
|
|
59
|
+
>
|
|
30
60
|
<div
|
|
31
61
|
style={{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
62
|
+
display: "flex",
|
|
63
|
+
justifyContent: "flex-end",
|
|
64
|
+
padding: "4px 8px",
|
|
65
|
+
borderBottom: `1px solid ${srgbToHex(tokens.border.srgb)}`,
|
|
35
66
|
}}
|
|
36
67
|
>
|
|
37
68
|
<CopyButton text={code} />
|
|
38
69
|
</div>
|
|
39
70
|
<pre
|
|
40
71
|
style={{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
padding: 16,
|
|
45
|
-
paddingRight: 80,
|
|
46
|
-
overflow: "auto",
|
|
72
|
+
padding: "12px 16px",
|
|
73
|
+
whiteSpace: "pre-wrap",
|
|
74
|
+
wordBreak: "break-word",
|
|
47
75
|
fontSize: 13,
|
|
48
76
|
lineHeight: 1.5,
|
|
49
77
|
fontFamily: "'SF Mono', 'Fira Code', 'Fira Mono', Menlo, monospace",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useRef, useEffect, useCallback } from "react";
|
|
2
|
-
import { useTokens } from "@newtonedev/components";
|
|
2
|
+
import { useTokens, Icon } from "@newtonedev/components";
|
|
3
3
|
import { srgbToHex } from "newtone";
|
|
4
4
|
import type { Preset } from "../types";
|
|
5
5
|
import { presetHasUnpublishedChanges } from "../utils/presets";
|
|
@@ -145,21 +145,15 @@ export function PresetSelector({
|
|
|
145
145
|
>
|
|
146
146
|
{activePreset?.name ?? "Default"}
|
|
147
147
|
</span>
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
viewBox="0 0 24 24"
|
|
152
|
-
fill="none"
|
|
153
|
-
stroke="currentColor"
|
|
154
|
-
strokeWidth={2}
|
|
148
|
+
<Icon
|
|
149
|
+
name="expand_more"
|
|
150
|
+
size={14}
|
|
155
151
|
style={{
|
|
156
152
|
transform: isOpen ? "rotate(180deg)" : "none",
|
|
157
153
|
transition: "transform 150ms ease",
|
|
158
154
|
flexShrink: 0,
|
|
159
|
-
}}
|
|
160
|
-
|
|
161
|
-
<polyline points="6 9 12 15 18 9" />
|
|
162
|
-
</svg>
|
|
155
|
+
} as any}
|
|
156
|
+
/>
|
|
163
157
|
</button>
|
|
164
158
|
|
|
165
159
|
{isOpen && (
|
|
@@ -303,16 +297,7 @@ export function PresetSelector({
|
|
|
303
297
|
flexShrink: 0,
|
|
304
298
|
}}
|
|
305
299
|
>
|
|
306
|
-
<
|
|
307
|
-
width={14}
|
|
308
|
-
height={14}
|
|
309
|
-
viewBox="0 0 24 24"
|
|
310
|
-
fill="currentColor"
|
|
311
|
-
>
|
|
312
|
-
<circle cx={12} cy={5} r={2} />
|
|
313
|
-
<circle cx={12} cy={12} r={2} />
|
|
314
|
-
<circle cx={12} cy={19} r={2} />
|
|
315
|
-
</svg>
|
|
300
|
+
<Icon name="more_vert" size={14} color={textSecondary} />
|
|
316
301
|
</button>
|
|
317
302
|
)}
|
|
318
303
|
</>
|
|
@@ -435,17 +420,7 @@ export function PresetSelector({
|
|
|
435
420
|
cursor: "pointer",
|
|
436
421
|
}}
|
|
437
422
|
>
|
|
438
|
-
<
|
|
439
|
-
width={14}
|
|
440
|
-
height={14}
|
|
441
|
-
viewBox="0 0 24 24"
|
|
442
|
-
fill="none"
|
|
443
|
-
stroke="currentColor"
|
|
444
|
-
strokeWidth={2}
|
|
445
|
-
>
|
|
446
|
-
<line x1={12} y1={5} x2={12} y2={19} />
|
|
447
|
-
<line x1={5} y1={12} x2={19} y2={12} />
|
|
448
|
-
</svg>
|
|
423
|
+
<Icon name="add" size={14} color={textSecondary} />
|
|
449
424
|
New preset
|
|
450
425
|
</button>
|
|
451
426
|
</div>
|
|
@@ -9,17 +9,19 @@ import type { PreviewView } from "../types";
|
|
|
9
9
|
interface PreviewWindowProps {
|
|
10
10
|
readonly view: PreviewView;
|
|
11
11
|
readonly selectedVariantId: string | null;
|
|
12
|
-
readonly propOverrides?: Record<string, unknown>;
|
|
13
12
|
readonly onNavigate: (view: PreviewView) => void;
|
|
14
13
|
readonly onSelectVariant: (variantId: string) => void;
|
|
14
|
+
readonly propOverrides?: Record<string, unknown>;
|
|
15
|
+
readonly onPropOverride?: (name: string, value: unknown) => void;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export function PreviewWindow({
|
|
18
19
|
view,
|
|
19
20
|
selectedVariantId,
|
|
20
|
-
propOverrides,
|
|
21
21
|
onNavigate,
|
|
22
22
|
onSelectVariant,
|
|
23
|
+
propOverrides,
|
|
24
|
+
onPropOverride,
|
|
23
25
|
}: PreviewWindowProps) {
|
|
24
26
|
const tokens = useTokens();
|
|
25
27
|
|
|
@@ -59,8 +61,9 @@ export function PreviewWindow({
|
|
|
59
61
|
<ComponentDetailView
|
|
60
62
|
componentId={view.componentId}
|
|
61
63
|
selectedVariantId={selectedVariantId}
|
|
62
|
-
propOverrides={propOverrides}
|
|
63
64
|
onSelectVariant={onSelectVariant}
|
|
65
|
+
propOverrides={propOverrides}
|
|
66
|
+
onPropOverride={onPropOverride}
|
|
64
67
|
/>
|
|
65
68
|
)}
|
|
66
69
|
</div>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useCallback, type KeyboardEvent } from "react";
|
|
2
|
-
import { useTokens, getComponent, generateComponentCode, Select } from "@newtonedev/components";
|
|
3
|
-
import type { EditableProp } from "@newtonedev/components";
|
|
2
|
+
import { useTokens, getComponent, generateComponentCode, Select, NewtoneProvider, Icon } from "@newtonedev/components";
|
|
3
|
+
import type { EditableProp, NewtoneThemeConfig, ColorMode } from "@newtonedev/components";
|
|
4
4
|
import { srgbToHex } from "newtone";
|
|
5
5
|
import { CodeBlock } from "./CodeBlock";
|
|
6
|
+
import { ComponentRenderer } from "../preview/ComponentRenderer";
|
|
6
7
|
import type { SidebarSelection } from "../types";
|
|
7
8
|
|
|
8
9
|
interface RightSidebarProps {
|
|
@@ -12,6 +13,8 @@ interface RightSidebarProps {
|
|
|
12
13
|
readonly onResetOverrides: () => void;
|
|
13
14
|
readonly onClose: () => void;
|
|
14
15
|
readonly onScopeToComponent: () => void;
|
|
16
|
+
readonly previewConfig: NewtoneThemeConfig;
|
|
17
|
+
readonly colorMode: ColorMode;
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
export function RightSidebar({
|
|
@@ -21,6 +24,8 @@ export function RightSidebar({
|
|
|
21
24
|
onResetOverrides,
|
|
22
25
|
onClose,
|
|
23
26
|
onScopeToComponent,
|
|
27
|
+
previewConfig,
|
|
28
|
+
colorMode,
|
|
24
29
|
}: RightSidebarProps) {
|
|
25
30
|
const tokens = useTokens();
|
|
26
31
|
const visible = selection !== null;
|
|
@@ -79,19 +84,7 @@ export function RightSidebar({
|
|
|
79
84
|
alignItems: "center",
|
|
80
85
|
}}
|
|
81
86
|
>
|
|
82
|
-
<
|
|
83
|
-
width={16}
|
|
84
|
-
height={16}
|
|
85
|
-
viewBox="0 0 24 24"
|
|
86
|
-
fill="none"
|
|
87
|
-
stroke="currentColor"
|
|
88
|
-
strokeWidth={2}
|
|
89
|
-
strokeLinecap="round"
|
|
90
|
-
strokeLinejoin="round"
|
|
91
|
-
>
|
|
92
|
-
<line x1="19" y1="12" x2="5" y2="12" />
|
|
93
|
-
<polyline points="12 19 5 12 12 5" />
|
|
94
|
-
</svg>
|
|
87
|
+
<Icon name="arrow_back" size={16} color={srgbToHex(tokens.textSecondary.srgb)} />
|
|
95
88
|
</button>
|
|
96
89
|
{selection.scope === "variant" && variant ? (
|
|
97
90
|
<>
|
|
@@ -154,6 +147,27 @@ export function RightSidebar({
|
|
|
154
147
|
padding: 16,
|
|
155
148
|
}}
|
|
156
149
|
>
|
|
150
|
+
{/* Live Preview */}
|
|
151
|
+
<div
|
|
152
|
+
style={{
|
|
153
|
+
marginBottom: 20,
|
|
154
|
+
borderRadius: 8,
|
|
155
|
+
border: `1px solid ${srgbToHex(tokens.border.srgb)}`,
|
|
156
|
+
overflow: "hidden",
|
|
157
|
+
}}
|
|
158
|
+
>
|
|
159
|
+
<NewtoneProvider
|
|
160
|
+
config={previewConfig}
|
|
161
|
+
initialMode={colorMode}
|
|
162
|
+
key={colorMode}
|
|
163
|
+
>
|
|
164
|
+
<PreviewSurface
|
|
165
|
+
componentId={selection.componentId}
|
|
166
|
+
propOverrides={propOverrides}
|
|
167
|
+
/>
|
|
168
|
+
</NewtoneProvider>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
157
171
|
<h3
|
|
158
172
|
style={{
|
|
159
173
|
fontSize: 13,
|
|
@@ -222,6 +236,31 @@ export function RightSidebar({
|
|
|
222
236
|
);
|
|
223
237
|
}
|
|
224
238
|
|
|
239
|
+
function PreviewSurface({
|
|
240
|
+
componentId,
|
|
241
|
+
propOverrides,
|
|
242
|
+
}: {
|
|
243
|
+
readonly componentId: string;
|
|
244
|
+
readonly propOverrides: Record<string, unknown>;
|
|
245
|
+
}) {
|
|
246
|
+
const previewTokens = useTokens();
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<div
|
|
250
|
+
style={{
|
|
251
|
+
display: "flex",
|
|
252
|
+
alignItems: "center",
|
|
253
|
+
justifyContent: "center",
|
|
254
|
+
padding: 24,
|
|
255
|
+
height: 120,
|
|
256
|
+
backgroundColor: srgbToHex(previewTokens.backgroundElevated.srgb),
|
|
257
|
+
}}
|
|
258
|
+
>
|
|
259
|
+
<ComponentRenderer componentId={componentId} props={propOverrides} />
|
|
260
|
+
</div>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
225
264
|
function PropControl({
|
|
226
265
|
prop,
|
|
227
266
|
value,
|
|
@@ -257,14 +296,7 @@ function PropControl({
|
|
|
257
296
|
|
|
258
297
|
return (
|
|
259
298
|
<div>
|
|
260
|
-
<div
|
|
261
|
-
style={{
|
|
262
|
-
display: "flex",
|
|
263
|
-
alignItems: "center",
|
|
264
|
-
justifyContent: "space-between",
|
|
265
|
-
marginBottom: 4,
|
|
266
|
-
}}
|
|
267
|
-
>
|
|
299
|
+
<div style={{ marginBottom: 4 }}>
|
|
268
300
|
<span
|
|
269
301
|
style={{
|
|
270
302
|
fontSize: 12,
|
|
@@ -274,15 +306,6 @@ function PropControl({
|
|
|
274
306
|
>
|
|
275
307
|
{prop.label}
|
|
276
308
|
</span>
|
|
277
|
-
<span
|
|
278
|
-
style={{
|
|
279
|
-
fontSize: 11,
|
|
280
|
-
color: srgbToHex(tokens.textSecondary.srgb),
|
|
281
|
-
fontFamily: "'SF Mono', 'Fira Code', Menlo, monospace",
|
|
282
|
-
}}
|
|
283
|
-
>
|
|
284
|
-
{prop.control}
|
|
285
|
-
</span>
|
|
286
309
|
</div>
|
|
287
310
|
|
|
288
311
|
{prop.control === "select" && prop.options && (
|
|
@@ -318,6 +341,54 @@ function PropControl({
|
|
|
318
341
|
/>
|
|
319
342
|
)}
|
|
320
343
|
|
|
344
|
+
{prop.control === "discrete-slider" && prop.options && (() => {
|
|
345
|
+
const options = prop.options!;
|
|
346
|
+
const currentIndex = options.findIndex((o) => o.value === value);
|
|
347
|
+
const idx = currentIndex >= 0 ? currentIndex : 0;
|
|
348
|
+
|
|
349
|
+
return (
|
|
350
|
+
<div>
|
|
351
|
+
<input
|
|
352
|
+
type="range"
|
|
353
|
+
min={0}
|
|
354
|
+
max={options.length - 1}
|
|
355
|
+
step={1}
|
|
356
|
+
value={idx}
|
|
357
|
+
onChange={(e) => onChange(options[Number(e.target.value)].value)}
|
|
358
|
+
aria-label={prop.label}
|
|
359
|
+
style={{
|
|
360
|
+
width: "100%",
|
|
361
|
+
accentColor: srgbToHex(tokens.accent.fill.srgb),
|
|
362
|
+
cursor: "pointer",
|
|
363
|
+
}}
|
|
364
|
+
/>
|
|
365
|
+
<div
|
|
366
|
+
style={{
|
|
367
|
+
display: "flex",
|
|
368
|
+
justifyContent: "space-between",
|
|
369
|
+
marginTop: 2,
|
|
370
|
+
}}
|
|
371
|
+
>
|
|
372
|
+
{options.map((o) => (
|
|
373
|
+
<span
|
|
374
|
+
key={String(o.value)}
|
|
375
|
+
style={{
|
|
376
|
+
fontSize: 11,
|
|
377
|
+
fontFamily: "'SF Mono', 'Fira Code', Menlo, monospace",
|
|
378
|
+
color: o.value === value
|
|
379
|
+
? srgbToHex(tokens.textPrimary.srgb)
|
|
380
|
+
: srgbToHex(tokens.textTertiary.srgb),
|
|
381
|
+
fontWeight: o.value === value ? 600 : 400,
|
|
382
|
+
}}
|
|
383
|
+
>
|
|
384
|
+
{o.label}
|
|
385
|
+
</span>
|
|
386
|
+
))}
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
389
|
+
);
|
|
390
|
+
})()}
|
|
391
|
+
|
|
321
392
|
{prop.control === "toggle" && (
|
|
322
393
|
<div
|
|
323
394
|
role="switch"
|
|
@@ -359,14 +430,6 @@ function PropControl({
|
|
|
359
430
|
}}
|
|
360
431
|
/>
|
|
361
432
|
</div>
|
|
362
|
-
<span
|
|
363
|
-
style={{
|
|
364
|
-
fontSize: 12,
|
|
365
|
-
color: srgbToHex(tokens.textSecondary.srgb),
|
|
366
|
-
}}
|
|
367
|
-
>
|
|
368
|
-
{value ? "true" : "false"}
|
|
369
|
-
</span>
|
|
370
433
|
</div>
|
|
371
434
|
)}
|
|
372
435
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
import { useTokens } from "@newtonedev/components";
|
|
2
|
+
import { useTokens, Icon } from "@newtonedev/components";
|
|
3
3
|
import type { ColorMode } from "@newtonedev/components";
|
|
4
4
|
import { srgbToHex } from "newtone";
|
|
5
5
|
import type { ColorResult } from "newtone";
|
|
@@ -18,87 +18,13 @@ import type { Preset } from "../types";
|
|
|
18
18
|
const SIDEBAR_WIDTH = 360;
|
|
19
19
|
|
|
20
20
|
const ACCORDION_SECTIONS = [
|
|
21
|
-
{ id: "dynamic-range", label: "Dynamic Range" },
|
|
22
|
-
{ id: "colors", label: "Colors" },
|
|
23
|
-
{ id: "fonts", label: "Fonts" },
|
|
24
|
-
{ id: "icons", label: "Icons" },
|
|
25
|
-
{ id: "others", label: "Others" },
|
|
21
|
+
{ id: "dynamic-range", label: "Dynamic Range", icon: "contrast" },
|
|
22
|
+
{ id: "colors", label: "Colors", icon: "palette" },
|
|
23
|
+
{ id: "fonts", label: "Fonts", icon: "text_fields" },
|
|
24
|
+
{ id: "icons", label: "Icons", icon: "grid_view" },
|
|
25
|
+
{ id: "others", label: "Others", icon: "tune" },
|
|
26
26
|
] as const;
|
|
27
27
|
|
|
28
|
-
function SectionIcon({ id }: { readonly id: string }) {
|
|
29
|
-
const props = {
|
|
30
|
-
width: 16,
|
|
31
|
-
height: 16,
|
|
32
|
-
viewBox: "0 0 24 24",
|
|
33
|
-
fill: "none",
|
|
34
|
-
stroke: "currentColor",
|
|
35
|
-
strokeWidth: 2,
|
|
36
|
-
strokeLinecap: "round" as const,
|
|
37
|
-
strokeLinejoin: "round" as const,
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
switch (id) {
|
|
41
|
-
case "dynamic-range":
|
|
42
|
-
// Sun/contrast icon
|
|
43
|
-
return (
|
|
44
|
-
<svg {...props}>
|
|
45
|
-
<circle cx="12" cy="12" r="5" />
|
|
46
|
-
<line x1="12" y1="1" x2="12" y2="3" />
|
|
47
|
-
<line x1="12" y1="21" x2="12" y2="23" />
|
|
48
|
-
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
|
|
49
|
-
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
|
|
50
|
-
<line x1="1" y1="12" x2="3" y2="12" />
|
|
51
|
-
<line x1="21" y1="12" x2="23" y2="12" />
|
|
52
|
-
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
|
|
53
|
-
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
|
|
54
|
-
</svg>
|
|
55
|
-
);
|
|
56
|
-
case "colors":
|
|
57
|
-
// Palette/droplet icon
|
|
58
|
-
return (
|
|
59
|
-
<svg {...props}>
|
|
60
|
-
<path d="M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z" />
|
|
61
|
-
</svg>
|
|
62
|
-
);
|
|
63
|
-
case "fonts":
|
|
64
|
-
// Type/text icon
|
|
65
|
-
return (
|
|
66
|
-
<svg {...props}>
|
|
67
|
-
<polyline points="4 7 4 4 20 4 20 7" />
|
|
68
|
-
<line x1="9" y1="20" x2="15" y2="20" />
|
|
69
|
-
<line x1="12" y1="4" x2="12" y2="20" />
|
|
70
|
-
</svg>
|
|
71
|
-
);
|
|
72
|
-
case "icons":
|
|
73
|
-
// Grid icon
|
|
74
|
-
return (
|
|
75
|
-
<svg {...props}>
|
|
76
|
-
<rect x="3" y="3" width="7" height="7" />
|
|
77
|
-
<rect x="14" y="3" width="7" height="7" />
|
|
78
|
-
<rect x="3" y="14" width="7" height="7" />
|
|
79
|
-
<rect x="14" y="14" width="7" height="7" />
|
|
80
|
-
</svg>
|
|
81
|
-
);
|
|
82
|
-
case "others":
|
|
83
|
-
// Sliders icon
|
|
84
|
-
return (
|
|
85
|
-
<svg {...props}>
|
|
86
|
-
<line x1="4" y1="21" x2="4" y2="14" />
|
|
87
|
-
<line x1="4" y1="10" x2="4" y2="3" />
|
|
88
|
-
<line x1="12" y1="21" x2="12" y2="12" />
|
|
89
|
-
<line x1="12" y1="8" x2="12" y2="3" />
|
|
90
|
-
<line x1="20" y1="21" x2="20" y2="16" />
|
|
91
|
-
<line x1="20" y1="12" x2="20" y2="3" />
|
|
92
|
-
<line x1="1" y1="14" x2="7" y2="14" />
|
|
93
|
-
<line x1="9" y1="8" x2="15" y2="8" />
|
|
94
|
-
<line x1="17" y1="16" x2="23" y2="16" />
|
|
95
|
-
</svg>
|
|
96
|
-
);
|
|
97
|
-
default:
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
28
|
interface SidebarProps {
|
|
103
29
|
readonly state: ConfiguratorState;
|
|
104
30
|
readonly dispatch: (action: ConfiguratorAction) => void;
|
|
@@ -262,23 +188,17 @@ export function Sidebar({
|
|
|
262
188
|
}}
|
|
263
189
|
>
|
|
264
190
|
<span style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
|
265
|
-
<
|
|
191
|
+
<Icon name={section.icon} size={16} />
|
|
266
192
|
{section.label}
|
|
267
193
|
</span>
|
|
268
|
-
<
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
viewBox="0 0 24 24"
|
|
272
|
-
fill="none"
|
|
273
|
-
stroke="currentColor"
|
|
274
|
-
strokeWidth={2}
|
|
194
|
+
<Icon
|
|
195
|
+
name="expand_more"
|
|
196
|
+
size={16}
|
|
275
197
|
style={{
|
|
276
198
|
transform: isOpen ? "rotate(180deg)" : "none",
|
|
277
199
|
transition: "transform 150ms ease",
|
|
278
|
-
}}
|
|
279
|
-
|
|
280
|
-
<polyline points="6 9 12 15 18 9" />
|
|
281
|
-
</svg>
|
|
200
|
+
} as any}
|
|
201
|
+
/>
|
|
282
202
|
</button>
|
|
283
203
|
{isOpen && (
|
|
284
204
|
<div
|
|
@@ -201,9 +201,20 @@ export function useEditorState({
|
|
|
201
201
|
}
|
|
202
202
|
}, [sidebarSelection, initOverridesFromVariant]);
|
|
203
203
|
|
|
204
|
-
const handlePropOverride = useCallback(
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
const handlePropOverride = useCallback(
|
|
205
|
+
(propName: string, value: unknown) => {
|
|
206
|
+
setPropOverrides((prev) => ({ ...prev, [propName]: value }));
|
|
207
|
+
// Re-open sidebar if closed while viewing a component (e.g. icon browser click)
|
|
208
|
+
setSidebarSelection((prev) => {
|
|
209
|
+
if (prev !== null) return prev;
|
|
210
|
+
if (previewView.kind === "component") {
|
|
211
|
+
return { scope: "component", componentId: previewView.componentId };
|
|
212
|
+
}
|
|
213
|
+
return prev;
|
|
214
|
+
});
|
|
215
|
+
},
|
|
216
|
+
[previewView],
|
|
217
|
+
);
|
|
207
218
|
|
|
208
219
|
const handleResetOverrides = useCallback(() => {
|
|
209
220
|
if (sidebarSelection?.scope === "variant") {
|