@newtonedev/editor 0.1.1
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 +3 -0
- package/dist/Editor.d.ts.map +1 -0
- package/dist/components/CodeBlock.d.ts +7 -0
- package/dist/components/CodeBlock.d.ts.map +1 -0
- package/dist/components/EditorHeader.d.ts +16 -0
- package/dist/components/EditorHeader.d.ts.map +1 -0
- package/dist/components/EditorShell.d.ts +10 -0
- package/dist/components/EditorShell.d.ts.map +1 -0
- package/dist/components/FontPicker.d.ts +11 -0
- package/dist/components/FontPicker.d.ts.map +1 -0
- package/dist/components/PresetSelector.d.ts +14 -0
- package/dist/components/PresetSelector.d.ts.map +1 -0
- package/dist/components/PreviewWindow.d.ts +11 -0
- package/dist/components/PreviewWindow.d.ts.map +1 -0
- package/dist/components/RightSidebar.d.ts +12 -0
- package/dist/components/RightSidebar.d.ts.map +1 -0
- package/dist/components/Sidebar.d.ts +25 -0
- package/dist/components/Sidebar.d.ts.map +1 -0
- package/dist/components/TableOfContents.d.ts +9 -0
- package/dist/components/TableOfContents.d.ts.map +1 -0
- package/dist/components/ThemeBar.d.ts +8 -0
- package/dist/components/ThemeBar.d.ts.map +1 -0
- package/dist/components/sections/ColorsSection.d.ts +14 -0
- package/dist/components/sections/ColorsSection.d.ts.map +1 -0
- package/dist/components/sections/DynamicRangeSection.d.ts +9 -0
- package/dist/components/sections/DynamicRangeSection.d.ts.map +1 -0
- package/dist/components/sections/FontsSection.d.ts +9 -0
- package/dist/components/sections/FontsSection.d.ts.map +1 -0
- package/dist/components/sections/IconsSection.d.ts +9 -0
- package/dist/components/sections/IconsSection.d.ts.map +1 -0
- package/dist/components/sections/OthersSection.d.ts +9 -0
- package/dist/components/sections/OthersSection.d.ts.map +1 -0
- package/dist/components/sections/index.d.ts +6 -0
- package/dist/components/sections/index.d.ts.map +1 -0
- package/dist/hooks/useEditorState.d.ts +53 -0
- package/dist/hooks/useEditorState.d.ts.map +1 -0
- package/dist/hooks/useHover.d.ts +8 -0
- package/dist/hooks/useHover.d.ts.map +1 -0
- package/dist/hooks/usePresets.d.ts +33 -0
- package/dist/hooks/usePresets.d.ts.map +1 -0
- package/dist/index.cjs +3846 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3819 -0
- package/dist/index.js.map +1 -0
- package/dist/preview/CategoryView.d.ts +7 -0
- package/dist/preview/CategoryView.d.ts.map +1 -0
- package/dist/preview/ComponentDetailView.d.ts +9 -0
- package/dist/preview/ComponentDetailView.d.ts.map +1 -0
- package/dist/preview/ComponentRenderer.d.ts +7 -0
- package/dist/preview/ComponentRenderer.d.ts.map +1 -0
- package/dist/preview/OverviewView.d.ts +7 -0
- package/dist/preview/OverviewView.d.ts.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/presets.d.ts +5 -0
- package/dist/utils/presets.d.ts.map +1 -0
- package/package.json +51 -0
- package/src/Editor.tsx +128 -0
- package/src/components/CodeBlock.tsx +58 -0
- package/src/components/EditorHeader.tsx +86 -0
- package/src/components/EditorShell.tsx +67 -0
- package/src/components/FontPicker.tsx +351 -0
- package/src/components/PresetSelector.tsx +455 -0
- package/src/components/PreviewWindow.tsx +69 -0
- package/src/components/RightSidebar.tsx +374 -0
- package/src/components/Sidebar.tsx +332 -0
- package/src/components/TableOfContents.tsx +152 -0
- package/src/components/ThemeBar.tsx +76 -0
- package/src/components/sections/ColorsSection.tsx +485 -0
- package/src/components/sections/DynamicRangeSection.tsx +399 -0
- package/src/components/sections/FontsSection.tsx +132 -0
- package/src/components/sections/IconsSection.tsx +66 -0
- package/src/components/sections/OthersSection.tsx +70 -0
- package/src/components/sections/index.ts +5 -0
- package/src/hooks/useEditorState.ts +381 -0
- package/src/hooks/useHover.ts +8 -0
- package/src/hooks/usePresets.ts +254 -0
- package/src/index.ts +52 -0
- package/src/preview/CategoryView.tsx +134 -0
- package/src/preview/ComponentDetailView.tsx +126 -0
- package/src/preview/ComponentRenderer.tsx +107 -0
- package/src/preview/OverviewView.tsx +177 -0
- package/src/types.ts +77 -0
- package/src/utils/presets.ts +24 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface CategoryViewProps {
|
|
2
|
+
readonly categoryId: string;
|
|
3
|
+
readonly onNavigateToComponent: (componentId: string) => void;
|
|
4
|
+
}
|
|
5
|
+
export declare function CategoryView({ categoryId, onNavigateToComponent, }: CategoryViewProps): import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=CategoryView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CategoryView.d.ts","sourceRoot":"","sources":["../../src/preview/CategoryView.tsx"],"names":[],"mappings":"AAMA,UAAU,iBAAiB;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,qBAAqB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/D;AAED,wBAAgB,YAAY,CAAC,EAC3B,UAAU,EACV,qBAAqB,GACtB,EAAE,iBAAiB,kDAuHnB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface ComponentDetailViewProps {
|
|
2
|
+
readonly componentId: string;
|
|
3
|
+
readonly selectedVariantId: string | null;
|
|
4
|
+
readonly propOverrides?: Record<string, unknown>;
|
|
5
|
+
readonly onSelectVariant: (variantId: string) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function ComponentDetailView({ componentId, selectedVariantId, propOverrides, onSelectVariant, }: ComponentDetailViewProps): import("react/jsx-runtime").JSX.Element | null;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=ComponentDetailView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComponentDetailView.d.ts","sourceRoot":"","sources":["../../src/preview/ComponentDetailView.tsx"],"names":[],"mappings":"AAMA,UAAU,wBAAwB;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjD,QAAQ,CAAC,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD;AAED,wBAAgB,mBAAmB,CAAC,EAClC,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,eAAe,GAChB,EAAE,wBAAwB,kDA2G1B"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface ComponentRendererProps {
|
|
2
|
+
readonly componentId: string;
|
|
3
|
+
readonly props: Record<string, unknown>;
|
|
4
|
+
}
|
|
5
|
+
export declare function ComponentRenderer({ componentId, props }: ComponentRendererProps): import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=ComponentRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComponentRenderer.d.ts","sourceRoot":"","sources":["../../src/preview/ComponentRenderer.tsx"],"names":[],"mappings":"AAaA,UAAU,sBAAsB;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAyDD,wBAAgB,iBAAiB,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,sBAAsB,kDAiC/E"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface OverviewViewProps {
|
|
2
|
+
readonly onNavigateToCategory: (categoryId: string) => void;
|
|
3
|
+
readonly onNavigateToComponent: (componentId: string) => void;
|
|
4
|
+
}
|
|
5
|
+
export declare function OverviewView({ onNavigateToCategory, onNavigateToComponent, }: OverviewViewProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=OverviewView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OverviewView.d.ts","sourceRoot":"","sources":["../../src/preview/OverviewView.tsx"],"names":[],"mappings":"AAMA,UAAU,iBAAiB;IACzB,QAAQ,CAAC,oBAAoB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,QAAQ,CAAC,qBAAqB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/D;AAED,wBAAgB,YAAY,CAAC,EAC3B,oBAAoB,EACpB,qBAAqB,GACtB,EAAE,iBAAiB,2CAwFnB"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ConfiguratorState } from "@newtonedev/configurator";
|
|
2
|
+
import type { NewtoneThemeConfig } from "@newtonedev/components";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
export interface Preset {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly draft_state: ConfiguratorState;
|
|
8
|
+
readonly published_state: ConfiguratorState | null;
|
|
9
|
+
}
|
|
10
|
+
export type SaveStatus = "saved" | "saving" | "unsaved" | "error";
|
|
11
|
+
export type ThemeName = "neutral" | "primary" | "secondary" | "strong";
|
|
12
|
+
export type PreviewView = {
|
|
13
|
+
readonly kind: "overview";
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: "category";
|
|
16
|
+
readonly categoryId: string;
|
|
17
|
+
} | {
|
|
18
|
+
readonly kind: "component";
|
|
19
|
+
readonly componentId: string;
|
|
20
|
+
};
|
|
21
|
+
export type SidebarSelection = null | {
|
|
22
|
+
readonly scope: "component";
|
|
23
|
+
readonly componentId: string;
|
|
24
|
+
} | {
|
|
25
|
+
readonly scope: "variant";
|
|
26
|
+
readonly componentId: string;
|
|
27
|
+
readonly variantId: string;
|
|
28
|
+
};
|
|
29
|
+
export interface EditorPersistence {
|
|
30
|
+
/** Save draft state. Called on 2s debounce. */
|
|
31
|
+
readonly onSaveDraft: (params: {
|
|
32
|
+
readonly state: ConfiguratorState;
|
|
33
|
+
readonly presets: readonly Preset[];
|
|
34
|
+
}) => Promise<{
|
|
35
|
+
error?: unknown;
|
|
36
|
+
}>;
|
|
37
|
+
/** Publish the active preset. */
|
|
38
|
+
readonly onPublish: (params: {
|
|
39
|
+
readonly state: ConfiguratorState;
|
|
40
|
+
readonly presets: readonly Preset[];
|
|
41
|
+
readonly activePresetId: string;
|
|
42
|
+
}) => Promise<{
|
|
43
|
+
error?: unknown;
|
|
44
|
+
}>;
|
|
45
|
+
/** Persist preset metadata (used by preset CRUD operations). */
|
|
46
|
+
readonly persistPresets: (params: {
|
|
47
|
+
readonly presets: readonly Preset[];
|
|
48
|
+
readonly activePresetId: string;
|
|
49
|
+
readonly publishedPresetId: string | null;
|
|
50
|
+
}) => Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
export interface EditorHeaderSlots {
|
|
53
|
+
readonly left?: ReactNode;
|
|
54
|
+
readonly right?: ReactNode;
|
|
55
|
+
}
|
|
56
|
+
export interface EditorProps {
|
|
57
|
+
readonly initialState: ConfiguratorState;
|
|
58
|
+
readonly initialIsPublished: boolean;
|
|
59
|
+
readonly initialPresets: readonly Preset[];
|
|
60
|
+
readonly initialActivePresetId: string;
|
|
61
|
+
readonly initialPublishedPresetId: string | null;
|
|
62
|
+
readonly defaultState: ConfiguratorState;
|
|
63
|
+
readonly chromeThemeConfig: NewtoneThemeConfig;
|
|
64
|
+
readonly persistence: EditorPersistence;
|
|
65
|
+
readonly headerSlots?: EditorHeaderSlots;
|
|
66
|
+
readonly onNavigate?: (view: PreviewView) => void;
|
|
67
|
+
readonly initialPreviewView?: PreviewView;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Preset } from "../types";
|
|
2
|
+
export declare function findPreset(presets: readonly Preset[], presetId: string): Preset | undefined;
|
|
3
|
+
export declare function updatePresetInArray(presets: readonly Preset[], presetId: string, updater: (preset: Preset) => Preset): readonly Preset[];
|
|
4
|
+
export declare function presetHasUnpublishedChanges(preset: Preset): boolean;
|
|
5
|
+
//# sourceMappingURL=presets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/utils/presets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,wBAAgB,UAAU,CACxB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,QAAQ,EAAE,MAAM,GACf,MAAM,GAAG,SAAS,CAEpB;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAClC,SAAS,MAAM,EAAE,CAEnB;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAMnE"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@newtonedev/editor",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Shared color system editor for Newtone applications",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/joshuaallenmx/newtone-api.git",
|
|
9
|
+
"directory": "packages/editor"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://newtone.dev",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "./dist/index.cjs",
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"react-native": "./src/index.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"react-native": "./src/index.ts",
|
|
21
|
+
"import": "./dist/index.js",
|
|
22
|
+
"require": "./dist/index.cjs"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup && rm -f tsconfig.tsbuildinfo && tsc --emitDeclarationOnly",
|
|
31
|
+
"dev": "tsup --watch",
|
|
32
|
+
"typecheck": "tsc --noEmit"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": ">=18.0.0",
|
|
36
|
+
"react-native": ">=0.70.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"newtone": "^0.1.0",
|
|
40
|
+
"@newtonedev/components": "^0.1.0",
|
|
41
|
+
"@newtonedev/configurator": "^0.1.0",
|
|
42
|
+
"react-native-web": "^0.19.10"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/react": "^18.2.0",
|
|
46
|
+
"react": "^18.2.0",
|
|
47
|
+
"react-dom": "^18.2.0",
|
|
48
|
+
"tsup": "^8.0.0",
|
|
49
|
+
"typescript": "^5.4.0"
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/Editor.tsx
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { NewtoneProvider } from "@newtonedev/components";
|
|
2
|
+
import { useEditorState } from "./hooks/useEditorState";
|
|
3
|
+
import { EditorShell } from "./components/EditorShell";
|
|
4
|
+
import { Sidebar } from "./components/Sidebar";
|
|
5
|
+
import { EditorHeader } from "./components/EditorHeader";
|
|
6
|
+
import { ThemeBar } from "./components/ThemeBar";
|
|
7
|
+
import { TableOfContents } from "./components/TableOfContents";
|
|
8
|
+
import { PreviewWindow } from "./components/PreviewWindow";
|
|
9
|
+
import { RightSidebar } from "./components/RightSidebar";
|
|
10
|
+
import type { EditorProps } from "./types";
|
|
11
|
+
|
|
12
|
+
export function Editor({
|
|
13
|
+
initialState,
|
|
14
|
+
initialIsPublished,
|
|
15
|
+
initialPresets,
|
|
16
|
+
initialActivePresetId,
|
|
17
|
+
initialPublishedPresetId,
|
|
18
|
+
defaultState,
|
|
19
|
+
chromeThemeConfig,
|
|
20
|
+
persistence,
|
|
21
|
+
headerSlots,
|
|
22
|
+
onNavigate,
|
|
23
|
+
initialPreviewView,
|
|
24
|
+
}: EditorProps) {
|
|
25
|
+
const editor = useEditorState({
|
|
26
|
+
initialState,
|
|
27
|
+
initialIsPublished,
|
|
28
|
+
initialPresets,
|
|
29
|
+
initialActivePresetId,
|
|
30
|
+
initialPublishedPresetId,
|
|
31
|
+
defaultState,
|
|
32
|
+
persistence,
|
|
33
|
+
onNavigate,
|
|
34
|
+
initialPreviewView,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<NewtoneProvider config={chromeThemeConfig}>
|
|
39
|
+
<EditorShell
|
|
40
|
+
sidebar={
|
|
41
|
+
<Sidebar
|
|
42
|
+
state={editor.configuratorState}
|
|
43
|
+
dispatch={editor.dispatch}
|
|
44
|
+
previewColors={editor.previewColors}
|
|
45
|
+
isDirty={editor.isDirty}
|
|
46
|
+
onRevert={editor.handleRevert}
|
|
47
|
+
presets={editor.presets}
|
|
48
|
+
activePresetId={editor.activePresetId}
|
|
49
|
+
publishedPresetId={editor.publishedPresetId}
|
|
50
|
+
onSwitchPreset={editor.switchPreset}
|
|
51
|
+
onCreatePreset={editor.createPreset}
|
|
52
|
+
onRenamePreset={editor.renamePreset}
|
|
53
|
+
onDeletePreset={editor.deletePreset}
|
|
54
|
+
onDuplicatePreset={editor.duplicatePreset}
|
|
55
|
+
colorMode={editor.colorMode}
|
|
56
|
+
onColorModeChange={editor.handleColorModeChange}
|
|
57
|
+
/>
|
|
58
|
+
}
|
|
59
|
+
navbar={
|
|
60
|
+
<EditorHeader
|
|
61
|
+
saveStatus={editor.saveStatus}
|
|
62
|
+
isPublished={editor.isPublished}
|
|
63
|
+
publishing={editor.publishing}
|
|
64
|
+
onPublish={editor.handlePublish}
|
|
65
|
+
onRetry={() => editor.saveDraft(editor.latestStateRef.current)}
|
|
66
|
+
headerSlots={headerSlots}
|
|
67
|
+
/>
|
|
68
|
+
}
|
|
69
|
+
content={
|
|
70
|
+
<div
|
|
71
|
+
style={{
|
|
72
|
+
flex: 1,
|
|
73
|
+
display: "flex",
|
|
74
|
+
overflow: "hidden",
|
|
75
|
+
minWidth: 0,
|
|
76
|
+
}}
|
|
77
|
+
>
|
|
78
|
+
<TableOfContents
|
|
79
|
+
activeView={editor.previewView}
|
|
80
|
+
selectedComponentId={editor.selectedComponentId}
|
|
81
|
+
onNavigate={editor.handlePreviewNavigate}
|
|
82
|
+
/>
|
|
83
|
+
<div
|
|
84
|
+
style={{
|
|
85
|
+
flex: 1,
|
|
86
|
+
display: "flex",
|
|
87
|
+
flexDirection: "column",
|
|
88
|
+
overflow: "hidden",
|
|
89
|
+
minWidth: 0,
|
|
90
|
+
}}
|
|
91
|
+
>
|
|
92
|
+
<NewtoneProvider
|
|
93
|
+
config={editor.themeConfig}
|
|
94
|
+
initialMode={editor.colorMode}
|
|
95
|
+
initialTheme={editor.activeTheme}
|
|
96
|
+
key={`${editor.colorMode}-${editor.activeTheme}`}
|
|
97
|
+
>
|
|
98
|
+
<ThemeBar
|
|
99
|
+
activeTheme={editor.activeTheme}
|
|
100
|
+
onThemeChange={editor.handleThemeChange}
|
|
101
|
+
/>
|
|
102
|
+
<div style={{ flex: 1, overflowY: "auto", minWidth: 0 }}>
|
|
103
|
+
<PreviewWindow
|
|
104
|
+
view={editor.previewView}
|
|
105
|
+
selectedVariantId={editor.selectedVariantId}
|
|
106
|
+
propOverrides={editor.propOverrides}
|
|
107
|
+
onNavigate={editor.handlePreviewNavigate}
|
|
108
|
+
onSelectVariant={editor.handleSelectVariant}
|
|
109
|
+
/>
|
|
110
|
+
</div>
|
|
111
|
+
</NewtoneProvider>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
}
|
|
115
|
+
rightPanel={
|
|
116
|
+
<RightSidebar
|
|
117
|
+
selection={editor.sidebarSelection}
|
|
118
|
+
propOverrides={editor.propOverrides}
|
|
119
|
+
onPropOverride={editor.handlePropOverride}
|
|
120
|
+
onResetOverrides={editor.handleResetOverrides}
|
|
121
|
+
onClose={editor.handleCloseSidebar}
|
|
122
|
+
onScopeToComponent={editor.handleScopeToComponent}
|
|
123
|
+
/>
|
|
124
|
+
}
|
|
125
|
+
/>
|
|
126
|
+
</NewtoneProvider>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { useState, useCallback } from "react";
|
|
2
|
+
import { useTokens, Button } from "@newtonedev/components";
|
|
3
|
+
import { srgbToHex } from "newtone";
|
|
4
|
+
|
|
5
|
+
export function CopyButton({ text }: { readonly text: string }) {
|
|
6
|
+
const [copied, setCopied] = useState(false);
|
|
7
|
+
|
|
8
|
+
const handleCopy = useCallback(async () => {
|
|
9
|
+
await navigator.clipboard.writeText(text);
|
|
10
|
+
setCopied(true);
|
|
11
|
+
setTimeout(() => setCopied(false), 2000);
|
|
12
|
+
}, [text]);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Button variant="ghost" size="sm" icon={copied ? "check" : "content_copy"} onPress={handleCopy}>
|
|
16
|
+
{copied ? "Copied!" : "Copy"}
|
|
17
|
+
</Button>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function CodeBlock({
|
|
22
|
+
code,
|
|
23
|
+
}: {
|
|
24
|
+
readonly code: string;
|
|
25
|
+
}) {
|
|
26
|
+
const tokens = useTokens();
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div style={{ position: "relative" }}>
|
|
30
|
+
<div
|
|
31
|
+
style={{
|
|
32
|
+
position: "absolute",
|
|
33
|
+
top: 8,
|
|
34
|
+
right: 8,
|
|
35
|
+
}}
|
|
36
|
+
>
|
|
37
|
+
<CopyButton text={code} />
|
|
38
|
+
</div>
|
|
39
|
+
<pre
|
|
40
|
+
style={{
|
|
41
|
+
backgroundColor: srgbToHex(tokens.backgroundSunken.srgb),
|
|
42
|
+
border: `1px solid ${srgbToHex(tokens.border.srgb)}`,
|
|
43
|
+
borderRadius: 8,
|
|
44
|
+
padding: 16,
|
|
45
|
+
paddingRight: 80,
|
|
46
|
+
overflow: "auto",
|
|
47
|
+
fontSize: 13,
|
|
48
|
+
lineHeight: 1.5,
|
|
49
|
+
fontFamily: "'SF Mono', 'Fira Code', 'Fira Mono', Menlo, monospace",
|
|
50
|
+
color: srgbToHex(tokens.textPrimary.srgb),
|
|
51
|
+
margin: 0,
|
|
52
|
+
}}
|
|
53
|
+
>
|
|
54
|
+
<code>{code}</code>
|
|
55
|
+
</pre>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { useTokens, Button } from "@newtonedev/components";
|
|
3
|
+
import { srgbToHex } from "newtone";
|
|
4
|
+
import type { SaveStatus } from "../types";
|
|
5
|
+
|
|
6
|
+
interface EditorHeaderProps {
|
|
7
|
+
readonly saveStatus: SaveStatus;
|
|
8
|
+
readonly isPublished: boolean;
|
|
9
|
+
readonly publishing: boolean;
|
|
10
|
+
readonly onPublish: () => void;
|
|
11
|
+
readonly onRetry: () => void;
|
|
12
|
+
readonly headerSlots?: {
|
|
13
|
+
readonly left?: ReactNode;
|
|
14
|
+
readonly right?: ReactNode;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const STATUS_LABEL: Record<SaveStatus, string> = {
|
|
19
|
+
saved: "Saved",
|
|
20
|
+
saving: "Saving...",
|
|
21
|
+
unsaved: "Unsaved changes",
|
|
22
|
+
error: "Save failed",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function EditorHeader({
|
|
26
|
+
saveStatus,
|
|
27
|
+
isPublished,
|
|
28
|
+
publishing,
|
|
29
|
+
onPublish,
|
|
30
|
+
onRetry,
|
|
31
|
+
headerSlots,
|
|
32
|
+
}: EditorHeaderProps) {
|
|
33
|
+
const tokens = useTokens();
|
|
34
|
+
const borderColor = srgbToHex(tokens.border.srgb);
|
|
35
|
+
|
|
36
|
+
const statusColor: Record<SaveStatus, string> = {
|
|
37
|
+
saved: srgbToHex(tokens.success.srgb),
|
|
38
|
+
saving: srgbToHex(tokens.warning.srgb),
|
|
39
|
+
unsaved: srgbToHex(tokens.textSecondary.srgb),
|
|
40
|
+
error: srgbToHex(tokens.error.srgb),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div
|
|
45
|
+
style={{
|
|
46
|
+
display: "flex",
|
|
47
|
+
alignItems: "center",
|
|
48
|
+
justifyContent: "space-between",
|
|
49
|
+
padding: "12px 24px",
|
|
50
|
+
borderBottom: `1px solid ${borderColor}`,
|
|
51
|
+
backgroundColor: srgbToHex(tokens.background.srgb),
|
|
52
|
+
flexShrink: 0,
|
|
53
|
+
}}
|
|
54
|
+
>
|
|
55
|
+
<div style={{ display: "flex", alignItems: "center", gap: 16 }}>
|
|
56
|
+
{headerSlots?.left}
|
|
57
|
+
</div>
|
|
58
|
+
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
|
|
59
|
+
<span
|
|
60
|
+
style={{
|
|
61
|
+
fontSize: 12,
|
|
62
|
+
color: statusColor[saveStatus],
|
|
63
|
+
fontWeight: 500,
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
{STATUS_LABEL[saveStatus]}
|
|
67
|
+
</span>
|
|
68
|
+
{saveStatus === "error" && (
|
|
69
|
+
<Button variant="ghost" size="sm" icon="refresh" onPress={onRetry}>
|
|
70
|
+
Retry
|
|
71
|
+
</Button>
|
|
72
|
+
)}
|
|
73
|
+
<Button
|
|
74
|
+
variant="primary"
|
|
75
|
+
size="sm"
|
|
76
|
+
icon="publish"
|
|
77
|
+
onPress={onPublish}
|
|
78
|
+
disabled={isPublished || publishing}
|
|
79
|
+
>
|
|
80
|
+
{publishing ? "Publishing..." : isPublished ? "Published" : "Publish"}
|
|
81
|
+
</Button>
|
|
82
|
+
{headerSlots?.right}
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { useTokens } from "@newtonedev/components";
|
|
3
|
+
import { srgbToHex } from "newtone";
|
|
4
|
+
|
|
5
|
+
const SIDEBAR_WIDTH = 360;
|
|
6
|
+
|
|
7
|
+
interface EditorShellProps {
|
|
8
|
+
readonly sidebar: ReactNode;
|
|
9
|
+
readonly navbar: ReactNode;
|
|
10
|
+
readonly content: ReactNode;
|
|
11
|
+
readonly rightPanel: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function EditorShell({
|
|
15
|
+
sidebar,
|
|
16
|
+
navbar,
|
|
17
|
+
content,
|
|
18
|
+
rightPanel,
|
|
19
|
+
}: EditorShellProps) {
|
|
20
|
+
const tokens = useTokens();
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
style={{
|
|
25
|
+
display: "flex",
|
|
26
|
+
height: "100vh",
|
|
27
|
+
overflow: "hidden",
|
|
28
|
+
backgroundColor: srgbToHex(tokens.background.srgb),
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
31
|
+
<div
|
|
32
|
+
style={{
|
|
33
|
+
flex: 1,
|
|
34
|
+
display: "flex",
|
|
35
|
+
flexDirection: "column",
|
|
36
|
+
height: "100vh",
|
|
37
|
+
overflow: "hidden",
|
|
38
|
+
minWidth: 0,
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
{navbar}
|
|
42
|
+
|
|
43
|
+
<div
|
|
44
|
+
style={{
|
|
45
|
+
display: "flex",
|
|
46
|
+
flex: 1,
|
|
47
|
+
overflow: "hidden",
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
{content}
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<div
|
|
55
|
+
style={{
|
|
56
|
+
position: "relative",
|
|
57
|
+
width: SIDEBAR_WIDTH,
|
|
58
|
+
flexShrink: 0,
|
|
59
|
+
overflow: "hidden",
|
|
60
|
+
}}
|
|
61
|
+
>
|
|
62
|
+
{sidebar}
|
|
63
|
+
{rightPanel}
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|