settings.cljs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. (ns frontend.components.settings
  2. (:require [clojure.string :as string]
  3. [frontend.components.svg :as svg]
  4. [frontend.components.plugins :as plugins]
  5. [frontend.config :as config]
  6. [frontend.context.i18n :refer [t]]
  7. [frontend.storage :as storage]
  8. [frontend.date :as date]
  9. [frontend.dicts :as dicts]
  10. [frontend.handler :as handler]
  11. [frontend.handler.config :as config-handler]
  12. [frontend.handler.notification :as notification]
  13. [frontend.handler.route :as route-handler]
  14. [frontend.handler.ui :as ui-handler]
  15. [frontend.handler.user :as user-handler]
  16. [frontend.handler.plugin :as plugin-handler]
  17. [frontend.handler.file-sync :as file-sync-handler]
  18. [frontend.handler.global-config :as global-config-handler]
  19. [frontend.modules.instrumentation.core :as instrument]
  20. [frontend.modules.shortcut.data-helper :as shortcut-helper]
  21. [frontend.state :as state]
  22. [frontend.ui :as ui]
  23. [electron.ipc :as ipc]
  24. [promesa.core :as p]
  25. [frontend.util :refer [classnames web-platform?] :as util]
  26. [frontend.version :refer [version]]
  27. [goog.object :as gobj]
  28. [reitit.frontend.easy :as rfe]
  29. [rum.core :as rum]
  30. [frontend.mobile.util :as mobile-util]
  31. [frontend.db :as db]))
  32. (defn toggle
  33. [label-for name state on-toggle & [detail-text]]
  34. [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
  35. [:label.block.text-sm.font-medium.leading-5.opacity-70
  36. {:for label-for}
  37. name]
  38. [:div.rounded-md.sm:max-w-tss.sm:col-span-2
  39. [:div.rounded-md {:style {:display "flex" :gap "1rem" :align-items "center"}}
  40. (ui/toggle state on-toggle true)
  41. detail-text]]])
  42. (rum/defcs app-updater < rum/reactive
  43. [state version]
  44. (let [update-pending? (state/sub :electron/updater-pending?)
  45. {:keys [type payload]} (state/sub :electron/updater)]
  46. [:span.cp__settings-app-updater
  47. [:div.ctls.flex.items-center
  48. [:div.mt-1.sm:mt-0.sm:col-span-2
  49. {:style {:display "flex" :gap "0.5rem" :align-items "center"}}
  50. [:div (cond
  51. (mobile-util/native-android?)
  52. (ui/button
  53. "Check for updates"
  54. :class "text-sm p-1 mr-1"
  55. :href "https://github.com/logseq/logseq/releases" )
  56. (mobile-util/native-ios?)
  57. (ui/button
  58. "Check for updates"
  59. :class "text-sm p-1 mr-1"
  60. :href "https://apps.apple.com/app/logseq/id1601013908" )
  61. (util/electron?)
  62. (ui/button
  63. (if update-pending? "Checking ..." "Check for updates")
  64. :class "text-sm p-1 mr-1"
  65. :disabled update-pending?
  66. :on-click #(js/window.apis.checkForUpdates false))
  67. :else
  68. nil)]
  69. [:div.text-sm.opacity-50 (str "Version " version)]]]
  70. (when-not (or update-pending?
  71. (string/blank? type))
  72. [:div.update-state.text-sm
  73. (case type
  74. "update-not-available"
  75. [:p "Your app is up-to-date 🎉"]
  76. "update-available"
  77. (let [{:keys [name url]} payload]
  78. [:p (str "Found new release ")
  79. [:a.link
  80. {:on-click
  81. (fn [e]
  82. (js/window.apis.openExternal url)
  83. (util/stop e))}
  84. svg/external-link name " 🎉"]])
  85. "error"
  86. [:p "⚠️ Oops, Something Went Wrong!" [:br] " Please check out the "
  87. [:a.link
  88. {:on-click
  89. (fn [e]
  90. (js/window.apis.openExternal "https://github.com/logseq/logseq/releases")
  91. (util/stop e))}
  92. svg/external-link " release channel"]])])]))
  93. (rum/defc outdenting-hint
  94. []
  95. [:div.ui__modal-panel
  96. {:style {:box-shadow "0 4px 20px 4px rgba(0, 20, 60, .1), 0 4px 80px -8px rgba(0, 20, 60, .2)"}}
  97. [:div {:style {:margin "12px" :max-width "500px"}}
  98. [:p.text-sm
  99. "The left side shows outdenting with the default setting, and the right shows outdenting with logical outdenting enabled. "
  100. [:a.text-sm
  101. {:target "_blank" :href "https://discuss.logseq.com/t/whats-your-preferred-outdent-behavior-the-direct-one-or-the-logical-one/978"}
  102. "→ Learn more"]]
  103. [:img {:src "https://discuss.logseq.com/uploads/default/original/1X/e8ea82f63a5e01f6d21b5da827927f538f3277b9.gif"
  104. :width 500
  105. :height 500}]]])
  106. (defn row-with-button-action
  107. [{:keys [left-label action button-label href on-click desc -for]}]
  108. [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
  109. ;; left column
  110. [:label.block.text-sm.font-medium.leading-5.opacity-70
  111. {:for -for}
  112. left-label]
  113. ;; right column
  114. [:div.mt-1.sm:mt-0.sm:col-span-2
  115. {:style {:display "flex" :gap "0.5rem" :align-items "center"}}
  116. [:div (if action action (ui/button
  117. button-label
  118. :class "text-sm p-1"
  119. :href href
  120. :on-click on-click))]
  121. (when-not (or (util/mobile?)
  122. (mobile-util/native-platform?))
  123. [:div.text-sm desc])]])
  124. (defn edit-config-edn []
  125. (row-with-button-action
  126. {:left-label (t :settings-page/custom-configuration)
  127. :button-label (t :settings-page/edit-config-edn)
  128. :href (rfe/href :file {:path (config/get-repo-config-path)})
  129. :on-click #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))
  130. :-for "config_edn"}))
  131. (defn edit-global-config-edn []
  132. (row-with-button-action
  133. {:left-label (t :settings-page/custom-global-configuration)
  134. :button-label (t :settings-page/edit-global-config-edn)
  135. :href (rfe/href :file {:path (global-config-handler/global-config-path)})
  136. :on-click #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))
  137. :-for "global_config_edn"}))
  138. (defn edit-custom-css []
  139. (row-with-button-action
  140. {:left-label (t :settings-page/custom-theme)
  141. :button-label (t :settings-page/edit-custom-css)
  142. :href (rfe/href :file {:path (config/get-custom-css-path)})
  143. :on-click #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))
  144. :-for "customize_css"}))
  145. (defn edit-export-css []
  146. (row-with-button-action
  147. {:left-label (t :settings-page/export-theme)
  148. :button-label (t :settings-page/edit-export-css)
  149. :href (rfe/href :file {:path (config/get-export-css-path)})
  150. :on-click #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))
  151. :-for "customize_css"}))
  152. (defn show-brackets-row [t show-brackets?]
  153. [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
  154. [:label.block.text-sm.font-medium.leading-5.opacity-70
  155. {:for "show_brackets"}
  156. (t :settings-page/show-brackets)]
  157. [:div
  158. [:div.rounded-md.sm:max-w-xs
  159. (ui/toggle show-brackets?
  160. config-handler/toggle-ui-show-brackets!
  161. true)]]
  162. (when (not (or (util/mobile?) (mobile-util/native-platform?)))
  163. [:div {:style {:text-align "right"}}
  164. (ui/render-keyboard-shortcut (shortcut-helper/gen-shortcut-seq :ui/toggle-brackets))])])
  165. (rum/defcs switch-spell-check-row < rum/reactive
  166. [state t]
  167. (let [enabled? (state/sub [:electron/user-cfgs :spell-check])]
  168. [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
  169. [:label.block.text-sm.font-medium.leading-5.opacity-70
  170. (t :settings-page/spell-checker)]
  171. [:div
  172. [:div.rounded-md.sm:max-w-xs
  173. (ui/toggle
  174. enabled?
  175. (fn []
  176. (state/set-state! [:electron/user-cfgs :spell-check] (not enabled?))
  177. (p/then (ipc/ipc "userAppCfgs" :spell-check (not enabled?))
  178. #(when (js/confirm (t :relaunch-confirm-to-work))
  179. (js/logseq.api.relaunch))))
  180. true)]]]))
  181. (rum/defcs switch-git-auto-commit-row < rum/reactive
  182. [state t]
  183. (let [enabled? (state/get-git-auto-commit-enabled?)]
  184. [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
  185. [:label.block.text-sm.font-medium.leading-5.opacity-70
  186. (t :settings-page/git-switcher-label)]
  187. [:div
  188. [:div.rounded-md.sm:max-w-xs
  189. (ui/toggle
  190. enabled?
  191. (fn []
  192. (state/set-state! [:electron/user-cfgs :git/disable-auto-commit?] enabled?)
  193. (ipc/ipc "userAppCfgs" :git/disable-auto-commit? enabled?))
  194. true)]]]))
  195. (rum/defcs git-auto-commit-seconds < rum/reactive
  196. [state t]
  197. (let [secs (or (state/sub [:electron/user-cfgs :git/auto-commit-seconds]) 60)]
  198. [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
  199. [:label.block.text-sm.font-medium.leading-5.opacity-70
  200. (t :settings-page/git-commit-delay)]
  201. [:div.mt-1.sm:mt-0.sm:col-span-2
  202. [:div.max-w-lg.rounded-md.sm:max-w-xs
  203. [:input#home-default-page.form-input.is-small.transition.duration-150.ease-in-out
  204. {:default-value secs
  205. :on-blur (fn [event]
  206. (let [value (-> (util/evalue event)
  207. util/safe-parse-int)]
  208. (if (and (number? value)
  209. (< 0 value (inc 600)))
  210. (do
  211. (state/set-state! [:electron/user-cfgs :git/auto-commit-seconds] value)
  212. (ipc/ipc "userAppCfgs" :git/auto-commit-seconds value))
  213. (when-let [elem (gobj/get event "target")]
  214. (notification/show!
  215. [:div "Invalid value! Must be a number between 1 and 600."]
  216. :warning true)
  217. (gobj/set elem "value" secs)))))}]]]]))
  218. (rum/defc app-auto-update-row < rum/reactive [t]
  219. (let [enabled? (state/sub [:electron/user-cfgs :auto-update])
  220. enabled? (if (nil? enabled?) true enabled?)]
  221. (toggle "usage-diagnostics"
  222. (t :settings-page/auto-updater)
  223. enabled?
  224. #((state/set-state! [:electron/user-cfgs :auto-update] (not enabled?))
  225. (ipc/ipc "userAppCfgs" :auto-update (not enabled?))))))
  226. (defn language-row [t preferred-language]
  227. (let [on-change (fn [e]
  228. (let [lang-code (util/evalue e)]
  229. (state/set-preferred-language! lang-code)
  230. (ui-handler/re-render-root!)))
  231. action [:select.form-select.is-small {:value preferred-language
  232. :on-change on-change}
  233. (for [language dicts/languages]
  234. (let [lang-code (name (:value language))
  235. lang-label (:label language)]
  236. [:option {:key lang-code :value lang-code} lang-label]))]]
  237. (row-with-button-action {:left-label (t :language)
  238. :-for "preferred_language"
  239. :action action})))
  240. (defn theme-modes-row [t switch-theme system-theme? dark?]
  241. (let [pick-theme [:ul.theme-modes-options
  242. [:li {:on-click (partial state/use-theme-mode! "light")
  243. :class (classnames [{:active (and (not system-theme?) (not dark?))}])} [:i.mode-light] [:strong "light"]]
  244. [:li {:on-click (partial state/use-theme-mode! "dark")
  245. :class (classnames [{:active (and (not system-theme?) dark?)}])} [:i.mode-dark] [:strong "dark"]]
  246. [:li {:on-click (partial state/use-theme-mode! "system")
  247. :class (classnames [{:active system-theme?}])} [:i.mode-system] [:strong "system"]]]]
  248. (row-with-button-action {:left-label (t :right-side-bar/switch-theme (string/capitalize switch-theme))
  249. :-for "toggle_theme"
  250. :action pick-theme
  251. :desc (ui/render-keyboard-shortcut (shortcut-helper/gen-shortcut-seq :ui/toggle-theme))})))
  252. (defn file-format-row [t preferred-format]
  253. [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
  254. [:label.block.text-sm.font-medium.leading-5.opacity-70
  255. {:for "preferred_format"}
  256. (t :settings-page/preferred-file-format)]
  257. [:div.mt-1.sm:mt-0.sm:col-span-2
  258. [:div.max-w-lg.rounded-md
  259. [:select.form-select.is-small
  260. {:value (name preferred-format)
  261. :on-change (fn [e]
  262. (let [format (-> (util/evalue e)
  263. (string/lower-case)
  264. keyword)]
  265. (user-handler/set-preferred-format! format)))}
  266. (for [format (map name [:org :markdown])]
  267. [:option {:key format :value format} (string/capitalize format)])]]]])
  268. (defn date-format-row [t preferred-date-format]
  269. [: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
  270. [:label.block.text-sm.font-medium.leading-5.opacity-70
  271. {:for "custom_date_format"}
  272. (t :settings-page/custom-date-format)]
  273. [:div.mt-1.sm:mt-0.sm:col-span-2
  274. [:div.max-w-lg.rounded-md
  275. [:select.form-select.is-small
  276. {:value preferred-date-format
  277. :on-change (fn [e]
  278. (let [format (util/evalue e)]
  279. (when-not (string/blank? format)
  280. (config-handler/set-config! :journal/page-title-format format)
  281. (notification/show!
  282. [:div "You must re-index your graph for this change to take effect"]
  283. :warning false)
  284. (state/close-modal!)
  285. (route-handler/redirect! {:to :repos}))))}
  286. (for [format (sort (date/journal-title-formatters))]
  287. [:option {:key format} format])]]]])
  288. (defn workflow-row [t preferred-workflow]
  289. [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
  290. [:label.block.text-sm.font-medium.leading-5.opacity-70
  291. {:for "preferred_workflow"}
  292. (t :settings-page/preferred-workflow)]
  293. [:div.mt-1.sm:mt-0.sm:col-span-2
  294. [:div.max-w-lg.rounded-md
  295. [:select.form-select.is-small
  296. {:value (name preferred-workflow)
  297. :on-change (fn [e]
  298. (-> (util/evalue e)
  299. string/lower-case
  300. keyword
  301. (#(if (= % :now) :now :todo))
  302. user-handler/set-preferred-workflow!))}
  303. (for [workflow [:now :todo]]
  304. [:option {:key (name workflow) :value (name workflow)}
  305. (if (= workflow :now) "NOW/LATER" "TODO/DOING")])]]]])
  306. (defn outdenting-row [t logical-outdenting?]
  307. (toggle "preferred_outdenting"
  308. [(t :settings-page/preferred-outdenting)
  309. (ui/tippy {:html (outdenting-hint)
  310. :class "tippy-hover ml-2"
  311. :interactive true
  312. :disabled false}
  313. (svg/info))]
  314. logical-outdenting?
  315. config-handler/toggle-logical-outdenting!))
  316. (defn tooltip-row [t enable-tooltip?]
  317. (toggle "enable_tooltip"
  318. (t :settings-page/enable-tooltip)
  319. enable-tooltip?
  320. (fn []
  321. (config-handler/toggle-ui-enable-tooltip!))))
  322. (defn shortcut-tooltip-row [t enable-shortcut-tooltip?]
  323. (toggle "enable_tooltip"
  324. (t :settings-page/enable-shortcut-tooltip)
  325. enable-shortcut-tooltip?
  326. (fn []
  327. (state/toggle-shortcut-tooltip!))))
  328. (defn timetracking-row [t enable-timetracking?]
  329. (toggle "enable_timetracking"
  330. (t :settings-page/enable-timetracking)
  331. enable-timetracking?
  332. #(let [value (not enable-timetracking?)]
  333. (config-handler/set-config! :feature/enable-timetracking? value))))
  334. (defn update-home-page
  335. [event]
  336. (let [value (util/evalue event)]
  337. (cond
  338. (string/blank? value)
  339. (let [home (get (state/get-config) :default-home {})
  340. new-home (dissoc home :page)]
  341. (config-handler/set-config! :default-home new-home)
  342. (notification/show! "Home default page updated successfully!" :success))
  343. (db/page-exists? value)
  344. (let [home (get (state/get-config) :default-home {})
  345. new-home (assoc home :page value)]
  346. (config-handler/set-config! :default-home new-home)
  347. (notification/show! "Home default page updated successfully!" :success))
  348. :else
  349. (notification/show! (str "The page \"" value "\" doesn't exist yet. Please create that page first, and then try again.") :warning))))
  350. (defn journal-row [enable-journals?]
  351. (toggle "enable_journals"
  352. (t :settings-page/enable-journals)
  353. enable-journals?
  354. (fn []
  355. (let [value (not enable-journals?)]
  356. (config-handler/set-config! :feature/enable-journals? value)))))
  357. (defn enable-all-pages-public-row [t enable-all-pages-public?]
  358. (toggle "all pages public"
  359. (t :settings-page/enable-all-pages-public)
  360. enable-all-pages-public?
  361. (fn []
  362. (let [value (not enable-all-pages-public?)]
  363. (config-handler/set-config! :publishing/all-pages-public? value)))))
  364. ;; (defn enable-block-timestamps-row [t enable-block-timestamps?]
  365. ;; (toggle "block timestamps"
  366. ;; (t :settings-page/enable-block-time)
  367. ;; enable-block-timestamps?
  368. ;; (fn []
  369. ;; (let [value (not enable-block-timestamps?)]
  370. ;; (config-handler/set-config! :feature/enable-block-timestamps? value)))))
  371. (defn encryption-row [enable-encryption?]
  372. (toggle "enable_encryption"
  373. (t :settings-page/enable-encryption)
  374. enable-encryption?
  375. #(let [value (not enable-encryption?)]
  376. (config-handler/set-config! :feature/enable-encryption? value)
  377. (when value
  378. (state/close-modal!)
  379. (js/setTimeout (fn [] (state/pub-event! [:graph/ask-for-re-index (atom false)]))
  380. 100)))
  381. [:p.text-sm.opacity-50 "⚠️ This feature is experimental! "
  382. [:span "You can use "]
  383. [:a {:href "https://github.com/kanru/logseq-encrypt-ui"
  384. :target "_blank"}
  385. "logseq-encrypt-ui"]
  386. [:span " to decrypt your graph."]]))
  387. (rum/defc keyboard-shortcuts-row [t]
  388. (row-with-button-action
  389. {:left-label (t :settings-page/customize-shortcuts)
  390. :button-label (t :settings-page/shortcut-settings)
  391. :on-click #((state/close-settings!)
  392. (route-handler/redirect! {:to :shortcut-setting}))
  393. :-for "customize_shortcuts"}))
  394. (defn zotero-settings-row []
  395. [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
  396. [:label.block.text-sm.font-medium.leading-5.opacity-70
  397. {:for "zotero_settings"}
  398. "Zotero"]
  399. [:div.mt-1.sm:mt-0.sm:col-span-2
  400. [:div
  401. (ui/button
  402. "Settings"
  403. :class "text-sm p-1"
  404. :style {:margin-top "0px"}
  405. :on-click
  406. (fn []
  407. (state/close-settings!)
  408. (route-handler/redirect! {:to :zotero-setting})))]]])
  409. (defn auto-push-row [_t current-repo enable-git-auto-push?]
  410. (when (and current-repo (string/starts-with? current-repo "https://"))
  411. (toggle "enable_git_auto_push"
  412. "Enable Git auto push"
  413. enable-git-auto-push?
  414. (fn []
  415. (let [value (not enable-git-auto-push?)]
  416. (config-handler/set-config! :git-auto-push value))))))
  417. (defn usage-diagnostics-row [t instrument-disabled?]
  418. (toggle "usage-diagnostics"
  419. (t :settings-page/disable-sentry)
  420. (not instrument-disabled?)
  421. (fn [] (instrument/disable-instrument
  422. (not instrument-disabled?)))
  423. [:span.text-sm.opacity-50 "Logseq will never collect your local graph database or sell your data."]))
  424. (defn clear-cache-row [t]
  425. (row-with-button-action {:left-label (t :settings-page/clear-cache)
  426. :button-label (t :settings-page/clear)
  427. :on-click handler/clear-cache!
  428. :-for "clear_cache"}))
  429. (defn version-row [t version]
  430. (row-with-button-action {:left-label (t :settings-page/current-version)
  431. :action (app-updater version)
  432. :-for "current-version"}))
  433. (defn developer-mode-row [t developer-mode?]
  434. (toggle "developer_mode"
  435. (t :settings-page/developer-mode)
  436. developer-mode?
  437. (fn []
  438. (let [mode (not developer-mode?)]
  439. (state/set-developer-mode! mode)))
  440. [:div.text-sm.opacity-50 (t :settings-page/developer-mode-desc)]))
  441. (rum/defc plugin-enabled-switcher
  442. [t]
  443. (let [value (state/lsp-enabled?-or-theme)
  444. [on? set-on?] (rum/use-state value)
  445. on-toggle #(let [v (not on?)]
  446. (set-on? v)
  447. (storage/set :lsp-core-enabled v))]
  448. [:div.flex.items-center
  449. (ui/toggle on? on-toggle true)
  450. (when (not= (boolean value) on?)
  451. [:div.relative.opacity-70
  452. [:span.absolute.whitespace-nowrap
  453. {:style {:top -18 :left 10}}
  454. (ui/button (t :plugin/restart)
  455. :on-click #(js/logseq.api.relaunch)
  456. :small? true :intent "logseq")]])]))
  457. (rum/defc flashcards-enabled-switcher
  458. [enable-flashcards?]
  459. (ui/toggle enable-flashcards?
  460. (fn []
  461. (let [value (not enable-flashcards?)]
  462. (config-handler/set-config! :feature/enable-flashcards? value)))
  463. true))
  464. (rum/defc user-proxy-settings
  465. [{:keys [protocol host port] :as agent-opts}]
  466. (ui/button [:span
  467. (when-let [e (and protocol host port (str protocol "://" host ":" port))]
  468. [:strong.pr-1 e])
  469. (ui/icon "edit")]
  470. :on-click #(state/set-sub-modal!
  471. (fn [_] (plugins/user-proxy-settings-panel agent-opts))
  472. {:id :https-proxy-panel :center? true})))
  473. (defn plugin-system-switcher-row []
  474. (row-with-button-action
  475. {:left-label (t :settings-page/plugin-system)
  476. :action (plugin-enabled-switcher t)}))
  477. (defn flashcards-switcher-row [enable-flashcards?]
  478. (row-with-button-action
  479. {:left-label (t :settings-page/enable-flashcards)
  480. :action (flashcards-enabled-switcher enable-flashcards?)}))
  481. (defn https-user-agent-row [agent-opts]
  482. (row-with-button-action
  483. {:left-label (t :settings-page/network-proxy)
  484. :action (user-proxy-settings agent-opts)}))
  485. (rum/defcs settings-general < rum/reactive
  486. [_state current-repo]
  487. (let [preferred-language (state/sub [:preferred-language])
  488. theme (state/sub :ui/theme)
  489. dark? (= "dark" theme)
  490. system-theme? (state/sub :ui/system-theme?)
  491. switch-theme (if dark? "light" "dark")]
  492. [:div.panel-wrap.is-general
  493. (version-row t version)
  494. (language-row t preferred-language)
  495. (theme-modes-row t switch-theme system-theme? dark?)
  496. (when (config/global-config-enabled?) (edit-global-config-edn))
  497. (when current-repo (edit-config-edn))
  498. (when current-repo (edit-custom-css))
  499. (when current-repo (edit-export-css))
  500. (keyboard-shortcuts-row t)]))
  501. (rum/defcs settings-editor < rum/reactive
  502. [_state current-repo]
  503. (let [preferred-format (state/get-preferred-format)
  504. preferred-date-format (state/get-date-formatter)
  505. preferred-workflow (state/get-preferred-workflow)
  506. enable-timetracking? (state/enable-timetracking?)
  507. enable-all-pages-public? (state/all-pages-public?)
  508. logical-outdenting? (state/logical-outdenting?)
  509. enable-tooltip? (state/enable-tooltip?)
  510. enable-shortcut-tooltip? (state/sub :ui/shortcut-tooltip?)
  511. show-brackets? (state/show-brackets?)
  512. enable-git-auto-push? (state/enable-git-auto-push? current-repo)]
  513. [:div.panel-wrap.is-editor
  514. (file-format-row t preferred-format)
  515. (date-format-row t preferred-date-format)
  516. (workflow-row t preferred-workflow)
  517. ;; (enable-block-timestamps-row t enable-block-timestamps?)
  518. (show-brackets-row t show-brackets?)
  519. (when (util/electron?) (switch-spell-check-row t))
  520. (outdenting-row t logical-outdenting?)
  521. (when-not (or (util/mobile?) (mobile-util/native-platform?))
  522. (shortcut-tooltip-row t enable-shortcut-tooltip?))
  523. (when-not (or (util/mobile?) (mobile-util/native-platform?))
  524. (tooltip-row t enable-tooltip?))
  525. (timetracking-row t enable-timetracking?)
  526. (enable-all-pages-public-row t enable-all-pages-public?)
  527. (auto-push-row t current-repo enable-git-auto-push?)]))
  528. (rum/defc settings-git
  529. []
  530. [:div.panel-wrap
  531. [:div.text-sm.my-4
  532. [:span.text-sm.opacity-50.my-4
  533. "You can view a page's edit history by clicking the three vertical dots "
  534. "in the top-right corner and selecting \"Check page's history\". "
  535. "Logseq uses "]
  536. [:a {:href "https://git-scm.com/" :target "_blank"}
  537. "Git"]
  538. [:span.text-sm.opacity-50.my-4
  539. " for version control."]]
  540. [:br]
  541. (switch-git-auto-commit-row t)
  542. (git-auto-commit-seconds t)
  543. (ui/admonition
  544. :warning
  545. [:p (t :settings-page/git-confirm)])])
  546. (rum/defc settings-advanced < rum/reactive
  547. []
  548. (let [instrument-disabled? (state/sub :instrument/disabled?)
  549. developer-mode? (state/sub [:ui/developer-mode?])
  550. https-agent-opts (state/sub [:electron/user-cfgs :settings/agent])]
  551. [:div.panel-wrap.is-advanced
  552. (when (and (or util/mac? util/win32?) (util/electron?)) (app-auto-update-row t))
  553. (usage-diagnostics-row t instrument-disabled?)
  554. (when-not (mobile-util/native-platform?) (developer-mode-row t developer-mode?))
  555. (when (util/electron?) (https-user-agent-row https-agent-opts))
  556. (clear-cache-row t)
  557. (ui/admonition
  558. :warning
  559. [:p "Clearing the cache will discard open graphs. You will lose unsaved changes."])]))
  560. (rum/defc sync-enabled-switcher
  561. [enabled?]
  562. (ui/toggle enabled?
  563. (fn []
  564. (let [value (not enabled?)]
  565. (storage/set :logseq-sync-enabled value)
  566. (state/set-state! :feature/enable-sync? value)))
  567. true))
  568. (defn sync-switcher-row [enabled?]
  569. (row-with-button-action
  570. {:left-label (str (t :settings-page/sync) " 🔐")
  571. :action (sync-enabled-switcher enabled?)}))
  572. (rum/defc settings-features < rum/reactive
  573. []
  574. (let [current-repo (state/get-current-repo)
  575. enable-journals? (state/enable-journals? current-repo)
  576. enable-encryption? (state/enable-encryption? current-repo)
  577. enable-flashcards? (state/enable-flashcards? current-repo)
  578. enable-sync? (state/enable-sync?)]
  579. [:div.panel-wrap.is-features.mb-8
  580. (journal-row enable-journals?)
  581. (when (not enable-journals?)
  582. [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
  583. [:label.block.text-sm.font-medium.leading-5.opacity-70
  584. {:for "default page"}
  585. (t :settings-page/home-default-page)]
  586. [:div.mt-1.sm:mt-0.sm:col-span-2
  587. [:div.max-w-lg.rounded-md.sm:max-w-xs
  588. [:input#home-default-page.form-input.is-small.transition.duration-150.ease-in-out
  589. {:default-value (state/sub-default-home-page)
  590. :on-blur update-home-page
  591. :on-key-press (fn [e]
  592. (when (= "Enter" (util/ekey e))
  593. (update-home-page e)))}]]]])
  594. (when (and (util/electron?) config/enable-plugins?) (plugin-system-switcher-row))
  595. (flashcards-switcher-row enable-flashcards?)
  596. (zotero-settings-row)
  597. (encryption-row enable-encryption?)
  598. (when-not web-platform?
  599. [:div
  600. [:hr]
  601. [:h2.mb-4 "Alpha test (sponsors only)"]
  602. (sync-switcher-row enable-sync?)])]))
  603. (rum/defcs settings
  604. < (rum/local [:general :general] ::active)
  605. {:will-mount
  606. (fn [state]
  607. (state/load-app-user-cfgs)
  608. state)
  609. :will-unmount
  610. (fn [state]
  611. (state/close-settings!)
  612. state)}
  613. rum/reactive
  614. [state]
  615. (let [current-repo (state/sub :git/current-repo)
  616. ;; enable-block-timestamps? (state/enable-block-timestamps?)
  617. _installed-plugins (state/sub :plugin/installed-plugins)
  618. plugins-of-settings (and plugin-handler/lsp-enabled? (seq (plugin-handler/get-enabled-plugins-if-setting-schema)))
  619. *active (::active state)]
  620. [:div#settings.cp__settings-main
  621. [:header
  622. [:h1.title (t :settings)]]
  623. [:div.cp__settings-inner
  624. [:aside.md:w-64 {:style {:min-width "10rem"}}
  625. [:ul.settings-menu
  626. (for [[label id text icon]
  627. [[:general "general" (t :settings-page/tab-general) (ui/icon "adjustments" {:style {:font-size 20}})]
  628. [:editor "editor" (t :settings-page/tab-editor) (ui/icon "writing" {:style {:font-size 20}})]
  629. (when (and
  630. (util/electron?)
  631. (not (file-sync-handler/synced-file-graph? current-repo)))
  632. [:git "git" (t :settings-page/tab-version-control) (ui/icon "history" {:style {:font-size 20}})])
  633. [:advanced "advanced" (t :settings-page/tab-advanced) (ui/icon "bulb" {:style {:font-size 20}})]
  634. [:features "features" (t :settings-page/tab-features) (ui/icon "app-feature" {:style {:font-size 20}
  635. :extension? true})]
  636. (when plugins-of-settings
  637. [:plugins-setting "plugins" (t :settings-of-plugins) (ui/icon "puzzle")])]]
  638. (when label
  639. [:li.settings-menu-item
  640. {:key text
  641. :class (util/classnames [{:active (= label (first @*active))}])
  642. :on-click #(reset! *active [label (first @*active)])}
  643. [:a.flex.items-center.settings-menu-link
  644. {:data-id id}
  645. icon
  646. [:strong text]]]))]]
  647. [:article
  648. (case (first @*active)
  649. :plugins-setting
  650. (let [label (second @*active)]
  651. (state/pub-event! [:go/plugins-settings (:id (first plugins-of-settings))])
  652. (reset! *active [label label])
  653. nil)
  654. :general
  655. (settings-general current-repo)
  656. :editor
  657. (settings-editor current-repo)
  658. :git
  659. (settings-git)
  660. :advanced
  661. (settings-advanced)
  662. :features
  663. (settings-features)
  664. nil)]]]))