This commit is contained in:
Rizky 2023-12-16 05:26:36 +07:00
parent 25bf1382ab
commit c0b75c75ad
20 changed files with 178 additions and 73 deletions

View File

@ -10,7 +10,7 @@ export const parseJs = (meta: IMeta) => {
const result = {} as {
local?: typeof local | undefined;
passprop?: typeof passprop | undefined;
props?: Record<string, { name: string; value: string; fn?: any }>;
props?: Record<string, { value: string; fn?: any }>;
};
try {

View File

@ -1,4 +1,5 @@
import { FC } from "react";
import { active } from "./logic/ed-global";
import { EdAddItem } from "./panel/header/mid/add-item";
import { EdAddSection } from "./panel/header/mid/add-section";
import { EdAddText } from "./panel/header/mid/add-text";
@ -23,7 +24,7 @@ export const EdMid: FC<{}> = () => {
<div className="border-r border-r-slate-100 text-slate-400 text-[9px] flex items-center px-1 mr-1">
ADD
</div>
<EdAddSection />
{!active.comp_id && <EdAddSection />}
<EdAddItem />
<EdAddText />
<EdCompPicker />

View File

@ -128,11 +128,12 @@ export const EDGlobal = {
site: deepClone(EmptySite),
site_dts: "",
script: {
siteTypes: {} as Record<string, string>,
site_types: {} as Record<string, string>,
loaded: false,
do_edit: async (newval: string, all?: boolean) => {},
db: null as any,
api: null as any,
init_local_effect: {} as Record<string, boolean>,
},
page: {
root_id: "root",

View File

@ -1,6 +1,6 @@
import { createId } from "@paralleldrive/cuid2";
import { useGlobal, waitUntil } from "web-utils";
import { MContent } from "../../../../../utils/types/general";
import { IContent, MContent } from "../../../../../utils/types/general";
import { IItem } from "../../../../../utils/types/item";
import { EDGlobal, active } from "../../../logic/ed-global";
import { getMetaById } from "../../../logic/tree/build";
@ -37,11 +37,12 @@ export const EdAddItem = () => {
let mitem = meta.mitem;
if (mitem) {
const item = meta.item as IContent;
if (
meta.item.type === "text" ||
(meta.item.type === "item" && meta.item.component?.id)
item.type === "text" ||
(item.type === "item" && item.component?.id)
) {
const parent_id = meta.parent_item.id;
const parent_id = meta.parent?.id || "root";
const parent = getMetaById(
p,
parent_id === "root" ? meta.item.id : parent_id

View File

@ -3,7 +3,6 @@ import { useGlobal } from "web-utils";
import { MContent } from "../../../../../utils/types/general";
import { ISection } from "../../../../../utils/types/section";
import { EDGlobal, active } from "../../../logic/ed-global";
import { getMetaById } from "../../../logic/tree/build";
import { fillID } from "../../../logic/tree/fill-id";
import { TopBtn } from "../top-btn";

View File

@ -4,7 +4,7 @@ import { EDGlobal, active } from "../../../logic/ed-global";
import { getMetaById } from "../../../logic/tree/build";
import { createId } from "@paralleldrive/cuid2";
import { IText } from "../../../../../utils/types/text";
import { MContent } from "../../../../../utils/types/general";
import { IContent, MContent } from "../../../../../utils/types/general";
import { fillID } from "../../../logic/tree/fill-id";
import { prepSection } from "./prep-section";
import { IItem } from "../../../../../utils/types/item";
@ -40,14 +40,15 @@ export const EdAddText = () => {
let mitem = meta.mitem as MContent;
if (mitem) {
const item = meta.item as IContent;
if (
meta.item.type === "text" ||
(meta.item.type === "item" && meta.item.component?.id)
item.type === "text" ||
(item.type === "item" && item.component?.id)
) {
const parent_id = meta.parent_item.id;
const parent_id = meta.parent?.id || "root";
const parent = getMetaById(
p,
parent_id === "root" ? meta.item.id : parent_id
parent_id === "root" ? item.id : parent_id
);
if (!parent) {
alert("Failed to add text!");

View File

@ -1,4 +1,5 @@
import { useGlobal, useLocal } from "web-utils";
import { IContent } from "../../../../utils/types/general";
import { Vi } from "../../../vi/vi";
import { EDGlobal, active } from "../../logic/ed-global";
@ -17,34 +18,35 @@ export const EdMain = () => {
`
)}
>
<div
className={cx(
"absolute inset-0 flex",
active.hover.id &&
css`
.s-${active.hover.id} {
&::after {
content: " ";
pointer-events: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
border: 2px solid #73b8ff;
}
}
`
)}
>
<div className={mainStyle()}>
<Vi
meta={p.page.meta}
api_url={p.site.config.api_url}
site_id={p.site.id}
page_id={p.page.cur.id}
entry={p.page.entry}
api={p.script.api}
db={p.script.db}
script={{ init_local_effect: p.script.init_local_effect }}
visit={(meta, parts) => {
if (
(meta.item as IContent).type === "text" &&
!meta.item.adv?.jsBuilt
) {
parts.props.spellCheck = false;
parts.props.contentEditable = true;
parts.props.dangerouslySetInnerHTML = {
__html: meta.mitem?.get("html") || "",
};
parts.props.onBlur = (e) => {
e.stopPropagation();
const mitem = meta.mitem;
if (mitem) {
mitem.set("html", e.currentTarget.innerHTML);
}
};
}
parts.props.className = cx(
parts.props.className,
active.item_id === meta.item.id &&
@ -86,6 +88,27 @@ export const EdMain = () => {
);
};
const mainStyle = () => {
return cx(
"absolute inset-0 flex",
active.hover.id &&
css`
.s-${active.hover.id} {
&::after {
content: " ";
pointer-events: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
border: 2px solid #73b8ff;
}
}
`
);
};
function setEndOfContenteditable(div: any) {
let range: any, sel: any;
if (document.createRange) {

View File

@ -88,7 +88,7 @@ export const EdScriptMonaco: FC<{}> = () => {
{
site_dts: p.site_dts,
script: {
siteTypes: {},
siteTypes: p.script.site_types,
},
site: p.site.config,
},

View File

@ -2,9 +2,10 @@ import { useGlobal } from "web-utils";
import { jscript } from "../../../../../utils/script/jscript";
import { Loading } from "../../../../../utils/ui/loading";
import { Modal } from "../../../../../utils/ui/modal";
import { EDGlobal } from "../../../logic/ed-global";
import { EDGlobal, active } from "../../../logic/ed-global";
import { propPopover } from "../../side/prop-master/prop-form";
import { EdScriptWorkbench } from "./workbench";
import { treeRebuild } from "../../../logic/tree/build";
export const EdPopScript = () => {
const p = useGlobal(EDGlobal, "EDITOR");
@ -14,16 +15,21 @@ export const EdPopScript = () => {
open={p.ui.popup.script.open}
onOpenChange={(open) => {
if (!open) {
p.ui.popup.script.open = false;
const script = p.ui.popup.script;
if (script) {
script.open = false;
if (
p.ui.popup.script.prop_name &&
p.ui.popup.script.type === "prop-master"
) {
propPopover.name = p.ui.popup.script.prop_name;
if (script.prop_name && script.type === "prop-master") {
propPopover.name = script.prop_name;
}
if (script.type === "item") {
delete p.script.init_local_effect[active.item_id];
treeRebuild(p, { note: "script-close" });
}
p.render();
}
p.render();
}
}}
>

View File

@ -33,7 +33,8 @@ export const declareScope = async (
for (const m of parents) {
if (active.comp_id && m.parent?.id === "root" && active.instance) {
const meta = p.page.meta[active.instance.item_id];
console.log(meta.scope.val);
if (!m.scope.def) m.scope.def = {};
m.scope.def.props = meta.scope?.def?.props;
}
const def = m.scope.def;
@ -48,6 +49,23 @@ declare global {
const ${def.local.name} = ${def.local.value};
}`,
});
} else if (def.props) {
Object.keys(def.props).map((e) => {
addScope({
monaco,
loc: {
item_id: m.item.id,
type: "prop",
comp_id: m.parent?.comp_id,
prop_name: e,
},
source: `\
export const {};
declare global {
const ${e} = null as any;
}`,
});
});
}
}
}
@ -55,7 +73,12 @@ declare global {
const addScope = (arg: {
monaco: Monaco;
loc: { item_id: string; type: "prop" | "item" };
loc: {
item_id: string;
type: "prop" | "item";
comp_id?: string;
prop_name?: string;
};
source: string;
}) => {
const { monaco, source } = arg;

View File

@ -1,7 +1,7 @@
import { useGlobal } from "web-utils";
import { EdScriptMonaco } from "./monaco";
import { EDGlobal, active } from "../../../logic/ed-global";
import { IItem } from "../../../../../utils/types/item";
import { EDGlobal, active } from "../../../logic/ed-global";
import { EdScriptMonaco } from "./monaco";
import { EdScriptSnippet } from "./snippet";
export const EdScriptWorkbench = () => {
@ -10,9 +10,9 @@ export const EdScriptWorkbench = () => {
<div className="flex flex-1 items-stretch">
<div className="flex flex-1 flex-col ">
<div className="flex border-b">
{p.ui.popup.script.type === "prop-master" ? (
<CompTitle />
) : (
{p.ui.popup.script.type === "prop-master" && <CompTitleMaster />}
{p.ui.popup.script.type === "prop-instance" && <CompTitleInstance />}
{p.ui.popup.script.type === "item" && (
<>
<div className="flex p-2 space-x-1">
{[
@ -46,7 +46,8 @@ export const EdScriptWorkbench = () => {
);
})}
</div>
{p.ui.popup.script.mode === "js" && <EdScriptSnippet />}
{p.ui.popup.script.mode === "js" &&
p.ui.popup.script.type === "item" && <EdScriptSnippet />}
</>
)}
</div>
@ -58,7 +59,27 @@ export const EdScriptWorkbench = () => {
);
};
const CompTitle = () => {
const CompTitleInstance = () => {
const p = useGlobal(EDGlobal, "EDITOR");
const item = p.page.meta[active.item_id].item as IItem;
if (item && item.component?.id) {
const props = item.component.props;
return (
<div className="flex text-xs p-2 space-x-1 items-center">
<div>{item.name}</div>
<ArrowRight />
<div>{p.ui.popup.script.prop_name}</div>
<ArrowRight />
<div>{p.ui.popup.script.prop_kind}</div>
</div>
);
}
return <></>;
};
const CompTitleMaster = () => {
const p = useGlobal(EDGlobal, "EDITOR");
const item = p.comp.list[active.comp_id].doc
@ -69,7 +90,7 @@ const CompTitle = () => {
if (item && item.component?.id) {
const props = item.component.props;
return (
<div className="flex text-xs space-x-1 items-center">
<div className="flex text-xs p-2 space-x-1 items-center">
<div>{item.name}</div>
<ArrowRight />
<div>{p.ui.popup.script.prop_name}</div>

View File

@ -20,7 +20,6 @@ export const EdTreeBody = () => {
const TypedTree = DNDTree<IMeta>;
active.hover.renderTree = local.render;
expandTreeHook(p, local);
let tree: NodeModel<IMeta>[] = [];

View File

@ -2,6 +2,7 @@ import { TreeMethods } from "@minoru/react-dnd-treeview";
import { useEffect } from "react";
import { IMeta, PG, active } from "../../../../logic/ed-global";
import { getMetaById } from "../../../../logic/tree/build";
import { IContent } from "../../../../../../utils/types/general";
export const expandTreeHook = (
p: PG,
@ -21,14 +22,14 @@ export const expandTreeHook = (
);
const cur = getMetaById(p, active.item_id);
if (cur && cur.parent_item) {
const id = cur.parent_item.mitem?.get("id");
if (cur && cur.parent?.id) {
const id = cur.parent.id;
if (id) {
shouldOpen.add(id);
let meta: IMeta | undefined = getMetaById(p, id);
while (meta) {
const id = meta.parent_item.id;
const id = meta.parent?.id;
if (id && !shouldOpen.has(id)) {
shouldOpen.add(id);
meta = getMetaById(p, id);
@ -52,7 +53,7 @@ export const expandTreeHook = (
local.render();
if (active.item_id) {
const meta = getMetaById(p, active.item_id);
if (meta && meta.item.type !== "text") {
if (meta && (meta.item as IContent).type !== "text") {
setTimeout(() => {
const el = document.getElementsByClassName(active.item_id);
if (el.length > 0) {

View File

@ -11,6 +11,9 @@ export const ViGlobal = {
api: null as any,
db: null as any,
},
script: {
init_local_effect: undefined as undefined | Record<string, boolean>,
},
visit: undefined as
| undefined
| ((meta: IMeta, parts: ReturnType<typeof viParts>) => void),

View File

@ -35,7 +35,7 @@ export const viEvalProps = (
`
);
meta.scope.def.props[name] = { name, value: prop.valueBuilt };
meta.scope.def.props[name] = { value: prop.valueBuilt };
let val = fn(...Object.values(arg));
if (typeof val === "function") {
@ -58,7 +58,7 @@ export const viEvalProps = (
export const updatePropScope = (meta: IMeta, scope: any) => {
if (meta.scope.def?.props) {
for (const prop of Object.values(meta.scope.def.props)) {
for (const [name, prop] of Object.entries(meta.scope.def.props)) {
if (prop.fn) {
const all_scope = {
...scope,
@ -66,7 +66,7 @@ export const updatePropScope = (meta: IMeta, scope: any) => {
};
const fn = new Function(
...Object.keys(all_scope),
`// [${meta.item.name}] ${prop.name}: ${meta.item.id}
`// [${meta.item.name}] ${name}: ${meta.item.id}
return ${prop.value || ""}
`
);

View File

@ -10,7 +10,11 @@ import { createViLocal } from "./local";
import { createViPassProp } from "./passprop";
export const viEvalScript = (
vi: { meta: VG["meta"]; visit?: VG["visit"] },
vi: {
meta: VG["meta"];
visit?: VG["visit"];
script?: { init_local_effect: any };
},
meta: IMeta,
scope: any
) => {
@ -30,7 +34,7 @@ export const viEvalScript = (
if (!meta.script) {
meta.script = {
result: null,
Local: createViLocal(meta, scope),
Local: createViLocal(meta, scope, vi.script?.init_local_effect),
PassProp: createViPassProp(vi, meta, scope),
};
}

View File

@ -2,7 +2,11 @@ import { ReactNode, useEffect, useRef, useState } from "react";
import { IMeta } from "../../../ed/logic/ed-global";
import { updatePropScope } from "./eval-prop";
export const createViLocal = (meta: IMeta, scope: any) => {
export const createViLocal = (
meta: IMeta,
scope: any,
init_local_effect: any
) => {
return <T extends Record<string, any>>(arg: {
children: ReactNode;
name: string;
@ -20,6 +24,7 @@ export const createViLocal = (meta: IMeta, scope: any) => {
}
const val = meta.scope.val;
val[arg.name] = local;
updatePropScope(meta, scope);
if (arg.hook) {
@ -27,13 +32,20 @@ export const createViLocal = (meta: IMeta, scope: any) => {
}
useEffect(() => {
const fn = async () => {
if (arg.effect) {
await arg.effect(local);
let should_run = !init_local_effect[meta.item.id];
if (should_run) {
if (typeof init_local_effect === "object") {
init_local_effect[meta.item.id] = true;
}
};
const fn = async () => {
if (arg.effect) {
await arg.effect(local);
}
};
fn();
}
fn();
return () => {};
}, []);

View File

@ -21,7 +21,7 @@ export const ErrorBox = withErrorBoundary(
if (meta && local.meta !== meta) {
local.meta = meta;
resetError();
setTimeout(resetError);
}
let _meta = meta;

View File

@ -5,21 +5,25 @@ import { viLoad } from "./load/load";
import { VG, ViGlobal } from "./render/global";
import { ViRoot } from "./root";
import { ErrorBox } from "./utils/error-box";
import { viParts } from "./render/parts";
export const Vi: FC<{
meta: Record<string, IMeta>;
entry: string[];
api_url: string;
site_id: string;
page_id: string;
api?: any;
db?: any;
script?: { init_local_effect: Record<string, boolean> };
visit?: VG["visit"];
}> = ({ meta, entry, api_url, site_id, api, db, visit }) => {
}> = ({ meta, entry, api_url, site_id, api, db, visit, script }) => {
const vi = useGlobal(ViGlobal, "VI");
if (vi.meta !== meta) {
vi.meta = meta;
}
if (script) {
vi.script.init_local_effect = script.init_local_effect;
}
vi.visit = visit;
if (vi.status === "init") {

View File

@ -63,7 +63,7 @@ export const jsMount = async (editor: MonacoEditor, monaco: Monaco, p?: PG) => {
type: "" as "prop" | "item",
item_id: "" as string | undefined,
comp_id: "",
instance_id: "",
prop_name: "",
};
try {
arg = JSON.parse(cpath.substring(0, cpath.length - 5) || "{}");
@ -88,6 +88,12 @@ export const jsMount = async (editor: MonacoEditor, monaco: Monaco, p?: PG) => {
p.render();
}
} else if (arg.type === "prop") {
active.comp_id = arg.comp_id;
p.ui.popup.script.prop_name = arg.prop_name;
p.ui.popup.script.type = "prop-instance";
p.ui.popup.script.prop_kind = "value";
p.ui.popup.script.open = true;
p.render();
}
}, 100);
}