| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814 |
- (ns frontend.components.settings
- (:require [clojure.string :as string]
- [frontend.components.svg :as svg]
- [frontend.components.plugins :as plugins]
- [frontend.components.assets :as assets]
- [frontend.config :as config]
- [frontend.context.i18n :refer [t]]
- [frontend.storage :as storage]
- [frontend.date :as date]
- [frontend.dicts :as dicts]
- [frontend.handler :as handler]
- [frontend.handler.config :as config-handler]
- [frontend.handler.notification :as notification]
- [frontend.handler.route :as route-handler]
- [frontend.handler.ui :as ui-handler]
- [frontend.handler.user :as user-handler]
- [frontend.handler.plugin :as plugin-handler]
- [frontend.handler.file-sync :as file-sync-handler]
- [frontend.handler.global-config :as global-config-handler]
- [frontend.modules.instrumentation.core :as instrument]
- [frontend.modules.shortcut.data-helper :as shortcut-helper]
- [frontend.state :as state]
- [frontend.ui :as ui]
- [electron.ipc :as ipc]
- [promesa.core :as p]
- [frontend.util :refer [classnames web-platform?] :as util]
- [frontend.version :refer [version]]
- [goog.object :as gobj]
- [reitit.frontend.easy :as rfe]
- [rum.core :as rum]
- [frontend.mobile.util :as mobile-util]
- [frontend.db :as db]
- [frontend.components.conversion :as conversion-component]))
- (defn toggle
- [label-for name state on-toggle & [detail-text]]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- {:for label-for}
- name]
- [:div.rounded-md.sm:max-w-tss.sm:col-span-2
- [:div.rounded-md {:style {:display "flex" :gap "1rem" :align-items "center"}}
- (ui/toggle state on-toggle true)
- detail-text]]])
- (rum/defcs app-updater < rum/reactive
- [state version]
- (let [update-pending? (state/sub :electron/updater-pending?)
- {:keys [type payload]} (state/sub :electron/updater)]
- [:span.cp__settings-app-updater
- [:div.ctls.flex.items-center
- [:div.mt-1.sm:mt-0.sm:col-span-2
- {:style {:display "flex" :gap "0.5rem" :align-items "center"}}
- [:div (cond
- (mobile-util/native-android?)
- (ui/button
- "Check for updates"
- :class "text-sm p-1 mr-1"
- :href "https://github.com/logseq/logseq/releases" )
- (mobile-util/native-ios?)
- (ui/button
- "Check for updates"
- :class "text-sm p-1 mr-1"
- :href "https://apps.apple.com/app/logseq/id1601013908" )
- (util/electron?)
- (ui/button
- (if update-pending? "Checking ..." "Check for updates")
- :class "text-sm p-1 mr-1"
- :disabled update-pending?
- :on-click #(js/window.apis.checkForUpdates false))
- :else
- nil)]
- [:div.text-sm.opacity-50 (str "Version " version)]]]
- (when-not (or update-pending?
- (string/blank? type))
- [:div.update-state.text-sm
- (case type
- "update-not-available"
- [:p "Your app is up-to-date 🎉"]
- "update-available"
- (let [{:keys [name url]} payload]
- [:p (str "Found new release ")
- [:a.link
- {:on-click
- (fn [e]
- (js/window.apis.openExternal url)
- (util/stop e))}
- svg/external-link name " 🎉"]])
- "error"
- [:p "⚠️ Oops, Something Went Wrong!" [:br] " Please check out the "
- [:a.link
- {:on-click
- (fn [e]
- (js/window.apis.openExternal "https://github.com/logseq/logseq/releases")
- (util/stop e))}
- svg/external-link " release channel"]])])]))
- (rum/defc outdenting-hint
- []
- [:div.ui__modal-panel
- {:style {:box-shadow "0 4px 20px 4px rgba(0, 20, 60, .1), 0 4px 80px -8px rgba(0, 20, 60, .2)"}}
- [:div {:style {:margin "12px" :max-width "500px"}}
- [:p.text-sm
- "The left side shows outdenting with the default setting, and the right shows outdenting with logical outdenting enabled. "
- [:a.text-sm
- {:target "_blank" :href "https://discuss.logseq.com/t/whats-your-preferred-outdent-behavior-the-direct-one-or-the-logical-one/978"}
- "→ Learn more"]]
- [:img {:src "https://discuss.logseq.com/uploads/default/original/1X/e8ea82f63a5e01f6d21b5da827927f538f3277b9.gif"
- :width 500
- :height 500}]]])
- (defn row-with-button-action
- [{:keys [left-label action button-label href on-click desc -for]}]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- ;; left column
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- {:for -for}
- left-label]
- ;; right column
- [:div.mt-1.sm:mt-0.sm:col-span-2
- {:style {:display "flex" :gap "0.5rem" :align-items "center"}}
- [:div (if action action (ui/button
- button-label
- :class "text-sm p-1"
- :href href
- :on-click on-click))]
- (when-not (or (util/mobile?)
- (mobile-util/native-platform?))
- [:div.text-sm desc])]])
- (defn edit-config-edn []
- (row-with-button-action
- {:left-label (t :settings-page/custom-configuration)
- :button-label (t :settings-page/edit-config-edn)
- :href (rfe/href :file {:path (config/get-repo-config-path)})
- :on-click #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))
- :-for "config_edn"}))
- (defn edit-global-config-edn []
- (row-with-button-action
- {:left-label (t :settings-page/custom-global-configuration)
- :button-label (t :settings-page/edit-global-config-edn)
- :href (rfe/href :file {:path (global-config-handler/global-config-path)})
- :on-click #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))
- :-for "global_config_edn"}))
- (defn edit-custom-css []
- (row-with-button-action
- {:left-label (t :settings-page/custom-theme)
- :button-label (t :settings-page/edit-custom-css)
- :href (rfe/href :file {:path (config/get-custom-css-path)})
- :on-click #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))
- :-for "customize_css"}))
- (defn edit-export-css []
- (row-with-button-action
- {:left-label (t :settings-page/export-theme)
- :button-label (t :settings-page/edit-export-css)
- :href (rfe/href :file {:path (config/get-export-css-path)})
- :on-click #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))
- :-for "customize_css"}))
- (defn show-brackets-row [t show-brackets?]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- {:for "show_brackets"}
- (t :settings-page/show-brackets)]
- [:div
- [:div.rounded-md.sm:max-w-xs
- (ui/toggle show-brackets?
- config-handler/toggle-ui-show-brackets!
- true)]]
- (when (not (or (util/mobile?) (mobile-util/native-platform?)))
- [:div {:style {:text-align "right"}}
- (ui/render-keyboard-shortcut (shortcut-helper/gen-shortcut-seq :ui/toggle-brackets))])])
- (rum/defcs switch-spell-check-row < rum/reactive
- [state t]
- (let [enabled? (state/sub [:electron/user-cfgs :spell-check])]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- (t :settings-page/spell-checker)]
- [:div
- [:div.rounded-md.sm:max-w-xs
- (ui/toggle
- enabled?
- (fn []
- (state/set-state! [:electron/user-cfgs :spell-check] (not enabled?))
- (p/then (ipc/ipc :userAppCfgs :spell-check (not enabled?))
- #(when (js/confirm (t :relaunch-confirm-to-work))
- (js/logseq.api.relaunch))))
- true)]]]))
- (rum/defcs switch-git-auto-commit-row < rum/reactive
- [state t]
- (let [enabled? (state/get-git-auto-commit-enabled?)]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- (t :settings-page/git-switcher-label)]
- [:div
- [:div.rounded-md.sm:max-w-xs
- (ui/toggle
- enabled?
- (fn []
- (state/set-state! [:electron/user-cfgs :git/disable-auto-commit?] enabled?)
- (ipc/ipc :userAppCfgs :git/disable-auto-commit? enabled?))
- true)]]]))
- (rum/defcs git-auto-commit-seconds < rum/reactive
- [state t]
- (let [secs (or (state/sub [:electron/user-cfgs :git/auto-commit-seconds]) 60)]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- (t :settings-page/git-commit-delay)]
- [:div.mt-1.sm:mt-0.sm:col-span-2
- [:div.max-w-lg.rounded-md.sm:max-w-xs
- [:input#home-default-page.form-input.is-small.transition.duration-150.ease-in-out
- {:default-value secs
- :on-blur (fn [event]
- (let [value (-> (util/evalue event)
- util/safe-parse-int)]
- (if (and (number? value)
- (< 0 value (inc 600)))
- (do
- (state/set-state! [:electron/user-cfgs :git/auto-commit-seconds] value)
- (ipc/ipc :userAppCfgs :git/auto-commit-seconds value))
- (when-let [elem (gobj/get event "target")]
- (notification/show!
- [:div "Invalid value! Must be a number between 1 and 600."]
- :warning true)
- (gobj/set elem "value" secs)))))}]]]]))
- (rum/defc app-auto-update-row < rum/reactive [t]
- (let [enabled? (state/sub [:electron/user-cfgs :auto-update])
- enabled? (if (nil? enabled?) true enabled?)]
- (toggle "usage-diagnostics"
- (t :settings-page/auto-updater)
- enabled?
- #((state/set-state! [:electron/user-cfgs :auto-update] (not enabled?))
- (ipc/ipc :userAppCfgs :auto-update (not enabled?))))))
- (defn language-row [t preferred-language]
- (let [on-change (fn [e]
- (let [lang-code (util/evalue e)]
- (state/set-preferred-language! lang-code)
- (ui-handler/re-render-root!)))
- action [:select.form-select.is-small {:value preferred-language
- :on-change on-change}
- (for [language dicts/languages]
- (let [lang-code (name (:value language))
- lang-label (:label language)]
- [:option {:key lang-code :value lang-code} lang-label]))]]
- (row-with-button-action {:left-label (t :language)
- :-for "preferred_language"
- :action action})))
- (defn theme-modes-row [t switch-theme system-theme? dark?]
- (let [pick-theme [:ul.theme-modes-options
- [:li {:on-click (partial state/use-theme-mode! "light")
- :class (classnames [{:active (and (not system-theme?) (not dark?))}])} [:i.mode-light] [:strong "light"]]
- [:li {:on-click (partial state/use-theme-mode! "dark")
- :class (classnames [{:active (and (not system-theme?) dark?)}])} [:i.mode-dark] [:strong "dark"]]
- [:li {:on-click (partial state/use-theme-mode! "system")
- :class (classnames [{:active system-theme?}])} [:i.mode-system] [:strong "system"]]]]
- (row-with-button-action {:left-label (t :right-side-bar/switch-theme (string/capitalize switch-theme))
- :-for "toggle_theme"
- :action pick-theme
- :desc (ui/render-keyboard-shortcut (shortcut-helper/gen-shortcut-seq :ui/toggle-theme))})))
- (defn file-format-row [t preferred-format]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- {:for "preferred_format"}
- (t :settings-page/preferred-file-format)]
- [:div.mt-1.sm:mt-0.sm:col-span-2
- [:div.max-w-lg.rounded-md
- [:select.form-select.is-small
- {:value (name preferred-format)
- :on-change (fn [e]
- (let [format (-> (util/evalue e)
- (string/lower-case)
- keyword)]
- (user-handler/set-preferred-format! format)))}
- (for [format (map name [:org :markdown])]
- [:option {:key format :value format} (string/capitalize format)])]]]])
- (defn date-format-row [t preferred-date-format]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- {:for "custom_date_format"}
- (t :settings-page/custom-date-format)]
- [:div.mt-1.sm:mt-0.sm:col-span-2
- [:div.max-w-lg.rounded-md
- [:select.form-select.is-small
- {:value preferred-date-format
- :on-change (fn [e]
- (let [format (util/evalue e)]
- (when-not (string/blank? format)
- (config-handler/set-config! :journal/page-title-format format)
- (notification/show!
- [:div "You must re-index your graph for this change to take effect"]
- :warning false)
- (state/close-modal!)
- (route-handler/redirect! {:to :repos}))))}
- (for [format (sort (date/journal-title-formatters))]
- [:option {:key format} format])]]]])
- (defn workflow-row [t preferred-workflow]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- {:for "preferred_workflow"}
- (t :settings-page/preferred-workflow)]
- [:div.mt-1.sm:mt-0.sm:col-span-2
- [:div.max-w-lg.rounded-md
- [:select.form-select.is-small
- {:value (name preferred-workflow)
- :on-change (fn [e]
- (-> (util/evalue e)
- string/lower-case
- keyword
- (#(if (= % :now) :now :todo))
- user-handler/set-preferred-workflow!))}
- (for [workflow [:now :todo]]
- [:option {:key (name workflow) :value (name workflow)}
- (if (= workflow :now) "NOW/LATER" "TODO/DOING")])]]]])
- (defn outdenting-row [t logical-outdenting?]
- (toggle "preferred_outdenting"
- [(t :settings-page/preferred-outdenting)
- (ui/tippy {:html (outdenting-hint)
- :class "tippy-hover ml-2"
- :interactive true
- :disabled false}
- (svg/info))]
- logical-outdenting?
- config-handler/toggle-logical-outdenting!))
- (defn tooltip-row [t enable-tooltip?]
- (toggle "enable_tooltip"
- (t :settings-page/enable-tooltip)
- enable-tooltip?
- (fn []
- (config-handler/toggle-ui-enable-tooltip!))))
- (defn shortcut-tooltip-row [t enable-shortcut-tooltip?]
- (toggle "enable_tooltip"
- (t :settings-page/enable-shortcut-tooltip)
- enable-shortcut-tooltip?
- (fn []
- (state/toggle-shortcut-tooltip!))))
- (defn timetracking-row [t enable-timetracking?]
- (toggle "enable_timetracking"
- (t :settings-page/enable-timetracking)
- enable-timetracking?
- #(let [value (not enable-timetracking?)]
- (config-handler/set-config! :feature/enable-timetracking? value))))
- (defn update-home-page
- [event]
- (let [value (util/evalue event)]
- (cond
- (string/blank? value)
- (let [home (get (state/get-config) :default-home {})
- new-home (dissoc home :page)]
- (config-handler/set-config! :default-home new-home)
- (notification/show! "Home default page updated successfully!" :success))
- (db/page-exists? value)
- (let [home (get (state/get-config) :default-home {})
- new-home (assoc home :page value)]
- (config-handler/set-config! :default-home new-home)
- (notification/show! "Home default page updated successfully!" :success))
- :else
- (notification/show! (str "The page \"" value "\" doesn't exist yet. Please create that page first, and then try again.") :warning))))
- (defn journal-row [enable-journals?]
- (toggle "enable_journals"
- (t :settings-page/enable-journals)
- enable-journals?
- (fn []
- (let [value (not enable-journals?)]
- (config-handler/set-config! :feature/enable-journals? value)))))
- (defn enable-all-pages-public-row [t enable-all-pages-public?]
- (toggle "all pages public"
- (t :settings-page/enable-all-pages-public)
- enable-all-pages-public?
- (fn []
- (let [value (not enable-all-pages-public?)]
- (config-handler/set-config! :publishing/all-pages-public? value)))))
- ;; (defn enable-block-timestamps-row [t enable-block-timestamps?]
- ;; (toggle "block timestamps"
- ;; (t :settings-page/enable-block-time)
- ;; enable-block-timestamps?
- ;; (fn []
- ;; (let [value (not enable-block-timestamps?)]
- ;; (config-handler/set-config! :feature/enable-block-timestamps? value)))))
- (defn encryption-row [enable-encryption?]
- (toggle "enable_encryption"
- (t :settings-page/enable-encryption)
- enable-encryption?
- #(let [value (not enable-encryption?)]
- (config-handler/set-config! :feature/enable-encryption? value)
- (when value
- (state/close-modal!)
- ;; FIXME: Don't send the `(atom false)` ! Should check multi-window! or internal status error happens
- (js/setTimeout (fn [] (state/pub-event! [:graph/ask-for-re-index (atom false) nil]))
- 100)))
- [:p.text-sm.opacity-50 "⚠️ This feature is experimental! "
- [:span "You can use "]
- [:a {:href "https://github.com/kanru/logseq-encrypt-ui"
- :target "_blank"}
- "logseq-encrypt-ui"]
- [:span " to decrypt your graph."]]))
- (rum/defc keyboard-shortcuts-row [t]
- (row-with-button-action
- {:left-label (t :settings-page/customize-shortcuts)
- :button-label (t :settings-page/shortcut-settings)
- :on-click #((state/close-settings!)
- (route-handler/redirect! {:to :shortcut-setting}))
- :-for "customize_shortcuts"}))
- (defn zotero-settings-row []
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- {:for "zotero_settings"}
- "Zotero"]
- [:div.mt-1.sm:mt-0.sm:col-span-2
- [:div
- (ui/button
- "Settings"
- :class "text-sm p-1"
- :style {:margin-top "0px"}
- :on-click
- (fn []
- (state/close-settings!)
- (route-handler/redirect! {:to :zotero-setting})))]]])
- (defn auto-push-row [_t current-repo enable-git-auto-push?]
- (when (and current-repo (string/starts-with? current-repo "https://"))
- (toggle "enable_git_auto_push"
- "Enable Git auto push"
- enable-git-auto-push?
- (fn []
- (let [value (not enable-git-auto-push?)]
- (config-handler/set-config! :git-auto-push value))))))
- (defn usage-diagnostics-row [t instrument-disabled?]
- (toggle "usage-diagnostics"
- (t :settings-page/disable-sentry)
- (not instrument-disabled?)
- (fn [] (instrument/disable-instrument
- (not instrument-disabled?)))
- [:span.text-sm.opacity-50 "Logseq will never collect your local graph database or sell your data."]))
- (defn clear-cache-row [t]
- (row-with-button-action {:left-label (t :settings-page/clear-cache)
- :button-label (t :settings-page/clear)
- :on-click handler/clear-cache!
- :-for "clear_cache"}))
- (defn version-row [t version]
- (row-with-button-action {:left-label (t :settings-page/current-version)
- :action (app-updater version)
- :-for "current-version"}))
- (defn developer-mode-row [t developer-mode?]
- (toggle "developer_mode"
- (t :settings-page/developer-mode)
- developer-mode?
- (fn []
- (let [mode (not developer-mode?)]
- (state/set-developer-mode! mode)))
- [:div.text-sm.opacity-50 (t :settings-page/developer-mode-desc)]))
- (rum/defc plugin-enabled-switcher
- [t]
- (let [value (state/lsp-enabled?-or-theme)
- [on? set-on?] (rum/use-state value)
- on-toggle #(let [v (not on?)]
- (set-on? v)
- (storage/set :lsp-core-enabled v))]
- [:div.flex.items-center
- (ui/toggle on? on-toggle true)
- (when (not= (boolean value) on?)
- [:div.relative.opacity-70
- [:span.absolute.whitespace-nowrap
- {:style {:top -18 :left 10}}
- (ui/button (t :plugin/restart)
- :on-click #(js/logseq.api.relaunch)
- :small? true :intent "logseq")]])]))
- (rum/defc flashcards-enabled-switcher
- [enable-flashcards?]
- (ui/toggle enable-flashcards?
- (fn []
- (let [value (not enable-flashcards?)]
- (config-handler/set-config! :feature/enable-flashcards? value)))
- true))
- (rum/defc user-proxy-settings
- [{:keys [protocol host port] :as agent-opts}]
- (ui/button [:span
- (when-let [e (and protocol host port (str protocol "://" host ":" port))]
- [:strong.pr-1 e])
- (ui/icon "edit")]
- :small? true
- :on-click #(state/set-sub-modal!
- (fn [_] (plugins/user-proxy-settings-panel agent-opts))
- {:id :https-proxy-panel :center? true})))
- (defn plugin-system-switcher-row []
- (row-with-button-action
- {:left-label (t :settings-page/plugin-system)
- :action (plugin-enabled-switcher t)}))
- (defn flashcards-switcher-row [enable-flashcards?]
- (row-with-button-action
- {:left-label (t :settings-page/enable-flashcards)
- :action (flashcards-enabled-switcher enable-flashcards?)}))
- (defn https-user-agent-row [agent-opts]
- (row-with-button-action
- {:left-label (t :settings-page/network-proxy)
- :action (user-proxy-settings agent-opts)}))
- (defn filename-format-row []
- (row-with-button-action
- {:left-label (t :settings-page/filename-format)
- :button-label (t :settings-page/edit-setting)
- :on-click #(state/set-sub-modal!
- (fn [_] (conversion-component/files-breaking-changed))
- {:id :filename-format-panel :center? true})}))
- (rum/defcs settings-general < rum/reactive
- [_state current-repo]
- (let [preferred-language (state/sub [:preferred-language])
- theme (state/sub :ui/theme)
- dark? (= "dark" theme)
- system-theme? (state/sub :ui/system-theme?)
- switch-theme (if dark? "light" "dark")]
- [:div.panel-wrap.is-general
- (version-row t version)
- (language-row t preferred-language)
- (theme-modes-row t switch-theme system-theme? dark?)
- (when (config/global-config-enabled?) (edit-global-config-edn))
- (when current-repo (edit-config-edn))
- (when current-repo (edit-custom-css))
- (when current-repo (edit-export-css))
- (keyboard-shortcuts-row t)]))
- (rum/defcs settings-editor < rum/reactive
- [_state current-repo]
- (let [preferred-format (state/get-preferred-format)
- preferred-date-format (state/get-date-formatter)
- preferred-workflow (state/get-preferred-workflow)
- enable-timetracking? (state/enable-timetracking?)
- enable-all-pages-public? (state/all-pages-public?)
- logical-outdenting? (state/logical-outdenting?)
- enable-tooltip? (state/enable-tooltip?)
- enable-shortcut-tooltip? (state/sub :ui/shortcut-tooltip?)
- show-brackets? (state/show-brackets?)
- enable-git-auto-push? (state/enable-git-auto-push? current-repo)]
- [:div.panel-wrap.is-editor
- (file-format-row t preferred-format)
- (date-format-row t preferred-date-format)
- (workflow-row t preferred-workflow)
- ;; (enable-block-timestamps-row t enable-block-timestamps?)
- (show-brackets-row t show-brackets?)
- (when (util/electron?) (switch-spell-check-row t))
- (outdenting-row t logical-outdenting?)
- (when-not (or (util/mobile?) (mobile-util/native-platform?))
- (shortcut-tooltip-row t enable-shortcut-tooltip?))
- (when-not (or (util/mobile?) (mobile-util/native-platform?))
- (tooltip-row t enable-tooltip?))
- (timetracking-row t enable-timetracking?)
- (enable-all-pages-public-row t enable-all-pages-public?)
- (auto-push-row t current-repo enable-git-auto-push?)]))
- (rum/defc settings-git
- []
- [:div.panel-wrap
- [:div.text-sm.my-4
- [:span.text-sm.opacity-50.my-4
- "You can view a page's edit history by clicking the three vertical dots "
- "in the top-right corner and selecting \"Check page's history\". "
- "Logseq uses "]
- [:a {:href "https://git-scm.com/" :target "_blank"}
- "Git"]
- [:span.text-sm.opacity-50.my-4
- " for version control."]]
- [:br]
- (switch-git-auto-commit-row t)
- (git-auto-commit-seconds t)
- (ui/admonition
- :warning
- [:p (t :settings-page/git-confirm)])])
- (rum/defc settings-advanced < rum/reactive
- [current-repo]
- (let [instrument-disabled? (state/sub :instrument/disabled?)
- developer-mode? (state/sub [:ui/developer-mode?])
- https-agent-opts (state/sub [:electron/user-cfgs :settings/agent])]
- [:div.panel-wrap.is-advanced
- (when (and (or util/mac? util/win32?) (util/electron?)) (app-auto-update-row t))
- (usage-diagnostics-row t instrument-disabled?)
- (when-not (mobile-util/native-platform?) (developer-mode-row t developer-mode?))
- (when (util/electron?) (https-user-agent-row https-agent-opts))
- (when (and (util/electron?) (not (config/demo-graph? current-repo))) (filename-format-row))
- (clear-cache-row t)
- (ui/admonition
- :warning
- [:p "Clearing the cache will discard open graphs. You will lose unsaved changes."])]))
- (rum/defc sync-enabled-switcher
- [enabled?]
- (ui/toggle enabled?
- (fn []
- (let [value (not enabled?)]
- (storage/set :logseq-sync-enabled value)
- (state/set-state! :feature/enable-sync? value)))
- true))
- (defn sync-switcher-row [enabled?]
- (row-with-button-action
- {:left-label (t :settings-page/sync)
- :action (sync-enabled-switcher enabled?)}))
- (rum/defc whiteboards-enabled-switcher
- [enabled?]
- (ui/toggle enabled?
- (fn []
- (let [value (not enabled?)]
- (config-handler/set-config! :feature/enable-whiteboards? value)))
- true))
- (defn whiteboards-switcher-row [enabled?]
- (row-with-button-action
- {:left-label (t :settings-page/enable-whiteboards)
- :action (whiteboards-enabled-switcher enabled?)}))
- (rum/defc settings-features < rum/reactive
- []
- (let [current-repo (state/get-current-repo)
- enable-journals? (state/enable-journals? current-repo)
- enable-encryption? (state/enable-encryption? current-repo)
- enable-flashcards? (state/enable-flashcards? current-repo)
- enable-sync? (state/enable-sync?)
- enable-whiteboards? (state/enable-whiteboards? current-repo)
- logged-in? (user-handler/logged-in?)]
- [:div.panel-wrap.is-features.mb-8
- (journal-row enable-journals?)
- (when (not enable-journals?)
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- {:for "default page"}
- (t :settings-page/home-default-page)]
- [:div.mt-1.sm:mt-0.sm:col-span-2
- [:div.max-w-lg.rounded-md.sm:max-w-xs
- [:input#home-default-page.form-input.is-small.transition.duration-150.ease-in-out
- {:default-value (state/sub-default-home-page)
- :on-blur update-home-page
- :on-key-press (fn [e]
- (when (= "Enter" (util/ekey e))
- (update-home-page e)))}]]]])
- (when (and (util/electron?) config/enable-plugins?) (plugin-system-switcher-row))
- (flashcards-switcher-row enable-flashcards?)
- (zotero-settings-row)
- (encryption-row enable-encryption?)
- (when-not web-platform?
- [:div.mt-1.sm:mt-0.sm:col-span-2
- [:hr]
- (if logged-in?
- [:div
- (user-handler/email)
- [:p (ui/button (t :logout) {:class "p-1"
- :icon "logout"
- :on-click user-handler/logout})]]
- [:div
- (ui/button (t :login) {:class "p-1"
- :icon "login"
- :on-click (fn []
- (state/close-settings!)
- (js/window.open config/LOGIN-URL))})
- [:p.text-sm.opacity-50 (t :settings-page/login-prompt)]])])
- (when-not web-platform?
- [:<>
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- [:label.flex.font-medium.leading-5.self-start.mt-1 (ui/icon (if logged-in? "lock-open" "lock") {:class "mr-1"}) (t :settings-page/beta-features)]]
- [:div.flex.flex-col.gap-4
- {:class (when-not user-handler/alpha-or-beta-user? "opacity-50 pointer-events-none cursor-not-allowed")}
- (sync-switcher-row enable-sync?)
- [:div.text-sm
- "Click"
- [:a.mx-1 {:href "https://blog.logseq.com/how-to-setup-and-use-logseq-sync/"
- :target "_blank"}
- "here"]
- "for instructions on how to set up and use Sync."]]])
- (when-not web-platform?
- [:<>
- [:hr]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
- [:label.flex.font-medium.leading-5.self-start.mt-1 (ui/icon (if logged-in? "lock-open" "lock") {:class "mr-1"}) (t :settings-page/alpha-features)]]
- [:div.flex.flex-col.gap-4
- {:class (when-not user-handler/alpha-user? "opacity-50 pointer-events-none cursor-not-allowed")}
- (whiteboards-switcher-row enable-whiteboards?)]])]))
- (rum/defcs settings
- < (rum/local [:general :general] ::active)
- {:will-mount
- (fn [state]
- (state/load-app-user-cfgs)
- state)
- :will-unmount
- (fn [state]
- (state/close-settings!)
- state)}
- rum/reactive
- [state]
- (let [current-repo (state/sub :git/current-repo)
- ;; enable-block-timestamps? (state/enable-block-timestamps?)
- _installed-plugins (state/sub :plugin/installed-plugins)
- plugins-of-settings (and config/lsp-enabled? (seq (plugin-handler/get-enabled-plugins-if-setting-schema)))
- *active (::active state)]
- [:div#settings.cp__settings-main
- [:header
- [:h1.title (t :settings)]]
- [:div.cp__settings-inner
- [:aside.md:w-64 {:style {:min-width "10rem"}}
- [:ul.settings-menu
- (for [[label id text icon]
- [[:general "general" (t :settings-page/tab-general) (ui/icon "adjustments")]
- [:editor "editor" (t :settings-page/tab-editor) (ui/icon "writing")]
- (when (and
- (util/electron?)
- (not (file-sync-handler/synced-file-graph? current-repo)))
- [:git "git" (t :settings-page/tab-version-control) (ui/icon "history")])
- ;; (when (util/electron?)
- ;; [:assets "assets" (t :settings-page/tab-assets) (ui/icon "box")])
- [:advanced "advanced" (t :settings-page/tab-advanced) (ui/icon "bulb")]
- [:features "features" (t :settings-page/tab-features) (ui/icon "app-feature" {:extension? true
- :style {:margin-left 2}})]
- (when plugins-of-settings
- [:plugins-setting "plugins" (t :settings-of-plugins) (ui/icon "puzzle")])]]
- (when label
- [:li.settings-menu-item
- {:key text
- :class (util/classnames [{:active (= label (first @*active))}])
- :on-click #(reset! *active [label (first @*active)])}
- [:a.flex.items-center.settings-menu-link
- {:data-id id}
- icon
- [:strong text]]]))]]
- [:article
- (case (first @*active)
- :plugins-setting
- (let [label (second @*active)]
- (state/pub-event! [:go/plugins-settings (:id (first plugins-of-settings))])
- (reset! *active [label label])
- nil)
- :general
- (settings-general current-repo)
- :editor
- (settings-editor current-repo)
- :git
- (settings-git)
- :assets
- (assets/settings-content)
- :advanced
- (settings-advanced current-repo)
- :features
- (settings-features)
- nil)]]]))
|