diff --git a/app/srv/ws/sync/actions/code_edit.ts b/app/srv/ws/sync/actions/code_edit.ts index 76652dfc..03481f87 100644 --- a/app/srv/ws/sync/actions/code_edit.ts +++ b/app/srv/ws/sync/actions/code_edit.ts @@ -1,4 +1,4 @@ -import { transform } from "esbuild"; +import { TransformResult, transform } from "esbuild"; import { g } from "utils/global"; import { Doc } from "yjs"; import { MContent } from "../../../../web/src/utils/types/general"; @@ -41,14 +41,17 @@ export const code_edit: SAction["code"]["edit"] = async function ( if (mitem) { if (arg.type === "adv") { + const mode = arg.mode; try { - const res = await transform(`render(${src})`, { - jsx: "transform", - format: "cjs", - loader: "tsx", - }); + let res = undefined as undefined | TransformResult; + if (mode === "js") { + res = await transform(`render(${src})`, { + jsx: "transform", + format: "cjs", + loader: "tsx", + }); + } doc?.transact(() => { - const mode = arg.mode; let adv = mitem.get("adv"); if (!adv) { mitem.set("adv", new Y.Map() as any); @@ -59,7 +62,7 @@ export const code_edit: SAction["code"]["edit"] = async function ( try { if (adv) { adv.set(mode, src); - if (mode === "js") { + if (mode === "js" && res) { adv.set("jsBuilt", res.code); } } diff --git a/app/web/src/nova/ed/logic/ed-global.ts b/app/web/src/nova/ed/logic/ed-global.ts index f1dcc5a4..d784ff5b 100644 --- a/app/web/src/nova/ed/logic/ed-global.ts +++ b/app/web/src/nova/ed/logic/ed-global.ts @@ -236,6 +236,7 @@ export const EDGlobal = { script: { open: false, mode: "js" as "js" | "css" | "html", + lastMode: "js" as "js" | "css" | "html", type: "item" as "item" | "prop-master" | "prop-instance", prop_kind: "" as PropFieldKind, prop_name: "", diff --git a/app/web/src/nova/ed/panel/popup/page/page-tree.tsx b/app/web/src/nova/ed/panel/popup/page/page-tree.tsx index 2f9f3024..9ac3238c 100644 --- a/app/web/src/nova/ed/panel/popup/page/page-tree.tsx +++ b/app/web/src/nova/ed/panel/popup/page/page-tree.tsx @@ -3,7 +3,7 @@ import { FC, ReactNode } from "react"; import { useGlobal, useLocal } from "web-utils"; import { EDGlobal } from "../../../logic/ed-global"; import { pagePicker, reloadPagePicker } from "./page-reload"; - +import { validate } from "uuid"; export type PageItem = { id: string; name: string; @@ -76,7 +76,7 @@ export const edPageTreeRender: NodeRender = ( data: { name: local.rename_to, id_site: p.site.id, - parent_id: rename_id, + parent_id: validate(rename_id) ? rename_id : null, }, }); } diff --git a/app/web/src/nova/ed/panel/popup/script/workbench.tsx b/app/web/src/nova/ed/panel/popup/script/workbench.tsx index b4a7ce20..30a1dd9d 100644 --- a/app/web/src/nova/ed/panel/popup/script/workbench.tsx +++ b/app/web/src/nova/ed/panel/popup/script/workbench.tsx @@ -29,9 +29,17 @@ export const EdScriptWorkbench = () => { canBack: active.script_nav.list.length > 0, }; + if (p.ui.popup.script.type === "item") { + setTimeout(() => { + p.ui.popup.script.mode = p.ui.popup.script.lastMode; + p.render(); + }, 200); + } + const is_error = p.ui.popup.script.typings.status === "error" && p.ui.popup.script.mode === "js"; + return (
@@ -115,7 +123,7 @@ export const EdScriptWorkbench = () => { border: 1px solid ${e.color}; `, "uppercase text-white text-[12px] cursor-pointer flex items-center justify-center transition-all hover:opacity-100 w-[40px] text-center", - p.ui.popup.script.mode === e.type + p.ui.popup.script.lastMode === e.type ? css` background: ${e.color}; color: white; @@ -124,6 +132,7 @@ export const EdScriptWorkbench = () => { )} onClick={() => { p.ui.popup.script.mode = e.type as any; + p.ui.popup.script.lastMode = e.type as any; p.render(); }} > 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 daac5f37..71f8fde2 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 @@ -33,6 +33,8 @@ export const FieldNumUnit: FC<{ }) => { const local = useLocal({ val: 0, + val_str: "", + focus: false, unit: "", drag: { clientX: 0, old: 0 }, dragging: false, @@ -57,6 +59,9 @@ export const FieldNumUnit: FC<{ } if (!parseInt(val)) unt = ""; } + if (!local.focus) { + local.val_str = val; + } local.val = parseInt(val) || 0; if (positiveOnly && local.val < 0) { local.val = Math.max(0, local.val); @@ -154,9 +159,18 @@ export const FieldNumUnit: FC<{ !!disabled && "text-center text-gray-400" )} disabled={!!disabled} - value={typeof disabled === "string" ? disabled : local.val} + value={typeof disabled === "string" ? disabled : local.val_str} + onFocus={() => { + local.focus = true; + local.render(); + }} + onBlur={() => { + local.focus = false; + local.render(); + }} onChange={(e) => { - local.val = parseInt(e.currentTarget.value) || 0; + local.val_str = e.currentTarget.value; + local.val = parseInt(local.val_str) || 0; local.render(); update(local.val + local.unit); }} diff --git a/app/web/src/nova/ed/panel/tree/node/item/action/copy.tsx b/app/web/src/nova/ed/panel/tree/node/item/action/copy.tsx index a06450ff..6e292843 100644 --- a/app/web/src/nova/ed/panel/tree/node/item/action/copy.tsx +++ b/app/web/src/nova/ed/panel/tree/node/item/action/copy.tsx @@ -1,3 +1,4 @@ +import { deepClone } from "web-utils"; import { IContent } from "../../../../../../../utils/types/general"; import { PG } from "../../../../../logic/ed-global"; @@ -6,9 +7,37 @@ export const edActionCopy = async (p: PG, item: IContent) => { name: "clipboard-read", allowWithoutGesture: false, } as any); + + const new_item = deepClone(item); + + const walk = (item: IContent) => { + if (item.type !== "text") { + for (const [key, child] of Object.entries(item.childs)) { + if (child && Object.keys(child).length === 1) { + const meta = p.page.meta[child.id]; + if (meta) { + const new_child = deepClone(meta.item); + item.childs[key as any] = new_child; + walk(new_child); + + if (new_child.component?.props) { + for (const [k, v] of Object.entries(new_child.component.props)) { + if (v.meta?.type === "content-element" && v.content) { + walk(v.content); + } + } + } + } + } + } + } + }; + + walk(new_item); + if (perm.state !== "granted") { await navigator.clipboard.read(); } - let str = `prasi-clipboard:` + JSON.stringify(item); + let str = `prasi-clipboard:` + JSON.stringify(new_item); navigator.clipboard.writeText(str); }; diff --git a/app/web/src/nova/ed/panel/tree/node/item/action/paste.tsx b/app/web/src/nova/ed/panel/tree/node/item/action/paste.tsx index a0a4fa6e..0d0f49db 100644 --- a/app/web/src/nova/ed/panel/tree/node/item/action/paste.tsx +++ b/app/web/src/nova/ed/panel/tree/node/item/action/paste.tsx @@ -1,35 +1,67 @@ import { syncronize } from "y-pojo"; import { fillID } from "../../../../../../../render/editor/tools/fill-id"; import { IContent } from "../../../../../../../utils/types/general"; -import { MItem } from "../../../../../../../utils/types/item"; +import { IItem, MItem } from "../../../../../../../utils/types/item"; +import { MSection } from "../../../../../../../utils/types/section"; import { getMetaById } from "../../../../../logic/active/get-meta"; import { PG, active } from "../../../../../logic/ed-global"; import { treeRebuild } from "../../../../../logic/tree/build"; +import { TypedArray } from "yjs-types"; +import { loadComponent } from "../../../../../logic/comp/load"; export const edActionPaste = async (p: PG, item: IContent) => { - const mitem = getMetaById(p, item.id)?.mitem; + let mitem = getMetaById(p, item.id)?.mitem; if (mitem) { const res = await navigator.clipboard.readText(); if (typeof res === "string" && res.startsWith("prasi-clipboard:")) { const clip = JSON.parse( res.substring("prasi-clipboard:".length) - ) as IContent; + ) as IItem; + + const load_comp_ids = new Set(); + const walk = (item: IItem) => { + if (item.component?.id && !p.comp.list[item.component.id]) { + load_comp_ids.add(item.component.id); + } + + if (item.component?.props) { + for (const [k, v] of Object.entries(item.component.props)) { + if (v.meta?.type === "content-element" && v.content) { + walk(v.content); + } + } + } + if (item.childs) { + for (const child of item.childs) { + if (child.type === "item") walk(child); + } + } + }; + walk(clip); + if (load_comp_ids.size > 0) { + for (const id of load_comp_ids) { + await loadComponent(p, id); + } + } + + let mchilds = mitem.get("childs") as + | TypedArray + | undefined; + + if ((clip as any).type === "section") { + const mroot = p.page.doc?.getMap("map").get("root"); + if (mroot) { + mchilds = mroot.get("childs") as any; + } + } mitem.doc?.transact(() => { - const mchilds = mitem.get("childs"); if (mchilds) { let child: any = { ...clip }; - if (item.type === "section") { - child = { ...clip, type: "item" }; - } else { - if (item.type === "text") { - (mitem as MItem).set("type", "item"); - item.type = "item" as any; - } - if (clip.type === "section") { - child = { ...clip, type: "item" }; - } + if (item.type === "text") { + (mitem as MItem).set("type", "item"); + item.type = "item" as any; } const map = new Y.Map(); const newchild = fillID(child);