plugins.cljs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. (ns frontend.components.plugins
  2. (:require [rum.core :as rum]
  3. [frontend.state :as state]
  4. [cljs-bean.core :as bean]
  5. [frontend.ui :as ui]
  6. [frontend.util :as util]
  7. [electron.ipc :as ipc]
  8. [promesa.core :as p]
  9. [frontend.components.svg :as svg]
  10. [frontend.handler.notification :as notification]
  11. [frontend.handler.plugin :as plugin-handler]
  12. [clojure.string :as string]))
  13. (rum/defc installed-themes
  14. < rum/reactive
  15. []
  16. (let [themes (state/sub :plugin/installed-themes)
  17. selected (state/sub :plugin/selected-theme)
  18. themes (cons {:name "Default Theme" :url nil :description "Logseq default light/dark theme."} themes)]
  19. [:div.cp__themes-installed
  20. [:h2.mb-4.text-xl "Installed Themes"]
  21. (for [opt themes]
  22. (let [current-selected (= selected (:url opt))]
  23. [:div.it.flex.px-3.py-2.mb-2.rounded-sm.justify-between
  24. {:key (:url opt)
  25. :class [(if current-selected "is-selected")]
  26. :on-click #(do (js/LSPluginCore.selectTheme (if current-selected nil (clj->js opt)))
  27. (state/set-modal! nil))}
  28. [:section
  29. [:strong.block (:name opt)]
  30. [:small.opacity-30 (:description opt)]]
  31. [:small.flex-shrink-0.flex.items-center.opacity-10
  32. (if current-selected "current")]]))]))
  33. (rum/defc unpacked-plugin-loader
  34. [unpacked-pkg-path]
  35. (rum/use-effect!
  36. (fn []
  37. (let [err-handle
  38. (fn [^js e]
  39. (case (keyword (aget e "name"))
  40. :IllegalPluginPackageError
  41. (notification/show! "Illegal Logseq plugin package." :error)
  42. :ExistedImportedPluginPackageError
  43. (notification/show! "Existed Imported plugin package." :error)
  44. :default)
  45. (plugin-handler/reset-unpacked-state))
  46. reg-handle #(plugin-handler/reset-unpacked-state)]
  47. (when unpacked-pkg-path
  48. (doto js/LSPluginCore
  49. (.once "error" err-handle)
  50. (.once "registered" reg-handle)
  51. (.register (bean/->js {:url unpacked-pkg-path}))))
  52. #(doto js/LSPluginCore
  53. (.off "error" err-handle)
  54. (.off "registered" reg-handle))))
  55. [unpacked-pkg-path])
  56. (when unpacked-pkg-path
  57. [:strong.inline-flex.px-3 "Loading ..."]))
  58. (rum/defc simple-markdown-display
  59. < rum/reactive
  60. []
  61. (let [[content item] (state/sub :plugin/active-readme)]
  62. [:div.cp__plugins-details
  63. {:on-click (fn [^js/MouseEvent e]
  64. (when-let [target (.-target e)]
  65. (when (and (= (string/lower-case (.-nodeName target)) "a")
  66. (not (string/blank? (. target getAttribute "href"))))
  67. (js/apis.openExternal (. target getAttribute "href"))
  68. (.preventDefault e))))}
  69. (when-let [repo (:repository item)]
  70. (when-let [repo (if (string? repo) repo (:url repo))]
  71. [:div.p-4.rounded-md.bg-base-3
  72. [:strong [:a.flex.items-center {:target "_blank" :href repo} [:span.mr-1 (svg/github {:width 25 :height 25})] repo]]]))
  73. [:div.p-1.bg-transparent.border-none.ls-block
  74. {:style {:min-height "60vw"}
  75. :dangerouslySetInnerHTML {:__html content}}]]))
  76. (rum/defc plugin-item-card
  77. [{:keys [id name settings version url description author icon usf] :as item}]
  78. (let [disabled (:disabled settings)]
  79. [:div.cp__plugins-item-card
  80. [:div.l.link-block
  81. {:on-click #(plugin-handler/open-readme! url item simple-markdown-display)}
  82. (if icon
  83. [:img.icon {:src icon}]
  84. svg/folder)]
  85. [:div.r
  86. [:h3.head.text-xl.font-bold.pt-1.5
  87. {:on-click #(plugin-handler/open-readme! url item simple-markdown-display)}
  88. [:span name]
  89. [:sup.inline-block.px-1.text-xs.opacity-30 version]]
  90. [:div.desc.text-xs.opacity-60
  91. [:p description]
  92. ;;[:small (js/JSON.stringify (bean/->js settings))]
  93. ]
  94. [:div.flag
  95. [:p.text-xs.text-gray-300.pr-2.flex.justify-between.dark:opacity-40
  96. [:small author]
  97. [:small (str "ID: " id)]]]
  98. [:div.ctl
  99. [:div.l
  100. [:div.de
  101. [:strong svg/settings-sm]
  102. [:ul.menu-list
  103. [:li {:on-click #(if usf (js/apis.openPath usf))} "Open settings"]
  104. [:li {:on-click #(js/apis.openPath url)} "Open plugin package"]
  105. [:li {:on-click
  106. #(let [confirm-fn
  107. (ui/make-confirm-modal
  108. {:title (str "Are you sure uninstall plugin [" name "] ?")
  109. :on-confirm (fn [_ {:keys [close-fn]}]
  110. (close-fn)
  111. (plugin-handler/unregister-plugin id))})]
  112. (state/set-modal! confirm-fn))}
  113. "Uninstall plugin"]]]]
  114. [:div.flex.items-center
  115. [:small.de (if disabled "Disabled" "Enabled")]
  116. (ui/toggle (not disabled)
  117. (fn []
  118. (js-invoke js/LSPluginCore (if disabled "enable" "disable") id))
  119. true)]]]]))
  120. (rum/defc installed-page
  121. < rum/reactive
  122. []
  123. (let [installed-plugins (state/sub :plugin/installed-plugins)
  124. selected-unpacked-pkg (state/sub :plugin/selected-unpacked-pkg)]
  125. [:div.cp__plugins-page-installed
  126. [:h1 "Installed Plugins"]
  127. [:div.mb-6.flex.items-center.justify-between
  128. (ui/button
  129. "Load unpacked plugin"
  130. :intent "logseq"
  131. :on-click plugin-handler/load-unpacked-plugin)
  132. (unpacked-plugin-loader selected-unpacked-pkg)
  133. (when (util/electron?)
  134. (ui/button
  135. [:span.flex.items-center
  136. ;;svg/settings-sm
  137. "Open plugin preferences file"]
  138. :intent "logseq"
  139. :on-click (fn []
  140. (p/let [root (plugin-handler/get-ls-dotdir-root)]
  141. (js/apis.openPath (str root "/preferences.json"))))))]
  142. [:div.cp__plugins-item-lists.grid-cols-1.md:grid-cols-2.lg:grid-cols-3
  143. (for [[_ item] installed-plugins]
  144. (rum/with-key (plugin-item-card item) (:id item)))]]))
  145. (defn open-select-theme!
  146. []
  147. (state/set-modal! installed-themes))
  148. (rum/defc hook-ui-slot
  149. ([type payload] (hook-ui-slot type payload nil))
  150. ([type payload opts]
  151. (let [id (str "slot__" (util/rand-str 8))]
  152. (rum/use-effect!
  153. (fn []
  154. (plugin-handler/hook-plugin-app type {:slot id :payload payload} nil)
  155. #())
  156. [])
  157. [:div.lsp-hook-ui-slot
  158. (merge opts {:id id})])))