Files
logseq/src/main/frontend/components/plugins_settings.cljs

150 lines
4.9 KiB
Clojure

(ns frontend.components.plugins-settings
(:require [rum.core :as rum]
[frontend.util :as util]
[frontend.ui :as ui]
[frontend.handler.plugin :as plugin-handler]
[cljs-bean.core :as bean]
[goog.functions :refer [debounce]]))
(defn- dom-purify
[html opts]
(try
(js-invoke js/DOMPurify "sanitize" html (bean/->js opts))
(catch js/Error e
(js/console.warn e) html)))
(rum/defc html-content
[html]
[:div.html-content.pl-1.flex-1.text-sm
{:dangerouslySetInnerHTML {:__html (dom-purify html nil)}}])
(rum/defc edit-settings-file
[pid {:keys [class]}]
[:a.text-sm.hover:underline
{:class class
:on-click #(plugin-handler/open-settings-file-in-default-app! pid)}
"Edit settings.json"])
(rum/defc render-item-input
[val {:keys [key type title default description inputAs]} update-setting!]
[:div.desc-item.as-input
{:data-key key :key key}
[:h2 [:code key] (ui/icon "caret-right") [:strong title]]
[:label.form-control
(html-content description)
(let [input-as (util/safe-lower-case (or inputAs (name type)))
input-as (if (= input-as "string") :text (keyword input-as))]
[(if (= input-as :textarea) :textarea :input)
{:class (util/classnames [{:form-input (not (contains? #{:color :range} input-as))}])
:type (name input-as)
:defaultValue (or val default)
:on-key-down #(.stopPropagation %)
:on-change (debounce #(update-setting! key (util/evalue %)) 1000)}])]])
(rum/defc render-item-toggle
[val {:keys [key title description default]} update-setting!]
(let [val (if (boolean? val) val (boolean default))]
[:div.desc-item.as-toggle
{:data-key key}
[:h2 [:code key] (ui/icon "caret-right") [:strong title]]
[:label.form-control
(ui/checkbox {:checked val
:on-change #(update-setting! key (not val))})
(html-content description)]]))
(rum/defc render-item-enum
[val {:keys [key title description default enumChoices enumPicker]} update-setting!]
(let [val (or val default)
vals (into #{} (if (sequential? val) val [val]))
options (map (fn [v] {:label v :value v
:selected (contains? vals v)}) enumChoices)
picker (keyword enumPicker)]
[:div.desc-item.as-enum
{:data-key key}
[:h2 [:code key] (ui/icon "caret-right") [:strong title]]
[:div.form-control
[(if (contains? #{:radio :checkbox} picker) :div.wrap :label.wrap)
(html-content description)
(case picker
:radio (ui/radio-list options #(update-setting! key %) nil)
:checkbox (ui/checkbox-list options #(update-setting! key %) nil)
;; select
(ui/select options (fn [_ value ] (update-setting! key value))))
]]]))
(rum/defc render-item-object
[_val {:keys [key title description _default]} pid]
[:div.desc-item.as-object
{:data-key key}
[:h2 [:code key] (ui/icon "caret-right") [:strong title]]
[:div.form-control
(html-content description)
[:div.pl-1 (edit-settings-file pid nil)]]])
(rum/defc render-item-heading
[{:keys [key title description]}]
[:div.heading-item
{:data-key key}
[:h2 title]
(html-content description)])
(rum/defc render-item-not-handled
[s]
[:p.text-red-500 (str "#Not Handled# " s)])
(rum/defc settings-container
[schema ^js pl]
(let [^js plugin-settings (.-settings pl)
pid (.-id pl)
[settings, set-settings] (rum/use-state (bean/->clj (.toJSON plugin-settings)))
update-setting! (fn [k v] (.set plugin-settings (name k) (bean/->js v)))]
(rum/use-effect!
(fn []
(let [on-change (fn [^js s]
(when-let [s (bean/->clj s)]
(set-settings s)))]
(.on plugin-settings "change" on-change)
#(.off plugin-settings "change" on-change)))
[pid])
(if (seq schema)
[:<>
[:h2.text-xl.px-2.pt-1.opacity-90 "ID: " pid]
[:div.cp__plugins-settings-inner
;; settings.json
[:span.edit-file
(edit-settings-file pid nil)]
;; render items
(for [desc schema
:let [key (:key desc)
val (get settings (keyword key))
type (keyword (:type desc))
desc (update desc :description #(plugin-handler/markdown-to-html %))]]
(rum/with-key
(condp contains? type
#{:string :number} (render-item-input val desc update-setting!)
#{:boolean} (render-item-toggle val desc update-setting!)
#{:enum} (render-item-enum val desc update-setting!)
#{:object} (render-item-object val desc pid)
#{:heading} (render-item-heading desc)
(render-item-not-handled key))
key))]]
;; no settings
[:h2.font-bold.text-lg.py-4.warning "No Settings Schema!"])))