diff --git a/app/srv/ws/sync/actions/page_load.ts b/app/srv/ws/sync/actions/page_load.ts index ec86df98..80c83fa5 100644 --- a/app/srv/ws/sync/actions/page_load.ts +++ b/app/srv/ws/sync/actions/page_load.ts @@ -239,6 +239,6 @@ const scanMeta = async (doc: DPage, sync: SyncConnection) => { comps[id] = { id, snapshot: await gzipAsync(snap.bin) }; } } - + return { meta: simplifyMeta(meta), comps, entry }; }; diff --git a/app/web/src/nova/ed/logic/comp/load.tsx b/app/web/src/nova/ed/logic/comp/load.tsx index 5cc062d4..483d8404 100644 --- a/app/web/src/nova/ed/logic/comp/load.tsx +++ b/app/web/src/nova/ed/logic/comp/load.tsx @@ -1 +1,85 @@ -export const loadComponent = async (comp_id: string) => {}; +import { compress, decompress } from "wasm-gzip"; +import { DComp } from "../../../../utils/types/root"; +import { PG } from "../ed-global"; + +export const loadcomp = { + timeout: 0 as any, + pending: new Set(), +}; + +export const loadComponent = async (p: PG, id_comp: string) => { + return new Promise((resolve) => { + if (p.comp.list[id_comp]) { + resolve(true); + return; + } + + loadcomp.pending.add(id_comp); + clearTimeout(loadcomp.timeout); + loadcomp.timeout = setTimeout(async () => { + const comps = await p.sync.comp.load([...loadcomp.pending]); + let result = Object.entries(comps); + + for (const [id_comp, comp] of result) { + for (const cur of Object.values(comp)) { + if (cur && cur.snapshot) { + await loadCompSnapshot(p, id_comp, cur.snapshot); + } + } + } + loadcomp.pending.clear(); + resolve(result.length > 0); + }, 150); + }); +}; + +export const loadCompSnapshot = async ( + p: PG, + id_comp: string, + snapshot: Uint8Array +) => { + const doc = new Y.Doc() as DComp; + Y.applyUpdate(doc as any, decompress(snapshot)); + const mitem = doc.getMap("map").get("root"); + if (mitem) { + if (typeof p.comp.list[id_comp]?.on_update === "function") { + doc.off("update", p.comp.list[id_comp].on_update); + } + + p.comp.list[id_comp] = { + comp: { id: id_comp, snapshot }, + doc, + } as any; + + p.comp.list[id_comp] = { + ...p.comp.list[id_comp], + async on_update(bin, origin) { + if (origin === "sv_remote" || origin === "local") { + return; + } + + const res = await p.sync.yjs.sv_local( + "comp", + id_comp, + Buffer.from(compress(bin)) + ); + + if (res) { + const diff_local = Y.encodeStateAsUpdate( + doc as any, + decompress(res.sv) + ); + Y.applyUpdate(doc as any, decompress(res.diff), "local"); + await p.sync.yjs.diff_local( + "comp", + id_comp, + Buffer.from(compress(diff_local)) + ); + p.render(); + } + }, + }; + + doc.on("update", p.comp.list[id_comp].on_update); + } +}; diff --git a/app/web/src/nova/ed/logic/ed-route.ts b/app/web/src/nova/ed/logic/ed-route.ts index 47f4eb91..66a4ada6 100644 --- a/app/web/src/nova/ed/logic/ed-route.ts +++ b/app/web/src/nova/ed/logic/ed-route.ts @@ -2,6 +2,7 @@ import { compress, decompress } from "wasm-gzip"; import { PG } from "./ed-global"; import { loadSite } from "./ed-site"; import { treeRebuild } from "./tree/build"; +import { loadCompSnapshot } from "./comp/load"; export const edRoute = async (p: PG) => { if (p.status === "ready" || p.status === "init") { @@ -49,7 +50,7 @@ export const reloadPage = async (p: PG, page_id: string, note: string) => { if (remotePage.comps) { for (const [id_comp, c] of Object.entries(remotePage.comps)) { if (c && c.snapshot) { - // await loadCompSnapshot(p, id_comp, c.snapshot); + await loadCompSnapshot(p, id_comp, c.snapshot); } } } diff --git a/app/web/src/nova/ed/panel/popup/comp/comp-preview.tsx b/app/web/src/nova/ed/panel/popup/comp/comp-preview.tsx index 8f9d24db..8631ae32 100644 --- a/app/web/src/nova/ed/panel/popup/comp/comp-preview.tsx +++ b/app/web/src/nova/ed/panel/popup/comp/comp-preview.tsx @@ -4,9 +4,9 @@ import { produceCSS } from "../../../../../utils/css/gen"; import { IItem } from "../../../../../utils/types/item"; import { IText } from "../../../../../utils/types/text"; import { EDGlobal, PG, active } from "../../../logic/ed-global"; -// import { loadComponent } from "../../../logic/tree/sync-walk"; import { EdCompPreviewTree } from "./comp-preview-tree"; import { compPicker, reloadCompPicker } from "./comp-reload"; +import { loadComponent } from "../../../logic/comp/load"; export const EdCompPreview = () => { const p = useGlobal(EDGlobal, "EDITOR"); @@ -19,9 +19,9 @@ export const EdCompPreview = () => { useEffect(() => { if (!p.comp.list[comp_id] && !!comp_id) { - // loadComponent(p, comp_id).then(() => { - // p.render(); - // }); + loadComponent(p, comp_id).then(() => { + p.render(); + }); } }, [comp_id]); diff --git a/app/web/src/nova/vi/meta/comp/init-comp-load.tsx b/app/web/src/nova/vi/meta/comp/init-comp-load.tsx index 60a18f85..191b40cc 100644 --- a/app/web/src/nova/vi/meta/comp/init-comp-load.tsx +++ b/app/web/src/nova/vi/meta/comp/init-comp-load.tsx @@ -7,14 +7,14 @@ export const initLoadComp = async ( item: IItem, load: (comp_ids: string[]) => Promise ) => { - const comp_ids: string[] = []; + const comp_ids = new Set(); genMeta( { ...p, on: { visit_component: async (id) => { if (!p.comps[id]) { - comp_ids.push(id); + comp_ids.add(id); } }, }, @@ -23,8 +23,8 @@ export const initLoadComp = async ( { item } ); - if (comp_ids.length > 0) { - await load(comp_ids); + if (comp_ids.size > 0) { + await load([...comp_ids]); await initLoadComp(p, item, load); } };