@valbuild/ui 0.15.0 → 0.17.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/valbuild-ui.cjs.d.ts +13 -18
- package/dist/valbuild-ui.cjs.js +7599 -1654
- package/dist/valbuild-ui.esm.js +7600 -1655
- package/package.json +5 -2
- package/src/assets/icons/ImageIcon.tsx +15 -7
- package/src/assets/icons/Section.tsx +41 -0
- package/src/assets/icons/TextIcon.tsx +20 -0
- package/src/components/Button.tsx +18 -7
- package/src/components/DraggableList.stories.tsx +20 -0
- package/src/components/DraggableList.tsx +95 -0
- package/src/components/Dropdown.tsx +2 -0
- package/src/components/ExpandLogo.tsx +72 -0
- package/src/components/RichTextEditor/Plugins/Toolbar.tsx +1 -16
- package/src/components/RichTextEditor/RichTextEditor.tsx +2 -2
- package/src/components/User.tsx +17 -0
- package/src/components/ValMenu.tsx +40 -0
- package/src/components/ValOverlay.tsx +513 -29
- package/src/components/ValOverlayContext.tsx +63 -0
- package/src/components/ValWindow.stories.tsx +3 -3
- package/src/components/ValWindow.tsx +26 -18
- package/src/components/dashboard/DashboardButton.tsx +25 -0
- package/src/components/dashboard/DashboardDropdown.tsx +59 -0
- package/src/components/dashboard/Dropdown.stories.tsx +11 -0
- package/src/components/dashboard/Dropdown.tsx +70 -0
- package/src/components/dashboard/FormGroup.stories.tsx +37 -0
- package/src/components/dashboard/FormGroup.tsx +36 -0
- package/src/components/dashboard/Grid.stories.tsx +52 -0
- package/src/components/dashboard/Grid.tsx +126 -0
- package/src/components/dashboard/Grid2.stories.tsx +56 -0
- package/src/components/dashboard/Grid2.tsx +72 -0
- package/src/components/dashboard/Tree.stories.tsx +91 -0
- package/src/components/dashboard/Tree.tsx +72 -0
- package/src/components/dashboard/ValDashboard.tsx +148 -0
- package/src/components/dashboard/ValDashboardEditor.tsx +269 -0
- package/src/components/dashboard/ValDashboardGrid.tsx +142 -0
- package/src/components/dashboard/ValTreeNavigator.tsx +253 -0
- package/src/components/forms/Form.tsx +2 -2
- package/src/components/forms/{TextForm.tsx → TextArea.tsx} +5 -3
- package/src/dto/SerializedSchema.ts +69 -0
- package/src/dto/Session.ts +12 -0
- package/src/dto/SessionMode.ts +5 -0
- package/src/dto/Tree.ts +18 -0
- package/src/exports.ts +1 -0
- package/src/utils/Remote.ts +15 -0
- package/src/utils/resolvePath.ts +33 -0
- package/tailwind.config.js +20 -1
|
@@ -0,0 +1,142 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { Internal, SerializedModule, SourcePath } from "@valbuild/core";
|
|
2
|
+
import { Json, JsonArray } from "@valbuild/core/src/Json";
|
|
3
|
+
import { ValApi } from "@valbuild/core";
|
|
4
|
+
import classNames from "classnames";
|
|
5
|
+
import { Dispatch, FC, SetStateAction, useState } from "react";
|
|
6
|
+
import Chevron from "../../assets/icons/Chevron";
|
|
7
|
+
import { DraggableList, DraggableResult } from "../DraggableList";
|
|
8
|
+
|
|
9
|
+
const ValTreeArrayModuleItem: FC<{
|
|
10
|
+
submodule: Json;
|
|
11
|
+
selectedModule: string;
|
|
12
|
+
setSelectedModule: Dispatch<SetStateAction<string>>;
|
|
13
|
+
idx: number;
|
|
14
|
+
path: string;
|
|
15
|
+
reOrder: (oldIdx: number, newIdx: number) => void;
|
|
16
|
+
reorderMode: boolean;
|
|
17
|
+
}> = ({
|
|
18
|
+
submodule,
|
|
19
|
+
selectedModule,
|
|
20
|
+
setSelectedModule,
|
|
21
|
+
idx,
|
|
22
|
+
path,
|
|
23
|
+
reOrder,
|
|
24
|
+
reorderMode,
|
|
25
|
+
}) => {
|
|
26
|
+
const title = resolveTitle(submodule);
|
|
27
|
+
return (
|
|
28
|
+
<div className="w-fit" draggable id={idx.toString()}>
|
|
29
|
+
<div className="flex gap-4">
|
|
30
|
+
<button
|
|
31
|
+
onClick={() => setSelectedModule(path + idx.toString())}
|
|
32
|
+
className={classNames(
|
|
33
|
+
"px-4 py-2 text-start hover:bg-light-gray/20 hover:rounded-lg",
|
|
34
|
+
{
|
|
35
|
+
"font-extrabold ":
|
|
36
|
+
module.path + idx.toString() === selectedModule,
|
|
37
|
+
}
|
|
38
|
+
)}
|
|
39
|
+
>
|
|
40
|
+
{title}
|
|
41
|
+
</button>
|
|
42
|
+
{reorderMode && (
|
|
43
|
+
<div className="flex gap-2">
|
|
44
|
+
<button
|
|
45
|
+
onClick={() => reOrder(idx, idx + 1)}
|
|
46
|
+
className="disabled:text-dark-gray"
|
|
47
|
+
>
|
|
48
|
+
<Chevron className="rotate-90" />
|
|
49
|
+
</button>
|
|
50
|
+
<button
|
|
51
|
+
onClick={() => reOrder(idx, idx - 1)}
|
|
52
|
+
className="disabled:text-dark-gray"
|
|
53
|
+
>
|
|
54
|
+
<Chevron className="-rotate-90" />
|
|
55
|
+
</button>
|
|
56
|
+
</div>
|
|
57
|
+
)}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const DEFAULT_TITLE = "Untitled";
|
|
64
|
+
function resolveTitle(submodule: Json): string {
|
|
65
|
+
if (!submodule) {
|
|
66
|
+
return DEFAULT_TITLE;
|
|
67
|
+
}
|
|
68
|
+
if (typeof submodule === "string") {
|
|
69
|
+
return submodule;
|
|
70
|
+
}
|
|
71
|
+
if (typeof submodule === "object") {
|
|
72
|
+
if ("title" in submodule && typeof submodule.title === "string") {
|
|
73
|
+
return submodule.title;
|
|
74
|
+
}
|
|
75
|
+
if ("name" in submodule && typeof submodule.name === "string") {
|
|
76
|
+
return submodule.name;
|
|
77
|
+
}
|
|
78
|
+
const firstStringField = Object.entries(submodule).find(([, value]) => {
|
|
79
|
+
return typeof value === "string";
|
|
80
|
+
})?.[1];
|
|
81
|
+
if (typeof firstStringField === "string") {
|
|
82
|
+
return firstStringField;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return DEFAULT_TITLE;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const ValTreeNavigatorArrayModule: FC<{
|
|
89
|
+
module: SerializedModule;
|
|
90
|
+
selectedModule: string;
|
|
91
|
+
setSelectedModule: Dispatch<SetStateAction<string>>;
|
|
92
|
+
valApi: ValApi;
|
|
93
|
+
}> = ({ module, selectedModule, setSelectedModule }) => {
|
|
94
|
+
const [collapsed, setCollapsed] = useState(true);
|
|
95
|
+
const [items, setItems] = useState<Json[]>(
|
|
96
|
+
(module.source as JsonArray).map((submodule) => submodule as Json)
|
|
97
|
+
);
|
|
98
|
+
const [reOrderMode, setReOrderMode] = useState(false);
|
|
99
|
+
|
|
100
|
+
const reOrder = async (oldIndex: number, newIndex: number) => {
|
|
101
|
+
const sanitizedNewIndex =
|
|
102
|
+
newIndex < 0 ? items.length - 1 : newIndex % items.length;
|
|
103
|
+
const path = module.path + oldIndex.toString();
|
|
104
|
+
const newPath = module.path + sanitizedNewIndex.toString();
|
|
105
|
+
// const [moduleId, modulePath] = Internal.splitModuleIdAndModulePath(
|
|
106
|
+
// path as SourcePath
|
|
107
|
+
// );
|
|
108
|
+
|
|
109
|
+
const [newModuleId, newModulePath] = Internal.splitModuleIdAndModulePath(
|
|
110
|
+
newPath as SourcePath
|
|
111
|
+
);
|
|
112
|
+
// const patch: PatchJSON = [
|
|
113
|
+
// {
|
|
114
|
+
// op: "move",
|
|
115
|
+
// from: `/${modulePath
|
|
116
|
+
// .split(".")
|
|
117
|
+
// .map((p) => {
|
|
118
|
+
// return JSON.parse(p);
|
|
119
|
+
// })
|
|
120
|
+
// .join("/")}`,
|
|
121
|
+
// path: `/${newModulePath
|
|
122
|
+
// .split(".")
|
|
123
|
+
// .map((p) => {
|
|
124
|
+
// return JSON.parse(p);
|
|
125
|
+
// })
|
|
126
|
+
// .join("/")}`,
|
|
127
|
+
// },
|
|
128
|
+
// ];
|
|
129
|
+
// await valApi.patchModuleContent(moduleId, patch);
|
|
130
|
+
if (selectedModule === path) {
|
|
131
|
+
setSelectedModule(`${newModuleId}.${newModulePath}`);
|
|
132
|
+
}
|
|
133
|
+
setItems((items) => {
|
|
134
|
+
const newItems = [...items];
|
|
135
|
+
const item = newItems.splice(oldIndex, 1)[0];
|
|
136
|
+
newItems.splice(sanitizedNewIndex, 0, item);
|
|
137
|
+
return newItems;
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const toggleReorderMode = () => {
|
|
142
|
+
setReOrderMode(!reOrderMode);
|
|
143
|
+
if (collapsed) setCollapsed(false);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<div className="relative flex flex-col gap-3">
|
|
148
|
+
<div className="flex items-center justify-between ">
|
|
149
|
+
<button
|
|
150
|
+
className="flex items-center justify-between px-4 py-2 hover:bg-light-gray/20 hover:rounded-lg "
|
|
151
|
+
onClick={() => {
|
|
152
|
+
setSelectedModule(`${module.path.toString()}`);
|
|
153
|
+
setCollapsed(!collapsed);
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
<div className="flex items-center gap-2">
|
|
157
|
+
<Chevron className={classNames({ "rotate-90": !collapsed })} />
|
|
158
|
+
<h1 className="text-xl">{module.path}</h1>
|
|
159
|
+
</div>
|
|
160
|
+
</button>
|
|
161
|
+
<div className="flex gap-2">
|
|
162
|
+
<button
|
|
163
|
+
className="relative w-[20px] h-[20px] flex flex-col justify-between items-center"
|
|
164
|
+
onClick={toggleReorderMode}
|
|
165
|
+
>
|
|
166
|
+
<Chevron className="top-0 -rotate-90" />
|
|
167
|
+
<Chevron className="rotate-90 " />
|
|
168
|
+
</button>
|
|
169
|
+
<button className="text-2xl w-[20px] h-[20px] rounded-full flex justify-center items-center">
|
|
170
|
+
+
|
|
171
|
+
</button>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
175
|
+
{!collapsed && (
|
|
176
|
+
<DraggableList
|
|
177
|
+
onDragEnd={(res: DraggableResult) => reOrder(res.from, res.to)}
|
|
178
|
+
>
|
|
179
|
+
{items.map((submodule, idx) => (
|
|
180
|
+
<ValTreeArrayModuleItem
|
|
181
|
+
submodule={submodule}
|
|
182
|
+
idx={idx}
|
|
183
|
+
selectedModule={selectedModule}
|
|
184
|
+
setSelectedModule={setSelectedModule}
|
|
185
|
+
path={module.path}
|
|
186
|
+
key={idx}
|
|
187
|
+
reOrder={reOrder}
|
|
188
|
+
reorderMode={reOrderMode}
|
|
189
|
+
/>
|
|
190
|
+
))}
|
|
191
|
+
</DraggableList>
|
|
192
|
+
)}
|
|
193
|
+
</div>
|
|
194
|
+
);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const ValTreeNavigatorModule: FC<{
|
|
198
|
+
module: SerializedModule;
|
|
199
|
+
setSelectedModule: Dispatch<SetStateAction<string>>;
|
|
200
|
+
}> = ({ module, setSelectedModule }) => {
|
|
201
|
+
return (
|
|
202
|
+
<div className="relative flex flex-col gap-3 px-4 py-2 hover:bg-light-gray/20 hover:rounded-lg ">
|
|
203
|
+
<button
|
|
204
|
+
className="flex items-center justify-between"
|
|
205
|
+
onClick={() => setSelectedModule(module.path)}
|
|
206
|
+
>
|
|
207
|
+
<div className="flex items-center gap-2">
|
|
208
|
+
<Chevron className={classNames("opacity-0")} />
|
|
209
|
+
<h1 className="text-xl">{module.path}</h1>
|
|
210
|
+
</div>
|
|
211
|
+
</button>
|
|
212
|
+
</div>
|
|
213
|
+
);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
interface ValTreeNavigator {
|
|
217
|
+
modules: SerializedModule[];
|
|
218
|
+
selectedModule: string;
|
|
219
|
+
setSelectedModule: Dispatch<SetStateAction<string>>;
|
|
220
|
+
valApi: ValApi;
|
|
221
|
+
}
|
|
222
|
+
export const ValTreeNavigator: FC<ValTreeNavigator> = ({
|
|
223
|
+
modules,
|
|
224
|
+
selectedModule,
|
|
225
|
+
setSelectedModule,
|
|
226
|
+
valApi,
|
|
227
|
+
}) => {
|
|
228
|
+
console.log("hello?????????????", modules);
|
|
229
|
+
return (
|
|
230
|
+
<div
|
|
231
|
+
className={classNames("flex flex-col gap-4 font-serif text-lg px-4 py-3")}
|
|
232
|
+
>
|
|
233
|
+
{modules.map((module, idx) => (
|
|
234
|
+
<div key={idx}>
|
|
235
|
+
{module.schema.type === "array" ? (
|
|
236
|
+
<ValTreeNavigatorArrayModule
|
|
237
|
+
module={module}
|
|
238
|
+
key={idx}
|
|
239
|
+
selectedModule={selectedModule}
|
|
240
|
+
setSelectedModule={setSelectedModule}
|
|
241
|
+
valApi={valApi}
|
|
242
|
+
/>
|
|
243
|
+
) : (
|
|
244
|
+
<ValTreeNavigatorModule
|
|
245
|
+
module={module}
|
|
246
|
+
setSelectedModule={setSelectedModule}
|
|
247
|
+
/>
|
|
248
|
+
)}
|
|
249
|
+
</div>
|
|
250
|
+
))}
|
|
251
|
+
</div>
|
|
252
|
+
);
|
|
253
|
+
};
|
|
@@ -4,7 +4,7 @@ import { useEffect, useState } from "react";
|
|
|
4
4
|
import { RichTextEditor } from "../RichTextEditor/RichTextEditor";
|
|
5
5
|
import { FormContainer } from "./FormContainer";
|
|
6
6
|
import { ImageForm, ImageData } from "./ImageForm";
|
|
7
|
-
import { TextData,
|
|
7
|
+
import { TextData, TextArea } from "./TextArea";
|
|
8
8
|
|
|
9
9
|
export type Inputs = {
|
|
10
10
|
[path: string]:
|
|
@@ -89,7 +89,7 @@ export function Form({ onSubmit, inputs }: FormProps): React.ReactElement {
|
|
|
89
89
|
/>
|
|
90
90
|
)}
|
|
91
91
|
{input.status === "completed" && input.type === "text" && (
|
|
92
|
-
<
|
|
92
|
+
<TextArea
|
|
93
93
|
name={path}
|
|
94
94
|
text={input.data}
|
|
95
95
|
onChange={(data) => {
|
|
@@ -2,18 +2,20 @@ export type TextData = string;
|
|
|
2
2
|
export type TextInputProps = {
|
|
3
3
|
name: string;
|
|
4
4
|
text: TextData;
|
|
5
|
+
disabled?: boolean;
|
|
5
6
|
onChange: (value: string) => void;
|
|
6
7
|
};
|
|
7
8
|
|
|
8
|
-
export function
|
|
9
|
+
export function TextArea({ name, disabled, text, onChange }: TextInputProps) {
|
|
9
10
|
return (
|
|
10
11
|
<div
|
|
11
|
-
className="w-full py-2 grow-wrap"
|
|
12
|
+
className="w-full h-full py-2 overflow-y-scroll grow-wrap"
|
|
12
13
|
data-replicated-value={text} /* see grow-wrap */
|
|
13
14
|
>
|
|
14
15
|
<textarea
|
|
16
|
+
disabled={disabled}
|
|
15
17
|
name={name}
|
|
16
|
-
className="
|
|
18
|
+
className="p-2 border outline-none resize-none bg-fill text-primary border-border focus-visible:border-highlight"
|
|
17
19
|
defaultValue={text}
|
|
18
20
|
onChange={(e) => onChange(e.target.value)}
|
|
19
21
|
/>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export default {};
|
|
2
|
+
// TODO:
|
|
3
|
+
// import type { SerializedSchema as SerializedSchemaT } from "@valbuild/core";
|
|
4
|
+
// import { z } from "zod";
|
|
5
|
+
//
|
|
6
|
+
// export const SerializedSchema: z.ZodType<SerializedSchemaT> = z.lazy(() => {
|
|
7
|
+
// const SerializedStringSchema = z.object({
|
|
8
|
+
// _type: z.literal("string"),
|
|
9
|
+
// opt: z.boolean(),
|
|
10
|
+
// });
|
|
11
|
+
// const SerializedBooleanSchema = z.object({
|
|
12
|
+
// _type: z.literal("boolean"),
|
|
13
|
+
// opt: z.boolean(),
|
|
14
|
+
// });
|
|
15
|
+
// const SerializedNumberSchema = z.object({
|
|
16
|
+
// _type: z.literal("number"),
|
|
17
|
+
// opt: z.boolean(),
|
|
18
|
+
// });
|
|
19
|
+
// const SerializedLiteralSchema = z.object({
|
|
20
|
+
// _type: z.literal("literal"),
|
|
21
|
+
// value: z.string(),
|
|
22
|
+
// opt: z.boolean(),
|
|
23
|
+
// });
|
|
24
|
+
// const SerializedObjectSchema = z.object({
|
|
25
|
+
// _type: z.literal("object"),
|
|
26
|
+
// opt: z.boolean(),
|
|
27
|
+
// items: z.record(SerializedSchema),
|
|
28
|
+
// });
|
|
29
|
+
// const SerializedOneOfSchema = z.object({
|
|
30
|
+
// _type: z.literal("oneOf"),
|
|
31
|
+
// opt: z.boolean(),
|
|
32
|
+
// });
|
|
33
|
+
// const SerializedArraySchema = z.object({
|
|
34
|
+
// _type: z.literal("array"),
|
|
35
|
+
// item: SerializedSchema,
|
|
36
|
+
// opt: z.boolean(),
|
|
37
|
+
// });
|
|
38
|
+
// const SerializedUnionSchema = z.object({
|
|
39
|
+
// _type: z.literal("union"),
|
|
40
|
+
// opt: z.boolean(),
|
|
41
|
+
// });
|
|
42
|
+
// const SerializedRichTextSchema = z.object({
|
|
43
|
+
// _type: z.literal("richtext"),
|
|
44
|
+
// opt: z.boolean(),
|
|
45
|
+
// });
|
|
46
|
+
// const SerializedImageSchema = z.object({
|
|
47
|
+
// _type: z.literal("image"),
|
|
48
|
+
// opt: z.boolean(),
|
|
49
|
+
// });
|
|
50
|
+
// const SerializedI18nSchema = z.object({
|
|
51
|
+
// _type: z.literal("i18n"),
|
|
52
|
+
// locales: z.array(z.string()),
|
|
53
|
+
// item: SerializedSchema,
|
|
54
|
+
// opt: z.boolean(),
|
|
55
|
+
// });
|
|
56
|
+
// return z.union([
|
|
57
|
+
// SerializedStringSchema,
|
|
58
|
+
// SerializedLiteralSchema,
|
|
59
|
+
// SerializedBooleanSchema,
|
|
60
|
+
// SerializedNumberSchema,
|
|
61
|
+
// SerializedObjectSchema,
|
|
62
|
+
// SerializedOneOfSchema,
|
|
63
|
+
// SerializedArraySchema,
|
|
64
|
+
// SerializedUnionSchema,
|
|
65
|
+
// SerializedRichTextSchema,
|
|
66
|
+
// SerializedImageSchema,
|
|
67
|
+
// SerializedI18nSchema,
|
|
68
|
+
// ]);
|
|
69
|
+
// });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { SessionMode } from "./SessionMode";
|
|
3
|
+
|
|
4
|
+
export const Session = z.object({
|
|
5
|
+
id: z.string(),
|
|
6
|
+
mode: SessionMode,
|
|
7
|
+
full_name: z.string().nullable(),
|
|
8
|
+
username: z.string().nullable(),
|
|
9
|
+
avatar_url: z.string().url().nullable(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type Session = z.infer<typeof Session>;
|
package/src/dto/Tree.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const Tree = z.object({
|
|
4
|
+
git: z.object({
|
|
5
|
+
commit: z.string(),
|
|
6
|
+
branch: z.string(),
|
|
7
|
+
}),
|
|
8
|
+
modules: z.record(
|
|
9
|
+
z.object({
|
|
10
|
+
// TODO: types!
|
|
11
|
+
schema: z.any().optional(),
|
|
12
|
+
source: z.any().optional(),
|
|
13
|
+
// TODO: patches
|
|
14
|
+
})
|
|
15
|
+
),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export type Tree = z.infer<typeof Tree>;
|
package/src/exports.ts
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ApiTreeResponse,
|
|
3
|
+
Internal,
|
|
4
|
+
Json,
|
|
5
|
+
SerializedSchema,
|
|
6
|
+
SourcePath,
|
|
7
|
+
} from "@valbuild/core";
|
|
8
|
+
import { result } from "@valbuild/core/fp";
|
|
9
|
+
|
|
10
|
+
export type Modules = ApiTreeResponse["modules"];
|
|
11
|
+
|
|
12
|
+
export function resolvePath(sourcePath: SourcePath, modules: Modules) {
|
|
13
|
+
const [moduleId, modulePath] =
|
|
14
|
+
Internal.splitModuleIdAndModulePath(sourcePath);
|
|
15
|
+
const valModule = modules[moduleId];
|
|
16
|
+
console.log("resolvePath", sourcePath, moduleId, modulePath, modules);
|
|
17
|
+
if (!valModule?.source) {
|
|
18
|
+
return result.err({
|
|
19
|
+
message: `Module "${moduleId}" has no source`,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
if (!valModule?.schema) {
|
|
23
|
+
return result.err({
|
|
24
|
+
message: `Module "${moduleId}" has no schema`,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return result.ok(
|
|
28
|
+
Internal.resolvePath(modulePath, valModule.source, valModule.schema) as {
|
|
29
|
+
source: Json;
|
|
30
|
+
schema: SerializedSchema;
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
}
|
package/tailwind.config.js
CHANGED
|
@@ -3,6 +3,12 @@ module.exports = {
|
|
|
3
3
|
content: [__dirname + "/src/**/*.{js,ts,jsx,tsx}"],
|
|
4
4
|
darkMode: ["class", '[data-mode="dark"]'],
|
|
5
5
|
theme: {
|
|
6
|
+
zIndex: {
|
|
7
|
+
overlay: 8999, // 1 less than the NextJS error z-index: 9000
|
|
8
|
+
hover: 8996,
|
|
9
|
+
window: 8997,
|
|
10
|
+
full: 8998,
|
|
11
|
+
},
|
|
6
12
|
colors: {
|
|
7
13
|
base: "var(--val-theme-base)",
|
|
8
14
|
highlight: "var(--val-theme-highlight)",
|
|
@@ -42,11 +48,24 @@ module.exports = {
|
|
|
42
48
|
"0%": { transform: "rotate(0deg)" },
|
|
43
49
|
"100%": { transform: "rotate(-45deg)" },
|
|
44
50
|
},
|
|
51
|
+
spin: {
|
|
52
|
+
"0%": { transform: "rotate(0deg)" },
|
|
53
|
+
"100%": { transform: "rotate(360deg)" },
|
|
54
|
+
},
|
|
45
55
|
},
|
|
46
56
|
animation: {
|
|
47
57
|
rotateLeft: "rotateLeft 200ms ease-in-out",
|
|
48
58
|
rotateRight: "rotateRight 200ms ease-in-out",
|
|
59
|
+
spin: "spin 1s linear infinite",
|
|
60
|
+
},
|
|
61
|
+
transitionProperty: {
|
|
62
|
+
opacity: ["opacity"],
|
|
49
63
|
},
|
|
50
64
|
},
|
|
51
|
-
plugins: [
|
|
65
|
+
plugins: [
|
|
66
|
+
function ({ addVariant }) {
|
|
67
|
+
addVariant("all-but-last-child", "& > *:not(:last-child)");
|
|
68
|
+
addVariant("children", "& *");
|
|
69
|
+
},
|
|
70
|
+
],
|
|
52
71
|
};
|