@valbuild/ui 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/dist/valbuild-ui.cjs.js +41 -15
  2. package/dist/valbuild-ui.esm.js +41 -15
  3. package/package.json +7 -3
  4. package/server/.tmp/assets/index-18cfa26c.css +1 -0
  5. package/server/.tmp/assets/index-513f7a9c.js +197 -0
  6. package/{index.html → server/.tmp/index.html} +3 -1
  7. package/server/dist/style.css +0 -3
  8. package/server/dist/valbuild-ui-main.cjs.js +60 -34
  9. package/server/dist/valbuild-ui-main.esm.js +60 -34
  10. package/server/dist/valbuild-ui-server.cjs.js +1 -1
  11. package/server/dist/valbuild-ui-server.esm.js +1 -1
  12. package/.babelrc.json +0 -10
  13. package/.storybook/main.js +0 -25
  14. package/.storybook/preview-head.html +0 -6
  15. package/.storybook/preview.js +0 -33
  16. package/.storybook/theme.css +0 -34
  17. package/CHANGELOG.md +0 -0
  18. package/components.json +0 -16
  19. package/fix-server-hack.js +0 -54
  20. package/fullscreen.vite.config.ts +0 -9
  21. package/jest.config.js +0 -4
  22. package/postcss.config.js +0 -6
  23. package/rollup.config.js +0 -23
  24. package/server.vite.config.ts +0 -31
  25. package/src/App.tsx +0 -73
  26. package/src/assets/icons/Bold.tsx +0 -23
  27. package/src/assets/icons/Chevron.tsx +0 -28
  28. package/src/assets/icons/FontColor.tsx +0 -30
  29. package/src/assets/icons/ImageIcon.tsx +0 -29
  30. package/src/assets/icons/Italic.tsx +0 -24
  31. package/src/assets/icons/Logo.tsx +0 -103
  32. package/src/assets/icons/Section.tsx +0 -41
  33. package/src/assets/icons/Strikethrough.tsx +0 -22
  34. package/src/assets/icons/TextIcon.tsx +0 -20
  35. package/src/assets/icons/Underline.tsx +0 -22
  36. package/src/assets/icons/Undo.tsx +0 -20
  37. package/src/components/Button.tsx +0 -68
  38. package/src/components/Checkbox.tsx +0 -51
  39. package/src/components/DraggableList.stories.tsx +0 -20
  40. package/src/components/DraggableList.tsx +0 -95
  41. package/src/components/Dropdown.tsx +0 -101
  42. package/src/components/EditButton.tsx +0 -10
  43. package/src/components/ErrorText.tsx +0 -3
  44. package/src/components/ExpandLogo.tsx +0 -72
  45. package/src/components/Grid.stories.tsx +0 -43
  46. package/src/components/Grid.tsx +0 -139
  47. package/src/components/RichTextEditor/ContentEditable.tsx +0 -117
  48. package/src/components/RichTextEditor/Nodes/ImageNode.tsx +0 -100
  49. package/src/components/RichTextEditor/Plugins/AutoFocus.tsx +0 -12
  50. package/src/components/RichTextEditor/Plugins/ImagePlugin.tsx +0 -45
  51. package/src/components/RichTextEditor/Plugins/LinkEditorPlugin.tsx +0 -58
  52. package/src/components/RichTextEditor/Plugins/Toolbar.tsx +0 -412
  53. package/src/components/RichTextEditor/RichTextEditor.tsx +0 -105
  54. package/src/components/UploadModal.tsx +0 -109
  55. package/src/components/User.tsx +0 -17
  56. package/src/components/ValFormField.tsx +0 -574
  57. package/src/components/ValFullscreen.tsx +0 -1278
  58. package/src/components/ValMenu.tsx +0 -92
  59. package/src/components/ValOverlay.tsx +0 -488
  60. package/src/components/ValOverlayContext.tsx +0 -80
  61. package/src/components/ValWindow.stories.tsx +0 -146
  62. package/src/components/ValWindow.tsx +0 -220
  63. package/src/components/dashboard/DashboardButton.tsx +0 -25
  64. package/src/components/dashboard/DashboardDropdown.tsx +0 -59
  65. package/src/components/dashboard/Dropdown.stories.tsx +0 -11
  66. package/src/components/dashboard/Dropdown.tsx +0 -70
  67. package/src/components/dashboard/FormGroup.stories.tsx +0 -37
  68. package/src/components/dashboard/FormGroup.tsx +0 -42
  69. package/src/components/dashboard/Grid2.stories.tsx +0 -56
  70. package/src/components/dashboard/Grid2.tsx +0 -72
  71. package/src/components/dashboard/Tree.stories.tsx +0 -91
  72. package/src/components/dashboard/Tree.tsx +0 -72
  73. package/src/components/dashboard/ValDashboardEditor.tsx +0 -269
  74. package/src/components/dashboard/ValDashboardGrid.tsx +0 -142
  75. package/src/components/dashboard/ValTreeNavigator.tsx +0 -253
  76. package/src/components/forms/Form.tsx +0 -126
  77. package/src/components/forms/FormContainer.tsx +0 -24
  78. package/src/components/forms/ImageForm.tsx +0 -195
  79. package/src/components/forms/TextArea.tsx +0 -24
  80. package/src/components/ui/accordion.tsx +0 -58
  81. package/src/components/ui/alert-dialog.tsx +0 -139
  82. package/src/components/ui/avatar.tsx +0 -48
  83. package/src/components/ui/button.tsx +0 -56
  84. package/src/components/ui/calendar.tsx +0 -62
  85. package/src/components/ui/card.tsx +0 -86
  86. package/src/components/ui/checkbox.tsx +0 -28
  87. package/src/components/ui/command.tsx +0 -153
  88. package/src/components/ui/dialog.tsx +0 -120
  89. package/src/components/ui/dropdown-menu.tsx +0 -198
  90. package/src/components/ui/form.tsx +0 -177
  91. package/src/components/ui/input.tsx +0 -24
  92. package/src/components/ui/label.tsx +0 -24
  93. package/src/components/ui/popover.tsx +0 -29
  94. package/src/components/ui/progress.tsx +0 -26
  95. package/src/components/ui/radio-group.tsx +0 -42
  96. package/src/components/ui/scroll-area.tsx +0 -51
  97. package/src/components/ui/select.tsx +0 -119
  98. package/src/components/ui/switch.tsx +0 -27
  99. package/src/components/ui/tabs.tsx +0 -53
  100. package/src/components/ui/toggle.tsx +0 -43
  101. package/src/components/ui/tooltip.tsx +0 -28
  102. package/src/components/usePatch.ts +0 -86
  103. package/src/components/useTheme.ts +0 -45
  104. package/src/dto/SerializedSchema.ts +0 -69
  105. package/src/dto/Session.ts +0 -12
  106. package/src/dto/SessionMode.ts +0 -5
  107. package/src/dto/Tree.ts +0 -18
  108. package/src/exports.ts +0 -6
  109. package/src/index.css +0 -115
  110. package/src/index.tsx +0 -14
  111. package/src/lib/IValStore.ts +0 -6
  112. package/src/lib/utils.ts +0 -6
  113. package/src/main.jsx +0 -10
  114. package/src/richtext/conversion/conversion.test.ts +0 -146
  115. package/src/richtext/conversion/lexicalToRichTextSource.test.ts +0 -89
  116. package/src/richtext/conversion/lexicalToRichTextSource.ts +0 -285
  117. package/src/richtext/conversion/parseRichTextSource.test.ts +0 -469
  118. package/src/richtext/conversion/parseRichTextSource.ts +0 -233
  119. package/src/richtext/conversion/richTextSourceToLexical.test.ts +0 -381
  120. package/src/richtext/conversion/richTextSourceToLexical.ts +0 -293
  121. package/src/richtext/shadowRootPolyFill.js +0 -115
  122. package/src/server.ts +0 -70
  123. package/src/stories/Button.stories.tsx +0 -20
  124. package/src/stories/Checkbox.stories.tsx +0 -14
  125. package/src/stories/Dropdown.stories.tsx +0 -23
  126. package/src/stories/Introduction.mdx +0 -221
  127. package/src/stories/RichTextEditor.stories.tsx +0 -24
  128. package/src/stories/assets/code-brackets.svg +0 -1
  129. package/src/stories/assets/colors.svg +0 -1
  130. package/src/stories/assets/comments.svg +0 -1
  131. package/src/stories/assets/direction.svg +0 -1
  132. package/src/stories/assets/flow.svg +0 -1
  133. package/src/stories/assets/plugin.svg +0 -1
  134. package/src/stories/assets/repo.svg +0 -1
  135. package/src/stories/assets/stackalt.svg +0 -1
  136. package/src/utils/Remote.ts +0 -15
  137. package/src/utils/imageMimeType.ts +0 -23
  138. package/src/utils/readImage.ts +0 -54
  139. package/src/utils/resolvePath.ts +0 -32
  140. package/src/vite-env.d.ts +0 -1
  141. package/src/vite-index.tsx +0 -7
  142. package/src/vite-server.ts +0 -42
  143. package/tailwind.config.js +0 -83
  144. package/tsconfig.json +0 -19
  145. package/vite.config.ts +0 -43
