| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328 |
- (ns frontend.components.settings
- (:require [clojure.string :as string]
- [electron.ipc :as ipc]
- [frontend.colors :as colors]
- [frontend.components.assets :as assets]
- [frontend.components.file-sync :as fs]
- [frontend.components.shortcut :as shortcut]
- [frontend.components.svg :as svg]
- [frontend.config :as config]
- [frontend.context.i18n :refer [t]]
- [frontend.date :as date]
- [frontend.db :as db]
- [frontend.dicts :as dicts]
- [frontend.handler.config :as config-handler]
- [frontend.handler.db-based.rtc :as rtc-handler]
- [frontend.handler.file-sync :as file-sync-handler]
- [frontend.handler.global-config :as global-config-handler]
- [frontend.handler.notification :as notification]
- [frontend.handler.plugin :as plugin-handler]
- [frontend.handler.property :as property-handler]
- [frontend.handler.route :as route-handler]
- [frontend.handler.ui :as ui-handler]
- [frontend.handler.user :as user-handler]
- [frontend.mobile.util :as mobile-util]
- [frontend.modules.instrumentation.core :as instrument]
- [frontend.modules.shortcut.data-helper :as shortcut-helper]
- [frontend.spec.storage :as storage-spec]
- [frontend.state :as state]
- [frontend.storage :as storage]
- [frontend.ui :as ui]
- [frontend.util :refer [classnames web-platform?] :as util]
- [frontend.version :as fv]
- [goog.object :as gobj]
- [goog.string :as gstring]
- [logseq.db :as ldb]
- [logseq.shui.ui :as shui]
- [promesa.core :as p]
- [reitit.frontend.easy :as rfe]
- [rum.core :as rum]))
- (defn toggle
- [label-for name state on-toggle & [detail-text]]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center
- [: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.flex.gap-4.items-center.flex-wrap
- [:div (cond
- (mobile-util/native-android?)
- (ui/button
- (t :settings-page/check-for-updates)
- :class "text-sm mr-1"
- :href "https://github.com/logseq/logseq/releases")
- (mobile-util/native-ios?)
- (ui/button
- (t :settings-page/check-for-updates)
- :class "text-sm mr-1"
- :href "https://apps.apple.com/app/logseq/id1601013908")
- (util/electron?)
- (ui/button
- (if update-pending? (t :settings-page/checking) (t :settings-page/check-for-updates))
- :class "text-sm mr-1"
- :disabled update-pending?
- :on-click #(js/window.apis.checkForUpdates false))
- :else
- nil)]
- [:div.text-sm.cursor
- {:title (str (t :settings-page/revision) config/revision)
- :on-click (fn []
- (notification/show! [:div "Current Revision: "
- [:a {:target "_blank"
- :href (str "https://github.com/logseq/logseq/commit/" config/revision)}
- config/revision]]
- :info
- false))}
- version]
- [:a.text-sm.fade-link.underline.inline
- {:target "_blank"
- :href "https://docs.logseq.com/#/page/changelog"}
- (t :settings-page/changelog)]]]
- (when-not (or update-pending?
- (string/blank? type))
- [:div.update-state.text-sm
- (case type
- "update-not-available"
- [:p (t :settings-page/app-updated)]
- "update-available"
- (let [{:keys [name url]} payload]
- [:p (str (t :settings-page/update-available))
- [:a.link
- {:on-click
- (fn [e]
- (js/window.apis.openExternal url)
- (util/stop e))}
- svg/external-link name " 🎉"]])
- "error"
- [:p (t :settings-page/update-error-1) [:br] (t :settings-page/update-error-2)
- [: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
- (t :settings-page/preferred-outdenting-tip)
- [:a.text-sm
- {:target "_blank" :href "https://discuss.logseq.com/t/whats-your-preferred-outdent-behavior-the-direct-one-or-the-logical-one/978"}
- (t :settings-page/preferred-outdenting-tip-more)]]
- [:img {:src "https://discuss.logseq.com/uploads/default/original/1X/e8ea82f63a5e01f6d21b5da827927f538f3277b9.gif"
- :width 500
- :height 500}]]])
- (rum/defc auto-expand-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
- (t :settings-page/auto-expand-block-refs-tip)]
- [:img {:src "https://user-images.githubusercontent.com/28241963/225818326-118deda9-9d1e-477d-b0ce-771ca0bcd976.gif"
- :width 500
- :height 500}]]])
- (defn row-with-button-action
- [{:keys [left-label description action button-label href on-click desc -for stretch center?]
- :or {center? true}}]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4
- {:class (if center? "sm:items-center" "sm:items-start")}
- ;; left column
- [:div.flex.flex-col
- [:label.block.text-sm.font-medium.leading-5.opacity-70.pt-2
- {:for -for}
- left-label]
- (when description
- [:div.text-xs.text-gray-10 description])]
- ;; right column
- [:div.mt-1.sm:mt-0.sm:col-span-2.flex.items-center
- {:style {:display "flex" :gap "0.5rem" :align-items "center"}}
- [:div {:style (when stretch {:width "100%"})}
- (if action action (shui/button
- {:as-child (not (string/blank? href))
- :size :sm
- :on-click on-click}
- (if (string/blank? href) button-label
- (shui/link {:href href} button-label))))]
- (when-not (or (util/mobile?)
- (mobile-util/native-platform?))
- [:div.text-sm.flex 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 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 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 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 ui-handler/toggle-settings-modal!
- :-for "export_css"}))
- (defn show-brackets-row [t show-brackets?]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center
- [: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))])])
- (defn toggle-wide-mode-row [t wide-mode?]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- {:for "wide_mode"}
- (t :settings-page/wide-mode)]
- [:div
- [:div.rounded-md.sm:max-w-xs
- (ui/toggle wide-mode?
- ui-handler/toggle-wide-mode!
- 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-wide-mode))])])
- (defn editor-font-family-row [t font]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- {:for "font_family"}
- (t :settings-page/editor-font)]
- [:div.rounded-md.sm:max-w-xs.flex.gap-2
- (for [t [:default :serif :mono]
- :let [t (name t)
- tt (string/capitalize t)
- active? (= font t)]]
- (shui/button
- {:variant :secondary
- :class (when active? "border-primary border-[2px]")
- :on-click #(state/set-editor-font! t)}
- [:span.flex.flex-col
- {:class (str "ls-font-" t)}
- [:strong "Ag"]
- [:small tt]]))]])
- (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-center
- [: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-center
- [: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?)
- (p/do!
- (ipc/ipc :userAppCfgs :git/disable-auto-commit? enabled?)
- (ipc/ipc :setGitAutoCommit)))
- true)]]]))
- (rum/defcs switch-git-commit-on-close-row < rum/reactive
- [state t]
- (let [enabled? (state/get-git-commit-on-close-enabled?)]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- (t :settings-page/git-commit-on-close)]
- [:div
- [:div.rounded-md.sm:max-w-xs
- (ui/toggle
- enabled?
- (fn []
- (state/set-state! [:electron/user-cfgs :git/commit-on-close?] (not enabled?))
- (ipc/ipc :userAppCfgs :git/commit-on-close? (not 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-center
- [: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 86400)))
- (p/do!
- (state/set-state! [:electron/user-cfgs :git/auto-commit-seconds] value)
- (ipc/ipc :userAppCfgs :git/auto-commit-seconds value)
- (ipc/ipc :setGitAutoCommit))
- (when-let [elem (gobj/get event "target")]
- (notification/show!
- [:div "Invalid value! Must be a number between 1 and 86400"]
- :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})))
- (rum/defc theme-modes-row < rum/reactive
- [t]
- (let [theme (state/sub :ui/theme)
- dark? (= "dark" theme)
- system-theme? (state/sub :ui/system-theme?)
- switch-theme (if dark? "light" "dark")
- color-accent (state/sub :ui/radix-color)
- pick-theme [:ul.cp__theme-modes-options
- [:li {:on-click (partial state/use-theme-mode! "light")
- :class (classnames [{:active (and (not system-theme?) (not dark?))}])} [:i.mode-light {:class (when color-accent "radix")}] [:strong (t :settings-page/theme-light)]]
- [:li {:on-click (partial state/use-theme-mode! "dark")
- :class (classnames [{:active (and (not system-theme?) dark?)}])} [:i.mode-dark {:class (when color-accent "radix")}] [:strong (t :settings-page/theme-dark)]]
- [:li {:on-click (partial state/use-theme-mode! "system")
- :class (classnames [{:active system-theme?}])} [:i.mode-system {:class (when color-accent "radix")}] [:strong (t :settings-page/theme-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))})))
- (rum/defc accent-color-row < rum/reactive
- [_in-modal?]
- (let [color-accent (state/sub :ui/radix-color)
- pick-theme [:div.cp__accent-colors-list-wrap
- {:class (if _in-modal? "as-modal-picker" "")}
- (for [color (concat [:none :logseq] colors/color-list)
- :let [active? (= color color-accent)
- none? (= color :none)]]
- [:div.flex.items-center {:style {:height 28}}
- (ui/tippy
- {:html (case color
- :none [:p {:style {:max-width "300px"}}
- "Cancel accent color. This is currently in beta stage and mainly used for compatibility with custom themes."]
- :logseq "Logseq classical color"
- (str (name color) " color"))
- :delay [1000, 100]}
- (shui/button
- {:class "w-5 h-5 px-1 rounded-full flex justify-center items-center transition ease-in duration-100 hover:cursor-pointer hover:opacity-100"
- :auto-focus (and _in-modal? active?)
- :style {:background-color (colors/variable color :09)
- :outline-color (colors/variable color (if active? :07 :06))
- :outline-width (if active? "4px" "1px")
- :outline-style :solid
- :opacity (if active? 1 0.5)}
- :variant :text
- :on-click (fn [_e] (state/set-color-accent! color))}
- [:strong
- {:class (if none? "h-0.5 w-full bg-red-700"
- "w-2 h-2 rounded-full transition ease-in duration-100")
- :style {:background-color (if-not none? (str "var(--rx-" (name color) "-07)") "")
- :opacity (if (or none? active?) 1 0)}}]))
- ])]]
- [:<>
- (row-with-button-action
- {:left-label (t :settings-page/accent-color)
- :description (t :settings-page/accent-color-alert)
- :-for "toggle_radix_theme"
- :desc (when-not _in-modal?
- [:span.pl-6 (ui/render-keyboard-shortcut
- (shortcut-helper/gen-shortcut-seq :ui/customize-appearance))])
- :stretch (boolean _in-modal?)
- :action pick-theme})]))
- (rum/defc modal-appearance-inner < rum/reactive
- []
- [:div.cp__settings-appearance-modal-inner
- [:h1.text-2xl.font-bold.pb-2.pt-1 (t :appearance)]
- (theme-modes-row t)
- (editor-font-family-row t (state/sub :ui/editor-font))
- (toggle-wide-mode-row t (state/sub :ui/wide-mode?))
- (show-brackets-row t (state/show-brackets?))
- (accent-color-row true)])
- (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-center
- [:label.block.text-sm.font-medium.leading-5.opacity-70
- {:for "custom_date_format"}
- (t :settings-page/custom-date-format)
- (when-not (config/db-based-graph? (state/get-current-repo))
- (ui/tippy {:html (t :settings-page/custom-date-format-warning)
- :class "tippy-hover ml-2"
- :interactive true
- :disabled false}
- (svg/info)))]
- [: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 [repo (state/get-current-repo)
- format (util/evalue e)
- db-based? (config/db-based-graph? repo)]
- (when-not (string/blank? format)
- (if db-based?
- (p/do!
- (property-handler/set-block-property! repo
- :logseq.class/Journal
- :logseq.property.journal/title-format
- format)
- (notification/show! "Please refresh the app for this change to take effect"))
- (do
- (config-handler/set-config! :journal/page-title-format format)
- (notification/show!
- [:div (t :settings-page/custom-date-format-notification)]
- :warning false)))
- (state/close-modal!)
- (shui/dialog-close-all!)
- (when-not db-based? (route-handler/redirect! {:to :graphs})))))}
- (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-center
- [: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 showing-full-blocks [t show-full-blocks?]
- (toggle "show_full_blocks"
- (t :settings-page/show-full-blocks)
- show-full-blocks?
- config-handler/toggle-show-full-blocks!))
- (defn preferred-pasting-file [t preferred-pasting-file?]
- (toggle "preferred_pasting_file"
- [(t :settings-page/preferred-pasting-file)
- (ui/tippy {:html (t :settings-page/preferred-pasting-file-hint)
- :class "tippy-hover ml-2"
- :interactive true
- :disabled false}
- (svg/info))]
- preferred-pasting-file?
- config-handler/toggle-preferred-pasting-file!))
- (defn auto-expand-row [t auto-expand-block-refs?]
- (toggle "auto_expand_block_refs"
- [(t :settings-page/auto-expand-block-refs)
- (ui/tippy {:html (auto-expand-hint)
- :class "tippy-hover ml-2"
- :interactive true
- :disabled false}
- (svg/info))]
- auto-expand-block-refs?
- config-handler/toggle-auto-expand-block-refs!))
- (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)]
- (p/do!
- (config-handler/set-config! :default-home new-home)
- (config-handler/set-config! :feature/enable-journals? true)
- (notification/show! "Journals enabled" :success)))
- ;; FIXME: home page should be db id instead of page name
- (ldb/get-page (db/get-db) 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 zotero-settings-row []
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center
- [: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
- (t :settings)
- :class "text-sm"
- :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 (t :settings-page/disable-sentry-desc)]))
- (defn clear-cache-row [t]
- (row-with-button-action {:left-label (t :settings-page/clear-cache)
- :button-label (t :settings-page/clear)
- :on-click #(state/pub-event! [:graph/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 ::storage-spec/lsp-core-enabled v))]
- [:div.flex.items-center.gap-2
- (ui/toggle on? on-toggle true)
- (when (not= (boolean value) on?)
- (ui/button (t :plugin/restart)
- :on-click #(js/logseq.api.relaunch)
- :small? true :intent "logseq"))]))
- (rum/defc http-server-enabled-switcher
- [t]
- (let [[value _] (rum/use-state (boolean (storage/get ::storage-spec/http-server-enabled)))
- [on? set-on?] (rum/use-state value)
- on-toggle #(let [v (not on?)]
- (set-on? v)
- (storage/set ::storage-spec/http-server-enabled v))]
- [:div.flex.items-center.gap-2
- (ui/toggle on? on-toggle true)
- (when (not= (boolean value) on?)
- (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 [type protocol host port] :as agent-opts}]
- (ui/button [:span.flex.items-center
- [:span.pr-1
- (case type
- "system" "System Default"
- "direct" "Direct"
- (and protocol host port (str protocol "://" host ":" port)))]
- (ui/icon "edit")]
- :class "text-sm"
- :on-click #(state/pub-event! [:go/proxy-settings agent-opts])))
- (defn plugin-system-switcher-row []
- (row-with-button-action
- {:left-label (t :settings-page/plugin-system)
- :action (plugin-enabled-switcher t)}))
- (defn http-server-switcher-row []
- (row-with-button-action
- {:left-label "HTTP APIs server"
- :action (http-server-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)}))
- (rum/defcs auto-chmod-row < rum/reactive
- [state t]
- (let [enabled? (if (= nil (state/sub [:electron/user-cfgs :feature/enable-automatic-chmod?]))
- true
- (state/sub [:electron/user-cfgs :feature/enable-automatic-chmod?]))]
- (toggle
- "automatic-chmod"
- (t :settings-page/auto-chmod)
- enabled?
- #(do
- (state/set-state! [:electron/user-cfgs :feature/enable-automatic-chmod?] (not enabled?))
- (ipc/ipc :userAppCfgs :feature/enable-automatic-chmod? (not enabled?)))
- [:span.text-sm.opacity-50 (t :settings-page/auto-chmod-desc)])))
- (rum/defcs native-titlebar-row < rum/reactive
- [state t]
- (let [enabled? (state/sub [:electron/user-cfgs :window/native-titlebar?])]
- (toggle
- "native-titlebar"
- (t :settings-page/native-titlebar)
- enabled?
- #(when (js/confirm (t :relaunch-confirm-to-work))
- (state/set-state! [:electron/user-cfgs :window/native-titlebar?] (not enabled?))
- (ipc/ipc :userAppCfgs :window/native-titlebar? (not enabled?))
- (js/logseq.api.relaunch))
- [:span.text-sm.opacity-50 (t :settings-page/native-titlebar-desc)])))
- (rum/defcs settings-general < rum/reactive
- [_state current-repo]
- (let [preferred-language (state/sub [:preferred-language])
- show-radix-themes? true]
- [:div.panel-wrap.is-general
- (version-row t fv/version)
- (language-row t preferred-language)
- (theme-modes-row t)
- (when (and (util/electron?) (not util/mac?)) (native-titlebar-row t))
- (when show-radix-themes? (accent-color-row false))
- (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))]))
- (defn file-format-row [t preferred-format]
- [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center
- [: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)])]]]])
- (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?)
- show-full-blocks? (state/show-full-blocks?)
- preferred-pasting-file? (state/preferred-pasting-file?)
- auto-expand-block-refs? (state/auto-expand-block-refs?)
- enable-tooltip? (state/enable-tooltip?)
- enable-shortcut-tooltip? (state/sub :ui/shortcut-tooltip?)
- show-brackets? (state/show-brackets?)
- wide-mode? (state/sub :ui/wide-mode?)
- editor-font (state/sub :ui/editor-font)
- enable-git-auto-push? (state/enable-git-auto-push? current-repo)
- db-graph? (config/db-based-graph? (state/get-current-repo))]
- [:div.panel-wrap.is-editor
- (when-not db-graph?
- (file-format-row t preferred-format))
- (date-format-row t preferred-date-format)
- (when-not db-graph?
- (workflow-row t preferred-workflow))
- (editor-font-family-row t editor-font)
- (show-brackets-row t show-brackets?)
- (toggle-wide-mode-row t wide-mode?)
- (when (util/electron?) (switch-spell-check-row t))
- (outdenting-row t logical-outdenting?)
- (showing-full-blocks t show-full-blocks?)
- (preferred-pasting-file t preferred-pasting-file?)
- (auto-expand-row t auto-expand-block-refs?)
- (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
- (ui/admonition
- :tip
- [:p (t :settings-page/git-tip)])
- [:span.text-sm.opacity-50.my-4
- (t :settings-page/git-desc-1)]
- [:br] [:br]
- [:span.text-sm.opacity-50.my-4
- (t :settings-page/git-desc-2)]
- [:a {:href "https://git-scm.com/" :target "_blank"}
- "Git"]
- [:span.text-sm.opacity-50.my-4
- (t :settings-page/git-desc-3)]]
- [:br]
- (switch-git-auto-commit-row t)
- (switch-git-commit-on-close-row t)
- (git-auto-commit-seconds t)])
- (rum/defc settings-advanced < rum/reactive
- []
- (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 (util/electron?) (auto-chmod-row t))
- (clear-cache-row t)
- (ui/admonition
- :warning
- [:p (t :settings-page/clear-cache-warning)])]))
- (rum/defc sync-enabled-switcher
- [enabled?]
- (ui/toggle enabled?
- (fn []
- (file-sync-handler/set-sync-enabled! (not enabled?)))
- true))
- (rum/defc sync-diff-merge-enabled-switcher
- [enabled?]
- (ui/toggle enabled?
- (fn []
- (file-sync-handler/set-sync-diff-merge-enabled! (not enabled?)))
- true))
- (defn sync-switcher-row [repo enabled?]
- (row-with-button-action
- (cond-> {:left-label (t :settings-page/sync)
- :action (sync-enabled-switcher enabled?)}
- (config/db-based-graph? repo)
- (merge {:action nil :desc "Not available yet for database graphs"}))))
- (defn sync-diff-merge-switcher-row [enabled?]
- (row-with-button-action
- {:left-label (str (t :settings-page/sync-diff-merge) " (Experimental!)") ;; Not included in i18n to avoid outdating translations
- :action (sync-diff-merge-enabled-switcher enabled?)
- :desc (ui/tippy {:html [:div
- [:div (t :settings-page/sync-diff-merge-desc)]
- [:div (t :settings-page/sync-diff-merge-warn)]]
- :class "tippy-hover ml-2"
- :interactive true
- :disabled false}
- (svg/info))}))
- (rum/defc rtc-enabled-switcher
- [enabled?]
- (ui/toggle enabled?
- (fn []
- (let [value (not enabled?)]
- (config-handler/set-config! :feature/enable-rtc? value)))
- true))
- (defn rtc-switcher-row [enabled?]
- (row-with-button-action
- {:left-label "RTC"
- :action (rtc-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-account-usage-description [pro-account? graph-usage]
- (let [count-usage (count graph-usage)
- count-limit (if pro-account? 10 1)
- count-percent (js/Math.round (/ count-usage count-limit 0.01))
- storage-usage (->> (map :used-gbs graph-usage)
- (reduce + 0))
- storage-usage-formatted (cond
- (zero? storage-usage) "0.0"
- (< storage-usage 0.01) "Less than 0.01"
- :else (gstring/format "%.2f" storage-usage))
- ;; TODO: check logic on this. What are the rules around storage limits?
- ;; do we, and should we be able to, give individual users more storage?
- ;; should that be on a per graph or per user basis?
- default-storage-limit (if pro-account? 10 0.05)
- storage-limit (->> (range 0 count-limit)
- (map #(get-in graph-usage [% :limit-gbs] default-storage-limit))
- (reduce + 0))
- storage-percent (/ storage-usage storage-limit 0.01)
- storage-percent-formatted (gstring/format "%.1f" storage-percent)]
- [:div.text-sm
- (when pro-account?
- [:<>
- (gstring/format "%s of %s synced graphs " count-usage count-limit)
- [:strong.text-white (gstring/format "(%s%%)" count-percent)]
- ", "])
- (gstring/format "%sGB of %sGB total storage " storage-usage-formatted storage-limit)
- [:strong.text-white (gstring/format "(%s%%)" storage-percent-formatted)]]))
- ; storage-usage-formatted "GB of " storage-limit "GB total storage"
- ; [:strong.text-white " (" storage-percent-formatted "%)"]]))
- (rum/defc settings-account-usage-graphs [_pro-account? graph-usage]
- (when (< 0 (count graph-usage))
- [:div.grid.gap-3 {:style {:grid-template-columns (str "repeat(" (count graph-usage) ", 1fr)")}}
- (for [{:keys [name used-percent]} graph-usage
- :let [color (if (<= 100 used-percent) "bg-red-500" "bg-blue-500")]]
- [:div.rounded-full.w-full.h-2 {:class "bg-black/50"
- :tooltip name}
- [:div.rounded-full.h-2 {:class color
- :style {:width (str used-percent "%")
- :min-width "0.5rem"
- :max-width "100%"}}]])]))
- (rum/defc ^:large-vars/cleanup-todo settings-account < rum/reactive
- []
- (let [current-graph-uuid (state/sub-current-file-sync-graph-uuid)
- graph-usage (state/get-remote-graph-usage)
- current-graph-is-remote? ((set (map :uuid graph-usage)) current-graph-uuid)
- logged-in? (user-handler/logged-in?)
- user-info (state/get-user-info)
- paid-user? (#{"active" "on_trial" "cancelled"} (:LemonStatus user-info))
- gift-user? (some #{"pro"} (:UserGroups user-info))
- pro-account? (or paid-user? gift-user?)
- expiration-date (some-> user-info :LemonEndsAt date/parse-iso)
- renewal-date (some-> user-info :LemonRenewsAt date/parse-iso)
- has-subscribed? (some? (:LemonStatus user-info))]
- [:div.panel-wrap.is-features.mb-8
- [:div.mt-1.sm:mt-0.sm:col-span-2
- (cond
- logged-in?
- [:div.grid.grid-cols-3.gap-8.pt-2
- [:div "Current plan"]
- [:div.col-span-2
- [:div {:class "w-full bg-gray-500/10 rounded-lg p-4 flex flex-col gap-4"}
- [:div.flex.gap-4.items-center
- (if pro-account?
- [:div.flex-1 "Pro"]
- [:div.flex-1 "Free"])
- (cond
- has-subscribed?
- (ui/button "Manage plan" {:class "p-1 h-8 justify-center"
- :disabled true
- :icon "upload"})
- ; :on-click user-handler/upgrade})
- (not pro-account?)
- (ui/button "Upgrade plan" {:class "p-1 h-8 justify-center"
- :icon "upload"
- :on-click user-handler/upgrade})
- :else nil)]
- (settings-account-usage-graphs pro-account? graph-usage)
- (settings-account-usage-description pro-account? graph-usage)
- (if current-graph-is-remote?
- (ui/button "Deactivate syncing" {:class "p-1 h-8 justify-center"
- :disabled true
- :background "gray"
- :icon "cloud-off"})
- (ui/button "Activate syncing" {:class "p-1 h-8 justify-center"
- :background "blue"
- :icon "cloud"
- :on-click #(fs/maybe-onboarding-show :sync-initiate)}))]]
- (when has-subscribed?
- [:<>
- [:div "Billing"]
- [:div.col-span-2.flex.flex-col.gap-4
- (cond
- ;; If there is no expiration date, print the renewal date
- (and renewal-date (nil? expiration-date))
- [:div
- [:strong.font-semibold "Next billing date: "
- (date/get-locale-string renewal-date)]]
- ;; If the expiration date is in the future, word it as such
- (< (js/Date.) expiration-date)
- [:div
- [:strong.font-semibold "Pro plan expires on: "
- (date/get-locale-string expiration-date)]]
- ;; Otherwise, ind
- :else
- [:div
- [:strong.font-semibold "Pro plan expired on: "
- (date/get-locale-string expiration-date)]])
- [:div (ui/button "Open invoices" {:class "w-full h-8 p-1 justify-center"
- :disabled true
- :background "gray"
- :icon "receipt"})]]])
- [:div "Profile"]
- [:div.col-span-2.grid.grid-cols-2.gap-4
- [:div.flex.flex-col.gap-2.box-border {:class "basis-1/2"}
- [:label.text-sm.font-semibold "First name"]
- [:input.rounded.border.px-2.py-1.box-border {:class "border-blue-500 bg-black/25 w-full"}]]
- [:div.flex.flex-col.gap-2 {:class "basis-1/2"}
- [:label.text-sm.font-semibold "Last name"]
- [:input.rounded.border.px-2.py-1.box-border {:class "border-blue-500 bg-black/25 w-full"}]]
- [:div.flex-1.flex.flex-col.gap-2.col-span-2
- [:label.text-sm.font-semibold "Username"]
- [:input.rounded.border.px-2.py-1.box-border {:class "border-blue-500 bg-black/25"
- :value (user-handler/email)}]]]
- [:div "Authentication"]
- [:div.col-span-2
- [:div.grid.grid-cols-2.gap-4
- [:div (ui/button (t :logout) {:class "p-1 h-8 justify-center w-full"
- :background "gray"
- :icon "logout"
- :on-click user-handler/logout})]
- [:div (ui/button "Reset password" {:class "p-1 h-8 justify-center w-full"
- :disabled true
- :background "gray"
- :icon "key"
- :on-click user-handler/logout})]
- [:div.col-span-2 (ui/button "Delete Account" {:class "p-1 h-8 justify-center w-full"
- :disabled true
- :background "red"})]]]]
- (not logged-in?)
- [:div.grid.grid-cols-3.gap-8.pt-2
- [:div "Authentication"]
- [:div.col-span-2.flex.flex-wrap.gap-4
- [:div.w-full.text-white "With a Logseq account, you can access cloud-based services like Logseq Sync and alpha/beta features."]
- [:div.flex-1 (ui/button "Sign up" {:class "h-8 w-full text-center justify-center"
- :on-click (fn []
- (state/close-settings!)
- (state/pub-event! [:user/login]))})]
- [:div.flex-1 (ui/button (t :login) {:icon "login"
- :class "h-8 w-full text-center justify-center"
- :background "gray"
- :on-click (fn []
- (state/close-settings!)
- (state/pub-event! [:user/login]))})]]
- [:div.col-span-3.flex.flex-col.gap-4 {:class "bg-black/20 p-4 rounded-lg"}
- [:div.flex.w-full.items-center
- [:div {:class "w-1/2 text-lg"}
- "Discover the power of "
- [:strong {:class "text-white/80"} "Logseq Sync"]]
- [:div {:class "w-1/2 bg-gradient-to-r from-white/10 to-transparent p-3 rounded-lg flex items-center gap-2 px-5 ml-5"}
- [:div.w-3.h-3.rounded-full.bg-green-500]
- "Synced"]]
- [:div.flex.w-full.gap-4
- [:div {:class "w-1/2 bg-black/50 rounded-lg p-4 pt-10 relative flex flex-col gap-4"}
- [:div.absolute.top-0.left-4.bg-gray-700.uppercase.px-2.py-1.rounded-b-lg.font-bold.text-xs "Free"]
- [:div
- [:strong.text-white.text-xl.font-normal "$0"]]
- [:div.text-white.font-bold {:class "h-[2.5rem] "} "Get started with basic syncing"]
- [:ul.text-xs.list-none.m-0.flex.flex-col.gap-0.5
- [:li "Unlimited unsynced graphs"]
- [:li "1 synced graph (up to 50MB, notes only)"]
- [:li "No asset syncing"]
- [:li "Access to core Logseq features"]]]
- [:div {:class "w-1/2 bg-black/50 rounded-lg p-4 pt-10 relative flex flex-col gap-4"}
- [:div.absolute.top-0.left-4.bg-blue-700.uppercase.px-2.py-1.rounded-b-lg.font-bold.text-xs "Pro"]
- [:div
- [:strong.text-white.text-xl.font-normal "$10"]
- [:span.text-xs.font-base {:class "ml-0.5"} "/ month"]]
- [:div.text-white.font-bold {:class "h-[2.5rem]"} "Unlock advanced syncing and more"]
- [:ul.text-xs.list-none.m-0.flex.flex-col.gap-0.5
- [:li "Unlimited unsynced graphs"]
- [:li "10 synced graphs (up to 5GB each)"]
- [:li "Sync assets up to 100MB per file"]
- [:li "Early access to alpha/beta features"]
- [:li "Upcoming cloud-based features, including Logseq Publish"]]]]]])]]))
- (rum/defc settings-features < rum/reactive
- []
- (let [current-repo (state/get-current-repo)
- enable-journals? (state/enable-journals? current-repo)
- enable-flashcards? (state/enable-flashcards? current-repo)
- enable-sync? (state/enable-sync?)
- enable-sync-diff-merge? (state/enable-sync-diff-merge?)
- db-based? (config/db-based-graph? current-repo)
- 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-center
- [: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-not db-based? (whiteboards-switcher-row enable-whiteboards?))
- (when (and (util/electron?) config/feature-plugin-system-on?)
- (plugin-system-switcher-row))
- (when (util/electron?)
- (http-server-switcher-row))
- (when-not db-based? (flashcards-switcher-row enable-flashcards?))
- (when-not db-based? (zotero-settings-row))
- (when (and config/dev? (config/db-based-graph? current-repo))
- ;; FIXME: Wire this up again to RTC init calls
- (rtc-switcher-row (state/enable-rtc? current-repo)))
- (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!)
- (state/pub-event! [:user/login]))})
- [: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-center
- [: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 current-repo enable-sync?)
- (when (and enable-sync? (not (config/db-based-graph? current-repo)))
- (sync-diff-merge-switcher-row enable-sync-diff-merge?))
- [:div.text-sm
- (t :settings-page/sync-desc-1)
- [:a.mx-1 {:href "https://blog.logseq.com/how-to-setup-and-use-logseq-sync/"
- :target "_blank"}
- (t :settings-page/sync-desc-2)]
- (t :settings-page/sync-desc-3)]]])]))
- ;; (when-not web-platform?
- ;; [:<>
- ;; [:hr]
- ;; [:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center
- ;; [: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")}
- ;; ;; features
- ;; ]])
- (def DEFAULT-ACTIVE-TAB-STATE (if config/ENABLE-SETTINGS-ACCOUNT-TAB [:account :account] [:general :general]))
- (rum/defc settings-effect
- < rum/static
- [active]
- (rum/use-effect!
- (fn []
- (let [active (and (sequential? active) (name (first active)))
- ^js ds (.-dataset js/document.body)]
- (if active
- (set! (.-settingsTab ds) active)
- (js-delete ds "settingsTab"))
- #(js-delete ds "settingsTab")))
- [active])
- [:<>])
- (rum/defcs settings-collaboration < rum/reactive
- (rum/local "" ::invite-email)
- {:will-mount (fn [state]
- (rtc-handler/<rtc-get-users-info)
- state)}
- [state]
- (let [*invite-email (::invite-email state)
- current-repo (state/get-current-repo)
- users (get (state/sub :rtc/users-info) current-repo)]
- [:div.panel-wrap.is-collaboration.mb-8
- [:div.flex.flex-col.gap-2.mt-4
- [:h2.opacity-50.font-medium "Members:"]
- [:div.users.flex.flex-col.gap-1
- (for [{user-name :user/name
- user-email :user/email
- graph<->user-user-type :graph<->user/user-type} users]
- [:div.flex.flex-row.items-center.gap-2 {:key (str "user-" user-name)}
- [:div user-name]
- (when user-email [:div.opacity-50.text-sm user-email])
- (when graph<->user-user-type [:div.opacity-50.text-sm (name graph<->user-user-type)])])]
- [:div.flex.flex-col.gap-4.mt-4
- (shui/input
- {:placeholder "Email address"
- :on-change #(reset! *invite-email (util/evalue %))})
- (shui/button
- {:on-click (fn []
- (let [user-email @*invite-email
- graph-uuid (ldb/get-graph-rtc-uuid (db/get-db))]
- (when-not (string/blank? user-email)
- (when graph-uuid
- (rtc-handler/<rtc-invite-email graph-uuid user-email)))))}
- "Invite")]]]))
- (rum/defcs ^:large-vars/cleanup-todo settings
- < (rum/local DEFAULT-ACTIVE-TAB-STATE ::active)
- {:will-mount
- (fn [state]
- (state/load-app-user-cfgs)
- state)
- :did-mount
- (fn [state]
- (let [active-tab (first (:rum/args state))
- *active (::active state)]
- (when (keyword? active-tab)
- (reset! *active [active-tab nil])))
- state)
- :will-unmount
- (fn [state]
- (state/close-settings!)
- state)}
- rum/reactive
- [state _active-tab]
- (let [current-repo (state/sub :git/current-repo)
- _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)
- logged-in? (user-handler/logged-in?)]
- [:div#settings.cp__settings-main
- (settings-effect @*active)
- [:div.cp__settings-inner
- [:aside.md:w-64 {:style {:min-width "10rem"}}
- [:header.cp__settings-header
- [:h1.cp__settings-modal-title (t :settings)]]
- [:ul.settings-menu
- (for [[label id text icon]
- [(when config/ENABLE-SETTINGS-ACCOUNT-TAB
- [:account "account" (t :settings-page/tab-account) (ui/icon "user-circle")])
- [:general "general" (t :settings-page/tab-general) (ui/icon "adjustments")]
- [:editor "editor" (t :settings-page/tab-editor) (ui/icon "writing")]
- [:keymap "keymap" (t :settings-page/tab-keymap) (ui/icon "keyboard")]
- (when (util/electron?)
- [:version-control "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")]
- (when logged-in?
- [:collaboration "collaboration" (t :settings-page/tab-collaboration) (ui/icon "users")])
- (when plugins-of-settings
- [:plugins-setting "plugins" (t :settings-of-plugins) (ui/icon "puzzle")])]]
- (when label
- [:li.settings-menu-item
- {:key text
- :data-id id
- :class (util/classnames [{:active (= label (first @*active))}])
- :on-click (fn []
- (if (= label :plugins-setting)
- (state/pub-event! [:go/plugins-settings (:id (first plugins-of-settings))])
- (reset! *active [label (first @*active)])))}
- [:a.flex.items-center.settings-menu-link icon [:strong text]]]))]]
- [:article
- [:header.cp__settings-header
- [:h1.cp__settings-category-title (t (keyword (str "settings-page/tab-" (name (first @*active)))))]]
- (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)
- :account
- (settings-account)
- :general
- (settings-general current-repo)
- :editor
- (settings-editor current-repo)
- :keymap
- (shortcut/shortcut-keymap-x)
- :version-control
- (settings-git)
- :assets
- (assets/settings-content)
- :advanced
- (settings-advanced)
- :features
- (settings-features)
- :collaboration
- (settings-collaboration)
- nil)]]]))
|