diff --git a/app/web/src/nova/ed/logic/tree/fill-id.tsx b/app/web/src/nova/ed/logic/tree/fill-id.tsx new file mode 100644 index 00000000..97aeeb37 --- /dev/null +++ b/app/web/src/nova/ed/logic/tree/fill-id.tsx @@ -0,0 +1,41 @@ +import { createId as cuid } from "@paralleldrive/cuid2"; +import { IContent } from "../../../../utils/types/general"; + +export const fillID = ( + object: IContent, + modify?: (obj: IContent) => boolean, + currentDepth?: number +) => { + const _depth = (currentDepth || 0) + 1; + + if (modify) { + if (modify(object)) { + object.id = cuid(); + } + } else { + object.id = cuid(); + } + + if ( + object.type === "item" && + object.component && + object.component.id && + object.component.props + ) { + for (const p of Object.values(object.component.props)) { + if (p.meta?.type === "content-element" && p.content) { + fillID(p.content, modify, _depth); + } + } + } + + if (object.type !== "text") { + if (object.childs && Array.isArray(object.childs)) { + for (const child of object.childs) { + fillID(child, modify, _depth); + } + } + } + + return object; +}; 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 ac711a2e..6f92a9f8 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 @@ -1,6 +1,10 @@ import { useGlobal } from "web-utils"; -import { EDGlobal } from "../../../logic/ed-global"; +import { EDGlobal, active } from "../../../logic/ed-global"; import { TopBtn } from "../top-btn"; +import { loadComponent } from "../../../logic/tree/sync-walk"; +import { MContent } from "../../../../../utils/types/general"; +import { fillID } from "../../../logic/tree/fill-id"; +import { IItem } from "../../../../../utils/types/item"; export const EdCompPicker = () => { const p = useGlobal(EDGlobal, "EDITOR"); @@ -8,7 +12,58 @@ export const EdCompPicker = () => { return ( { - p.ui.popup.comp.open = (comp_id) => {}; + p.ui.popup.comp.open = async (comp_id) => { + let comp_ref = p.comp.list[comp_id]; + if (!comp_ref) { + await loadComponent(p, comp_id); + comp_ref = p.comp.list[comp_id]; + } + + if (!comp_ref) { + alert("Cannot load component!"); + return; + } + + const comp = comp_ref.doc + .getMap("map") + .get("root") + ?.toJSON() as IItem; + if (!comp) { + alert("Failed to load component!"); + return; + } + + if (!active.item_id) { + const first_id = p.page.entry[0]; + if (first_id) { + const first = p.page.meta[first_id]; + console.log(first); + } + } else { + const active_meta = p.page.meta[active.item_id]; + if (active_meta) { + const item = active_meta.item; + const mitem = active_meta.mitem; + if (item && mitem) { + if (item.type !== "text") { + const map = new Y.Map() as MContent; + if (map) { + comp.originalId = comp.id; + syncronize(map as any, fillID(comp)); + const childs = mitem.get("childs"); + if (childs) { + childs.push([map]); + } + const newitem = map.toJSON(); + active.item_id = newitem.id; + } + } + } else { + alert("Failed to add component!"); + } + } + } + }; p.render(); }} style="slim" diff --git a/app/web/src/nova/ed/panel/popup/comp/comp-tree.tsx b/app/web/src/nova/ed/panel/popup/comp/comp-tree.tsx index 98a0855c..b92be9f8 100644 --- a/app/web/src/nova/ed/panel/popup/comp/comp-tree.tsx +++ b/app/web/src/nova/ed/panel/popup/comp/comp-tree.tsx @@ -170,6 +170,7 @@ export const edPageTreeRender: NodeRender = ( const Name: FC<{ name: ReactNode }> = ({ name }) => { if (typeof name !== "string") return name; + if (name === "__TRASH__") return "Trash"; if (name.startsWith("layout::")) { return ( diff --git a/app/web/src/nova/ed/panel/popup/page/page-popup.tsx b/app/web/src/nova/ed/panel/popup/page/page-popup.tsx index 1c2b2c83..8aaa6454 100644 --- a/app/web/src/nova/ed/panel/popup/page/page-popup.tsx +++ b/app/web/src/nova/ed/panel/popup/page/page-popup.tsx @@ -33,13 +33,32 @@ export const EdPopPage = () => { if (local.tree) { const parents: string[] = []; let cur = pagePicker.tree.find((e) => e.id === p.page.cur.id); - while (cur) { - if (typeof cur.id === "string") { - const parent_id = cur.parent; - parents.push(cur.id); - cur = pagePicker.tree.find((e) => e.id === parent_id); + + if (pagePicker.rename_id) { + let cur = pagePicker.tree.find((e) => e.id === pagePicker.rename_id); + while (cur) { + if (typeof cur.id === "string") { + if (parents.includes(cur.id)) { + continue; + } + const parent_id = cur.parent; + parents.push(cur.id); + cur = pagePicker.tree.find((e) => e.id === parent_id); + } + } + } else { + while (cur) { + if (typeof cur.id === "string") { + if (parents.includes(cur.id)) { + continue; + } + const parent_id = cur.parent; + parents.push(cur.id); + cur = pagePicker.tree.find((e) => e.id === parent_id); + } } } + if (parents.length <= 1) { local.tree.open("page-root"); } else { @@ -47,7 +66,12 @@ export const EdPopPage = () => { } } }); - }, [p.ui.popup.page.open, p.page.cur.id, pagePicker.site_id]); + }, [ + p.ui.popup.page.open, + p.page.cur.id, + pagePicker.site_id, + pagePicker.rename_id, + ]); if (!p.ui.popup.page.open) return null; @@ -102,73 +126,75 @@ export const EdPopPage = () => { )} >
- {pagePicker.status === "loading" && ( + {pagePicker.status === "loading" ? ( - )} + ) : ( + <> + {pagePicker.ref && ( + + { + if (local.tree !== ref) { + local.tree = ref; + } + }} + tree={filtered} + rootId={"page-root"} + onDrop={async (newTree: NodeModel[], opt) => { + pagePicker.tree = newTree; + p.render(); - {pagePicker.ref && ( - - { - if (local.tree !== ref) { - local.tree = ref; - } - }} - tree={filtered} - rootId={"page-root"} - onDrop={async (newTree: NodeModel[], opt) => { - pagePicker.tree = newTree; - p.render(); - - if (!opt.dragSource?.droppable) { - await db.page.update({ - where: { - id: opt.dragSourceId as string, - }, - data: { - id_folder: (opt.dropTargetId === "root" || - !opt.dropTargetId - ? null - : opt.dropTargetId) as string, - }, - select: { id: true }, - }); - } else { - await db.page_folder.update({ - where: { - id: opt.dragSourceId as string, - }, - data: { - parent_id: (opt.dropTargetId === "ROOT" || - !opt.dropTargetId - ? null - : opt.dropTargetId) as string, - }, - select: { - id: true, - }, - }); - } - reloadPagePicker(p); - }} - dragPreviewRender={() => <>} - canDrag={() => true} - canDrop={(tree, opt) => { - if (opt.dropTarget?.data?.type === "page") return false; - if (opt.dropTargetId === "page-root") return false; - return true; - }} - classes={{ root: "flex-1", dropTarget: "dropping" }} - render={edPageTreeRender} - /> - + if (!opt.dragSource?.droppable) { + await db.page.update({ + where: { + id: opt.dragSourceId as string, + }, + data: { + id_folder: (opt.dropTargetId === "root" || + !opt.dropTargetId + ? null + : opt.dropTargetId) as string, + }, + select: { id: true }, + }); + } else { + await db.page_folder.update({ + where: { + id: opt.dragSourceId as string, + }, + data: { + parent_id: (opt.dropTargetId === "ROOT" || + !opt.dropTargetId + ? null + : opt.dropTargetId) as string, + }, + select: { + id: true, + }, + }); + } + reloadPagePicker(p); + }} + dragPreviewRender={() => <>} + canDrag={() => true} + canDrop={(tree, opt) => { + if (opt.dropTarget?.data?.type === "page") return false; + if (opt.dropTargetId === "page-root") return false; + return true; + }} + classes={{ root: "flex-1", dropTarget: "dropping" }} + render={edPageTreeRender} + /> + + )} + )}
diff --git a/app/web/src/nova/ed/panel/popup/page/page-reload.ts b/app/web/src/nova/ed/panel/popup/page/page-reload.ts index 59fa6c21..82e9f98d 100644 --- a/app/web/src/nova/ed/panel/popup/page/page-reload.ts +++ b/app/web/src/nova/ed/panel/popup/page/page-reload.ts @@ -17,6 +17,7 @@ export const pagePicker = { status: "ready" as "loading" | "ready", search: "", render: () => {}, + rename_id: "" }; export const reloadPagePicker = async (p: PG) => { 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 e7327da2..074d878e 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 @@ -1,7 +1,7 @@ import { NodeModel, NodeRender } from "@minoru/react-dnd-treeview"; +import { FC, ReactNode } from "react"; import { useGlobal, useLocal } from "web-utils"; import { EDGlobal } from "../../../logic/ed-global"; -import { FC, ReactNode } from "react"; import { pagePicker, reloadPagePicker } from "./page-reload"; export type PageItem = { @@ -15,9 +15,9 @@ export const edPageTreeRender: NodeRender = ( { depth, isOpen, onToggle } ) => { const p = useGlobal(EDGlobal, "EDITOR"); - const local = useLocal({ renaming: node.id === "", rename_to: "" }); + const local = useLocal({ rename_to: "" }); const item = node.data; - if (!item || !item.name) return <>; + if (!item) return <>; return (
= ( )}
- {local.renaming ? ( + {pagePicker.rename_id === item.id ? ( { - local.renaming = false; + const rename_id = pagePicker.rename_id; + pagePicker.rename_id = ""; item.name = local.rename_to; - if (item.id === "") { + local.render(); + + if (item.id === "NEW") { if (item.name) { - db.page_folder.create({ - data: { name: local.rename_to, id_site: p.site.id }, + await db.page_folder.create({ + data: { + name: local.rename_to, + id_site: p.site.id, + parent_id: rename_id, + }, }); } - await reloadPagePicker(p); } else { - db.page_folder.update({ + await db.page_folder.update({ where: { id: item.id }, data: { name: local.rename_to }, }); } - local.render(); + + await reloadPagePicker(p); }} className="border px-1 bg-white flex-1 outline-none mr-1 border-blue-500 " onChange={(e) => { @@ -101,7 +108,7 @@ export const edPageTreeRender: NodeRender = ( )}
- {!local.renaming && ( + {pagePicker.rename_id !== item.id && (
{item.type === "folder" && ( <> @@ -110,15 +117,16 @@ export const edPageTreeRender: NodeRender = ( onClick={(e) => { e.stopPropagation(); pagePicker.tree.push({ - id: "", + id: "NEW", parent: item.id, text: "", data: { - id: "", + id: "NEW", name: "", type: "folder", }, }); + pagePicker.rename_id = "NEW"; p.render(); }} > @@ -148,7 +156,7 @@ export const edPageTreeRender: NodeRender = ( e.stopPropagation(); if (item.type === "folder") { local.rename_to = item.name; - local.renaming = true; + pagePicker.rename_id = item.id; local.render(); } else { p.ui.popup.page.form = item;