This commit is contained in:
Rizky 2023-12-03 09:47:39 +07:00
parent f9a492a290
commit 3c025dae19
21 changed files with 327 additions and 216 deletions

View File

@ -3,7 +3,7 @@ import {
ensureMProp, ensureMProp,
ensurePropContent, ensurePropContent,
} from "../../../../web/src/nova/ed/logic/tree/sync-walk-utils"; } from "../../../../web/src/nova/ed/logic/tree/sync-walk-utils";
import { MItem } from "../../../../web/src/utils/types/item"; import { IItem, MItem } from "../../../../web/src/utils/types/item";
import { import {
FNCompDef, FNCompDef,
FNComponent, FNComponent,
@ -12,12 +12,14 @@ import { parseJs } from "./parser/parse-js";
export const extractMItemProps = (arg: { export const extractMItemProps = (arg: {
mitem: MItem; mitem: MItem;
item: IItem;
item_comp: FNComponent; item_comp: FNComponent;
mcomp: MItem; mcomp: MItem;
scope: Exclude<ReturnType<typeof parseJs>, undefined>; scope: Exclude<ReturnType<typeof parseJs>, undefined>;
content_scope?: Record<string, string>;
mcontent: (mcontent: MItem, prop_name: string) => void; mcontent: (mcontent: MItem, prop_name: string) => void;
}) => { }) => {
const { mitem, item_comp, mcomp, scope } = arg; const { mitem, item, content_scope, item_comp, mcomp, scope } = arg;
const mitem_comp = mitem.get("component"); const mitem_comp = mitem.get("component");
const mprops = mcomp.get("component")?.get("props")?.toJSON() as Record< const mprops = mcomp.get("component")?.get("props")?.toJSON() as Record<
@ -30,6 +32,9 @@ export const extractMItemProps = (arg: {
for (const [k, v] of Object.entries(mprops)) { for (const [k, v] of Object.entries(mprops)) {
scope.props[k] = { name: k, value: `null as any` }; scope.props[k] = { name: k, value: `null as any` };
const mprop = ensureMProp(mitem_props, k, v); const mprop = ensureMProp(mitem_props, k, v);
parseJs(v.value, { item, content_scope });
item_comp.props[k] = v; item_comp.props[k] = v;
if (mprop && v.meta?.type === "content-element") { if (mprop && v.meta?.type === "content-element") {
scope.props[k].value = "null as ReactElement"; scope.props[k].value = "null as ReactElement";

View File

@ -14,7 +14,7 @@ import { gzipAsync } from "../entity/zlib";
import { SyncConnection } from "../type"; import { SyncConnection } from "../type";
import { loadComponent } from "./load-component"; import { loadComponent } from "./load-component";
import { extractMItemProps } from "./load-page-comp"; import { extractMItemProps } from "./load-page-comp";
import { parseJs } from "./parser/parse-js"; import { ArgParentMComp, parseJs } from "./parser/parse-js";
export const serverWalkLoad = async ( export const serverWalkLoad = async (
mitem: MItem, mitem: MItem,
@ -77,19 +77,6 @@ export const serverWalkLoad = async (
} }
}; };
type ArgParentMComp = EdMeta["parent_mcomp"] & {
id: string;
parent_ids: string[];
jsx_props: Record<
string,
{
id: string;
mitem: MItem;
parent_mcomp?: ArgParentMComp;
parent_ids: string[];
}
>;
};
export const serverWalkMap = ( export const serverWalkMap = (
p: { p: {
sync: SyncConnection; sync: SyncConnection;
@ -102,6 +89,7 @@ export const serverWalkMap = (
parent_ids: string[]; parent_ids: string[];
parent_item: EdMeta["parent_item"]; parent_item: EdMeta["parent_item"];
parent_mcomp?: ArgParentMComp; parent_mcomp?: ArgParentMComp;
content_scope?: Record<string, string>;
} }
) => { ) => {
const { mitem, parent_item, parent_mcomp } = arg; const { mitem, parent_item, parent_mcomp } = arg;
@ -133,10 +121,6 @@ export const serverWalkMap = (
item.id = override_id; item.id = override_id;
} }
if (item.name === "render_col") {
console.log(item);
}
const item_comp = item.component; const item_comp = item.component;
const mitem_comp = mitem.get("component"); const mitem_comp = mitem.get("component");
if (item_comp && item_comp.id) { if (item_comp && item_comp.id) {
@ -148,6 +132,8 @@ export const serverWalkMap = (
extractMItemProps({ extractMItemProps({
item_comp, item_comp,
mitem, mitem,
item,
content_scope: arg.content_scope,
mcomp: mitem, mcomp: mitem,
scope, scope,
mcontent(mcontent) {}, mcontent(mcontent) {},
@ -159,7 +145,10 @@ export const serverWalkMap = (
}; };
const js = item.adv?.js; const js = item.adv?.js;
if (typeof js === "string") { if (typeof js === "string") {
const s = parseJs(js); const s = parseJs(js, {
item,
content_scope: arg.content_scope,
});
const ps = p.scope[item.id].s; const ps = p.scope[item.id].s;
if (ps) { if (ps) {
if (s?.local) ps.local = s.local; if (s?.local) ps.local = s.local;
@ -206,24 +195,27 @@ export const serverWalkMap = (
jsx_props: {}, jsx_props: {},
}; };
const content_scope: Record<string, MItem> = {}; const content_scope: Record<string, string> = {};
extractMItemProps({ extractMItemProps({
item_comp, item_comp,
item,
mitem, mitem,
mcomp, mcomp,
scope, scope,
content_scope: arg.content_scope,
mcontent(mcontent, prop_name) { mcontent(mcontent, prop_name) {
const id = mcontent.get("id"); const id = mcontent.get("id");
if (id) { if (id) {
let cid = ref_ids[id] || id;
parent_mcomp.jsx_props[prop_name] = { parent_mcomp.jsx_props[prop_name] = {
id, id: cid,
mitem: mcontent, mitem: mcontent,
parent_mcomp: arg.parent_mcomp, parent_mcomp: arg.parent_mcomp,
parent_ids: [...arg.parent_ids, item.id], parent_ids: [...arg.parent_ids, item.id],
}; };
content_scope[prop_name] = mcontent; content_scope[prop_name] = cid;
} }
}, },
}); });
@ -233,7 +225,10 @@ export const serverWalkMap = (
const js = item.adv?.js; const js = item.adv?.js;
if (typeof js === "string") { if (typeof js === "string") {
const res = parseJs(js); const res = parseJs(js, {
item,
content_scope: arg.content_scope,
});
if (res) { if (res) {
scope.local = res.local; scope.local = res.local;
scope.passprop = res.passprop; scope.passprop = res.passprop;
@ -268,6 +263,7 @@ export const serverWalkMap = (
mitem: mitem as MItem, mitem: mitem as MItem,
}, },
parent_mcomp, parent_mcomp,
content_scope,
}); });
} }
} }
@ -289,7 +285,10 @@ export const serverWalkMap = (
const js = item.adv?.js; const js = item.adv?.js;
if (typeof js === "string") { if (typeof js === "string") {
const scope = parseJs(js); const scope = parseJs(js, {
item,
content_scope: arg.content_scope,
});
if (scope) pcomp.scope[id].s = scope; if (scope) pcomp.scope[id].s = scope;
} }
} }
@ -298,7 +297,10 @@ export const serverWalkMap = (
p.scope[item.id] = { p: arg.parent_ids, n: item.name, s: null }; p.scope[item.id] = { p: arg.parent_ids, n: item.name, s: null };
const js = item.adv?.js; const js = item.adv?.js;
if (typeof js === "string") { if (typeof js === "string") {
const scope = parseJs(js); const scope = parseJs(js, {
item,
content_scope: arg.content_scope,
});
if (scope) p.scope[item.id].s = scope; if (scope) p.scope[item.id].s = scope;
} }
} }
@ -317,6 +319,7 @@ export const serverWalkMap = (
} }
: undefined, : undefined,
parent_ids: [...arg.parent_ids, item.id], parent_ids: [...arg.parent_ids, item.id],
content_scope: arg.content_scope,
}); });
} }
}; };

View File

@ -1,6 +1,30 @@
import recast from "recast"; import recast from "recast";
import babel from "recast/parsers/babel-ts"; import babel from "recast/parsers/babel-ts";
export const parseJs = (code: string) => { import { IItem, MItem } from "../../../../../web/src/utils/types/item";
import { EdMeta } from "../../../../../web/src/nova/ed/logic/ed-global";
export type ArgParentMComp = EdMeta["parent_mcomp"] & {
id: string;
parent_ids: string[];
jsx_props: Record<
string,
{
id: string;
mitem: MItem;
parent_mcomp?: ArgParentMComp;
parent_ids: string[];
}
>;
};
export const parseJs = (
code: string,
arg: {
item: IItem;
content_scope?: Record<string, string>;
}
) => {
const { item } = arg;
const local = { name: "", value: "", index: 0 }; const local = { name: "", value: "", index: 0 };
const passprop: Record<string, { value: string; index: number }> = {}; const passprop: Record<string, { value: string; index: number }> = {};
const result = {} as { const result = {} as {
@ -8,6 +32,7 @@ export const parseJs = (code: string) => {
passprop: typeof passprop | undefined; passprop: typeof passprop | undefined;
props: Record<string, { name: string; value: string }>; props: Record<string, { name: string; value: string }>;
}; };
try { try {
const ast = recast.parse(code, { const ast = recast.parse(code, {
parser: babel, parser: babel,
@ -36,12 +61,14 @@ export const parseJs = (code: string) => {
attr.value.expression.type === "ObjectExpression" && attr.value.expression.type === "ObjectExpression" &&
attr.value.expression.loc attr.value.expression.loc
) { ) {
const loc = attr.value.expression.loc as any; const loc = attr.value.expression.loc as any;
const start = attr.value.expression.properties[0].loc?.start; const start = attr.value.expression.properties[0].loc?.start;
const end = attr.value.expression.properties[attr.value.expression.properties.length - 1].loc?.end; const end =
attr.value.expression.properties[
attr.value.expression.properties.length - 1
].loc?.end;
if (typeof start === 'number' && typeof end === 'number') { if (typeof start === "number" && typeof end === "number") {
local.value = code.substring( local.value = code.substring(
loc.start.index, loc.start.index,
loc.end.index loc.end.index
@ -67,7 +94,6 @@ export const parseJs = (code: string) => {
value: code.substring(loc.start.index, loc.end.index), value: code.substring(loc.start.index, loc.end.index),
index: loc.start.index, index: loc.start.index,
}; };
} }
} }
} }

View File

@ -55,6 +55,7 @@ export const treeRebuild = async (p: PG, arg?: { note?: string }) => {
comps: p.comp.list, comps: p.comp.list,
item_loading: p.ui.tree.item_loading, item_loading: p.ui.tree.item_loading,
meta: p.page.meta, meta: p.page.meta,
scope: p.page.scope,
}, },
{ {
is_layout: true, is_layout: true,
@ -131,6 +132,7 @@ export const treeRebuild = async (p: PG, arg?: { note?: string }) => {
item_loading: p.ui.tree.item_loading, item_loading: p.ui.tree.item_loading,
meta: p.page.meta, meta: p.page.meta,
tree: p.page.tree, tree: p.page.tree,
scope: p.page.scope,
}, },
{ {
is_layout: false, is_layout: false,
@ -160,24 +162,23 @@ export const treeRebuild = async (p: PG, arg?: { note?: string }) => {
p.page.building = false; p.page.building = false;
p.render(); p.render();
p.page.render(); p.page.render();
} }
}; };
export const getMRoot = (p: PG) => { export const getMRoot = (p: PG) => {
const root = p.page.doc?.getMap("map").get("root");
const root = p.page.doc?.getMap('map').get('root');
if (root) { if (root) {
return p.page.root_id === 'root' return p.page.root_id === "root"
? root ? root
: p.page.meta[p.page.root_id].mitem?.get('childs')?.get(0); : p.page.meta[p.page.root_id].mitem?.get("childs")?.get(0);
} }
} };
export const getMetaById = (p: PG, id: string) => { export const getMetaById = (p: PG, id: string) => {
if (active.comp_id) { if (active.comp_id) {
return p.comp.list[active.comp_id].meta[active.item_id]; if (p.comp.list[active.comp_id])
return p.comp.list[active.comp_id].meta[active.item_id];
} else { } else {
return p.page.meta[id] return p.page.meta[id];
} }
} };

View File

@ -5,7 +5,7 @@ import { MContent } from "../../../../utils/types/general";
import { IItem, MItem } from "../../../../utils/types/item"; import { IItem, MItem } from "../../../../utils/types/item";
import { FNCompDef, FNComponent } from "../../../../utils/types/meta-fn"; import { FNCompDef, FNComponent } from "../../../../utils/types/meta-fn";
import { MSection } from "../../../../utils/types/section"; import { MSection } from "../../../../utils/types/section";
import { EdMeta, PG, active } from "../ed-global"; import { EdMeta, IScope, PG, active } from "../ed-global";
import { loadCompSnapshot } from "./sync-walk-comp"; import { loadCompSnapshot } from "./sync-walk-comp";
import { import {
ensureMItemProps, ensureMItemProps,
@ -66,6 +66,7 @@ export const syncWalkMap = (
comps: PG["comp"]["list"]; comps: PG["comp"]["list"];
meta: Record<string, EdMeta>; meta: Record<string, EdMeta>;
component_not_found?: (comp_id: string) => void; component_not_found?: (comp_id: string) => void;
scope?: null | IScope;
}, },
arg: { arg: {
is_layout: boolean; is_layout: boolean;

View File

@ -1,73 +1,89 @@
import { createId } from "@paralleldrive/cuid2"; import { createId } from "@paralleldrive/cuid2";
import { useGlobal } from "web-utils"; import { useGlobal, waitUntil } from "web-utils";
import { MContent } from "../../../../../utils/types/general"; import { MContent } from "../../../../../utils/types/general";
import { IItem } from "../../../../../utils/types/item"; import { IItem } from "../../../../../utils/types/item";
import { EDGlobal, active } from "../../../logic/ed-global"; import { EDGlobal, active } from "../../../logic/ed-global";
import { getMetaById } from "../../../logic/tree/build"; import { getMetaById } from "../../../logic/tree/build";
import { fillID } from "../../../logic/tree/fill-id"; import { fillID } from "../../../logic/tree/fill-id";
import { TopBtn } from "../top-btn"; import { TopBtn } from "../top-btn";
import { prepSection } from "./prep-section";
export const EdAddItem = () => { export const EdAddItem = () => {
const p = useGlobal(EDGlobal, "EDITOR"); const p = useGlobal(EDGlobal, "EDITOR");
return <TopBtn style="slim" onClick={() => { return (
const meta = getMetaById(p, active.item_id); <TopBtn
style="slim"
onClick={async () => {
let meta = getMetaById(p, active.item_id);
if (!meta) { if (!meta) {
alert("Please select an item"); prepSection(p);
return; await waitUntil(() => getMetaById(p, active.item_id));
} meta = getMetaById(p, active.item_id);
const json = {
id: createId(),
name: `New Item`,
type: "item",
dim: { w: "full", h: "full" },
childs: [],
adv: {
css: "",
},
} as IItem;
let mitem = meta.mitem;
if (mitem) {
if (meta.item.type === 'text'
|| (meta.item.type === 'item' && meta.item.component?.id)) {
const parent_id = meta.parent_item.id;
const parent = getMetaById(p, parent_id === 'root' ? meta.item.id : parent_id);
if (!parent) {
alert('Failed to add text!');
} else {
mitem = parent.mitem;
} }
} if (!meta) return null;
if (mitem) { const json = {
const childs = mitem.get('childs'); id: createId(),
if (childs) { name: `New Item`,
const map = new Y.Map() as MContent; type: "item",
syncronize(map as any, fillID(json)); dim: { w: "full", h: "full" },
const childs = mitem.get("childs"); childs: [],
if (childs) { adv: {
childs.push([map]); css: "",
},
} as IItem;
let mitem = meta.mitem;
if (mitem) {
if (
meta.item.type === "text" ||
(meta.item.type === "item" && meta.item.component?.id)
) {
const parent_id = meta.parent_item.id;
const parent = getMetaById(
p,
parent_id === "root" ? meta.item.id : parent_id
);
if (!parent) {
alert("Failed to add text!");
} else {
mitem = parent.mitem;
}
}
if (mitem) {
const childs = mitem.get("childs");
if (childs) {
const map = new Y.Map() as MContent;
syncronize(map as any, fillID(json));
const childs = mitem.get("childs");
if (childs) {
childs.push([map]);
}
active.item_id = map.get("id") || "";
p.render();
}
} }
} }
} }}
}
}}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="15"
height="15"
fill="none"
viewBox="0 0 15 15"
> >
<path <svg
fill="currentColor" xmlns="http://www.w3.org/2000/svg"
fillRule="evenodd" width="15"
d="M1.5 2a.5.5 0 100-1 .5.5 0 000 1zm3 0a.5.5 0 100-1 .5.5 0 000 1zM8 1.5a.5.5 0 11-1 0 .5.5 0 011 0zm2.5.5a.5.5 0 100-1 .5.5 0 000 1zm3.5-.5a.5.5 0 11-1 0 .5.5 0 011 0zM1.5 14a.5.5 0 100-1 .5.5 0 000 1zm.5-3.5a.5.5 0 11-1 0 .5.5 0 011 0zM1.5 8a.5.5 0 100-1 .5.5 0 000 1zM2 4.5a.5.5 0 11-1 0 .5.5 0 011 0zM13.5 11a.5.5 0 100-1 .5.5 0 000 1zm.5-3.5a.5.5 0 11-1 0 .5.5 0 011 0zM13.5 5a.5.5 0 100-1 .5.5 0 000 1zM5 13.5a.5.5 0 11-1 0 .5.5 0 011 0zm2.5.5a.5.5 0 100-1 .5.5 0 000 1zm3.5-.5a.5.5 0 11-1 0 .5.5 0 011 0zm2.5.5a.5.5 0 100-1 .5.5 0 000 1zM4 5a1 1 0 011-1h5a1 1 0 011 1v5a1 1 0 01-1 1H5a1 1 0 01-1-1V5zm1 0h5v5H5V5z" height="15"
clipRule="evenodd" fill="none"
></path> viewBox="0 0 15 15"
</svg> >
</TopBtn> <path
} fill="currentColor"
fillRule="evenodd"
d="M1.5 2a.5.5 0 100-1 .5.5 0 000 1zm3 0a.5.5 0 100-1 .5.5 0 000 1zM8 1.5a.5.5 0 11-1 0 .5.5 0 011 0zm2.5.5a.5.5 0 100-1 .5.5 0 000 1zm3.5-.5a.5.5 0 11-1 0 .5.5 0 011 0zM1.5 14a.5.5 0 100-1 .5.5 0 000 1zm.5-3.5a.5.5 0 11-1 0 .5.5 0 011 0zM1.5 8a.5.5 0 100-1 .5.5 0 000 1zM2 4.5a.5.5 0 11-1 0 .5.5 0 011 0zM13.5 11a.5.5 0 100-1 .5.5 0 000 1zm.5-3.5a.5.5 0 11-1 0 .5.5 0 011 0zM13.5 5a.5.5 0 100-1 .5.5 0 000 1zM5 13.5a.5.5 0 11-1 0 .5.5 0 011 0zm2.5.5a.5.5 0 100-1 .5.5 0 000 1zm3.5-.5a.5.5 0 11-1 0 .5.5 0 011 0zm2.5.5a.5.5 0 100-1 .5.5 0 000 1zM4 5a1 1 0 011-1h5a1 1 0 011 1v5a1 1 0 01-1 1H5a1 1 0 01-1-1V5zm1 0h5v5H5V5z"
clipRule="evenodd"
></path>
</svg>
</TopBtn>
);
};

View File

@ -10,42 +10,49 @@ import { TopBtn } from "../top-btn";
export const EdAddSection = () => { export const EdAddSection = () => {
const p = useGlobal(EDGlobal, "EDITOR"); const p = useGlobal(EDGlobal, "EDITOR");
return <TopBtn style="slim" onClick={() => { return (
const meta = getMetaById(p, active.item_id); <TopBtn
style="slim"
onClick={() => {
const json = {
id: createId(),
name: `New Section`,
type: "section",
dim: { w: "full", h: "full" },
childs: [],
adv: {
css: "",
},
} as ISection;
if (!meta) { const root = p.page.doc?.getMap("map").get("root");
alert("Please select an item");
return;
}
const json = { if (root) {
id: createId(), const childs = root.get("childs");
name: `New Section`, if (childs) {
type: "section", const map = new Y.Map() as MContent;
dim: { w: "full", h: "full" }, syncronize(map as any, fillID(json));
childs: [], childs.push([map]);
adv: { active.item_id = json.id;
css: "", p.render();
}, }
} as ISection; }
}}
let mitem = meta.mitem;
if (mitem) {
}
}}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="15"
height="15"
fill="none"
viewBox="0 0 15 15"
> >
<path <svg
fill="currentColor" xmlns="http://www.w3.org/2000/svg"
fillRule="evenodd" width="15"
d="M2 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM2 5v5h11V5H2zm0-1a1 1 0 00-1 1v5a1 1 0 001 1h11a1 1 0 001-1V5a1 1 0 00-1-1H2zm-.5 10a.5.5 0 100-1 .5.5 0 000 1zM4 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM3.5 14a.5.5 0 100-1 .5.5 0 000 1zM6 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM5.5 14a.5.5 0 100-1 .5.5 0 000 1zM8 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM7.5 14a.5.5 0 100-1 .5.5 0 000 1zM10 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM9.5 14a.5.5 0 100-1 .5.5 0 000 1zM12 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM11.5 14a.5.5 0 100-1 .5.5 0 000 1zM14 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM13.5 14a.5.5 0 100-1 .5.5 0 000 1z" height="15"
clipRule="evenodd" fill="none"
></path> viewBox="0 0 15 15"
</svg> >
</TopBtn> <path
} fill="currentColor"
fillRule="evenodd"
d="M2 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM2 5v5h11V5H2zm0-1a1 1 0 00-1 1v5a1 1 0 001 1h11a1 1 0 001-1V5a1 1 0 00-1-1H2zm-.5 10a.5.5 0 100-1 .5.5 0 000 1zM4 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM3.5 14a.5.5 0 100-1 .5.5 0 000 1zM6 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM5.5 14a.5.5 0 100-1 .5.5 0 000 1zM8 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM7.5 14a.5.5 0 100-1 .5.5 0 000 1zM10 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM9.5 14a.5.5 0 100-1 .5.5 0 000 1zM12 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM11.5 14a.5.5 0 100-1 .5.5 0 000 1zM14 1.5a.5.5 0 11-1 0 .5.5 0 011 0zM13.5 14a.5.5 0 100-1 .5.5 0 000 1z"
clipRule="evenodd"
></path>
</svg>
</TopBtn>
);
};

View File

@ -1,76 +1,91 @@
import { useGlobal } from "web-utils"; import { useGlobal, waitUntil } from "web-utils";
import { TopBtn } from "../top-btn" import { TopBtn } from "../top-btn";
import { EDGlobal, active } from "../../../logic/ed-global"; import { EDGlobal, active } from "../../../logic/ed-global";
import { getMetaById } from "../../../logic/tree/build"; import { getMetaById } from "../../../logic/tree/build";
import { createId } from "@paralleldrive/cuid2"; import { createId } from "@paralleldrive/cuid2";
import { IText } from "../../../../../utils/types/text"; import { IText } from "../../../../../utils/types/text";
import { MContent } from "../../../../../utils/types/general"; import { MContent } from "../../../../../utils/types/general";
import { fillID } from "../../../logic/tree/fill-id"; import { fillID } from "../../../logic/tree/fill-id";
import { prepSection } from "./prep-section";
export const EdAddText = () => { export const EdAddText = () => {
const p = useGlobal(EDGlobal, "EDITOR"); const p = useGlobal(EDGlobal, "EDITOR");
return <TopBtn style="slim" onClick={() => { return (
const meta = getMetaById(p, active.item_id); <TopBtn
style="slim"
onClick={async () => {
let meta = getMetaById(p, active.item_id);
if (!meta) { if (!meta) {
alert("Please select an item"); prepSection(p);
return; await waitUntil(() => getMetaById(p, active.item_id));
} meta = getMetaById(p, active.item_id);
const json = {
id: createId(),
name: `New Text`,
type: "text",
dim: { w: "full", h: "full" },
layout: { align: "center", dir: "col", gap: 0 },
text: "",
html: "",
adv: {
css: "",
},
} as IText;
let mitem = meta.mitem;
if (mitem) {
if (meta.item.type === 'text'
|| (meta.item.type === 'item' && meta.item.component?.id)) {
const parent_id = meta.parent_item.id;
const parent = getMetaById(p, parent_id === 'root' ? meta.item.id : parent_id);
if (!parent) {
alert('Failed to add text!');
} else {
mitem = parent.mitem;
} }
} if (!meta) return null;
if (mitem) { const json = {
const childs = mitem.get('childs'); id: createId(),
if (childs) { name: `New Text`,
const map = new Y.Map() as MContent; type: "text",
syncronize(map as any, fillID(json)); dim: { w: "full", h: "full" },
const childs = mitem.get("childs"); layout: { align: "center", dir: "col", gap: 0 },
if (childs) { text: "",
childs.push([map]); html: "",
adv: {
css: "",
},
} as IText;
let mitem = meta.mitem;
if (mitem) {
if (
meta.item.type === "text" ||
(meta.item.type === "item" && meta.item.component?.id)
) {
const parent_id = meta.parent_item.id;
const parent = getMetaById(
p,
parent_id === "root" ? meta.item.id : parent_id
);
if (!parent) {
alert("Failed to add text!");
} else {
mitem = parent.mitem;
}
}
if (mitem) {
const childs = mitem.get("childs");
if (childs) {
const map = new Y.Map() as MContent;
syncronize(map as any, fillID(json));
const childs = mitem.get("childs");
if (childs) {
childs.push([map]);
}
active.item_id = map.get("id") || "";
p.render();
}
} }
} }
} }}
}
}}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="15"
height="15"
fill="none"
viewBox="0 0 15 15"
> >
<path <svg
fill="currentColor" xmlns="http://www.w3.org/2000/svg"
fillRule="evenodd" width="15"
d="M3.95 2.95V4.5a.45.45 0 01-.9 0v-2a.45.45 0 01.45-.45h8a.45.45 0 01.45.45v2a.45.45 0 11-.9 0V2.95h-3v9.1h1.204a.45.45 0 010 .9h-3.5a.45.45 0 110-.9H6.95v-9.1h-3z" height="15"
clipRule="evenodd" fill="none"
></path> viewBox="0 0 15 15"
</svg> >
</TopBtn> <path
} fill="currentColor"
fillRule="evenodd"
d="M3.95 2.95V4.5a.45.45 0 01-.9 0v-2a.45.45 0 01.45-.45h8a.45.45 0 01.45.45v2a.45.45 0 11-.9 0V2.95h-3v9.1h1.204a.45.45 0 010 .9h-3.5a.45.45 0 110-.9H6.95v-9.1h-3z"
clipRule="evenodd"
></path>
</svg>
</TopBtn>
);
};

View File

@ -0,0 +1,34 @@
import { createId } from "@paralleldrive/cuid2";
import { PG, active } from "../../../logic/ed-global";
import { ISection } from "../../../../../utils/types/section";
import { MContent } from "../../../../../utils/types/general";
import { fillID } from "../../../logic/tree/fill-id";
export const prepSection = (p: PG) => {
const root = p.page.doc?.getMap("map").get("root");
if (root) {
const childs = root.get("childs");
if (childs) {
if (p.page.tree.length === 0) {
const json = {
id: createId(),
name: `Section`,
type: "section",
dim: { w: "full", h: "full" },
childs: [],
adv: {
css: "",
},
} as ISection;
const map = new Y.Map() as MContent;
syncronize(map as any, fillID(json));
childs.push([map]);
active.item_id = json.id;
}
}
}
return;
};

View File

@ -10,7 +10,7 @@ import { HTML5Backend } from "react-dnd-html5-backend";
import { deepClone, useGlobal, useLocal, waitUntil } from "web-utils"; import { deepClone, useGlobal, useLocal, waitUntil } from "web-utils";
import { Loading } from "../../../../../utils/ui/loading"; import { Loading } from "../../../../../utils/ui/loading";
import { Modal } from "../../../../../utils/ui/modal"; import { Modal } from "../../../../../utils/ui/modal";
import { EDGlobal } from "../../../logic/ed-global"; import { EDGlobal, active } from "../../../logic/ed-global";
import { import {
pagePicker, pagePicker,
pagePickerRootItem, pagePickerRootItem,
@ -212,6 +212,8 @@ export const EdPopPage = () => {
if (isNew) { if (isNew) {
p.render(); p.render();
await reloadPagePicker(p); await reloadPagePicker(p);
active.comp_id = "";
active.item_id = "";
navigate(`/ed/${p.site.id}/${page.id}`); navigate(`/ed/${p.site.id}/${page.id}`);
} else { } else {
const found = pagePicker.tree.find( const found = pagePicker.tree.find(

View File

@ -11,9 +11,6 @@ export const declareScope = async (
monaco: Monaco monaco: Monaco
) => { ) => {
let active_id = active.item_id; let active_id = active.item_id;
const meta = getMetaById(p, active_id);
const parent = getMetaById(p, meta?.parent_item.id);
let s = deepClone(p.page.scope[active_id]); let s = deepClone(p.page.scope[active_id]);
if (active.comp_id && p.comp.list[active.comp_id]) { if (active.comp_id && p.comp.list[active.comp_id]) {

View File

@ -6,7 +6,7 @@ import { PG } from "../../../../../logic/ed-global";
import { getMetaById, treeRebuild } from "../../../../../logic/tree/build"; import { getMetaById, treeRebuild } from "../../../../../logic/tree/build";
export const edActionClone = (p: PG, item: IContent) => { export const edActionClone = (p: PG, item: IContent) => {
const mitem = getMetaById(p, item.id).mitem; const mitem = getMetaById(p, item.id)?.mitem;
if (mitem) { if (mitem) {
mitem.doc?.transact(() => { mitem.doc?.transact(() => {
mitem.parent.forEach((e: MContent, idx) => { mitem.parent.forEach((e: MContent, idx) => {

View File

@ -13,7 +13,7 @@ export const edActionCut = async (p: PG, item: IContent) => {
let str = `prasi-clipboard:` + JSON.stringify(item); let str = `prasi-clipboard:` + JSON.stringify(item);
navigator.clipboard.writeText(str); navigator.clipboard.writeText(str);
const mitem = getMetaById(p, item.id).mitem; const mitem = getMetaById(p, item.id)?.mitem;
if (mitem) { if (mitem) {
mitem.parent.forEach((e, k) => { mitem.parent.forEach((e, k) => {
if (e == mitem) { if (e == mitem) {

View File

@ -5,7 +5,7 @@ import { getMetaById, treeRebuild } from "../../../../../logic/tree/build";
import { fillID } from "../../../../../../../render/editor/tools/fill-id"; import { fillID } from "../../../../../../../render/editor/tools/fill-id";
export const edActionDetach = (p: PG, item: IItem) => { export const edActionDetach = (p: PG, item: IItem) => {
const mitem = getMetaById(p, item.id).mitem; const mitem = getMetaById(p, item.id)?.mitem;
if (mitem) { if (mitem) {
const compid = mitem.get("component")?.get("id"); const compid = mitem.get("component")?.get("id");
if (compid) { if (compid) {

View File

@ -7,7 +7,7 @@ export const edActionHide = (
item: IContent, item: IContent,
mode = "toggle" as "toggle" | "switch" mode = "toggle" as "toggle" | "switch"
) => { ) => {
const mitem = getMetaById(p, item.id).mitem; const mitem = getMetaById(p, item.id)?.mitem;
if (mitem) { if (mitem) {
const hidden = mitem.get("hidden"); const hidden = mitem.get("hidden");
if (mode === "toggle") { if (mode === "toggle") {

View File

@ -7,7 +7,7 @@ export const edActionNewComp = (
item: IItem, item: IItem,
e: React.MouseEvent<HTMLElement, MouseEvent> e: React.MouseEvent<HTMLElement, MouseEvent>
) => { ) => {
const mitem = getMetaById(p, item.id).mitem; const mitem = getMetaById(p, item.id)?.mitem;
if (mitem) { if (mitem) {
p.ui.popup.comp_group = { p.ui.popup.comp_group = {
mouse_event: e, mouse_event: e,

View File

@ -6,7 +6,7 @@ import { PG, active } from "../../../../../logic/ed-global";
import { getMetaById, treeRebuild } from "../../../../../logic/tree/build"; import { getMetaById, treeRebuild } from "../../../../../logic/tree/build";
export const edActionPaste = async (p: PG, item: IContent) => { export const edActionPaste = async (p: PG, item: IContent) => {
const mitem = getMetaById(p, item.id).mitem; const mitem = getMetaById(p, item.id)?.mitem;
if (mitem) { if (mitem) {
const res = await navigator.clipboard.readText(); const res = await navigator.clipboard.readText();
if (typeof res === "string" && res.startsWith("prasi-clipboard:")) { if (typeof res === "string" && res.startsWith("prasi-clipboard:")) {

View File

@ -5,7 +5,7 @@ import { PG } from "../../../../../logic/ed-global";
import { getMetaById, treeRebuild } from "../../../../../logic/tree/build"; import { getMetaById, treeRebuild } from "../../../../../logic/tree/build";
export const edActionUnwrap = (p: PG, item: IItem) => { export const edActionUnwrap = (p: PG, item: IItem) => {
const mitem = getMetaById(p, item.id).mitem; const mitem = getMetaById(p, item.id)?.mitem;
if (mitem) { if (mitem) {
mitem.parent.forEach((e: MContent, idx) => { mitem.parent.forEach((e: MContent, idx) => {
if (e.get("id") === mitem.get("id")) { if (e.get("id") === mitem.get("id")) {

View File

@ -7,7 +7,7 @@ import { syncronize } from "y-pojo";
import { getMetaById, treeRebuild } from "../../../../../logic/tree/build"; import { getMetaById, treeRebuild } from "../../../../../logic/tree/build";
export const edActionWrap = (p: PG, item: IText | IItem) => { export const edActionWrap = (p: PG, item: IText | IItem) => {
const mitem = getMetaById(p, item.id).mitem; const mitem = getMetaById(p, item.id)?.mitem;
if (mitem) { if (mitem) {
mitem.parent.forEach((e: MContent, idx) => { mitem.parent.forEach((e: MContent, idx) => {
if (e.get("id") === mitem.get("id")) { if (e.get("id") === mitem.get("id")) {

View File

@ -16,15 +16,17 @@ export const expandTreeHook = (
const open = JSON.parse(localStorage.getItem("prasi-tree-open") || "{}"); const open = JSON.parse(localStorage.getItem("prasi-tree-open") || "{}");
p.ui.tree.open = open; p.ui.tree.open = open;
let shouldOpen = new Set<string>(open[active.comp_id || p.page.cur.id] || []); let shouldOpen = new Set<string>(
open[active.comp_id || p.page.cur.id] || []
);
const cur = getMetaById(p, active.item_id); const cur = getMetaById(p, active.item_id);
if (cur && cur.parent_item) { if (cur && cur.parent_item) {
const id = cur.parent_item.mitem?.get('id'); const id = cur.parent_item.mitem?.get("id");
if (id) { if (id) {
let meta: EdMeta | null = getMetaById(p, id); let meta: EdMeta | undefined = getMetaById(p, id);
while (meta) { while (meta) {
const id = cur.parent_item.mitem?.get('id'); const id = cur.parent_item.mitem?.get("id");
if (id && !shouldOpen.has(id)) { if (id && !shouldOpen.has(id)) {
shouldOpen.add(id); shouldOpen.add(id);
meta = getMetaById(p, id); meta = getMetaById(p, id);
@ -36,9 +38,11 @@ export const expandTreeHook = (
} }
if (active.comp_id) { if (active.comp_id) {
const root = p.comp.list[active.comp_id].tree.find(e => e.parent === 'root'); const pcomp = p.comp.list[active.comp_id];
if (root && typeof root.id === 'string') if (pcomp) {
shouldOpen.add(root.id) const root = pcomp.tree.find((e) => e.parent === "root");
if (root && typeof root.id === "string") shouldOpen.add(root.id);
}
} }
if (shouldOpen.size > 0 && local.tree) { if (shouldOpen.size > 0 && local.tree) {
@ -46,7 +50,7 @@ export const expandTreeHook = (
local.render(); local.render();
if (active.item_id) { if (active.item_id) {
const meta = getMetaById(p, active.item_id); const meta = getMetaById(p, active.item_id);
if (meta && meta.item.type !== 'text') { if (meta && meta.item.type !== "text") {
setTimeout(() => { setTimeout(() => {
const el = document.getElementsByClassName(active.item_id); const el = document.getElementsByClassName(active.item_id);
if (el.length > 0) { if (el.length > 0) {

View File

@ -7,7 +7,7 @@ import { getMetaById } from "../../../logic/tree/build";
export const nodeOnDrop: ( export const nodeOnDrop: (
tree: NodeModel<EdMeta>[], tree: NodeModel<EdMeta>[],
options: DropOptions<EdMeta> options: DropOptions<EdMeta>
) => void = () => { }; ) => void = () => {};
export const canDrop = (p: PG, arg: DropOptions<EdMeta>) => { export const canDrop = (p: PG, arg: DropOptions<EdMeta>) => {
const { dragSource, dragSourceId, dropTargetId, dropTarget } = arg; const { dragSource, dragSourceId, dropTargetId, dropTarget } = arg;
@ -31,7 +31,7 @@ export const canDrop = (p: PG, arg: DropOptions<EdMeta>) => {
const to = dropTarget.data.item.type; const to = dropTarget.data.item.type;
if (from === "section" || from === "item") { if (from === "section" || from === "item") {
let parent = dropTarget.data; let parent: EdMeta | undefined = dropTarget.data;
while (parent) { while (parent) {
if (parent.item.id === dragSource.data.item.id) { if (parent.item.id === dragSource.data.item.id) {
return false; return false;