dekit-cli 0.4.3 → 0.5.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/dist/editor/assets/{index-HLKs1tz-.css → index-DKRQEtBb.css} +1 -1
- package/dist/editor/assets/index-E_PyZ4Xf.js +57 -0
- package/dist/editor/index.html +2 -2
- package/editor/src/App.tsx +122 -6
- package/editor/src/styles/editor.css +67 -0
- package/editor/src/types.ts +6 -0
- package/package.json +2 -2
- package/dist/editor/assets/index-hySfUCIY.js +0 -57
package/dist/editor/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Dekit Editor</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-E_PyZ4Xf.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DKRQEtBb.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
package/editor/src/App.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useEffect, useCallback, useRef } from "react";
|
|
2
|
-
import type { EditorConfig, NodeInfo, DOMTreeNode, IframeMessage } from "./types.js";
|
|
2
|
+
import type { EditorConfig, NodeInfo, DOMTreeNode, IframeMessage, PropertyDef } from "./types.js";
|
|
3
3
|
import { DEVICE_PRESETS, calcScale } from "./devices.js";
|
|
4
4
|
import type { DevicePreset } from "./types.js";
|
|
5
5
|
import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
|
|
@@ -26,8 +26,8 @@ export function App() {
|
|
|
26
26
|
const [deviceWidth, setDeviceWidth] = useState(0);
|
|
27
27
|
const [deviceHeight, setDeviceHeight] = useState(0);
|
|
28
28
|
const [zoomMode, setZoomMode] = useState<"fit" | number>("fit");
|
|
29
|
-
const [inspectMode, setInspectMode] = useState(
|
|
30
|
-
const [inspectLocked, setInspectLocked] = useState(
|
|
29
|
+
const [inspectMode, setInspectMode] = useState(true);
|
|
30
|
+
const [inspectLocked, setInspectLocked] = useState(true);
|
|
31
31
|
const inspectModeRef = useRef(false);
|
|
32
32
|
const altPressedRef = useRef(false);
|
|
33
33
|
const currentPageRef = useRef("");
|
|
@@ -35,6 +35,7 @@ export function App() {
|
|
|
35
35
|
const [canvasSize, setCanvasSize] = useState({ width: 0, height: 0 });
|
|
36
36
|
const [contextMenu, setContextMenu] = useState<{ x: number; y: number; cssSelector?: string; page: string } | null>(null);
|
|
37
37
|
const [focusedPanel, setFocusedPanel] = useState<"pages" | "layers" | null>(null);
|
|
38
|
+
const [propsOverrides, setPropsOverrides] = useState<Record<string, Record<string, string>>>({});
|
|
38
39
|
|
|
39
40
|
const configRef = useRef<EditorConfig | null>(null);
|
|
40
41
|
configRef.current = config;
|
|
@@ -236,9 +237,19 @@ export function App() {
|
|
|
236
237
|
return <div className="empty-state">Loading...</div>;
|
|
237
238
|
}
|
|
238
239
|
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
240
|
+
const currentOverrides = currentPage ? propsOverrides[currentPage] : undefined;
|
|
241
|
+
let iframeSrc = "";
|
|
242
|
+
if (currentPage) {
|
|
243
|
+
const base = `${config.designServerUrl}/page/${currentPage}`;
|
|
244
|
+
const params = new URLSearchParams();
|
|
245
|
+
if (currentOverrides) {
|
|
246
|
+
for (const [key, value] of Object.entries(currentOverrides)) {
|
|
247
|
+
params.set(`props.${key}`, value);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const qs = params.toString();
|
|
251
|
+
iframeSrc = qs ? `${base}?${qs}` : base;
|
|
252
|
+
}
|
|
242
253
|
|
|
243
254
|
return (
|
|
244
255
|
<div className="editor-layout">
|
|
@@ -357,6 +368,30 @@ export function App() {
|
|
|
357
368
|
|
|
358
369
|
{/* Right Panel */}
|
|
359
370
|
<div className="right-panel">
|
|
371
|
+
{currentPage && config.pageProperties[currentPage] && Object.keys(config.pageProperties[currentPage]).length > 0 && (
|
|
372
|
+
<div className="right-panel-props">
|
|
373
|
+
<div className="panel-header">Page Props</div>
|
|
374
|
+
<OverlayScrollbarsComponent className="props-panel-scroll" defer>
|
|
375
|
+
<PagePropsPanel
|
|
376
|
+
properties={config.pageProperties[currentPage]}
|
|
377
|
+
overrides={propsOverrides[currentPage] ?? {}}
|
|
378
|
+
onChange={(key, value) => {
|
|
379
|
+
setPropsOverrides((prev) => ({
|
|
380
|
+
...prev,
|
|
381
|
+
[currentPage]: { ...prev[currentPage], [key]: value },
|
|
382
|
+
}));
|
|
383
|
+
}}
|
|
384
|
+
onReset={() => {
|
|
385
|
+
setPropsOverrides((prev) => {
|
|
386
|
+
const next = { ...prev };
|
|
387
|
+
delete next[currentPage];
|
|
388
|
+
return next;
|
|
389
|
+
});
|
|
390
|
+
}}
|
|
391
|
+
/>
|
|
392
|
+
</OverlayScrollbarsComponent>
|
|
393
|
+
</div>
|
|
394
|
+
)}
|
|
360
395
|
<div className="right-panel-top">
|
|
361
396
|
<div className="panel-header">Layers</div>
|
|
362
397
|
<OverlayScrollbarsComponent className="layer-tree-scroll" defer>
|
|
@@ -743,3 +778,84 @@ function PropertyPanel({ node, nodeRef }: { node: NodeInfo; nodeRef: string }) {
|
|
|
743
778
|
</>
|
|
744
779
|
);
|
|
745
780
|
}
|
|
781
|
+
|
|
782
|
+
function PagePropsPanel({
|
|
783
|
+
properties,
|
|
784
|
+
overrides,
|
|
785
|
+
onChange,
|
|
786
|
+
onReset,
|
|
787
|
+
}: {
|
|
788
|
+
properties: Record<string, PropertyDef>;
|
|
789
|
+
overrides: Record<string, string>;
|
|
790
|
+
onChange: (key: string, value: string) => void;
|
|
791
|
+
onReset: () => void;
|
|
792
|
+
}) {
|
|
793
|
+
const hasOverrides = Object.keys(overrides).length > 0;
|
|
794
|
+
|
|
795
|
+
return (
|
|
796
|
+
<div className="page-props-panel">
|
|
797
|
+
{Object.entries(properties).map(([key, def]) => {
|
|
798
|
+
const overridden = key in overrides;
|
|
799
|
+
const currentValue = overridden ? overrides[key] : String(def.default);
|
|
800
|
+
|
|
801
|
+
return (
|
|
802
|
+
<div key={key} className="property-row">
|
|
803
|
+
<span className="property-key">{key}</span>
|
|
804
|
+
{def.type === "boolean" ? (
|
|
805
|
+
<input
|
|
806
|
+
type="checkbox"
|
|
807
|
+
className="props-checkbox"
|
|
808
|
+
checked={currentValue === "true"}
|
|
809
|
+
onChange={(e) => onChange(key, String(e.target.checked))}
|
|
810
|
+
/>
|
|
811
|
+
) : (
|
|
812
|
+
<PropInput
|
|
813
|
+
type={def.type}
|
|
814
|
+
value={currentValue}
|
|
815
|
+
onChange={(v) => onChange(key, v)}
|
|
816
|
+
/>
|
|
817
|
+
)}
|
|
818
|
+
</div>
|
|
819
|
+
);
|
|
820
|
+
})}
|
|
821
|
+
{hasOverrides && (
|
|
822
|
+
<button className="props-reset-btn" onClick={onReset}>
|
|
823
|
+
Reset
|
|
824
|
+
</button>
|
|
825
|
+
)}
|
|
826
|
+
</div>
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
function PropInput({
|
|
831
|
+
type,
|
|
832
|
+
value,
|
|
833
|
+
onChange,
|
|
834
|
+
}: {
|
|
835
|
+
type: "number" | "string";
|
|
836
|
+
value: string;
|
|
837
|
+
onChange: (value: string) => void;
|
|
838
|
+
}) {
|
|
839
|
+
const [draft, setDraft] = useState(value);
|
|
840
|
+
|
|
841
|
+
useEffect(() => {
|
|
842
|
+
setDraft(value);
|
|
843
|
+
}, [value]);
|
|
844
|
+
|
|
845
|
+
const commit = () => {
|
|
846
|
+
if (draft !== value) onChange(draft);
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
return (
|
|
850
|
+
<input
|
|
851
|
+
className="props-input"
|
|
852
|
+
type={type === "number" ? "number" : "text"}
|
|
853
|
+
value={draft}
|
|
854
|
+
onChange={(e) => setDraft(e.target.value)}
|
|
855
|
+
onBlur={commit}
|
|
856
|
+
onKeyDown={(e) => {
|
|
857
|
+
if (e.key === "Enter") (e.target as HTMLInputElement).blur();
|
|
858
|
+
}}
|
|
859
|
+
/>
|
|
860
|
+
);
|
|
861
|
+
}
|
|
@@ -451,3 +451,70 @@ body {
|
|
|
451
451
|
background: #094771;
|
|
452
452
|
color: #ffffff;
|
|
453
453
|
}
|
|
454
|
+
|
|
455
|
+
/* Page Props Panel */
|
|
456
|
+
.right-panel-props {
|
|
457
|
+
flex-shrink: 0;
|
|
458
|
+
display: flex;
|
|
459
|
+
flex-direction: column;
|
|
460
|
+
overflow: hidden;
|
|
461
|
+
border-bottom: 1px solid #4a4a4a;
|
|
462
|
+
max-height: 30%;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.right-panel-props .props-panel-scroll {
|
|
466
|
+
flex: 1;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.page-props-panel {
|
|
470
|
+
padding: 8px 12px;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.page-props-panel .property-row {
|
|
474
|
+
align-items: center;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.props-checkbox {
|
|
478
|
+
accent-color: #2563eb;
|
|
479
|
+
cursor: pointer;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.props-input {
|
|
483
|
+
background: transparent;
|
|
484
|
+
border: 1px solid #4a4a4a;
|
|
485
|
+
border-radius: 3px;
|
|
486
|
+
color: #ce9178;
|
|
487
|
+
padding: 2px 6px;
|
|
488
|
+
font-size: 12px;
|
|
489
|
+
width: 100px;
|
|
490
|
+
text-align: right;
|
|
491
|
+
outline: none;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.props-input:focus {
|
|
495
|
+
border-color: #2563eb;
|
|
496
|
+
color: #ffffff;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.props-input::-webkit-inner-spin-button,
|
|
500
|
+
.props-input::-webkit-outer-spin-button {
|
|
501
|
+
-webkit-appearance: none;
|
|
502
|
+
margin: 0;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.props-reset-btn {
|
|
506
|
+
margin-top: 8px;
|
|
507
|
+
width: 100%;
|
|
508
|
+
padding: 4px 0;
|
|
509
|
+
background: transparent;
|
|
510
|
+
border: 1px solid #4a4a4a;
|
|
511
|
+
border-radius: 3px;
|
|
512
|
+
color: #969696;
|
|
513
|
+
font-size: 11px;
|
|
514
|
+
cursor: pointer;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
.props-reset-btn:hover {
|
|
518
|
+
border-color: #666;
|
|
519
|
+
color: #cccccc;
|
|
520
|
+
}
|
package/editor/src/types.ts
CHANGED
|
@@ -21,9 +21,15 @@ export interface DeviceConfig {
|
|
|
21
21
|
name?: string;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
export interface PropertyDef {
|
|
25
|
+
type: "boolean" | "number" | "string";
|
|
26
|
+
default: unknown;
|
|
27
|
+
}
|
|
28
|
+
|
|
24
29
|
export interface EditorConfig {
|
|
25
30
|
pages: string[];
|
|
26
31
|
pagePaths: Record<string, string>;
|
|
32
|
+
pageProperties: Record<string, Record<string, PropertyDef>>;
|
|
27
33
|
components: string[];
|
|
28
34
|
device: DeviceConfig | null;
|
|
29
35
|
designServerUrl: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dekit-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A code-first design toolkit for agents and humans — create, preview, and screenshot HTML/CSS designs",
|
|
6
6
|
"keywords": [
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"docs/usage.md"
|
|
33
33
|
],
|
|
34
34
|
"engines": {
|
|
35
|
-
"node": ">=
|
|
35
|
+
"node": ">=20"
|
|
36
36
|
},
|
|
37
37
|
"bin": {
|
|
38
38
|
"dekit": "./bin/dekit.js"
|