diff --git a/app/web/src/nova/ed/logic/ed-global.ts b/app/web/src/nova/ed/logic/ed-global.ts index 48351674..5d580832 100644 --- a/app/web/src/nova/ed/logic/ed-global.ts +++ b/app/web/src/nova/ed/logic/ed-global.ts @@ -195,7 +195,6 @@ export const EDGlobal = { global_prop: [] as string[], ui: { zoom: localStorage.zoom || "100%", - should_render: false, side: { prop: true }, layout: { left: parseInt(localStorage.getItem("prasi-layout-left") || "250"), diff --git a/app/web/src/nova/ed/logic/ed-route.ts b/app/web/src/nova/ed/logic/ed-route.ts index 981eaae7..ae50b5c6 100644 --- a/app/web/src/nova/ed/logic/ed-route.ts +++ b/app/web/src/nova/ed/logic/ed-route.ts @@ -1,132 +1,132 @@ import { compress, decompress } from "wasm-gzip"; import { isTextEditing } from "./active/is-editing"; import { loadCompSnapshot } from "./comp/load"; -import { PG } from "./ed-global"; +import { PG, active } from "./ed-global"; import { loadSite } from "./ed-site"; import { treeRebuild } from "./tree/build"; export const edRoute = async (p: PG) => { - if (p.status === "ready" || p.status === "init") { - if (!p.site.domain && !p.site.name) { - p.status = "load-site"; - const site = await p.sync.site.load(p.site.id); - if (!site) { - p.status = "site-not-found"; - p.render(); - return; - } + if (p.status === "ready" || p.status === "init") { + if (!p.site.domain && !p.site.name) { + p.status = "load-site"; + const site = await p.sync.site.load(p.site.id); + if (!site) { + p.status = "site-not-found"; + p.render(); + return; + } - await loadSite(p, site, "from-route"); - } + await loadSite(p, site, "from-route"); + } - if ( - p.page.cur.id !== params.page_id || - !p.page.cur.snapshot || - !p.page.list[p.page.cur.id] - ) { - const page = p.page.list[params.page_id]; - if (page && p.page.doc && page.on_update) { - p.page.doc.off("update", page.on_update); + if ( + p.page.cur.id !== params.page_id || + !p.page.cur.snapshot || + !p.page.list[p.page.cur.id] + ) { + const page = p.page.list[params.page_id]; + if (page && p.page.doc && page.on_update) { + p.page.doc.off("update", page.on_update); - const cur = p.page.list[params.page_id]; - p.page.cur = cur.page; - p.page.doc = cur.doc; - } + const cur = p.page.list[params.page_id]; + p.page.cur = cur.page; + p.page.doc = cur.doc; + } - await reloadPage(p, params.page_id, "load-route"); - } - } + await reloadPage(p, params.page_id, "load-route"); + } + } }; export const reloadPage = async (p: PG, page_id: string, note: string) => { - p.status = "reload"; - const remotePage = await p.sync.page.load(page_id); + p.status = "reload"; + const remotePage = await p.sync.page.load(page_id); - if (!remotePage) { - p.status = "page-not-found"; - p.render(); - return; - } + if (!remotePage) { + p.status = "page-not-found"; + p.render(); + return; + } - if (remotePage.comps) { - for (const [id_comp, c] of Object.entries(remotePage.comps)) { - if (c && c.snapshot) { - await loadCompSnapshot(p, id_comp, c.snapshot); - } - } - } + if (remotePage.comps) { + for (const [id_comp, c] of Object.entries(remotePage.comps)) { + if (c && c.snapshot) { + await loadCompSnapshot(p, id_comp, c.snapshot); + } + } + } - p.page.cur = remotePage; - if (remotePage.snapshot) { - const doc = new Y.Doc(); - Y.applyUpdate(doc, decompress(remotePage.snapshot)); + p.page.cur = remotePage; + if (remotePage.snapshot) { + const doc = new Y.Doc(); + Y.applyUpdate(doc, decompress(remotePage.snapshot)); - let page = p.page.list[remotePage.id]; - if (!page) { - p.page.list[remotePage.id] = {} as any; - page = p.page.list[remotePage.id]; - } + let page = p.page.list[remotePage.id]; + if (!page) { + p.page.list[remotePage.id] = {} as any; + page = p.page.list[remotePage.id]; + } - if (page.on_update && page.doc) { - page.doc.off("update", page.on_update); - } + if (page.on_update && page.doc) { + page.doc.off("update", page.on_update); + } - page.on_update = async (bin: Uint8Array, origin: any) => { - if (origin === "local") return; + page.on_update = async (bin: Uint8Array, origin: any) => { + if (origin === "local") return; - const res = await p.sync.yjs.sv_local( - "page", - p.page.cur.id, - Buffer.from(compress(bin)), - ); + const res = await p.sync.yjs.sv_local( + "page", + p.page.cur.id, + Buffer.from(compress(bin)) + ); - if (res) { - const diff_local = Y.encodeStateAsUpdate( - doc as any, - decompress(res.sv), - ); - Y.applyUpdate(doc as any, decompress(res.diff), "local"); + if (res) { + const diff_local = Y.encodeStateAsUpdate( + doc as any, + decompress(res.sv) + ); + Y.applyUpdate(doc as any, decompress(res.diff), "local"); - if (!isTextEditing()) { - await treeRebuild(p, { note: note + " page-on-update" }); - } + if (!isTextEditing()) { + await treeRebuild(p, { note: note + " page-on-update" }); + } - await p.sync.yjs.diff_local( - "page", - p.page.cur.id, - Buffer.from(compress(diff_local)), - ); - p.ui.syncing = false; + await p.sync.yjs.diff_local( + "page", + p.page.cur.id, + Buffer.from(compress(diff_local)) + ); + p.ui.syncing = false; - p.page.entry = (doc as any) - .getMap("map") - .get("root") - ?.get("childs") - ?.map((e: any) => e.get("id")) as string[]; + p.page.entry = (doc as any) + .getMap("map") + .get("root") + ?.get("childs") + ?.map((e: any) => e.get("id")) as string[]; - if (p.ui.should_render) p.render(); - } - }; + if (active.should_render_main) p.render(); + } + }; - doc.on("update", page.on_update); + doc.on("update", page.on_update); - p.page.doc = doc as any; - if (p.page.doc) { - page.page = p.page.cur; - page.doc = p.page.doc; + p.page.doc = doc as any; + if (p.page.doc) { + page.page = p.page.cur; + page.doc = p.page.doc; - p.page.entry = p.page.doc - .getMap("map") - .get("root") - ?.get("childs") - ?.map((e) => e.get("id")) as string[]; - } + p.page.entry = p.page.doc + .getMap("map") + .get("root") + ?.get("childs") + ?.map((e) => e.get("id")) as string[]; + } - if (p.page.doc) { - await treeRebuild(p, { note: note + " page-init" }); - } - } + if (p.page.doc) { + await treeRebuild(p, { note: note + " page-init" }); + } + } - p.status = "ready"; - p.render(); + p.status = "ready"; + p.render(); }; diff --git a/app/web/src/nova/ed/panel/header/mid/add-item.tsx b/app/web/src/nova/ed/panel/header/mid/add-item.tsx index 2bb7279c..86f19eca 100644 --- a/app/web/src/nova/ed/panel/header/mid/add-item.tsx +++ b/app/web/src/nova/ed/panel/header/mid/add-item.tsx @@ -29,7 +29,7 @@ export const EdAddItem = () => { const json = { id: createId(), - name: `New Item`, + name: `new_item`, type: "item", dim: { w: "full", h: "full" }, childs: [], diff --git a/app/web/src/nova/ed/panel/header/mid/add-text.tsx b/app/web/src/nova/ed/panel/header/mid/add-text.tsx index b483ade0..3ab65f4f 100644 --- a/app/web/src/nova/ed/panel/header/mid/add-text.tsx +++ b/app/web/src/nova/ed/panel/header/mid/add-text.tsx @@ -33,7 +33,7 @@ export const EdAddText = () => { const json = { id: createId(), - name: `New Text`, + name: `new_text`, type: "text", dim: { w: "full", h: "full" }, layout: { align: "center", dir: "col", gap: 0 }, @@ -68,7 +68,7 @@ export const EdAddText = () => { if (mitem.get("type") === "section") { const json = { id: createId(), - name: `New Item`, + name: `new_item`, type: "item", dim: { w: "full", h: "full" }, childs: [], diff --git a/app/web/src/nova/ed/panel/header/mid/comp-picker.tsx b/app/web/src/nova/ed/panel/header/mid/comp-picker.tsx index f4aa17a1..8857dc7d 100644 --- a/app/web/src/nova/ed/panel/header/mid/comp-picker.tsx +++ b/app/web/src/nova/ed/panel/header/mid/comp-picker.tsx @@ -105,7 +105,7 @@ const addComponent = (mitem: MItem | MSection, comp: IItem) => { const addSection = (root: MRoot) => { const json = { id: createId(), - name: `New Section`, + name: `new_section`, type: "section", dim: { w: "full", h: "full" }, childs: [], diff --git a/app/web/src/nova/ed/panel/main/main.tsx b/app/web/src/nova/ed/panel/main/main.tsx index b481cae4..1997bcda 100644 --- a/app/web/src/nova/ed/panel/main/main.tsx +++ b/app/web/src/nova/ed/panel/main/main.tsx @@ -5,96 +5,96 @@ import { EDGlobal, IMeta, PG, active } from "../../logic/ed-global"; import { mainPerItemVisit } from "./main-per-item"; export const EdMain = () => { - const p = useGlobal(EDGlobal, "EDITOR"); - const local = useLocal({ - cache: null as any, - first_load: false, - width: 0, - height: 0, - }); + const p = useGlobal(EDGlobal, "EDITOR"); + const local = useLocal({ + cache: null as any, + first_load: false, + width: 0, + height: 0, + }); - let meta: undefined | IMeta = undefined; + let meta: undefined | IMeta = undefined; - if (active.comp_id) { - if (p.comp.list[active.comp_id]) { - meta = p.comp.list[active.comp_id].meta[active.item_id]; - } else { - active.comp_id = ""; - } - } else { - meta = p.page.meta[active.item_id]; - } + if (active.comp_id) { + if (p.comp.list[active.comp_id]) { + meta = p.comp.list[active.comp_id].meta[active.item_id]; + } else { + active.comp_id = ""; + } + } else { + meta = p.page.meta[active.item_id]; + } - if (active.should_render_main) { - local.cache = ( - { - return mainPerItemVisit(p, meta, parts); - }} - onStatusChanged={(status) => { - if (status !== "ready") { - active.should_render_main = true; - local.render(); - } else { - if (!local.first_load) { - local.first_load = true; - active.should_render_main = true; - local.render(); - } - } - }} - /> - ); - active.should_render_main = false; - } + if (active.should_render_main) { + local.cache = ( + { + return mainPerItemVisit(p, meta, parts); + }} + on_status_changed={(status) => { + if (status !== "ready") { + active.should_render_main = true; + local.render(); + } else { + if (!local.first_load) { + local.first_load = true; + active.should_render_main = true; + local.render(); + } + } + }} + /> + ); + active.should_render_main = false; + } - return ( -
{ - if (el) { - const bound = el.getBoundingClientRect(); - if (local.width !== bound.width || local.height !== bound.height) { - local.width = bound.width; - local.height = bound.height; - local.render(); - } - } - }} - > -
{local.cache}
-
- ); + return ( +
{ + if (el) { + const bound = el.getBoundingClientRect(); + if (local.width !== bound.width || local.height !== bound.height) { + local.width = bound.width; + local.height = bound.height; + local.render(); + } + } + }} + > +
{local.cache}
+
+ ); }; const mainStyle = (p: PG, meta?: IMeta) => { - let is_active = meta ? isMetaActive(p, meta) : false; + let is_active = meta ? isMetaActive(p, meta) : false; - const scale = parseInt(p.ui.zoom.replace("%", "")) / 100; + const scale = parseInt(p.ui.zoom.replace("%", "")) / 100; - let width = `${(1 / scale) * 100}%`; - if (p.mode === "mobile") { - width = `${(1 / scale) * 375}px`; - } + let width = `${(1 / scale) * 100}%`; + if (p.mode === "mobile") { + width = `${(1 / scale) * 375}px`; + } - return cx( - "absolute flex", - css` + return cx( + "absolute flex", + css` contain: content; `, - p.mode === "mobile" - ? css` + p.mode === "mobile" + ? css` border-left: 1px solid #ccc; border-right: 1px solid #ccc; background: white; @@ -103,22 +103,22 @@ const mainStyle = (p: PG, meta?: IMeta) => { overflow-y: auto; bottom: 0px; ` - : "inset-0", - p.mode === "mobile" - ? css` - width: ${width}; - height: ${`${(1 / scale) * 100}%`}; - transform: scale(${scale}); - transform-origin: 50% 0% 0px; - ` - : css` - width: ${width}; - height: ${`${(1 / scale) * 100}%`}; - transform: scale(${scale}); - transform-origin: 0% 0% 0px; - `, - active.hover.id && - css` + : "inset-0", + p.mode === "mobile" + ? css` + width: ${width}; + height: ${`${(1 / scale) * 100}%`}; + transform: scale(${scale}); + transform-origin: 50% 0% 0px; + ` + : css` + width: ${width}; + height: ${`${(1 / scale) * 100}%`}; + transform: scale(${scale}); + transform-origin: 0% 0% 0px; + `, + active.hover.id && + css` .s-${active.hover.id} { &::after { content: " "; @@ -132,8 +132,8 @@ const mainStyle = (p: PG, meta?: IMeta) => { } } `, - is_active && - css` + is_active && + css` .s-${active.item_id} { outline: none; @@ -148,6 +148,6 @@ const mainStyle = (p: PG, meta?: IMeta) => { border: 2px solid #1c88f3; } } - `, - ); + ` + ); }; diff --git a/app/web/src/nova/ed/panel/popup/script/scope/scope.tsx b/app/web/src/nova/ed/panel/popup/script/scope/scope.tsx index 8c280c6c..a175ff1f 100644 --- a/app/web/src/nova/ed/panel/popup/script/scope/scope.tsx +++ b/app/web/src/nova/ed/panel/popup/script/scope/scope.tsx @@ -34,10 +34,12 @@ export const declareScope = (p: PG, meta: IMeta, monaco: Monaco) => { for (const path of paths) { if (path.includes(meta)) { for (const m of path) { - if (m.instances) { - cur_path.length = 0; + if (m) { + if (m.instances) { + cur_path.length = 0; + } + cur_path.push(m); } - cur_path.push(m); } break; } diff --git a/app/web/src/nova/ed/panel/side/style/side-all.tsx b/app/web/src/nova/ed/panel/side/style/side-all.tsx index b3118db1..53284085 100644 --- a/app/web/src/nova/ed/panel/side/style/side-all.tsx +++ b/app/web/src/nova/ed/panel/side/style/side-all.tsx @@ -11,6 +11,7 @@ import { PanelLink } from "./panel/link"; import { PanelPadding } from "./panel/padding"; import { SideBox } from "./ui/SideBox"; import { SideLabel } from "./ui/SideLabel"; +import { treeRebuild } from "../../../logic/tree/build"; export const EdStyleAll = () => { const p = useGlobal(EDGlobal, "EDITOR"); @@ -27,7 +28,7 @@ export const EdStyleAll = () => { let mitem = meta.mitem; if (mitem) { - p.ui.should_render = true; + active.should_render_main = true; mitem.doc?.transact(() => { if (mitem) { if (p.mode === "mobile") { diff --git a/app/web/src/nova/ed/panel/side/style/ui/FieldNumUnit.tsx b/app/web/src/nova/ed/panel/side/style/ui/FieldNumUnit.tsx index 5bca4795..6e4a822b 100644 --- a/app/web/src/nova/ed/panel/side/style/ui/FieldNumUnit.tsx +++ b/app/web/src/nova/ed/panel/side/style/ui/FieldNumUnit.tsx @@ -70,8 +70,6 @@ export const FieldNumUnit: FC<{ local.render(); }, [value, unit]); - const [txPending, tx] = useTransition(); - useEffect(() => { // Only change the value if the drag was actually started. const onUpdate = (event: any) => { @@ -86,9 +84,7 @@ export const FieldNumUnit: FC<{ local.render(); - tx(() => { - update(local.val + local.unit); - }); + update(local.val + local.unit); } }; @@ -105,7 +101,7 @@ export const FieldNumUnit: FC<{ document.removeEventListener("pointermove", onUpdate); document.removeEventListener("pointerup", onEnd); }; - }, [local.drag.clientX, local.drag.old, local.val]); + }, [local.drag.clientX, local.drag.old, local.val, update]); const onStart = useCallback( (event: React.MouseEvent) => { diff --git a/app/web/src/nova/ed/panel/tree/node/item/name.tsx b/app/web/src/nova/ed/panel/tree/node/item/name.tsx index dde73681..71660c15 100644 --- a/app/web/src/nova/ed/panel/tree/node/item/name.tsx +++ b/app/web/src/nova/ed/panel/tree/node/item/name.tsx @@ -1,8 +1,9 @@ import { NodeModel, RenderParams } from "@minoru/react-dnd-treeview"; import { FC, useEffect } from "react"; import { useGlobal, useLocal } from "web-utils"; -import { EDGlobal, IMeta, active } from "../../../../logic/ed-global"; +import { IItem, MItem } from "../../../../../../utils/types/item"; import { Tooltip } from "../../../../../../utils/ui/tooltip"; +import { EDGlobal, IMeta, PG, active } from "../../../../logic/ed-global"; import { treeRebuild } from "../../../../logic/tree/build"; export const EdTreeName = ({ @@ -101,13 +102,15 @@ export const EdTreeName = ({ } }} onChange={(e) => { - local.rename = e.target.value.replace(/[\W_]+/g, "_"); + local.rename = e.target.value + .replace(/[^a-zA-Z\:\d\s:]+/g, "_") + .toLowerCase(); p.render(); }} /> ) : (
- + {/*
{node.id} - {item.originalId}
*/} @@ -117,20 +120,22 @@ export const EdTreeName = ({ ); }; -const Name: FC<{ name: string; is_jsx_prop: boolean }> = ({ +const Name: FC<{ name: string; is_jsx_prop: boolean; meta?: IMeta }> = ({ name, is_jsx_prop, + meta, }) => { if (is_jsx_prop) { return ( -
+
P -
{name}
+
{name}
+ {meta && meta.mitem && }
); } @@ -153,3 +158,76 @@ const Name: FC<{ name: string; is_jsx_prop: boolean }> = ({ return
{name}
; }; + +const GenerateJSX: FC<{ mitem: MItem }> = ({ mitem }) => { + const p = useGlobal(EDGlobal, "EDITOR"); + return ( + { + const genJSX = findDefaultJSX(p, mitem); + const ijson = mitem.toJSON() as IItem; + mitem.doc?.transact(() => { + syncronize(mitem as any, { + ...genJSX, + name: ijson.name, + id: ijson.id, + hidden: false, + originalId: ijson.originalId, + }); + }); + treeRebuild(p); + p.render(); + }} + > +
`, + }} + >
+
+ ); +}; + +export const findDefaultJSX = (p: PG, mitem: MItem): IItem => { + let resetJSXProp: any = false; + if (mitem && mitem.parent && (mitem.parent as any).get("content")) { + let name = ""; + (mitem as any).parent.parent.forEach((e: any, k: any) => { + if (e === mitem.parent) { + name = k; + } + }); + + if (name) { + try { + const cid = (mitem as any).parent.parent.parent.get("id"); + const comp = p.comp.list[cid].doc; + if (comp) { + const mchilds = comp + .getMap("map") + .get("root") + ?.get("childs") + ?.toJSON() as IItem[]; + for (const c of mchilds) { + if ( + c && + c.name && + c.name.startsWith("jsx:") && + c.name.substring(4).trim() === name + ) { + c.hidden = false; + c.name = name; + c.id = mitem.get("id") || ""; + c.originalId = mitem.get("originalId") || ""; + resetJSXProp = c; + } + } + } + } catch (e) {} + } + } + + return resetJSXProp; +}; diff --git a/app/web/src/nova/vi/render/render.tsx b/app/web/src/nova/vi/render/render.tsx index b5bb2b9a..af632fe7 100644 --- a/app/web/src/nova/vi/render/render.tsx +++ b/app/web/src/nova/vi/render/render.tsx @@ -52,7 +52,6 @@ export const ViRender: FC<{ } if (!meta) return null; - if (meta.item.hidden) return null; if (meta.item.adv?.js || meta.item.component?.id) { diff --git a/app/web/src/nova/vi/render/script/eval-script.tsx b/app/web/src/nova/vi/render/script/eval-script.tsx index 87b801f6..e000f950 100644 --- a/app/web/src/nova/vi/render/script/eval-script.tsx +++ b/app/web/src/nova/vi/render/script/eval-script.tsx @@ -84,13 +84,7 @@ const JsxProp: FC<{ meta: IMeta; passprop: any; }> = ({ fn, meta, passprop }) => { - const local = useLocal({ init: false, result: null as any }); - - if (!local.init) { - local.init = true; - local.result = fn({ passprop, meta }); - } - return local.result; + return fn({ passprop, meta }); }; export const replacement = { diff --git a/app/web/src/nova/vi/vi.tsx b/app/web/src/nova/vi/vi.tsx index 1206aacd..d1b4b8f9 100644 --- a/app/web/src/nova/vi/vi.tsx +++ b/app/web/src/nova/vi/vi.tsx @@ -1,4 +1,4 @@ -import { FC, Suspense } from "react"; +import { FC, Suspense, useState } from "react"; import { useGlobal } from "web-utils"; import { IMeta } from "../ed/logic/ed-global"; import { viLoad } from "./load/load"; @@ -19,7 +19,7 @@ export const Vi: FC<{ script?: { init_local_effect: Record }; visit?: VG["visit"]; render_stat?: "enabled" | "disabled"; - onStatusChanged?: (status: VG["status"]) => void; + on_status_changed?: (status: VG["status"]) => void; }> = ({ meta, entry, @@ -30,10 +30,10 @@ export const Vi: FC<{ visit, script, render_stat: rs, - onStatusChanged, + on_status_changed, }) => { const vi = useGlobal(ViGlobal, "VI"); - vi.on_status_changes = onStatusChanged; + vi.on_status_changes = on_status_changed; if (rs === "disabled") { render_stat.enabled = false; diff --git a/app/web/src/render/editor/panel/side/Side.tsx b/app/web/src/render/editor/panel/side/Side.tsx index cadd38ba..6cf47a15 100644 --- a/app/web/src/render/editor/panel/side/Side.tsx +++ b/app/web/src/render/editor/panel/side/Side.tsx @@ -17,6 +17,7 @@ import { CPInstance } from "./props/CPInstance"; import { CPMaster } from "./props/CPMaster"; import { SideBox } from "./ui/SideBox"; import { SideLabel } from "./ui/SideLabel"; +import { treeRebuild } from "../../../../nova/ed/logic/tree/build"; export const ESide = () => { const p = useGlobal(EditorGlobal, "EDITOR"); diff --git a/app/web/src/utils/css/font.ts b/app/web/src/utils/css/font.ts index dc7b7640..1fd508a8 100644 --- a/app/web/src/utils/css/font.ts +++ b/app/web/src/utils/css/font.ts @@ -36,7 +36,7 @@ export const cssFont = ( font.family = glbFont.defaultFont; } - return cx( + const res = cx( font.color && ` color: ${font.color}; @@ -69,4 +69,6 @@ export const cssFont = ( font-family: ${font.family}; ` ); + + return res; };