Pārlūkot izejas kodu

feat: [electron] export index.html together with other assets

Junyu Zhan 4 gadi atpakaļ
vecāks
revīzija
3cb6265e16

+ 20 - 11
resources/js/preload.js

@@ -5,7 +5,7 @@ const { ipcRenderer, contextBridge, shell, clipboard } = require('electron')
 const IS_MAC = process.platform === 'darwin'
 const IS_WIN32 = process.platform === 'win32'
 
-function getFilePathFromClipboard () {
+function getFilePathFromClipboard() {
   if (IS_WIN32) {
     const rawFilePath = clipboard.read('FileNameW')
     return rawFilePath.replace(new RegExp(String.fromCharCode(0), 'g'), '')
@@ -16,7 +16,7 @@ function getFilePathFromClipboard () {
   }
 }
 
-function isClipboardHasImage () {
+function isClipboardHasImage() {
   return !clipboard.readImage().isEmpty()
 }
 
@@ -34,7 +34,7 @@ contextBridge.exposeInMainWorld('apis', {
     await ipcRenderer.invoke('check-for-updates', ...args)
   },
 
-  setUpdatesCallback (cb) {
+  setUpdatesCallback(cb) {
     if (typeof cb !== 'function') return
 
     const channel = 'updates-callback'
@@ -42,19 +42,19 @@ contextBridge.exposeInMainWorld('apis', {
     ipcRenderer.on(channel, cb)
   },
 
-  installUpdatesAndQuitApp () {
+  installUpdatesAndQuitApp() {
     ipcRenderer.invoke('install-updates', true)
   },
 
-  async openExternal (url, options) {
+  async openExternal(url, options) {
     await shell.openExternal(url, options)
   },
 
-  async openPath (path) {
+  async openPath(path) {
     await shell.openPath(path)
   },
 
-  showItemInFolder (fullpath) {
+  showItemInFolder(fullpath) {
     if (IS_WIN32) {
       shell.openPath(path.dirname(fullpath))
     } else {
@@ -62,6 +62,15 @@ contextBridge.exposeInMainWorld('apis', {
     }
   },
 
+  /**
+   * save all publish assets to disk
+   *
+   * @param {string} html html file with embedded state
+   */
+  exportPublishAssets(html) {
+    ipcRenderer.invoke('export-publish-assets', html)
+  },
+
   /**
    * When from is empty. The resource maybe from
    * client paste or screenshoot.
@@ -70,7 +79,7 @@ contextBridge.exposeInMainWorld('apis', {
    * @param from?
    * @returns {Promise<void>}
    */
-  async copyFileToAssets (repoPathRoot, to, from) {
+  async copyFileToAssets(repoPathRoot, to, from) {
     if (from && fs.statSync(from).isDirectory()) {
       throw new Error('not support copy directory')
     }
@@ -105,7 +114,7 @@ contextBridge.exposeInMainWorld('apis', {
     }
   },
 
-  toggleMaxOrMinActiveWindow (isToggleMin = false) {
+  toggleMaxOrMinActiveWindow(isToggleMin = false) {
     ipcRenderer.invoke('toggle-max-or-min-active-win', isToggleMin)
   },
 
@@ -115,10 +124,10 @@ contextBridge.exposeInMainWorld('apis', {
    * @param args
    * @private
    */
-  async _callApplication (type, ...args) {
+  async _callApplication(type, ...args) {
     return await ipcRenderer.invoke('call-application', type, ...args)
   },
 
   getFilePathFromClipboard,
-  isClipboardHasImage
+  isClipboardHasImage,
 })

+ 33 - 2
src/electron/electron/core.cljs

@@ -3,9 +3,10 @@
             [electron.updater :refer [init-updater]]
             [electron.utils :refer [mac? win32? prod? dev? logger open]]
             [clojure.string :as string]
-            ["fs" :as fs]
+            [promesa.core :as p]
+            ["fs-extra" :as fs]
             ["path" :as path]
-            ["electron" :refer [BrowserWindow app protocol ipcMain] :as electron]
+            ["electron" :refer [BrowserWindow app protocol ipcMain dialog] :as electron]
             [clojure.core.async :as async]
             [electron.state :as state]))
 
@@ -54,10 +55,35 @@
        (callback #js {:path path}))))
   #(.unregisterProtocol protocol "assets"))
 
+(defn- handle-export-publish-assets [_event html]
+  (let
+   [app-path (. app getAppPath)
+    paths (js->clj (. dialog showOpenDialogSync (clj->js {:properties ["openDirectory" "createDirectory" "promptToCreate", "multiSelections"]})))]
+    (if (vector? paths)
+      (let [published-dir (str "published-at-" (.toString (.getTime (js/Date.))))
+            root-dir (path/join
+                      (first (js->clj paths))
+                      published-dir)
+            static-dir (path/join root-dir "static")
+            path (path/join root-dir "index.html")]
+        (p/let [_ (. fs ensureDir static-dir)]
+          (let  [_ (p/all  (concat
+                            [(. fs writeFile
+                                path
+                                html)]
+                            [(. fs copy (path/join app-path "404.html") (path/join root-dir "404.html"))]
+
+                            (map
+                             (fn [part]
+                               (. fs copy (path/join app-path part) (path/join static-dir part)))
+                             ["css" "fonts" "icons" "img" "js" "dev.html"])))]
+
+            (. dialog showMessageBox (clj->js {:message (str "Export publish assets to " root-dir " successfully")}))))))))
 (defn setup-app-manager!
   [^js win]
   (let [toggle-win-channel "toggle-max-or-min-active-win"
         call-app-channel "call-application"
+        export-publish-assets "export-publish-assets"
         web-contents (. win -webContents)]
     (doto ipcMain
       (.handle toggle-win-channel
@@ -70,6 +96,9 @@
                      (if (.isMaximized active-win)
                        (.unmaximize active-win)
                        (.maximize active-win))))))
+
+      (.handle export-publish-assets handle-export-publish-assets)
+
       (.handle call-app-channel
                (fn [_ type & args]
                  (try
@@ -91,10 +120,12 @@
       (.on "leave-full-screen" #(.send web-contents "full-screen" "leave")))
 
     #(do (.removeHandler ipcMain toggle-win-channel)
+         (.removeHandler ipcMain export-publish-assets)
          (.removeHandler ipcMain call-app-channel))))
 
 (defonce *win (atom nil))
 
+
 (defn- destroy-window!
   [^js win]
   (.destroy win))

+ 21 - 18
src/main/frontend/handler/export.cljs

@@ -59,24 +59,27 @@
 (defn export-repo-as-html!
   [repo]
   (when-let [db (db/get-conn repo)]
-    (let [db (if (state/all-pages-public?)
-               (db/clean-export! db)
-               (db/filter-only-public-pages-and-blocks db))
-          db-str (db/db->string db)
-          state (select-keys @state/state
-                             [:ui/theme :ui/cycle-collapse
-                              :ui/collapsed-blocks
-                              :ui/sidebar-collapsed-blocks
-                              :ui/show-recent?
-                              :config])
-          state (update state :config (fn [config]
-                                        {"local" (get config repo)}))
-          html-str (str "data:text/html;charset=UTF-8,"
-                        (js/encodeURIComponent (html/publishing-html db-str (pr-str state))))]
-      (when-let [anchor (gdom/getElement "download-as-html")]
-        (.setAttribute anchor "href" html-str)
-        (.setAttribute anchor "download" "index.html")
-        (.click anchor)))))
+    (let [db           (if (state/all-pages-publishable?)
+                         (db/clean-export! db)
+                         (db/filter-only-public-pages-and-blocks db))
+          db-str       (db/db->string db)
+          state        (select-keys @state/state
+                                    [:ui/theme :ui/cycle-collapse
+                                     :ui/collapsed-blocks
+                                     :ui/sidebar-collapsed-blocks
+                                     :ui/show-recent?
+                                     :config])
+          state        (update state :config (fn [config]
+                                               {"local" (get config repo)}))
+          raw-html-str (html/publishing-html db-str (pr-str state))
+          html-str     (str "data:text/html;charset=UTF-8,"
+                            (js/encodeURIComponent raw-html-str))]
+      (if (util/electron?)
+        (js/window.apis.exportPublishAssets raw-html-str)
+        (when-let [anchor (gdom/getElement "download-as-html")]
+          (.setAttribute anchor "href" html-str)
+          (.setAttribute anchor "download" "index.html")
+          (.click anchor))))))
 
 (defn export-repo-as-zip!
   [repo]