diff --git a/app/srv/api/nova-load.ts b/app/srv/api/nova-load.ts new file mode 100644 index 00000000..c4d5f46d --- /dev/null +++ b/app/srv/api/nova-load.ts @@ -0,0 +1,35 @@ +import { dir } from "dir"; +import { apiContext } from "service-srv"; +import { g } from "utils/global"; + +export const _ = { + url: "/nova-load/:mode/:id/**", + async api(mode: "site" | "page" | "code", id: string) { + const { req, res } = apiContext(this); + + if (mode === "site") { + const code = await db.code.findFirst({ where: { id_site: id } }); + if (code) { + const file = Bun.file( + dir.path(`${g.datadir}/site/build/${code.id}/${req.params["*"]}`) + ); + if (await file.exists()) { + return new Response(file as any); + } + } + } + if (mode === "page") { + const code = await db.code_assign.findMany({ where: { id_page: id } }); + return code.map((e) => e.id); + } else if (mode === "code") { + const file = Bun.file( + dir.path(`${g.datadir}/site/build/${id}/${req.params["*"]}`) + ); + if (await file.exists()) { + return new Response(file as any); + } + } + + return "This is nova-load.ts"; + }, +}; diff --git a/app/web/src/base/page/ed.tsx b/app/web/src/base/page/ed.tsx index 951bdea9..ef10d4a5 100644 --- a/app/web/src/base/page/ed.tsx +++ b/app/web/src/base/page/ed.tsx @@ -13,7 +13,7 @@ export default page({ if (!edInitSync(p)) { return ; } - + return ; }, }); diff --git a/app/web/src/nova/ed/ed-base.tsx b/app/web/src/nova/ed/ed-base.tsx index c011204e..9ae87ed6 100644 --- a/app/web/src/nova/ed/ed-base.tsx +++ b/app/web/src/nova/ed/ed-base.tsx @@ -1,17 +1,17 @@ import { useGlobal } from "web-utils"; import { Loading } from "../../utils/ui/loading"; import { EdLeft } from "./ed-left"; +import { EdRight } from "./ed-right"; import { EDGlobal } from "./logic/ed-global"; import { edInit } from "./logic/ed-init"; import { edRoute } from "./logic/ed-route"; import { edUndoManager } from "./logic/ed-undo"; import { EdMain } from "./panel/main/main"; import { EdPane } from "./panel/main/pane-resize"; +import { EdPopCode } from "./panel/popup/code/code"; import { EdPopCompGroup } from "./panel/popup/comp/comp-group"; import { EdPopSite } from "./panel/popup/site/site"; import { EdScriptInit } from "./panel/script/monaco/init"; -import { EdRight } from "./ed-right"; -import { EdPopCode } from "./panel/popup/code/code"; export const EdBase = () => { const p = useGlobal(EDGlobal, "EDITOR"); @@ -19,12 +19,12 @@ export const EdBase = () => { edUndoManager(p); if (p.status === "init") { - edInit(p); + edInit(p) } edRoute(p); - if (p.status === "loading" || p.status === "init") { + if (p.status === "loading") { return ; } if (p.status === "site-not-found" || p.status === "page-not-found") { diff --git a/app/web/src/nova/ed/logic/ed-global.ts b/app/web/src/nova/ed/logic/ed-global.ts index 97e93f73..7a8e3e32 100644 --- a/app/web/src/nova/ed/logic/ed-global.ts +++ b/app/web/src/nova/ed/logic/ed-global.ts @@ -82,6 +82,7 @@ export const EDGlobal = { meta: {} as Record, entry: [] as string[], tree: [] as NodeModel[], + render: () => {}, }, comp: { cur: EmptyComp, diff --git a/app/web/src/nova/ed/logic/ed-route.ts b/app/web/src/nova/ed/logic/ed-route.ts index 6c8f3427..295ce83a 100644 --- a/app/web/src/nova/ed/logic/ed-route.ts +++ b/app/web/src/nova/ed/logic/ed-route.ts @@ -3,7 +3,7 @@ import { PG } from "./ed-global"; import { treeRebuild } from "./tree/build"; export const edRoute = async (p: PG) => { - if (p.status === "ready") { + if (p.status === "ready" || p.status === "init") { if (!p.site.domain && !p.site.name) { p.status = "loading"; const site = await p.sync.site.load(p.site.id); diff --git a/app/web/src/nova/ed/panel/main/main.tsx b/app/web/src/nova/ed/panel/main/main.tsx index 52b0724e..a3a67190 100644 --- a/app/web/src/nova/ed/panel/main/main.tsx +++ b/app/web/src/nova/ed/panel/main/main.tsx @@ -15,6 +15,11 @@ export const EdMain = () => { meta: p.page.meta, entry: p.page.entry, }} + site_id={p.site.id} + page_id={p.page.cur.id} + bind={({ render }) => { + p.page.render = render; + }} /> )} diff --git a/app/web/src/nova/view/logic/global.ts b/app/web/src/nova/view/logic/global.ts index 18720301..3d59c223 100644 --- a/app/web/src/nova/view/logic/global.ts +++ b/app/web/src/nova/view/logic/global.ts @@ -1,9 +1,12 @@ +import { ReactElement } from "react"; import { EdMeta } from "../../ed/logic/ed-global"; export const ViewGlobal = { - mode: "init" as "init" | "ready", + mode: "init" as "init" | "load-code" | "loading-code" | "ready" | "rebuild", + current: { site_id: "", page_id: "" }, meta: {} as Record, entry: [] as string[], + bodyCache: null as null | ReactElement, }; export type VG = typeof ViewGlobal & { render: () => void }; diff --git a/app/web/src/nova/view/logic/init.ts b/app/web/src/nova/view/logic/init.ts index 79f5dc17..b0be3a9f 100644 --- a/app/web/src/nova/view/logic/init.ts +++ b/app/web/src/nova/view/logic/init.ts @@ -1,9 +1,15 @@ -import { useGlobal } from "web-utils"; -import { VG, ViewGlobal } from "./global"; +import { VG } from "./global"; import { VLoad } from "./types"; -export const VInit = (v: VG, load: VLoad) => { - v.mode = "ready"; +export const vInit = ( + v: VG, + arg: { load: VLoad; site_id: string; page_id: string } +) => { + const { load, site_id, page_id } = arg; + + v.mode = "load-code"; + v.current.site_id = site_id; + v.current.page_id = page_id; if (load.mode === "tree_meta") { v.meta = load.meta; diff --git a/app/web/src/nova/view/logic/load-code.ts b/app/web/src/nova/view/logic/load-code.ts new file mode 100644 index 00000000..9447b826 --- /dev/null +++ b/app/web/src/nova/view/logic/load-code.ts @@ -0,0 +1,57 @@ +import { VG } from "./global"; + +export const vLoadCode = async (v: VG) => { + if (v.mode === "load-code") { + v.mode = "loading-code"; + + const { site_id, page_id } = v.current; + const w = window as any; + const promises = [ + new Promise(async (resolve) => { + const module = await importCJS(`/nova-load/site/${site_id}/index.js`); + for (const [k, v] of Object.entries(module)) { + w[k] = v; + } + resolve(); + }), + ]; + + const code_ids = await api.nova_load("page", page_id); + for (const id of code_ids) { + promises.push( + new Promise(async (resolve) => { + const module = await importCJS(`/nova-load/code/${id}/index.js`); + for (const [k, v] of Object.entries(module)) { + w[k] = v; + } + resolve(); + }) + ); + } + + await Promise.all(promises); + + v.mode = "rebuild"; + v.render(); + } +}; + +const importCJS = async (url: string) => { + const module = { exports: { __esModule: true as true | undefined } }; + const res = await fetch(url); + + const src = await res.text(); + if (src) { + const fn = new Function("module", src); + await fn(module); + + const result = { ...module.exports }; + if (result.__esModule) { + delete result.__esModule; + } + + return result; + } + + return {}; +}; diff --git a/app/web/src/nova/view/render/entry.tsx b/app/web/src/nova/view/render/entry.tsx new file mode 100644 index 00000000..bd3cd109 --- /dev/null +++ b/app/web/src/nova/view/render/entry.tsx @@ -0,0 +1,15 @@ +import { useGlobal } from "web-utils"; +import { ViewGlobal } from "../logic/global"; +import { VSection } from "./section"; + +export const VEntry = () => { + const v = useGlobal(ViewGlobal, "VIEW"); + + return ( + <> + {v.entry.map((section_id) => { + return ; + })} + + ); +}; diff --git a/app/web/src/nova/view/render/meta.tsx b/app/web/src/nova/view/render/meta.tsx new file mode 100644 index 00000000..89d42426 --- /dev/null +++ b/app/web/src/nova/view/render/meta.tsx @@ -0,0 +1,11 @@ +import { FC } from "react"; +import { useGlobal } from "web-utils"; +import { ViewGlobal } from "../logic/global"; + +export const ViewMeta: FC<{ id: string }> = ({ id }) => { + const v = useGlobal(ViewGlobal, "VIEW"); + + const meta = v.meta[id]; + const item = meta.item; + return
; +}; diff --git a/app/web/src/nova/view/render/section.tsx b/app/web/src/nova/view/render/section.tsx index d9eafba0..eb97916a 100644 --- a/app/web/src/nova/view/render/section.tsx +++ b/app/web/src/nova/view/render/section.tsx @@ -1,10 +1,6 @@ -import { FC, ReactNode } from "react"; -import { ISection } from "../../../utils/types/section"; +import { FC } from "react"; +import { ViewMeta } from "./meta"; -export const VSection: FC<{ item: ISection; children: ReactNode }> = ({ - item, - children, -}) => { - console.log(item); - return
; +export const VSection: FC<{ id: string }> = ({ id }) => { + return ; }; diff --git a/app/web/src/nova/view/view.tsx b/app/web/src/nova/view/view.tsx index 9147b59e..a57bf730 100644 --- a/app/web/src/nova/view/view.tsx +++ b/app/web/src/nova/view/view.tsx @@ -2,36 +2,50 @@ import { FC } from "react"; import { useGlobal } from "web-utils"; import { Loading } from "../../utils/ui/loading"; import { ViewGlobal } from "./logic/global"; -import { VInit } from "./logic/init"; +import { vInit } from "./logic/init"; +import { vLoadCode } from "./logic/load-code"; import { VLoad } from "./logic/types"; -import { VSection } from "./render/section"; -import { ISection } from "../../utils/types/section"; +import { VEntry } from "./render/entry"; export const View: FC<{ load: VLoad; -}> = ({ load }) => { + site_id: string; + page_id: string; + bind?: (arg: { render: () => void }) => void; +}> = ({ load, site_id, page_id, bind: onLoad }) => { const v = useGlobal(ViewGlobal, "VIEW"); - if (v.mode === "init") { - VInit(v, load); + if (v.current.page_id !== page_id || v.current.site_id !== site_id) { + v.mode = "init"; } - return ( -
- {v.mode !== "ready" ? ( - - ) : ( - v.entry.map((section_id) => { - const meta = v.meta[section_id]; - const section = meta.item as ISection; + if (onLoad) { + onLoad({ + render() { + v.mode = "rebuild"; + v.render(); + }, + }); + } - return ( - - Hello - - ); - }) - )} -
- ); + if (v.mode === "init") { + vInit(v, { load, page_id, site_id }); + if (v.mode === "init") { + return ; + } + } + + if (v.mode === "load-code" || v.mode === "loading-code") { + vLoadCode(v); + if (v.mode === "load-code" || v.mode === "loading-code") { + return ; + } + } + + if (v.mode === "rebuild") { + v.bodyCache = ; + v.mode = "ready"; + } + + return
{v.bodyCache}
; };