From a8fe6a691d4d37db876f467fc07aa64bebbbd3db Mon Sep 17 00:00:00 2001 From: Rizky Date: Wed, 8 Nov 2023 14:24:33 +0700 Subject: [PATCH] fix --- app/srv/api/export-mobile.ts | 51 +++ app/srv/util/build-npm.ts | 1 - app/srv/util/export-mobile.ts | 34 ++ .../panel/toolbar/center/ToolbarCenter.tsx | 45 ++- .../panel/toolbar/center/mobile/config.tsx | 342 ++++++++++++++++++ .../toolbar/center/mobile/export-mobile.tsx | 18 + app/web/src/render/live/logic/init.tsx | 2 +- app/web/src/render/live/logic/mobile.ts | 53 ++- 8 files changed, 518 insertions(+), 28 deletions(-) create mode 100644 app/srv/api/export-mobile.ts create mode 100644 app/srv/util/export-mobile.ts create mode 100644 app/web/src/render/editor/panel/toolbar/center/mobile/config.tsx create mode 100644 app/web/src/render/editor/panel/toolbar/center/mobile/export-mobile.tsx diff --git a/app/srv/api/export-mobile.ts b/app/srv/api/export-mobile.ts new file mode 100644 index 00000000..f69cc194 --- /dev/null +++ b/app/srv/api/export-mobile.ts @@ -0,0 +1,51 @@ +import { ExportMobileConfig } from "../../web/src/render/editor/panel/toolbar/center/mobile/config"; +import { exmobile } from "../util/export-mobile"; + +export const _ = { + url: "/export-mobile/:site_id/:action", + async api( + site_id: string, + action: + | "config" + | "set-config" + | "build-android" + | "remove-android" + | "build-ios" + | "remove-ios", + config?: ExportMobileConfig + ) { + if (action === "config") { + return await exmobile.config.read(site_id); + } else if (action === "set-config") { + if (config) { + return await exmobile.config.write(site_id, config); + } + } else if (action === "build-android") { + let result = await exmobile.config.modify(site_id, (conf) => ({ + ...conf, + android: true, + })); + return result; + } else if (action === "remove-android") { + let result = await exmobile.config.modify(site_id, (conf) => ({ + ...conf, + android: false, + })); + return result; + } else if (action === "build-ios") { + let result = await exmobile.config.modify(site_id, (conf) => ({ + ...conf, + ios: true, + })); + return result; + } else if (action === "remove-ios") { + let result = await exmobile.config.modify(site_id, (conf) => ({ + ...conf, + ios: false, + })); + return result; + } + + return "This is export-mobile.ts"; + }, +}; diff --git a/app/srv/util/build-npm.ts b/app/srv/util/build-npm.ts index e9805716..91edbd98 100644 --- a/app/srv/util/build-npm.ts +++ b/app/srv/util/build-npm.ts @@ -6,7 +6,6 @@ import { build } from "esbuild"; import { $ } from "execa"; import { dirAsync, writeAsync } from "fs-jetpack"; import { stat } from "fs/promises"; -import { apiContext } from "service-srv"; import { g } from "utils/global"; import { validate } from "uuid"; import { glb } from "../global"; diff --git a/app/srv/util/export-mobile.ts b/app/srv/util/export-mobile.ts new file mode 100644 index 00000000..2d529a56 --- /dev/null +++ b/app/srv/util/export-mobile.ts @@ -0,0 +1,34 @@ +import { dir } from "dir"; +import { g } from "utils/global"; +import { writeAsync, dirAsync } from "fs-jetpack"; +import { ExportMobileConfig } from "../../web/src/render/editor/panel/toolbar/center/mobile/config"; + +const mpath = (site_id: string, path?: string) => + dir.path(`${g.datadir}/mobile/${site_id}/${path || ""}`); + +export const exmobile = { + config: { + async modify( + site_id: string, + fn: (config: ExportMobileConfig) => ExportMobileConfig + ) { + const conf = await this.read(site_id); + let result = fn(conf); + this.write(site_id, result); + return result; + }, + write: async (site_id: string, config: ExportMobileConfig) => { + const path = mpath(site_id, "config.json"); + await dirAsync(mpath(site_id)); + await writeAsync(path, config); + }, + read: async (site_id: string) => { + const path = mpath(site_id, "config.json"); + if (await Bun.file(path).exists()) { + return await Bun.file(path).json(); + } + + return null; + }, + }, +}; diff --git a/app/web/src/render/editor/panel/toolbar/center/ToolbarCenter.tsx b/app/web/src/render/editor/panel/toolbar/center/ToolbarCenter.tsx index b7f73f50..53339aed 100644 --- a/app/web/src/render/editor/panel/toolbar/center/ToolbarCenter.tsx +++ b/app/web/src/render/editor/panel/toolbar/center/ToolbarCenter.tsx @@ -12,6 +12,7 @@ import { AddElement } from "./AddElement"; import { Export } from "./Export"; import { NPMImport } from "./NPMImport"; import { APIConfig } from "./api/APIConfig"; +import { ExportMobile } from "./mobile/export-mobile"; export const ToolbarCenter = () => { const p = useGlobal(EditorGlobal, "EDITOR"); @@ -192,17 +193,28 @@ export const ToolbarCenter = () => { ), }, - // { - // content: ( - // <> - // - // - // ), - // }, ]} />
+ } + popoverClassName={cx( + "bg-white shadow-2xl shadow-slate-400 outline-none border border-slate-300" + )} + > + + + ), + }, + ]} + /> + + {/* { ), }, ]} - /> + /> */} ); }; +const MobileIcon = () => ( + + + +); + const JSIcon = () => ( Promise; +}> = () => { + const p = useGlobal(EditorGlobal, "EDITOR"); + const local = useLocal({}, async () => { + setting.config = await api.export_mobile(p.site.id, "config"); + local.render(); + }); + + return ( +
+
+
+
Export Mobile
+
+
+
+
{ + if (setting.config?.android && confirm("Remove Android?")) { + setting.status = "building-android"; + local.render(); + setting.config = await api.export_mobile( + p.site.id, + "remove-android" + ); + setting.status = "ready"; + local.render(); + } + }} + > + {setting.config?.android ? : } +
+
Android
+ {setting.status !== "building-android" ? ( +
{ + setting.status = "building-android"; + local.render(); + setting.config = await api.export_mobile( + p.site.id, + "build-android" + ); + setting.status = "ready"; + local.render(); + }} + > + {!setting.config?.android ? "Add" : "Rebuild"} +
+ ) : ( +
...
+ )} +
+
+
{ + if (setting.config?.ios && confirm("Remove IOS?")) { + setting.status = "building-ios"; + local.render(); + setting.config = await api.export_mobile( + p.site.id, + "remove-ios" + ); + setting.status = "ready"; + local.render(); + } + }} + > + {setting.config?.ios ? : } +
+
IOS
+ {setting.status !== "building-ios" ? ( +
{ + setting.status = "building-ios"; + local.render(); + setting.config = await api.export_mobile( + p.site.id, + "build-ios" + ); + setting.status = "ready"; + local.render(); + }} + > + {!setting.config?.ios ? "Add" : "Rebuild"} +
+ ) : ( +
...
+ )} +
+
+
+ + {setting.config && ( + <> +
+
+ + + +
+
+ {setting.status === "saving" ? ( + "Saving..." + ) : ( +
{ + setting.status = "saving"; + local.render(); + await api.export_mobile( + p.site.id, + "set-config", + setting.config + ); + + if (setting.config?.android) { + setting.status = "building-android"; + local.render(); + await api.export_mobile(p.site.id, "build-android"); + } + + if (setting.config?.ios) { + setting.status = "building-ios"; + local.render(); + await api.export_mobile(p.site.id, "build-ios"); + } + + setting.status = "ready"; + local.render(); + }} + className="border border-blue-500 text-blue-500 px-2 cursor-pointer" + > + Save Setting +
+ )} +
+
+ {(setting.config?.android || setting.config?.ios) && ( +
+
+ + +
+ +
+ Download Project + `, + }} + > +
+
+ )} + + )} +
+ ); +}; + +const Input = (opt: { + render: () => void; + title: string; + name: keyof ExportMobileConfig; + placeholder: string; + site_id: string; +}) => { + if (!setting.config) return null; + + return ( +
+
+ {opt.title} +
+ { + if (setting.config) + (setting.config as any)[opt.name] = e.currentTarget.value; + opt.render(); + }} + spellCheck={false} + className="focus:bg-blue-50 flex-1" + placeholder={opt.placeholder} + /> +
+ ); +}; + +const Img = (opt: { + name: string; + text: string; + render: () => void; + site_id: string; +}) => { + const src = (setting.config as any)[opt.name]; + return ( +
+
+ {src && } +
+
+
+
Upload {opt.name}
+
{opt.text}
+
+ { + if (e.currentTarget.files) { + const res = await api._upload(e.currentTarget.files[0]); + (setting.config as any)[opt.name] = res; + setting.status = "saving"; + opt.render(); + await api.export_mobile( + opt.site_id, + "set-config", + setting.config + ); + + setting.status = "ready"; + opt.render(); + } + }} + className={cx( + "opacity-0 cursor-pointer absolute inset-0", + css` + cursor: pointer !important; + font-size: 0; + ` + )} + /> +
+
+ ); +}; + +const Check = () => ( + + + +); + +const Uncheck = () => ( + + + +); diff --git a/app/web/src/render/editor/panel/toolbar/center/mobile/export-mobile.tsx b/app/web/src/render/editor/panel/toolbar/center/mobile/export-mobile.tsx new file mode 100644 index 00000000..75fcf3fa --- /dev/null +++ b/app/web/src/render/editor/panel/toolbar/center/mobile/export-mobile.tsx @@ -0,0 +1,18 @@ +import { useLocal } from "web-utils"; +import { ExportMobileConfig, ExportMobileSetting } from "./config"; + +export const ExportMobile = () => { + const local = useLocal({ + config: null as null | ExportMobileConfig, + }); + return ( +
+ { + local.config = conf; + local.render(); + }} + /> +
+ ); +}; diff --git a/app/web/src/render/live/logic/init.tsx b/app/web/src/render/live/logic/init.tsx index 8c735291..ea1e3d4f 100644 --- a/app/web/src/render/live/logic/init.tsx +++ b/app/web/src/render/live/logic/init.tsx @@ -32,7 +32,7 @@ export const initLive = async (p: PG, domain_or_siteid: string) => { if (p.status === "init") { p.status = "loading"; - if (w.mobile && w.mobile.send) { + if (w.mobile && w.mobile.bind && w.mobile.send) { w.mobile.bind(p); w.mobile.send({ type: "ready" }); } diff --git a/app/web/src/render/live/logic/mobile.ts b/app/web/src/render/live/logic/mobile.ts index 5970931d..5c7ab09c 100644 --- a/app/web/src/render/live/logic/mobile.ts +++ b/app/web/src/render/live/logic/mobile.ts @@ -10,15 +10,48 @@ type NOTIF_ARG = { }; export const registerMobile = () => { const default_mobile = { + send: () => {}, + bind: (p: PG) => {}, notif: { register: (user_id: string) => {}, - send: (data: NOTIF_ARG) => {}, + send: async (data: NOTIF_ARG) => { + const p = getP(); + if (p) { + return await p.script.api._notif("send", { + type: "send", + id: + typeof data.user_id === "string" + ? data.user_id + : data.user_id.toString(), + body: data.body, + title: data.title, + data: data.data, + }); + } + }, onTap: (data: NOTIF_ARG) => {}, onReceive: (data: NOTIF_ARG) => {}, }, }; + + let config = { notif_token: "", p: null as null | PG }; + const getP = () => { + const p = config.p; + if (p && p.site && p.site.api_url) { + const api = w.prasiApi[p.site.api_url]; + if ( + api && + api.apiEntry && + api.apiEntry._notif && + p.script && + p.script.api + ) { + return p; + } + } + }; + if (window.parent) { - let config = { notif_token: "", p: null as null | PG }; window.addEventListener("message", async ({ data: raw }) => { if (typeof raw === "object" && raw.mobile) { const data = raw as unknown as @@ -86,22 +119,6 @@ export const registerMobile = () => { } }); - const getP = () => { - const p = config.p; - if (p && p.site && p.site.api_url) { - const api = w.prasiApi[p.site.api_url]; - if ( - api && - api.apiEntry && - api.apiEntry._notif && - p.script && - p.script.api - ) { - return p; - } - } - }; - const notifObject = { send: (msg: { type: "ready" }) => { window.parent.postMessage({ mobile: true, ...msg }, "*");