@@ -1,72 +0,0 @@
1
- import classNames from "classnames";
2
- import { Children, cloneElement, useRef } from "react";
3
-
4
- interface GridProps {
5
- children: React.ReactNode | React.ReactNode[];
6
- }
7
- export function Grid({ children }: GridProps): React.ReactElement {
8
- const leftColHeaderRef = useRef<HTMLDivElement>(null);
9
- const leftColBodyRef = useRef<HTMLDivElement>(null);
10
- const rightColHeaderRef = useRef<HTMLDivElement>(null);
11
- const rightColBodyRef = useRef<HTMLDivElement>(null);
12
-
13
- const [headerRow, bodyRow] = Children.toArray(children);
14
-
15
- return (
16
- <div className="flex flex-col w-full h-screen bg-warm-black overflow-clip">
17
- {cloneElement(headerRow as React.ReactElement, {
18
- leftColRef: leftColHeaderRef,
19
- rightColRef: rightColHeaderRef,
20
- })}
21
- {cloneElement(bodyRow as React.ReactElement, {
22
- leftColRef: leftColBodyRef,
23
- rightColRef: rightColBodyRef,
24
- })}
25
- </div>
26
- );
27
- }
28
-
29
- type GridRowProps = {
30
- children: React.ReactNode | React.ReactNode[];
31
- leftColRef?: React.RefObject<HTMLDivElement>;
32
- rightColRef?: React.RefObject<HTMLDivElement>;
33
- fill?: boolean;
34
- };
35
-
36
- Grid.Row = ({
37
- children,
38
- leftColRef,
39
- rightColRef,
40
- fill: bottomRow = false,
41
- }: GridRowProps): React.ReactElement => {
42
- const [leftCol, middleCol, rightCol] = Children.toArray(children);
43
- //implement mouseover event to share hover-event between rows
44
- console;
45
- return (
46
- <div
47
- className={classNames("flex w-full py-2 border-b border-dark-gray", {
48
- "h-full": bottomRow,
49
- })}
50
- >
51
- <div className="relative" style={{ width: "300px" }} ref={leftColRef}>
52
- {leftCol}
53
- {bottomRow && (
54
- <div
55
- className="absolute inset-y-0 right-0 cursor-col-resize w-[1px] bg-dark-gray hover:w-[2px] hover:bg-light-gray -my-[100px]"
56
- // onMouseDown={handleMouseDown("left")}
57
- ></div>
58
- )}
59
- </div>
60
- <div className="flex-auto">{middleCol}</div>
61
- <div className="relative" style={{ width: "300px" }} ref={rightColRef}>
62
- {rightCol}
63
- {bottomRow && (
64
- <div
65
- // onMouseDown={handleMouseDown("right")}
66
- className="absolute inset-y-0 left-0 cursor-col-resize w-[1px] bg-dark-gray hover:w-[2px] hover:bg-light-gray -my-2"
67
- ></div>
68
- )}
69
- </div>
70
- </div>
71
- );
72
- };
@@ -1,91 +0,0 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import { Tree } from "./Tree";
3
-
4
- const meta: Meta<typeof Tree> = { component: Tree };
5
-
6
- export default meta;
7
- type Story = StoryObj<typeof Tree>;
8
-
9
- type Node = {
10
- path: string;
11
- type: "string" | "image" | "section";
12
- children: Node[];
13
- };
14
-
15
- const nodes: Node[] = [
16
- {
17
- path: "Main nav",
18
- type: "section",
19
- children: [],
20
- },
21
- {
22
- path: "H1",
23
- type: "string",
24
- children: [
25
- {
26
- path: "Section 3",
27
- type: "string",
28
- children: [],
29
- },
30
- {
31
- path: "Section 4",
32
- type: "section",
33
- children: [
34
- {
35
- path: "Section 5",
36
- type: "string",
37
- children: [],
38
- },
39
- {
40
- path: "Section 6",
41
- type: "section",
42
- children: [
43
- {
44
- path: "Section 7",
45
- type: "string",
46
- children: [],
47
- },
48
- {
49
- path: "Image 1",
50
- type: "image",
51
- children: [],
52
- },
53
- {
54
- path: "Image 2",
55
- type: "image",
56
- children: [],
57
- },
58
- ],
59
- },
60
- ],
61
- },
62
- ],
63
- },
64
- ];
65
-
66
- const renderNodes = (node: Node) => (
67
- <Tree.Node path={node.path} type={node.type}>
68
- {node.children.map(renderNodes)}
69
- </Tree.Node>
70
- );
71
-
72
- export const Default: Story = {
73
- render: () => (
74
- <Tree rootPath="root">
75
- <Tree.Node path="Main nav" type="section" />
76
- <Tree.Node path="H1" type="string">
77
- <Tree.Node path="Section 3" type="string" />
78
- <Tree.Node path="Section 4" type="section">
79
- <Tree.Node path="Section 5" type="string" />
80
- <Tree.Node path="Section 6" type="section">
81
- <Tree.Node path="Section 7" type="string" />
82
- </Tree.Node>
83
- </Tree.Node>
84
- </Tree.Node>
85
- </Tree>
86
- ),
87
- };
88
-
89
- export const TestData: Story = {
90
- render: () => <Tree rootPath="root">{nodes.map(renderNodes)}</Tree>,
91
- };
@@ -1,72 +0,0 @@
1
- import { Children, cloneElement } from "react";
2
- import ImageIcon from "../../assets/icons/ImageIcon";
3
- import Section from "../../assets/icons/Section";
4
- import TextIcon from "../../assets/icons/TextIcon";
5
-
6
- type TreeProps = {
7
- children: React.ReactNode | React.ReactNode[];
8
- rootPath?: string;
9
- };
10
- export function Tree({ children, rootPath }: TreeProps): React.ReactElement {
11
- return (
12
- <div className="flex flex-col w-full py-2 text-xs">
13
- {Children.map(children, (child) => {
14
- return cloneElement(child as React.ReactElement, {
15
- paths: [rootPath],
16
- });
17
- })}
18
- </div>
19
- );
20
- }
21
- type TreeNodeProps = {
22
- children?: React.ReactNode | React.ReactNode[];
23
- path: string;
24
- paths?: string[];
25
- level?: number;
26
- type: "string" | "image" | "section";
27
- setActivePath?: (path: string) => void;
28
- };
29
- Tree.Node = ({
30
- children,
31
- paths = [],
32
- path,
33
- level = 1,
34
- type,
35
- setActivePath,
36
- }: TreeNodeProps): React.ReactElement => {
37
- const paddingLeft = level * 30;
38
- const logo =
39
- type === "string" ? (
40
- <TextIcon />
41
- ) : type === "image" ? (
42
- <ImageIcon className="h-[9px] w-[9px]" />
43
- ) : (
44
- <Section />
45
- );
46
- return (
47
- <div className="w-full">
48
- <button
49
- className="flex justify-between w-full group py-2 text-xs font-[400] shrink-0"
50
- onClick={() => {
51
- setActivePath && setActivePath(path);
52
- }}
53
- style={{ paddingLeft: paddingLeft }}
54
- >
55
- <div className="flex items-center justify-center gap-2">
56
- {logo}
57
- <p>{path}</p>
58
- </div>
59
- </button>
60
- {children && (
61
- <>
62
- {Children.map(children, (child) => {
63
- return cloneElement(child as React.ReactElement, {
64
- level: level + 1,
65
- paths: [...paths, path],
66
- });
67
- })}
68
- </>
69
- )}
70
- </div>
71
- );
72
- };
@@ -1,269 +0,0 @@
1
- import { SerializedModule } from "@valbuild/core";
2
- import { ValApi } from "@valbuild/core";
3
- import { LexicalEditor } from "lexical";
4
- import { FC, useEffect, useState } from "react";
5
- import { Inputs, RichTextEditor } from "../../exports";
6
- import Button from "../Button";
7
- import { ImageForm } from "../forms/ImageForm";
8
- import { TextArea } from "../forms/TextArea";
9
-
10
- interface ValDashboardEditorProps {
11
- selectedPath: string;
12
- valApi: ValApi;
13
- }
14
-
15
- export const ValDashboardEditor: FC<ValDashboardEditorProps> = ({
16
- selectedPath,
17
- }) => {
18
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
19
- const [selectedModule, setSelectedModule] = useState<SerializedModule>();
20
- const [inputs, setInputs] = useState<Inputs>({});
21
- const [inputIsDirty, setInputIsDirty] = useState<{ [path: string]: boolean }>(
22
- {}
23
- );
24
- const [richTextEditor, setRichTextEditor] = useState<{
25
- [path: string]: LexicalEditor;
26
- }>();
27
-
28
- useEffect(() => {
29
- // if (selectedPath) {
30
- // valApi.getModule(selectedPath).then((module) => {
31
- // setSelectedModule(module);
32
- // });
33
- // }
34
- }, [selectedPath]);
35
-
36
- useEffect(() => {
37
- // if (selectedModule && selectedModule?.source) {
38
- // setInputs({});
39
- // for (const key of Object.keys(selectedModule?.source)) {
40
- // if (key !== "rank") {
41
- // valApi
42
- // .getModule(`${selectedModule.path}.${key}`)
43
- // .then((serializedModule) => {
44
- // let input: Inputs[string] | undefined;
45
- // if (
46
- // serializedModule.schema.type === "string" &&
47
- // typeof serializedModule.source === "string"
48
- // ) {
49
- // input = {
50
- // status: "completed",
51
- // type: "text",
52
- // data: serializedModule.source,
53
- // };
54
- // } else if (
55
- // serializedModule.schema.type === "richtext" &&
56
- // typeof serializedModule.source === "object"
57
- // ) {
58
- // input = {
59
- // status: "completed",
60
- // type: "richtext",
61
- // data: serializedModule.source as RichText, // TODO: validate
62
- // };
63
- // } else if (
64
- // serializedModule.schema.type === "image" &&
65
- // serializedModule.source &&
66
- // typeof serializedModule.source === "object" &&
67
- // FILE_REF_PROP in serializedModule.source &&
68
- // typeof serializedModule.source[FILE_REF_PROP] === "string" &&
69
- // VAL_EXTENSION in serializedModule.source &&
70
- // typeof serializedModule.source[VAL_EXTENSION] === "string"
71
- // ) {
72
- // input = {
73
- // status: "completed",
74
- // type: "image",
75
- // data: Internal.convertImageSource(
76
- // serializedModule.source as FileSource<ImageMetadata>
77
- // ),
78
- // };
79
- // }
80
- // if (!input) {
81
- // throw new Error(
82
- // `Unsupported module type: ${serializedModule.schema.type}`
83
- // );
84
- // }
85
- // setInputs((inputs) => {
86
- // return {
87
- // ...inputs,
88
- // [serializedModule.path]: input,
89
- // } as Inputs;
90
- // });
91
- // });
92
- // }
93
- // }
94
- // }
95
- }, [selectedModule]);
96
-
97
- useEffect(() => {
98
- for (const key of Object.keys(inputs)) {
99
- if (!Object.keys(inputIsDirty).includes(key)) {
100
- setInputIsDirty({
101
- ...inputIsDirty,
102
- [key]: false,
103
- });
104
- }
105
- }
106
- }, [inputs]);
107
-
108
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
109
- const patchElement = async (path: string) => {
110
- // Promise.all(
111
- // Object.entries(inputs)
112
- // .filter(([k]) => k === key)
113
- // .map(([path, input]) => {
114
- // if (input.status === "completed") {
115
- // const [moduleId, modulePath] = Internal.splitModuleIdAndModulePath(
116
- // path as SourcePath
117
- // );
118
- // if (input.type === "text") {
119
- // const patch: PatchJSON = [
120
- // {
121
- // value: input.data,
122
- // op: "replace",
123
- // path: `/${modulePath
124
- // .split(".")
125
- // .map((p) => {
126
- // return JSON.parse(p);
127
- // })
128
- // .join("/")}`,
129
- // },
130
- // ];
131
- // console.log("patch", patch);
132
- // return valApi.patchModuleContent(moduleId, patch);
133
- // } else if (input.type === "image") {
134
- // const pathParts = modulePath.split(".").map((p) => JSON.parse(p));
135
- // if (!input?.data || !("src" in input.data)) {
136
- // // TODO: We probably need to have an Output type that is different from the Input: we have a union of both cases in Input right now, and we believe we do not want that
137
- // console.warn(
138
- // "No .src on input provided - this might mean no changes was made"
139
- // );
140
- // return;
141
- // }
142
- // const patch: PatchJSON = [
143
- // {
144
- // value: input.data.src,
145
- // op: "replace",
146
- // path: `/${pathParts.slice(0, -1).join("/")}/$${
147
- // pathParts[pathParts.length - 1]
148
- // }`,
149
- // },
150
- // ];
151
- // if (input.data.metadata) {
152
- // if (input.data.addMetadata) {
153
- // patch.push({
154
- // value: input.data.metadata,
155
- // op: "add",
156
- // path: `/${pathParts.join("/")}/metadata`,
157
- // });
158
- // } else {
159
- // patch.push({
160
- // value: input.data.metadata,
161
- // op: "replace",
162
- // path: `/${pathParts.join("/")}/metadata`,
163
- // });
164
- // }
165
- // }
166
- // console.log("patch", patch);
167
- // return valApi.patchModuleContent(moduleId, patch);
168
- // } else if (input.type === "richtext") {
169
- // const patch: PatchJSON = [
170
- // {
171
- // value: input.data,
172
- // op: "replace",
173
- // path: `/${modulePath
174
- // .split(".")
175
- // .map((p) => JSON.parse(p))
176
- // .join("/")}`,
177
- // },
178
- // ];
179
- // return valApi.patchModuleContent(moduleId, patch);
180
- // }
181
- // // eslint-disable-next-line @typescript-eslint/no-explicit-any
182
- // throw new Error(`Unsupported input type: ${(input as any).type}`);
183
- // } else {
184
- // console.error("Submitted incomplete input, ignoring...");
185
- // return Promise.resolve();
186
- // }
187
- // })
188
- // ).then((res) => {
189
- // console.log("patched", res);
190
- // });
191
- };
192
-
193
- return (
194
- <div className="flex flex-col items-start px-4">
195
- {selectedModule ? (
196
- <div className="flex flex-col items-start w-full py-3 gap-[36px] font-normal">
197
- {Object.entries(inputs).map(([path, input]) => {
198
- return (
199
- <div key={path} className={"flex flex-col justify-start "}>
200
- {input.status === "requested" && (
201
- <div className="p-2 text-center text-primary">Loading...</div>
202
- )}
203
- <div className="flex flex-col gap-1 font-[550]">
204
- <p>{path.split(".").slice(-1)[0].split('"').join("")}</p>
205
- {input.status === "completed" && input.type === "image" && (
206
- <ImageForm
207
- name={path}
208
- data={input.data}
209
- onChange={(data) => {
210
- if (data.value) {
211
- setInputs({
212
- ...inputs,
213
- [path]: {
214
- status: "completed",
215
- type: "image",
216
- data: data.value,
217
- },
218
- });
219
- setInputIsDirty({ ...inputIsDirty, [path]: true });
220
- }
221
- }}
222
- error={null}
223
- />
224
- )}
225
- {input.status === "completed" && input.type === "text" && (
226
- <TextArea
227
- name={path}
228
- text={input.data}
229
- onChange={(data) => {
230
- setInputs({
231
- ...inputs,
232
- [path]: {
233
- status: "completed",
234
- type: "text",
235
- data: data,
236
- },
237
- });
238
- setInputIsDirty({ ...inputIsDirty, [path]: true });
239
- }}
240
- />
241
- )}
242
- {input.status === "completed" &&
243
- input.type === "richtext" && (
244
- <RichTextEditor
245
- richtext={input.data}
246
- onEditor={(editor) => {
247
- setRichTextEditor({
248
- ...richTextEditor,
249
- [path]: editor,
250
- });
251
- }}
252
- />
253
- )}
254
- {inputIsDirty[path] && (
255
- <Button onClick={() => patchElement(path)}>
256
- Save changes
257
- </Button>
258
- )}
259
- </div>
260
- </div>
261
- );
262
- })}
263
- </div>
264
- ) : (
265
- <h1 className="px-4 py-3">No module selected</h1>
266
- )}
267
- </div>
268
- );
269
- };
@@ -1,142 +0,0 @@
1
- import { SerializedModule } from "@valbuild/core";
2
- import { ValApi } from "@valbuild/core";
3
- import classNames from "classnames";
4
- import React, { useState, FC, ReactNode, useEffect } from "react";
5
- import { ValDashboardEditor } from "./ValDashboardEditor";
6
- import { ValTreeNavigator } from "./ValTreeNavigator";
7
-
8
- interface PanelProps {
9
- header?: ReactNode;
10
- width?: number;
11
- onResize?: (width: number) => void;
12
- collapsible?: boolean;
13
- collapsed?: boolean;
14
- onCollapse?: () => void;
15
- children: ReactNode;
16
- }
17
-
18
- const Panel: FC<PanelProps> = ({
19
- header,
20
- width,
21
- onResize,
22
- collapsible,
23
- collapsed,
24
- onCollapse,
25
- children,
26
- }) => {
27
- const handleMouseDown = (e: React.MouseEvent) => {
28
- if (!onResize) return;
29
-
30
- e.preventDefault();
31
- const initialX = e.clientX;
32
- const initialWidth = width || 0;
33
-
34
- const handleMouseMove = (moveEvent: MouseEvent) => {
35
- const newWidth = initialWidth + moveEvent.clientX - initialX;
36
- onResize(newWidth);
37
- };
38
-
39
- const handleMouseUp = () => {
40
- window.removeEventListener("mousemove", handleMouseMove);
41
- window.removeEventListener("mouseup", handleMouseUp);
42
- };
43
-
44
- window.addEventListener("mousemove", handleMouseMove);
45
- window.addEventListener("mouseup", handleMouseUp);
46
- };
47
- return (
48
- <>
49
- {!collapsed ? (
50
- <div
51
- className={classNames(
52
- "relative border border-dark-gray min-w-0 h-full overflow-auto",
53
- {
54
- "flex-grow": !width,
55
- }
56
- )}
57
- style={width ? { width: `${width}px` } : {}}
58
- >
59
- {onResize && (
60
- <div
61
- className="absolute inset-y-0 right-0 cursor-col-resize w-[1px] bg-dark-gray hover:w-[2px] hover:bg-light-gray"
62
- onMouseDown={handleMouseDown}
63
- />
64
- )}
65
- <div className="bg-gray-300 border border-dark-gray flex justify-between items-center h-[75px] w-full font-serif px-4">
66
- {header}
67
- {collapsible && (
68
- <button
69
- onClick={onCollapse}
70
- className="px-2 py-1 font-bold text-white bg-red-500 rounded hover:bg-red-700"
71
- >
72
- {collapsed ? "Expand" : "Collapse"}
73
- </button>
74
- )}
75
- </div>
76
- <div>{children}</div>
77
- </div>
78
- ) : (
79
- <button
80
- onClick={onCollapse}
81
- className="absolute inset-y-0 right-[16px] w-fit flex items-center justify-end"
82
- >
83
- open panel again
84
- </button>
85
- )}
86
- </>
87
- );
88
- };
89
-
90
- interface ValDashboardGridProps {
91
- valApi: ValApi;
92
- editMode: boolean;
93
- }
94
-
95
- export const ValDashboardGrid: FC<ValDashboardGridProps> = ({
96
- valApi,
97
- editMode,
98
- }) => {
99
- const [widths, setWidths] = useState([300, (2 * window.innerWidth) / 3]);
100
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
101
- const [modules, setModules] = useState<SerializedModule[]>([]);
102
- const [selectedPath, setSelectedPath] = useState<string>("");
103
- useEffect(() => {
104
- // valApi.getTree({}).then((modules) => {
105
- // setModules(modules);
106
- // });
107
- }, [editMode]);
108
-
109
- const handleResize = (index: number) => (width: number) => {
110
- setWidths((prevWidths) => {
111
- const newWidths = [...prevWidths];
112
- newWidths[index] = Math.max(width, 300);
113
- return newWidths;
114
- });
115
- };
116
-
117
- return (
118
- <div className="flex justify-start h-screen">
119
- <Panel width={widths[0]} onResize={handleResize(0)}>
120
- <ValTreeNavigator
121
- modules={modules}
122
- selectedModule={selectedPath}
123
- setSelectedModule={setSelectedPath}
124
- valApi={valApi}
125
- />
126
- </Panel>
127
- <Panel
128
- header={
129
- selectedPath && (
130
- <div className="w-full max-w-[1000px] bg-dark-gray px-4 py-2 rounded-lg">
131
- {selectedPath}
132
- </div>
133
- )
134
- }
135
- width={widths[1]}
136
- onResize={handleResize(1)}
137
- >
138
- <ValDashboardEditor selectedPath={selectedPath} valApi={valApi} />
139
- </Panel>
140
- </div>
141
- );
142
- };