diff --git a/app/web/src/render/ed/logic/ed-global.ts b/app/web/src/render/ed/logic/ed-global.ts index e3eb63de..54fb622c 100644 --- a/app/web/src/render/ed/logic/ed-global.ts +++ b/app/web/src/render/ed/logic/ed-global.ts @@ -99,6 +99,7 @@ export const EDGlobal = { HTML: false, CSS: false, }, + rename_id: "", open: {} as Record, }, popup: { diff --git a/app/web/src/render/ed/panel/tree/node/item/action/detach.tsx b/app/web/src/render/ed/panel/tree/node/item/action/detach.tsx index a9bc4aa4..e694b1a6 100644 --- a/app/web/src/render/ed/panel/tree/node/item/action/detach.tsx +++ b/app/web/src/render/ed/panel/tree/node/item/action/detach.tsx @@ -17,14 +17,15 @@ export const edActionDetach = (p: PG, item: IItem) => { if (comp) { fillID(comp); comp.id = item.id; - delete comp.component; + if (comp.component) comp.component.id = ""; mitem.doc?.transact(() => { mitem.parent.forEach((e, k) => { - if (e == mitem) { + if (e.get("id") === mitem.get("id")) { mitem.parent.delete(k); const nmap = new Y.Map(); syncronize(nmap, comp); mitem.parent.insert(k, [nmap]); + console.log(nmap.toJSON()); } }); }); diff --git a/app/web/src/render/ed/panel/tree/node/item/action/hide.tsx b/app/web/src/render/ed/panel/tree/node/item/action/hide.tsx index 0e96622e..9c9558e8 100644 --- a/app/web/src/render/ed/panel/tree/node/item/action/hide.tsx +++ b/app/web/src/render/ed/panel/tree/node/item/action/hide.tsx @@ -1,12 +1,21 @@ import { IContent } from "../../../../../../../utils/types/general"; import { PG } from "../../../../../logic/ed-global"; -export const edActionHide = (p: PG, item: IContent) => { +export const edActionHide = ( + p: PG, + item: IContent, + mode = "toggle" as "toggle" | "switch" +) => { const mitem = p.page.meta[item.id].mitem; if (mitem) { const hidden = mitem.get("hidden"); - if (!hidden) mitem.set("hidden", "all"); - else if (hidden === "all") mitem.set("hidden", "only-editor"); - else if (hidden === "only-editor") mitem.delete("hidden"); + if (mode === "toggle") { + if (!hidden) mitem.set("hidden", "all"); + else mitem.delete("hidden"); + } else { + if (!hidden) mitem.set("hidden", "all"); + else if (hidden === "all") mitem.set("hidden", "only-editor"); + else if (hidden === "only-editor") mitem.delete("hidden"); + } } }; diff --git a/app/web/src/render/ed/panel/tree/node/item/action/rename.tsx b/app/web/src/render/ed/panel/tree/node/item/action/rename.tsx new file mode 100644 index 00000000..12167963 --- /dev/null +++ b/app/web/src/render/ed/panel/tree/node/item/action/rename.tsx @@ -0,0 +1,7 @@ +import { IContent } from "../../../../../../../utils/types/general"; +import { PG } from "../../../../../logic/ed-global"; + +export const edActionRename = (p: PG, item: IContent) => { + p.ui.tree.rename_id = item.id; + p.render(); +}; diff --git a/app/web/src/render/ed/panel/tree/node/item/ctx-menu.tsx b/app/web/src/render/ed/panel/tree/node/item/ctx-menu.tsx index 6e89d208..cb97d91b 100644 --- a/app/web/src/render/ed/panel/tree/node/item/ctx-menu.tsx +++ b/app/web/src/render/ed/panel/tree/node/item/ctx-menu.tsx @@ -14,6 +14,8 @@ import { edActionNewComp } from "./action/new-comp"; import { edActionPaste } from "./action/paste"; import { edActionWrap } from "./action/wrap"; import { edActionUnwrap } from "./action/unwrap"; +import { edActionRename } from "./action/rename"; +import { edActionDelete } from "./action/del"; export const EdTreeCtxMenu = ({ node, @@ -85,11 +87,28 @@ export const EdTreeCtxMenu = ({ onClick={(e) => edActionNewComp(p, item, e)} /> )} - {!item.hidden && ( - edActionHide(p, item)} /> + edActionHide(p, item)} + /> + {!isComponent && ( + edActionRename(p, item)} + /> )} + } + onClick={() => edActionCut(p, item)} + /> + edActionDelete(p, item)} + /> edActionClone(p, item)} /> - edActionCut(p, item)} /> edActionCopy(p, item)} /> {local.allowCopy && local.allowPaste && @@ -109,3 +128,18 @@ export const EdTreeCtxMenu = ({ ); }; + +const HotKey = (arg: { shortcut: string }) => { + const ctrl = + navigator.platform.toUpperCase().indexOf("MAC") >= 0 ? ( +
+ ) : ( +
CTRL
+ ); + return ( +
+ {ctrl} +
+
{arg.shortcut}
+
+ ); +}; diff --git a/app/web/src/render/ed/panel/tree/node/item/name.tsx b/app/web/src/render/ed/panel/tree/node/item/name.tsx index 9a9fbfd4..e6c3a437 100644 --- a/app/web/src/render/ed/panel/tree/node/item/name.tsx +++ b/app/web/src/render/ed/panel/tree/node/item/name.tsx @@ -1,5 +1,6 @@ import { NodeModel, RenderParams } from "@minoru/react-dnd-treeview"; -import { EdMeta } from "../../../../logic/ed-global"; +import { EDGlobal, EdMeta } from "../../../../logic/ed-global"; +import { useGlobal, useLocal } from "web-utils"; export const EdTreeName = ({ node, @@ -8,14 +9,63 @@ export const EdTreeName = ({ node: NodeModel; prm: RenderParams; }) => { + const p = useGlobal(EDGlobal, "EDITOR"); + const local = useLocal( + { + rename: "", + }, + () => { + local.rename = item?.name || ""; + } + ); const item = node.data?.item; - if (!item) return <>; + const mitem = node.data?.mitem; + if (!item || !mitem) return <>; + const isRenaming = p.ui.tree.rename_id === item.id; return ( -
-
- {node.data?.el || item.name} - {/*
{item.id}
*/} -
+
+ {isRenaming ? ( + { + e.currentTarget.select(); + }} + onKeyDown={(e) => { + e.stopPropagation(); + if (e.key === "Enter" || e.key === "Escape") { + if (e.key === "Escape") { + local.rename = item.name; + } else { + item.name = local.rename; + mitem.set("name", item.name); + } + + p.ui.tree.rename_id = ""; + p.render(); + setTimeout(() => { + const el = document.querySelector( + `.tree-${item.id}` + ) as HTMLInputElement; + if (el) el.focus(); + }); + } + }} + onChange={(e) => { + local.rename = e.target.value; + p.render(); + }} + /> + ) : ( +
+ {node.data?.el || item.name} + {/*
{item.id}
*/} +
+ )}
); }; diff --git a/app/web/src/render/ed/panel/tree/node/render.tsx b/app/web/src/render/ed/panel/tree/node/render.tsx index c668d4ef..0d61fee8 100644 --- a/app/web/src/render/ed/panel/tree/node/render.tsx +++ b/app/web/src/render/ed/panel/tree/node/render.tsx @@ -169,22 +169,27 @@ export const nodeRender: NodeRender = (node, prm) => { } if (e.key === "Enter") { - p.ui.tree.search = ""; - p.ui.prevent_indent_hook = false; - active.item_id = ""; - p.render(); - setTimeout(() => { - active.item_id = item.id; + if (p.ui.tree.search) { + p.ui.tree.search = ""; + p.ui.prevent_indent_hook = false; + active.item_id = ""; p.render(); setTimeout(() => { - const f = document.querySelector( - `.tree-${item.id}` - ) as HTMLInputElement; - if (f) { - f.focus(); - } + active.item_id = item.id; + p.render(); + setTimeout(() => { + const f = document.querySelector( + `.tree-${item.id}` + ) as HTMLInputElement; + if (f) { + f.focus(); + } + }); }); - }); + } else { + p.ui.tree.rename_id = item.id; + p.render(); + } return; } diff --git a/app/web/src/utils/ui/context-menu.css b/app/web/src/utils/ui/context-menu.css index b64c1c7b..7b020504 100644 --- a/app/web/src/utils/ui/context-menu.css +++ b/app/web/src/utils/ui/context-menu.css @@ -16,13 +16,17 @@ width: 100%; background: white; font-size: 14px; - padding: 3px 20px 3px 10px; + padding: 3px 5px 3px 10px; text-align: left; line-height: 1.5; margin: 0; outline: 0; } +.MenuItem:hover .hot-key { + border-color: white !important; +} + .MenuItem:last-child { border-bottom: 0px; } diff --git a/app/web/src/utils/ui/context-menu.tsx b/app/web/src/utils/ui/context-menu.tsx index 24d7127d..7d8d99d0 100644 --- a/app/web/src/utils/ui/context-menu.tsx +++ b/app/web/src/utils/ui/context-menu.tsx @@ -29,13 +29,14 @@ export const MenuItem = forwardRef< HTMLButtonElement, React.ButtonHTMLAttributes & { label: ReactNode; + hotKey?: ReactNode; disabled?: boolean; } ->(({ label, disabled, ...props }, ref) => { +>(({ label, disabled, hotKey, ...props }, ref) => { return ( ); }); @@ -165,7 +167,7 @@ export const Menu = forwardRef< // > //