273 lines
7.7 KiB
TypeScript
273 lines
7.7 KiB
TypeScript
import { createRouter, RadixRouter } from "radix3";
|
|
import { compress, decompress } from "wasm-gzip";
|
|
import { deepClone } from "web-utils";
|
|
import * as Y from "yjs";
|
|
import { registerSiteTypings } from "../../../utils/script/typings";
|
|
import { clientStartSync } from "../../../utils/sync/ws-client";
|
|
import { w } from "../../../utils/types/general";
|
|
import { Loading } from "../../../utils/ui/loading";
|
|
import { loadFrontEnd, loadTypings } from "./code-loader";
|
|
import { updateComponentMeta } from "./comp/load";
|
|
import { EmptySite, PG } from "./ed-global";
|
|
import { reloadPage } from "./ed-route";
|
|
import { loadSite } from "./ed-site";
|
|
import { treeRebuild } from "./tree/build";
|
|
import { format } from "date-fns";
|
|
|
|
const decoder = new TextDecoder();
|
|
|
|
const page = {
|
|
list: [] as { id: string; url: string }[],
|
|
route: null as null | RadixRouter<{ id: string; url: string }>,
|
|
};
|
|
|
|
export const loadSession = (p: PG) => {
|
|
const session = JSON.parse(
|
|
localStorage.getItem("prasi-session") || "null"
|
|
) as { data: { user: { id: string; username: string } } };
|
|
if (!session && location.pathname.startsWith("/ed/")) {
|
|
location.href = "/login";
|
|
return <Loading note="logging in" />;
|
|
}
|
|
|
|
if (session?.data?.user) {
|
|
p.user.id = session.data.user.id;
|
|
p.user.username = session.data.user.username;
|
|
} else {
|
|
p.user.id = "ab1390f5-40d5-448e-a8c3-84b0fb600930";
|
|
p.user.username = "anonymous";
|
|
}
|
|
};
|
|
|
|
export const edInitSync = (p: PG) => {
|
|
loadSession(p);
|
|
if (location.pathname.startsWith("/vi/")) {
|
|
if (page.list.length === 0) {
|
|
_db.page
|
|
.findMany({
|
|
where: {
|
|
id_site: params.site_id,
|
|
is_deleted: false,
|
|
is_default_layout: false,
|
|
},
|
|
select: {
|
|
id: true,
|
|
url: true,
|
|
},
|
|
})
|
|
.then((list) => {
|
|
page.list = list;
|
|
edInitSync(p);
|
|
});
|
|
|
|
return;
|
|
}
|
|
if (!page.route) {
|
|
page.route = createRouter();
|
|
for (const e of page.list) {
|
|
page.route.insert(e.url, e);
|
|
}
|
|
}
|
|
|
|
const arrpath = location.pathname.split("/");
|
|
const pathname = "/" + arrpath.slice(3).join("/");
|
|
|
|
if (!params.page_id) {
|
|
const res = page.route.lookup(pathname);
|
|
if (res) {
|
|
params.page_id = res.id;
|
|
if (res.params) {
|
|
for (const [k, v] of Object.entries(res.params)) {
|
|
if (!["site_id", "page_id"].includes(k)) {
|
|
params[k] = v;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (p.sync) {
|
|
if (p.site.id === "--loading--") return false;
|
|
if (params.site_id !== p.site.id) {
|
|
p.site = deepClone(EmptySite);
|
|
p.site.id = "--loading--";
|
|
p.ui.popup.code.init = false;
|
|
p.sync.site.load(params.site_id).then(async (site) => {
|
|
if (site) {
|
|
await loadSite(p, site, "from-sync");
|
|
p.render();
|
|
} else {
|
|
alert("Site not found. redirecting...");
|
|
location.href = `/ed/`;
|
|
}
|
|
return;
|
|
});
|
|
return false;
|
|
}
|
|
|
|
if (
|
|
!p.page.cur.id &&
|
|
!params.page_id &&
|
|
params.site_id &&
|
|
location.pathname.startsWith("/ed/")
|
|
) {
|
|
_db.page
|
|
.findFirst({
|
|
where: {
|
|
is_deleted: false,
|
|
is_default_layout: false,
|
|
id_site: params.site_id,
|
|
},
|
|
select: { id: true },
|
|
})
|
|
.then((e) => {
|
|
if (params.site_id === "_") {
|
|
alert("asdsa");
|
|
return;
|
|
}
|
|
if (e) location.href = `/ed/${params.site_id}/${e.id}`;
|
|
});
|
|
return false;
|
|
}
|
|
}
|
|
if (!p.sync && !p.sync_assigned) {
|
|
p.sync_assigned = true;
|
|
p.site = deepClone(EmptySite);
|
|
clientStartSync({
|
|
user_id: p.user.id,
|
|
site_id: params.site_id,
|
|
page_id: params.page_id,
|
|
events: {
|
|
opened() {
|
|
if (w.offline) {
|
|
console.log("reconnected!");
|
|
w.offline = false;
|
|
p.ui.syncing = true;
|
|
p.render();
|
|
} else {
|
|
w.offline = false;
|
|
p.render();
|
|
}
|
|
},
|
|
shakehand(client_id) {
|
|
p.user.client_id = client_id;
|
|
console.log(`Prasi connected: ${client_id}`);
|
|
},
|
|
disconnected() {
|
|
console.log("offline, reconnecting...");
|
|
w.offline = true;
|
|
p.render();
|
|
return {
|
|
reconnect: true,
|
|
};
|
|
},
|
|
async editor_start(e) {
|
|
if (params.site_id !== e.site_id || params.page_id !== e.page_id) {
|
|
if (!p.page.cur.id) {
|
|
p.site.id = e.site_id;
|
|
p.page.cur.id = e.page_id;
|
|
if (location.pathname.startsWith("/ed/")) {
|
|
location.href = `/ed/${e.site_id}/${e.page_id}`;
|
|
}
|
|
}
|
|
} else {
|
|
p.site.id = e.site_id;
|
|
p.page.cur.id = e.page_id;
|
|
p.render();
|
|
}
|
|
},
|
|
site_updated(site) {
|
|
for (const [k, v] of Object.entries(site)) {
|
|
if (k === "js" || k === "js_compiled") {
|
|
p.site[k] = decoder.decode(decompress(v as any));
|
|
} else {
|
|
(p.site as any)[k] = v;
|
|
}
|
|
}
|
|
p.render();
|
|
},
|
|
async code_changes({ ts, mode, status }) {
|
|
if (mode === "frontend") {
|
|
if (status === "ok") {
|
|
console.clear();
|
|
console.log(
|
|
`${format(Date.now(), "HH:mm:ss")} 🚧 Code updated from vscode `
|
|
);
|
|
|
|
await loadFrontEnd(p, ts);
|
|
} else if (status === "building") {
|
|
console.log(
|
|
`${format(
|
|
Date.now(),
|
|
"HH:mm:ss"
|
|
)} ⏳ Code changed from vscode, rebuilding...`
|
|
);
|
|
}
|
|
} else {
|
|
await loadTypings(p);
|
|
if (p.ui.monaco) {
|
|
registerSiteTypings(p.ui.monaco, p);
|
|
}
|
|
}
|
|
await treeRebuild(p);
|
|
p.render();
|
|
},
|
|
async remote_svlocal(data) {
|
|
let doc = null as any;
|
|
if (data.type === "page" && p.page.cur.id === data.id) {
|
|
doc = p.page.doc as Y.Doc;
|
|
} else if (data.type === "comp" && p.comp.list[data.id]) {
|
|
doc = p.comp.list[data.id].doc;
|
|
}
|
|
|
|
if (doc && p.sync) {
|
|
const diff_remote = Y.encodeStateAsUpdate(
|
|
doc,
|
|
decompress(data.sv_local)
|
|
);
|
|
const sv_remote = Y.encodeStateVector(doc);
|
|
const sv = Buffer.from(compress(sv_remote));
|
|
const diff = Buffer.from(compress(diff_remote));
|
|
const res = await p.sync.yjs.sv_remote(
|
|
data.type,
|
|
data.id,
|
|
sv,
|
|
diff
|
|
);
|
|
|
|
if (res) {
|
|
Y.applyUpdate(doc, decompress(res.diff), "sv_remote");
|
|
if (data.type === "page") {
|
|
delete p.preview.meta_cache[data.id];
|
|
await treeRebuild(p, { note: "sv_remote" });
|
|
} else if (data.type === "comp") {
|
|
const updated = await updateComponentMeta(p, doc, data.id);
|
|
if (updated) {
|
|
p.comp.list[data.id].meta = updated.meta;
|
|
p.comp.list[data.id].tree = updated.tree;
|
|
}
|
|
await treeRebuild(p, { note: "sv_remote" });
|
|
}
|
|
p.render();
|
|
}
|
|
}
|
|
},
|
|
},
|
|
}).then((e) => {
|
|
p.sync = e;
|
|
});
|
|
|
|
return false;
|
|
} else {
|
|
if (
|
|
params.page_id !== p.page.cur.id &&
|
|
location.pathname.startsWith("/ed")
|
|
) {
|
|
reloadPage(p, params.page_id, "change page");
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|