1
0
Эх сурвалжийг харах

Merge pull request #1383 from logseq/feat/ui-tweaks-settings

Feat/UI tweaks of settings
Tienson Qin 4 жил өмнө
parent
commit
78b8b7b1b1

+ 2 - 1
src/main/frontend/components/header.cljs

@@ -9,6 +9,7 @@
             [frontend.storage :as storage]
             [frontend.config :as config]
             [frontend.context.i18n :as i18n]
+            [frontend.handler.ui :as ui-handler]
             [frontend.handler.user :as user-handler]
             [frontend.handler.export :as export]
             [frontend.components.svg :as svg]
@@ -120,7 +121,7 @@
 
        (when current-repo
          {:title (t :settings)
-          :options {:href (rfe/href :settings)}
+          :options {:on-click #(ui-handler/toggle-settings-modal!)}
           :icon svg/settings-sm})
 
        (when current-repo

+ 1 - 0
src/main/frontend/components/onboarding.cljs

@@ -262,6 +262,7 @@
          [:tr [:td (t :help/toggle-doc-mode)] [:td "t d"]]
          [:tr [:td (t :help/toggle-theme)] [:td "t t"]]
          [:tr [:td (t :help/toggle-right-sidebar)] [:td "t r"]]
+         [:tr [:td (t :help/toggle-settings)] [:td "t s"]]
          [:tr [:td (t :help/toggle-insert-new-block)] [:td "t e"]]
          [:tr [:td (t :help/jump-to-journals)] [:td (util/->platform-shortcut "Alt-j")]]]]
        [:table

+ 1 - 1
src/main/frontend/components/page.cljs

@@ -176,7 +176,7 @@
   [state page-name close-fn]
   (let [input (get state ::input)]
     (rum/with-context [[t] i18n/*tongue-context*]
-      [:div
+      [:div.w-full.sm:max-w-lg.sm:w-96
        [:div.sm:flex.sm:items-start
         [:div.mt-3.text-center.sm:mt-0.sm:text-left
          [:h3#modal-headline.text-lg.leading-6.font-medium.text-gray-900

+ 20 - 17
src/main/frontend/components/right_sidebar.cljs

@@ -28,16 +28,16 @@
 (rum/defc block-cp < rum/reactive
   [repo idx block]
   (let [id (:block/uuid block)]
-    (page/page {:parameters {:path {:name (str id)}}
-                :sidebar? true
+    (page/page {:parameters  {:path {:name (str id)}}
+                :sidebar?    true
                 :sidebar/idx idx
-                :repo repo})))
+                :repo        repo})))
 
 (rum/defc page-cp < rum/reactive
   [repo page-name]
   (page/page {:parameters {:path {:name page-name}}
-              :sidebar? true
-              :repo repo}))
+              :sidebar?   true
+              :repo       repo}))
 
 (rum/defc page-graph < db-mixins/query
   [page]
@@ -51,7 +51,7 @@
        (graph-2d/graph
         (graph/build-graph-opts
          graph dark? false
-         {:width 600
+         {:width  600
           :height 600}))])))
 
 (defn recent-pages
@@ -60,8 +60,8 @@
     [:div.recent-pages.text-sm.flex-col.flex.ml-3.mt-2
      (if (seq pages)
        (for [page pages]
-         [:a.mb-1 {:key (str "recent-page-" page)
-                   :href (rfe/href :page {:name page})
+         [:a.mb-1 {:key      (str "recent-page-" page)
+                   :href     (rfe/href :page {:name page})
                    :on-click (fn [e]
                                (when (gobj/get e "shiftKey")
                                  (when-let [page (db/pull [:page/name (string/lower-case page)])]
@@ -87,7 +87,7 @@
                       (util/stop e)
                       (if-not (db/entity [:page/name "contents"])
                         (page-handler/create! "contents")
-                        (route-handler/redirect! {:to :page
+                        (route-handler/redirect! {:to          :page
                                                   :path-params {:name "contents"}})))}
       (t :right-side-bar/contents)]
      (contents)]
@@ -109,7 +109,7 @@
              block-id (:block/uuid block)
              format (:block/format block)]
          [[:div.ml-2.mt-1
-           (block/block-parents {:id "block-parent"
+           (block/block-parents {:id     "block-parent"
                                  :block? true} repo block-id format)]
           [:div.ml-2
            (block-cp repo idx block)]])])
@@ -118,14 +118,14 @@
     (when-let [block (db/entity repo [:block/uuid (:block/uuid block-data)])]
       (let [block-id (:block/uuid block-data)
             format (:block/format block-data)]
-        [(block/block-parents {:id "block-parent"
+        [(block/block-parents {:id     "block-parent"
                                :block? true} repo block-id format)
          [:div.ml-2
           (block-cp repo idx block-data)]]))
 
     :page
     (let [page-name (:page/name block-data)]
-      [[:a {:href (rfe/href :page {:name page-name})
+      [[:a {:href     (rfe/href :page {:name page-name})
             :on-click (fn [e]
                         (when (gobj/get e "shiftKey")
                           (.preventDefault e)))}
@@ -140,11 +140,11 @@
           blocks (if journal?
                    (rest blocks)
                    blocks)
-          sections (block/build-slide-sections blocks {:id "slide-reveal-js"
+          sections (block/build-slide-sections blocks {:id          "slide-reveal-js"
                                                        :start-level 2
-                                                       :slide? true
-                                                       :sidebar? true
-                                                       :page-name page-name})]
+                                                       :slide?      true
+                                                       :sidebar?    true
+                                                       :page-name   page-name})]
       [[:a {:href (rfe/href :page {:name page-name})}
         (db-model/get-page-original-name page-name)]
        [:div.ml-2.slide.mt-2
@@ -229,7 +229,10 @@
                                   :else to-val)]
                      (.setProperty (.-style js/document.documentElement)
                                    "--ls-right-sidebar-width"
-                                   (str (* to-val 100) "%"))))}}))))
+                                   (str (* to-val 100) "%"))))}}))
+             (.styleCursor false)
+             (.on "dragstart" #(.. js/document.documentElement -classList (add "is-resizing-buf")))
+             (.on "dragend" #(.. js/document.documentElement -classList (remove "is-resizing-buf")))))
        #())
      [])
     [:span.resizer {:ref el-ref}]))

+ 225 - 214
src/main/frontend/components/settings.cljs

@@ -27,8 +27,8 @@
        [:div
         [:h1.title.mb-1
          "Your email address:"]
-        [:div.mt-2.mb-4.relative.rounded-md.shadow-sm.max-w-xs
-         [:input#.form-input.block.w-full.pl-2.sm:text-sm.sm:leading-5
+        [:div.mt-2.mb-4.relative.rounded-md.max-w-xs
+         [:input#.form-input.is-small
           {:autoFocus true
            :on-change (fn [e]
                         (reset! email (util/evalue e)))}]]]]
@@ -51,8 +51,8 @@
        [:div
         [:h1.title.mb-1
          "Your cors address:"]
-        [:div.mt-2.mb-4.relative.rounded-md.shadow-sm.max-w-xs
-         [:input#.form-input.block.w-full.pl-2.sm:text-sm.sm:leading-5
+        [:div.mt-2.mb-4.relative.rounded-md.max-w-xs
+         [:input#.form-input.is-small
           {:autoFocus true
            :on-change (fn [e]
                         (reset! cors (util/evalue e)))}]]]]
@@ -68,13 +68,13 @@
 
 (defn toggle
   [label-for name state on-toggle]
-  [:div.mt-6.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start.sm:pt-5
+  [: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.mt-1.sm:mt-0.sm:col-span-2
     [:div.max-w-lg.rounded-md.sm:max-w-xs
-     (ui/toggle state on-toggle)]]])
+     (ui/toggle state on-toggle true)]]])
 
 (rum/defcs app-updater < rum/reactive
   [state]
@@ -119,12 +119,12 @@
       :important
       [:p.text-gray-700 (t :user/delete-account-notice)])
      [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
-      [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
+      [:span.flex.w-full.rounded-md.sm:ml-3.sm:w-auto
        [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
         {:type "button"
          :on-click user-handler/delete-account!}
         (t :user/delete-account)]]
-      [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
+      [:span.mt-3.flex.w-full.rounded-md.sm:mt-0.sm:w-auto
        [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
         {:type "button"
          :on-click close-fn}
@@ -150,219 +150,230 @@
         dark? (= "dark" theme)
         switch-theme (if dark? "white" "dark")]
     (rum/with-context [[t] i18n/*tongue-context*]
-      [:div#settings
+      [:div#settings.cp__settings-main
        [:h1.title (t :settings)]
 
-       [:div.mb-1.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start.sm:pt-5.pl-1
-        [:label.block.text-sm.font-medium.leading-5.sm:mt-px.sm:pt-2.opacity-70
-         {:for "toggle_theme"}
-         (t :right-side-bar/switch-theme (string/capitalize switch-theme))]
-        [:div.flex.flex-row.mt-1.sm:mt-0.sm:col-span-2.pt-2
-         [:div.max-w-lg.rounded-md.sm:max-w-xs
-          (ui/toggle dark?
-                     (fn []
-                       (state/set-theme! switch-theme)))]
-         [:span.ml-4.opacity-50 "t t"]]]
-
-       [:div.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start.sm:pt-5.pl-1
-        [:label.block.text-sm.font-medium.leading-5.opacity-70
-         {:for "show_brackets"}
-         (t :settings-page/show-brackets)]
-        [:div.flex.flex-row.mt-1.sm:mt-0.sm:col-span-2
-         [:div.max-w-lg.rounded-md.sm:max-w-xs
-          (ui/toggle show-brackets?
-                     config-handler/toggle-ui-show-brackets!)]
-         [:span.ml-4.opacity-50 "Ctrl-c Ctrl-b"]]]
-
-       [:div.mb-6.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start.sm:pt-5.pl-1
-        [:label.block.text-sm.font-medium.leading-5.sm:mt-px.sm:pt-2.opacity-70
-         {:for "preferred_language"}
-         (t :language)]
-        [:div.mt-1.sm:mt-0.sm:col-span-2
-         [:div.max-w-lg.rounded-md.shadow-sm.sm:max-w-xs
-          [:select.mt-1.form-select.block.w-full.pl-3.pr-10.py-2.text-base.leading-6.border-gray-300.focus:outline-none.focus:shadow-outline-blue.focus:border-blue-300.sm:text-sm.sm:leading-5
-           {:on-change (fn [e]
-                         (let [lang (util/evalue e)
-                               lang-val (filter (fn [el] (if (= (:label el) lang) true nil)) dicts/languages)
-                               lang-val (name (:value (first lang-val)))]
-                           (state/set-preferred-language! lang-val)
-                           (ui-handler/re-render-root!)))}
-           (for [language dicts/languages]
-             [:option (cond->
-                       {:key (:value language)}
-                        (= (name (:value language)) preferred-language)
-                        (assoc :selected "selected"))
-              (:label language)])]]]]
-
-       [:div.pl-1
-                        ;; config.edn
+       [:div.panel-wrap
+        [: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 "toggle_theme"}
+          (t :right-side-bar/switch-theme (string/capitalize switch-theme))]
+         [:div.flex.flex-row.mt-1.sm:mt-0.sm:col-span-2
+          [:div.max-w-lg.rounded-md.sm:max-w-xs
+           (ui/toggle dark?
+                      (fn []
+                        (state/set-theme! switch-theme))
+                      true)]
+          [:span.ml-4.opacity-50.text-sm "t t"]]]
+
+        [: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.flex.flex-row.mt-1.sm:mt-0.sm:col-span-2
+          [:div.max-w-lg.rounded-md.sm:max-w-xs
+           (ui/toggle show-brackets?
+                      config-handler/toggle-ui-show-brackets!
+                      true)]
+          [:span.ml-4.opacity-50.text-sm "Ctrl-c Ctrl-b"]]]
+
+        [: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_language"}
+          (t :language)]
+         [:div.mt-1.sm:mt-0.sm:col-span-2
+          [:div.max-w-lg.rounded-md
+           [:select.form-select.is-small
+            {:on-change (fn [e]
+                          (let [lang (util/evalue e)
+                                lang-val (filter (fn [el] (if (= (:label el) lang) true nil)) dicts/languages)
+                                lang-val (name (:value (first lang-val)))]
+                            (state/set-preferred-language! lang-val)
+                            (ui-handler/re-render-root!)))}
+            (for [language dicts/languages]
+              [:option (cond->
+                        {:key (:value language)}
+                         (= (name (:value language)) preferred-language)
+                         (assoc :selected "selected"))
+               (:label language)])]]]]
+
+        ;; config.edn
         (when current-repo
-          [:a {:href (rfe/href :file {:path (config/get-config-path)})}
-           (t :settings-page/edit-config-edn)])
-
-        [:hr]
-
-        [:div.mt-6.sm:mt-5
-         [:div.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start.sm:pt-5
-          [:label.block.text-sm.font-medium.leading-5.sm:mt-px.sm:pt-2.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.shadow-sm.sm:max-w-xs
-            [:select.mt-1.form-select.block.w-full.pl-3.pr-10.py-2.text-base.leading-6.border-gray-300.focus:outline-none.focus:shadow-outline-blue.focus:border-blue-300.sm:text-sm.sm:leading-5
-             {:on-change (fn [e]
-                           (let [format (-> (util/evalue e)
-                                            (string/lower-case)
-                                            keyword)]
-                             (user-handler/set-preferred-format! format)))}
-             (for [format [:org :markdown]]
-               [:option (cond->
-                         {:key (name format)}
-                          (= format preferred-format)
-                          (assoc :selected "selected"))
-                (string/capitalize (name format))])]]]]
-         [:div.mt-6.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start.sm:pt-5
-          [:label.block.text-sm.font-medium.leading-5.sm:mt-px.sm:pt-2.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.shadow-sm.sm:max-w-xs
-            [:select.mt-1.form-select.block.w-full.pl-3.pr-10.py-2.text-base.leading-6.border-gray-300.focus:outline-none.focus:shadow-outline-blue.focus:border-blue-300.sm:text-sm.sm:leading-5
-             {:on-change (fn [e]
-                           (let [workflow (-> (util/evalue e)
-                                              (string/lower-case)
-                                              keyword)
-                                 workflow (if (= workflow :now/later)
-                                            :now
-                                            :todo)]
-                             (user-handler/set-preferred-workflow! workflow)
-                             (config-handler/set-preferred-workflow! workflow)))}
-             (for [workflow [:now :todo]]
-               [:option (cond->
-                         {:key (name workflow)}
-                          (= workflow preferred-workflow)
-                          (assoc :selected "selected"))
-                (if (= workflow :now)
-                  "NOW/LATER"
-                  "TODO/DOING")])]]]]
-
-         (toggle "enable_timetracking"
-                 (t :settings-page/enable-timetracking)
-                 enable-timetracking?
-                 (fn []
-                   (let [value (not enable-timetracking?)]
-                     (config-handler/set-config! :feature/enable-timetracking? value))))
-
-                         ;; (toggle "enable_block_time"
-                         ;;         (t :settings-page/enable-block-time)
-                         ;;         enable-block-time?
-                         ;;         (fn []
-                         ;;           (let [value (not enable-block-time?)]
-                         ;;             (config-handler/set-config! :feature/enable-block-time? value))))
-
-         (toggle "enable_journals"
-                 (t :settings-page/enable-journals)
-                 enable-journals?
-                 (fn []
-                   (let [value (not enable-journals?)]
-                     (config-handler/set-config! :feature/enable-journals? value))))
-
-         (when (not enable-journals?)
-           [:div.mt-6.sm:mt-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start.sm:pt-5
-            [:label.block.text-sm.font-medium.leading-5.sm:mt-px.sm:pt-2.opacity-70
-             {:for "default page"}
-             (t :settings-page/home-default-page)]
+          [:div.mt-5.text-sm
+           [:a {:href (rfe/href :file {:path (config/get-config-path)})
+                :on-click #(js/setTimeout (fn [] (ui-handler/toggle-settings-modal!)))}
+            (t :settings-page/edit-config-edn)]])]
+
+       [:hr]
+
+       [:div.panel-wrap
+        [: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
+            {:on-change (fn [e]
+                          (let [format (-> (util/evalue e)
+                                           (string/lower-case)
+                                           keyword)]
+                            (user-handler/set-preferred-format! format)))}
+            (for [format [:org :markdown]]
+              [:option (cond->
+                        {:key (name format)}
+                         (= format preferred-format)
+                         (assoc :selected "selected"))
+               (string/capitalize (name 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_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
+            {:on-change (fn [e]
+                          (let [workflow (-> (util/evalue e)
+                                             (string/lower-case)
+                                             keyword)
+                                workflow (if (= workflow :now/later)
+                                           :now
+                                           :todo)]
+                            (user-handler/set-preferred-workflow! workflow)))}
+            (for [workflow [:now :todo]]
+              [:option (cond->
+                        {:key (name workflow)}
+                         (= workflow preferred-workflow)
+                         (assoc :selected "selected"))
+               (if (= workflow :now)
+                 "NOW/LATER"
+                 "TODO/DOING")])]]]]
+
+        (toggle "enable_timetracking"
+                (t :settings-page/enable-timetracking)
+                enable-timetracking?
+                (fn []
+                  (let [value (not enable-timetracking?)]
+                    (config-handler/set-config! :feature/enable-timetracking? value))))
+
+        ;; (toggle "enable_block_time"
+        ;;         (t :settings-page/enable-block-time)
+        ;;         enable-block-time?
+        ;;         (fn []
+        ;;           (let [value (not enable-block-time?)]
+        ;;             (config-handler/set-config! :feature/enable-block-time? value))))
+
+        (toggle "enable_journals"
+                (t :settings-page/enable-journals)
+                enable-journals?
+                (fn []
+                  (let [value (not enable-journals?)]
+                    (config-handler/set-config! :feature/enable-journals? value))))
+
+        (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       (fn [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))
+
+                                    (page-handler/page-exists? (string/lower-case 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! "Please make sure the page exists!" :warning))))}]]]])
+
+        (toggle "enable_encryption"
+                (t :settings-page/enable-encryption)
+                enable-encryption?
+                (fn []
+                  (let [value (not enable-encryption?)]
+                    (config-handler/set-config! :feature/enable-encryption? value))))
+
+        (when (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)))))]
+
+       [:hr]
+
+       [:div.panel-wrap
+        [:div.it.app-updater.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/current-version)]
+         [:div.wrap.sm:mt-0.sm:col-span-2
+          [:div.ver version]
+          (if (util/electron?) (app-updater))]]
+
+        [: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 "developer_mode"}
+          (t :settings-page/developer-mode)]
+
+         [:div.mt-1.sm:mt-0.sm:col-span-2
+          [:div.max-w-lg.rounded-md.sm:max-w-xs
+           (ui/toggle developer-mode?
+                      #(state/set-developer-mode! (not developer-mode?))
+                      true)]]]
+        [:div.text-sm.opacity-50
+         (t :settings-page/developer-mode-desc)]
+
+        (when logged?
+          [:div
+           [:div.mt-6.sm:mt-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center.sm:pt-5
+            [:label.block.text-sm.font-medium.leading-5.sm:mt-px..opacity-70
+             {:for "cors"}
+             (t :settings-page/custom-cors-proxy-server)]
             [:div.mt-1.sm:mt-0.sm:col-span-2
-             [:div.max-w-lg.rounded-md.shadow-sm.sm:max-w-xs
-              [:input#home-default-page.form-input.block.w-full.transition.duration-150.ease-in-out.sm:text-sm.sm:leading-5
-               {:default-value (state/sub-default-home-page)
+             [:div.max-w-lg.rounded-md.sm:max-w-xs
+              [:input#pat.form-input.is-small.transition.duration-150.ease-in-out
+               {:default-value cors-proxy
                 :on-blur       (fn [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))
-
-                                     (page-handler/page-exists? (string/lower-case 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! "Please make sure the page exists!" :warning))))}]]]])
-
-         (toggle "enable_encryption"
-                 (t :settings-page/enable-encryption)
-                 enable-encryption?
-                 (fn []
-                   (let [value (not enable-encryption?)]
-                     (config-handler/set-config! :feature/enable-encryption? value))))
-
-         (when (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))))) [:hr]
-
-         [:div.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start.sm:pt-5
-          [:label.block.text-sm.font-medium.leading-5.sm:mt-px.sm:pt-2.opacity-70
-           (t :settings-page/current-version)]
-          [:div.mt-1.sm:mt-0.sm:col-span-2
-           [:p version]
-           (if (util/electron?) (app-updater))]]
-
-         [:div.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start.sm:pt-5
-          [:label.block.text-sm.font-medium.leading-5.sm:mt-px.sm:pt-2.opacity-70
-           {:for "developer_mode"}
-           (t :settings-page/developer-mode)]
-          [:div.mt-1.sm:mt-0.sm:col-span-2
-           [:div.max-w-lg.rounded-md.shadow-sm.sm:max-w-xs
-            (ui/button (if developer-mode? (t :settings-page/disable-developer-mode) (t :settings-page/enable-developer-mode))
-                       :on-click #(state/set-developer-mode! (not developer-mode?)))]]]
-
-         [:br]
-         (t :settings-page/developer-mode-desc)
-
-         (when logged?
-           [:div
-            (ui/admonition
+                                 (when-let [server (util/evalue event)]
+                                   (user-handler/set-cors! server)
+                                   (notification/show! "Custom CORS proxy updated successfully!" :success)))
+                :on-key-press  (fn [event]
+                                 (let [k (gobj/get event "key")]
+                                   (if (= "Enter" k)
+                                     (when-let [server (util/evalue event)]
+                                       (user-handler/set-cors! server)
+                                       (notification/show! "Custom CORS proxy updated successfully!" :success)))))}]]]]
+           (ui/admonition
              :important
              [:p (t :settings-page/dont-use-other-peoples-proxy-servers)
               [:a {:href   "https://github.com/isomorphic-git/cors-proxy"
                    :target "_blank"}
                "https://github.com/isomorphic-git/cors-proxy"]])
-            [:div.mt-6.sm:mt-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start.sm:pt-5
-             [:label.block.text-sm.font-medium.leading-5.sm:mt-px.sm:pt-2.opacity-70
-              {:for "cors"}
-              (t :settings-page/custom-cors-proxy-server)]
-             [:div.mt-1.sm:mt-0.sm:col-span-2
-              [:div.max-w-lg.rounded-md.shadow-sm.sm:max-w-xs
-               [:input#pat.form-input.block.w-full.transition.duration-150.ease-in-out.sm:text-sm.sm:leading-5
-                {:default-value cors-proxy
-                 :on-blur       (fn [event]
-                                  (when-let [server (util/evalue event)]
-                                    (user-handler/set-cors! server)
-                                    (notification/show! "Custom CORS proxy updated successfully!" :success)))
-                 :on-key-press  (fn [event]
-                                  (let [k (gobj/get event "key")]
-                                    (if (= "Enter" k)
-                                      (when-let [server (util/evalue event)]
-                                        (user-handler/set-cors! server)
-                                        (notification/show! "Custom CORS proxy updated successfully!" :success)))))}]]]]])
-
-         (when logged?
-           [:div
-            [:hr]
-            [:div.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start.sm:pt-5
-             [:label.block.text-sm.font-medium.leading-5.sm:mt-px.sm:pt-2.opacity-70.text-red-600
-              {:for "delete account"}
-              (t :user/delete-account)]
-             [:div.mt-1.sm:mt-0.sm:col-span-2
-              [:div.max-w-lg.rounded-md.shadow-sm.sm:max-w-xs
-               (ui/button (t :user/delete-your-account)
-                 :on-click #(state/set-modal! delete-account-confirm))]]]])]]])))
+           ])
+
+        (when logged?
+          [:div
+           [:hr]
+           [:div.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center.sm:pt-5
+            [:label.block.text-sm.font-medium.leading-5.opacity-70.text-red-600.dark:text-red-400
+             {:for "delete account"}
+             (t :user/delete-account)]
+            [:div.mt-1.sm:mt-0.sm:col-span-2
+             [:div.max-w-lg.rounded-md.sm:max-w-xs
+              (ui/button (t :user/delete-your-account)
+                         :on-click (fn []
+                                     (ui-handler/toggle-settings-modal!)
+                                     (js/setTimeout #(state/set-modal! delete-account-confirm))))]]]])]])))

+ 66 - 3
src/main/frontend/components/settings.css

@@ -1,13 +1,76 @@
 .cp__settings {
+  &-main {
+    padding: 24px;
+
+    > h1.title {
+      margin-bottom: 2rem;
+    }
+
+    hr {
+      margin: 1rem 0;
+      opacity: .5;
+    }
+
+    .panel-wrap {
+      padding: 0 12px;
+
+      > .it {
+        margin-bottom: 0;
+        padding-bottom: 20px;
+        align-items: center;
+
+        label {
+          display: flex;
+          align-items: center;
+
+          & + div {
+            display: flex;
+            align-items: center;
+            min-height: 24px;
+            user-select: none;
+
+            .max-w-lg {
+              width: 100%;
+            }
+          }
+        }
+
+        &.app-updater {
+          padding-top: 15px;
+          align-items: start;
+
+          > .wrap {
+            display: block;
+
+            .ver {
+              position: relative;
+              top: -2px;
+            }
+          }
+        }
+
+        .form-select, .form-input {
+          width: 68%;
+        }
+      }
+    }
+
+    .admonitionblock {
+      p {
+        @apply text-sm;
+      }
+    }
+  }
+
   &-app-updater {
     min-height: 20px;
     position: relative;
-    margin-bottom: -10px;
+    margin-bottom: -5px;
 
     button.check-update {
       position: absolute;
       right: 0;
-      top: -45px;
+      top: -42px;
 
       &:disabled {
         cursor: progress;
@@ -41,4 +104,4 @@
       }
     }
   }
-}
+}

+ 19 - 1
src/main/frontend/components/sidebar.cljs

@@ -17,6 +17,7 @@
             [frontend.storage :as storage]
             [frontend.util :as util]
             [frontend.state :as state]
+            [frontend.handler.ui :as ui-handler]
             [frontend.handler.user :as user-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.route :as route-handler]
@@ -243,6 +244,21 @@
                     (state/sidebar-add-block! (state/get-current-repo) "help" :help nil))}
        "?"])))
 
+(rum/defc settings-modal
+  [settings-open?]
+  (rum/use-effect!
+   (fn []
+     (if settings-open?
+       (state/set-modal!
+        (fn [close-fn]
+          (gobj/set close-fn "user-close" #(ui-handler/toggle-settings-modal!))
+          [:div.settings-modal (settings/settings)]))
+       (state/set-modal! nil))
+
+     (util/lock-global-scroll settings-open?)
+     #())
+   [settings-open?]) nil)
+
 (rum/defcs sidebar <
   (mixins/modal :modal/show?)
   rum/reactive
@@ -290,7 +306,8 @@
         granted? (state/sub [:nfs/user-granted? (state/get-current-repo)])
         theme (state/sub :ui/theme)
         white? (= "white" (state/sub :ui/theme))
-        sidebar-open? (state/sub :ui/sidebar-open?)
+        settings-open? (state/sub :ui/settings-open?)
+        sidebar-open?  (state/sub :ui/sidebar-open?)
         route-name (get-in route-match [:data :name])
         global-graph-pages? (= :graph route-name)
         logged? (:name me)
@@ -337,6 +354,7 @@
 
         (ui/notification)
         (ui/modal)
+        (settings-modal settings-open?)
         (custom-context-menu)
         [:a#download.hidden]
         (when

+ 15 - 1
src/main/frontend/components/sidebar.css

@@ -52,6 +52,19 @@
   }
 }
 
+.settings-modal {
+  background-color: var(--ls-primary-background-color);
+
+  max-height: 80vh;
+  overflow: auto;
+  margin: -25px;
+  padding: 20px;
+
+  @screen sm {
+    width: 768px;
+  }
+}
+
 .cp__sidebar-layout {
   display: flex;
   flex-direction: column;
@@ -139,6 +152,8 @@
   &-inner {
     padding: 15px;
     padding-top: 0;
+    position: relative;
+    min-height: 100%;
 
     .resizer {
       position: absolute;
@@ -173,7 +188,6 @@
     display: block;
     width: var(--ls-right-sidebar-width);
     opacity: 1;
-    transition: width 0.2s;
   }
 
   .page {

+ 15 - 5
src/main/frontend/components/theme.css

@@ -44,14 +44,14 @@ html {
 }
 
 .form-checkbox {
-    color: var(--ls-page-checkbox-color, #6093a0);
-    background-color: var(--ls-page-checkbox-color, #6093a0);
-    border-color: var(--ls-page-checkbox-border-color, #6093a0);
-    border: none;
+  color: var(--ls-page-checkbox-color, #6093a0);
+  background-color: var(--ls-page-checkbox-color, #6093a0);
+  border-color: var(--ls-page-checkbox-border-color, #6093a0);
+  border: none;
 }
 
 .form-checkbox:hover {
-    transform: scale(1.1);
+  transform: scale(1.1);
 }
 
 html[data-theme=dark] {
@@ -205,3 +205,13 @@ html.is-electron {
     }
   }
 }
+
+html.locked-scroll {
+  overflow: hidden !important;
+}
+
+html.is-resizing-buf {
+  #right-sidebar {
+    transition: none;
+  }
+}

+ 2 - 0
src/main/frontend/dicts.cljs

@@ -160,6 +160,7 @@ title: How to take dummy notes?
         :help/toggle-contents "Toggle Contents"
         :help/toggle-theme "Toggle between dark/light theme"
         :help/toggle-right-sidebar "Toggle right sidebar"
+        :help/toggle-settings "Toggle settings"
         :help/toggle-insert-new-block "Toggle Enter/Alt+Enter for inserting new block"
         :help/jump-to-journals "Jump to Journals"
         :formatting "Formatting"
@@ -886,6 +887,7 @@ title: How to take dummy notes?
            :help/toggle-contents "打开/关闭目录"
            :help/toggle-theme "“在暗色/亮色主题之间切换”"
            :help/toggle-right-sidebar "启用/关闭右侧栏"
+           :help/toggle-settings "显示/关闭设置"
            :help/toggle-insert-new-block "切换 Enter/Alt+Enter 以插入新块"
            :help/jump-to-journals "跳转到日记"
            :formatting "格式化"

+ 4 - 0
src/main/frontend/handler/ui.cljs

@@ -33,6 +33,10 @@
         (state/sidebar-remove-block! id)
         (state/sidebar-add-block! current-repo id :contents nil)))))
 
+(defn toggle-settings-modal!
+  []
+  (state/toggle-settings!))
+
 ;; FIXME: re-render all embedded blocks since they will not be re-rendered automatically
 
 

+ 51 - 49
src/main/frontend/keyboards.cljs

@@ -30,66 +30,68 @@
   [f]
   (fn [e]
     (when-not (state/editing?)
-      (f e))))
+      (f e))
+    true))
 
 (def shortcut state/get-shortcut)
 
 (def re-index! #(repo-handler/re-index! nfs-handler/rebuild-index!))
 
 (defonce chords
-  {
-   ;; non-editing mode
-   (or (shortcut :editor/toggle-document-mode) "t d")
-   (enable-when-not-editing-mode! state/toggle-document-mode!)
-   (or (shortcut :ui/toggle-theme) "t t")
-   (enable-when-not-editing-mode! state/toggle-theme!)
-   (or (shortcut :ui/toggle-right-sidebar) "t r")
-   (enable-when-not-editing-mode! ui-handler/toggle-right-sidebar!)
-   (or (shortcut :ui/toggle-new-block) "t e")
-   (enable-when-not-editing-mode! state/toggle-new-block-shortcut!)
-   (or (shortcut :ui/show-contents) "t c")
-   [(enable-when-not-editing-mode! ui-handler/toggle-contents!) true]
-   (or (shortcut :ui/toggle-between-page-and-file) "s")
-   (enable-when-not-editing-mode! route-handler/toggle-between-page-and-file!)
-   (or (shortcut :git/commit) "c")
-   (enable-when-not-editing-mode! (git-handler/show-commit-modal! commit/add-commit-message))
-   "tab" (-> (editor-handler/on-tab :right)
-             enable-when-not-editing-mode!)
-   "shift+tab" (-> (editor-handler/on-tab :left)
-                   enable-when-not-editing-mode!)
+  (-> {;; non-editing mode
+       (or (shortcut :editor/toggle-document-mode) "t d")
+       (enable-when-not-editing-mode! state/toggle-document-mode!)
+       (or (shortcut :ui/toggle-theme) "t t")
+       (enable-when-not-editing-mode! state/toggle-theme!)
+       (or (shortcut :ui/toggle-right-sidebar) "t r")
+       (enable-when-not-editing-mode! ui-handler/toggle-right-sidebar!)
+       (or (shortcut :ui/toggle-new-block) "t e")
+       (enable-when-not-editing-mode! state/toggle-new-block-shortcut!)
+       (or (shortcut :ui/show-contents) "t c")
+       (enable-when-not-editing-mode! ui-handler/toggle-contents!)
+       (or (shortcut :editor/toggle-settings) "t s")
+       (enable-when-not-editing-mode! ui-handler/toggle-settings-modal!)
+       (or (shortcut :ui/toggle-between-page-and-file) "s")
+       (enable-when-not-editing-mode! route-handler/toggle-between-page-and-file!)
+       (or (shortcut :git/commit) "c")
+       (enable-when-not-editing-mode! (git-handler/show-commit-modal! commit/add-commit-message))
+       "tab" (-> (editor-handler/on-tab :right)
+                 enable-when-not-editing-mode!)
+       "shift+tab" (-> (editor-handler/on-tab :left)
+                       enable-when-not-editing-mode!)
 
-   (or (shortcut :editor/undo) "mod+z") [history-handler/undo! true]
-   (or (shortcut :editor/redo) "mod+y") [history-handler/redo! true]
-   (or (shortcut :editor/redo) "mod+shift+z") [history-handler/redo! true]
-   (or (shortcut :go/search) "mod+u") [route-handler/go-to-search! true]
-   (or (shortcut :go/journals) (if util/mac? "mod+j" "alt+j")) [route-handler/go-to-journals! true]
-   (or (shortcut :editor/zoom-in)
-       (if util/mac? "mod+." "alt+right")) [editor-handler/zoom-in! true]
-   (or (shortcut :editor/zoom-out)
-       (if util/mac? "mod+," "alt+left")) [editor-handler/zoom-out! true]
-   (or (shortcut :editor/cycle-todo)
-       "mod+enter") [editor-handler/cycle-todo! true]
-   (or (shortcut :editor/expand-block-children) "mod+down") [editor-handler/expand! true]
-   (or (shortcut :editor/collapse-block-children) "mod+up") [editor-handler/collapse! true]
-   (or (shortcut :editor/follow-link) "mod+o") [editor-handler/follow-link-under-cursor! true]
-   (or (shortcut :editor/open-link-in-sidebar) "mod+shift+o") [editor-handler/open-link-in-sidebar! true]
-   (or (shortcut :editor/bold) "mod+b") [editor-handler/bold-format! true]
-   (or (shortcut :editor/italics) "mod+i") [editor-handler/italics-format! true]
-   (or (shortcut :editor/highlight) "mod+h") [editor-handler/highlight-format! true]
-   (or (shortcut :editor/insert-link) "mod+k") [editor-handler/html-link-format! true]
-   (or (shortcut :editor/select-all-blocks) "mod+shift+a") [editor-handler/select-all-blocks! true]
-   (or (shortcut :editor/move-block-up) (if util/mac? "mod+shift+up" "alt+shift+up")) [(fn [state e] (editor-handler/move-up-down e true)) true]
-   (or (shortcut :editor/move-block-down) (if util/mac? "mod+shift+down" "alt+shift+down")) [(fn [state e] (editor-handler/move-up-down e false)) true]
-   (or (shortcut :editor/save) "mod+s") [editor-handler/save! true]
+       (or (shortcut :editor/undo) "mod+z") [history-handler/undo! true]
+       (or (shortcut :editor/redo) "mod+y") [history-handler/redo! true]
+       (or (shortcut :editor/redo) "mod+shift+z") [history-handler/redo! true]
+       (or (shortcut :go/search) "mod+u") [route-handler/go-to-search! true]
+       (or (shortcut :go/journals) (if util/mac? "mod+j" "alt+j")) [route-handler/go-to-journals! true]
+       (or (shortcut :editor/zoom-in) (if util/mac? "mod+." "alt+right")) [editor-handler/zoom-in! true]
+       (or (shortcut :editor/zoom-out) (if util/mac? "mod+," "alt+left")) [editor-handler/zoom-out! true]
+       (or (shortcut :editor/cycle-todo) "mod+enter") [editor-handler/cycle-todo! true]
+       (or (shortcut :editor/expand-block-children) "mod+down") [editor-handler/expand! true]
+       (or (shortcut :editor/collapse-block-children) "mod+up") [editor-handler/collapse! true]
+       (or (shortcut :editor/follow-link) "mod+o") [editor-handler/follow-link-under-cursor! true]
+       (or (shortcut :editor/open-link-in-sidebar) "mod+shift+o") [editor-handler/open-link-in-sidebar! true]
+       (or (shortcut :editor/bold) "mod+b") [editor-handler/bold-format! true]
+       (or (shortcut :editor/italics) "mod+i") [editor-handler/italics-format! true]
+       (or (shortcut :editor/highlight) "mod+h") [editor-handler/highlight-format! true]
+       (or (shortcut :editor/insert-link) "mod+k") [editor-handler/html-link-format! true]
+       (or (shortcut :editor/select-all-blocks) "mod+shift+a") [editor-handler/select-all-blocks! true]
+       (or (shortcut :editor/move-block-up) (if util/mac? "mod+shift+up" "alt+shift+up")) [(fn [state e] (editor-handler/move-up-down e true)) true]
+       (or (shortcut :editor/move-block-down) (if util/mac? "mod+shift+down" "alt+shift+down")) [(fn [state e] (editor-handler/move-up-down e false)) true]
+       (or (shortcut :editor/save) "mod+s") [editor-handler/save! true]
 
-   (or (shortcut :editor/next) "down") (fn [state e] (editor-handler/open-block! true))
-   (or (shortcut :editor/prev) "up") (fn [state e] (editor-handler/open-block! false))
+       (or (shortcut :editor/next) "down") (fn [state e] (editor-handler/open-block! true))
+       (or (shortcut :editor/prev) "up") (fn [state e] (editor-handler/open-block! false))
 
-   (or (shortcut :search/re-index) "mod+c mod+s") [search-handler/rebuild-indices! true]
+       (or (shortcut :search/re-index) "mod+c mod+s") [search-handler/rebuild-indices! true]
 
-   (or (shortcut :graph/re-index) "mod+c mod+r") [re-index! true]
+       (or (shortcut :graph/re-index) "mod+c mod+r") [re-index! true]
 
-   (or (shortcut :ui/toggle-brackets) "mod+c mod+b") [config-handler/toggle-ui-show-brackets! true]})
+       (or (shortcut :ui/toggle-brackets) "mod+c mod+b") [config-handler/toggle-ui-show-brackets! true]}
+      (merge
+       (when-not util/mac?
+         {"mod+," [#(ui-handler/toggle-settings-modal!) true]}))))
 
 (defonce bind! (gobj/get mousetrap "bind"))
 

+ 7 - 6
src/main/frontend/mixins.cljs

@@ -52,15 +52,16 @@
 ;;      (dissoc state name))})
 
 (defn hide-when-esc-or-outside
-  [state & {:keys [on-hide node visibilitychange?]}]
+  [state & {:keys [on-hide node visibilitychange? outside?]}]
   (try
     (let [dom-node (rum/dom-node state)]
       (when-let [dom-node (or node dom-node)]
-        (listen state js/window "mousedown"
-                (fn [e]
-                 ;; If the click target is outside of current node
-                  (when-not (dom/contains dom-node (.. e -target))
-                    (on-hide state e :click))))
+        (or (false? outside?)
+            (listen state js/window "mousedown"
+                    (fn [e]
+                      ;; If the click target is outside of current node
+                      (when-not (dom/contains dom-node (.. e -target))
+                        (on-hide state e :click)))))
         (listen state js/window "keydown"
                 (fn [e]
                   (case (.-keyCode e)

+ 13 - 1
src/main/frontend/state.cljs

@@ -46,7 +46,11 @@
     ;; custom shortcuts
     :shortcuts {:editor/new-block "enter"}
 
+    ;; modals
+    :modal/show? false
+
     ;; right sidebar
+    :ui/settings-open? false
     :ui/sidebar-open? false
     :ui/left-sidebar-open? false
     :ui/theme (or (storage/get :ui/theme) "dark")
@@ -897,7 +901,7 @@
 (defn set-modal!
   [modal-panel-content]
   (swap! state assoc
-         :modal/show? true
+         :modal/show? (boolean modal-panel-content)
          :modal/panel-content modal-panel-content))
 
 (defn close-modal!
@@ -1105,6 +1109,14 @@
   []
   (set-search-result! nil))
 
+(defn toggle!
+  [path]
+  (update-state! path not))
+
+(defn toggle-settings!
+  []
+  (toggle! :ui/settings-open?))
+
 ;; TODO: Move those to the uni `state`
 
 (defonce editor-op (atom nil))

+ 27 - 17
src/main/frontend/ui.cljs

@@ -388,14 +388,16 @@
 (def datepicker frontend.ui.date-picker/date-picker)
 
 (defn toggle
-  [on? on-click]
-  [:a {:on-click on-click}
-   [:span.relative.inline-block.flex-shrink-0.h-6.w-11.border-2.border-transparent.rounded-full.cursor-pointer.transition-colors.ease-in-out.duration-200.focus:outline-none.focus:shadow-outline
-    {:aria-checked "false", :tab-index "0", :role "checkbox"
-     :class        (if on? "bg-indigo-600" "bg-gray-200")}
-    [:span.inline-block.h-5.w-5.rounded-full.bg-white.shadow.transform.transition.ease-in-out.duration-200
-     {:class       (if on? "translate-x-5" "translate-x-0")
-      :aria-hidden "true"}]]])
+  ([on? on-click] (toggle on? on-click false))
+  ([on? on-click small?]
+   [:a.ui__toggle {:on-click on-click
+                   :class (if small? "is-small" "")}
+    [:span.wrapper.transition-colors.ease-in-out.duration-200
+     {:aria-checked "false", :tab-index "0", :role "checkbox"
+      :class        (if on? "bg-indigo-600" "bg-gray-200")}
+     [:span.switcher.transform.transition.ease-in-out.duration-200
+      {:class       (if on? (if small? "translate-x-4" "translate-x-5") "translate-x-0")
+       :aria-hidden "true"}]]]))
 
 (defn tooltip
   ([label children]
@@ -412,27 +414,27 @@
 (defonce modal-show? (atom false))
 (rum/defc modal-overlay
   [state]
-  [:div.fixed.inset-0.transition-opacity
+  [:div.ui__modal-overlay
    {:class (case state
              "entering" "ease-out duration-300 opacity-0"
              "entered" "ease-out duration-300 opacity-100"
              "exiting" "ease-in duration-200 opacity-100"
              "exited" "ease-in duration-200 opacity-0")}
-   [:div.absolute.inset-0.bg-gray-500.opacity-75]])
+   [:div.absolute.inset-0.opacity-75]])
 
 (rum/defc modal-panel
-  [panel-content state close-fn]
-  [:div.relative.bg-white.rounded-lg.px-4.pt-5.pb-4.overflow-hidden.shadow-xl.transform.transition-all.sm:max-w-lg.sm:w-full.sm:p-6
-   {:class (case state
+  [panel-content transition-state close-fn]
+  [:div.ui__modal-panel.transform.transition-all.sm:min-w-lg.sm.p-6
+   {:class (case transition-state
              "entering" "ease-out duration-300 opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
              "entered" "ease-out duration-300 opacity-100 translate-y-0 sm:scale-100"
              "exiting" "ease-in duration-200 opacity-100 translate-y-0 sm:scale-100"
              "exited" "ease-in duration-200 opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95")}
-   [:div.absolute.top-0.right-0.pt-4.pr-4
-    [:button.text-gray-400.hover:text-gray-500.focus:outline-none.focus:text-gray-500.transition.ease-in-out.duration-150
+   [:div.absolute.top-0.right-0.pt-2.pr-2
+    [:button.ui__modal-close
      {:aria-label "Close"
       :type       "button"
-      :on-click   close-fn}
+      :on-click   (fn [] (apply (or (gobj/get close-fn "user-close") close-fn) []))}
      [:svg.h-6.w-6
       {:stroke "currentColor", :view-box "0 0 24 24", :fill "none"}
       [:path
@@ -444,12 +446,20 @@
    (panel-content close-fn)])
 
 (rum/defc modal < rum/reactive
+  (mixins/event-mixin
+   (fn [state]
+     (mixins/hide-when-esc-or-outside
+      state
+      :on-hide (fn []
+                 (-> (.querySelector (rum/dom-node state) "button.ui__modal-close")
+                     (.click)))
+      :outside? false)))
   []
   (let [modal-panel-content (state/sub :modal/panel-content)
         show? (boolean modal-panel-content)
         close-fn #(state/close-modal!)
         modal-panel-content (or modal-panel-content (fn [close] [:div]))]
-    [:div.fixed.bottom-0.inset-x-0.px-4.pb-4.sm:inset-0.sm:flex.sm:items-center.sm:justify-center
+    [:div.ui__modal
      {:style {:z-index (if show? 10 -1)}}
      (css-transition
       {:in show? :timeout 0}

+ 61 - 0
src/main/frontend/ui.css

@@ -30,6 +30,53 @@
   }
 }
 
+.ui__toggle {
+  .wrapper {
+    @apply relative inline-block flex-shrink-0
+    h-6 w-11 border-2 border-transparent flex
+    rounded-full cursor-pointer focus:outline-none focus:shadow-outline;
+  }
+
+  .switcher {
+    @apply inline-block h-5 w-5 rounded-full bg-white shadow;
+  }
+
+  &.is-small {
+    .wrapper {
+      @apply h-4 w-8;
+    }
+
+    .switcher {
+      @apply h-3 w-3;
+    }
+  }
+}
+
+.ui__modal {
+  @apply fixed bottom-0 inset-x-0
+  sm:inset-0 sm:flex sm:items-center sm:justify-center
+  px-4 pb-4;
+
+  &-overlay {
+    @apply fixed inset-0 transition-opacity;
+  }
+
+  &-overlay div {
+    background: var(--ls-quaternary-background-color);
+  }
+
+  &-panel {
+    @apply relative bg-white rounded-md px-4 pt-5
+    pb-4 shadow-xl;
+  }
+
+  &-close {
+    @apply text-gray-400 hover:text-gray-500
+    focus:outline-none focus:text-gray-500
+    transition ease-in-out duration-150;
+  }
+}
+
 .ui__confirm-modal {
   .sublabel {
     display: flex;
@@ -83,17 +130,31 @@
 }
 
 .form-select {
+  @apply block w-full pl-3 pr-10 py-2 text-base leading-6
+  border-gray-300 focus:outline-none focus:shadow-outline-blue sm:text-sm sm:leading-5;
+
   background-color: var(--ls-primary-background-color, transparent);
   background-repeat: no-repeat;
   border-width: 1px;
   border-color: var(--ls-border-color);
+
+  &.is-small {
+    @apply pl-2 py-1.5 sm:leading-4 sm:text-xs;
+  }
 }
 
 .form-input {
+  @apply block w-full pl-2
+  sm:text-sm sm:leading-5;
+
   border-width: 1px;
   border-color: var(--ls-border-color);
 
   &:focus {
     box-shadow: 0 0 0 2px rgba(164, 202, 254, 0.45);
   }
+
+  &.is-small {
+    @apply py-1.5 sm:leading-4 sm:text-xs;
+  }
 }

+ 9 - 2
src/main/frontend/util.cljc

@@ -375,8 +375,15 @@
 (def moving-frequency 15)
 
 #?(:cljs
-    (defn cur-doc-top []
-      (.. js/document -documentElement -scrollTop)))
+   (defn cur-doc-top []
+     (.. js/document -documentElement -scrollTop)))
+
+#?(:cljs
+   (defn lock-global-scroll
+     ([] (lock-global-scroll true))
+     ([v] (js-invoke (.-classList (app-scroll-container-node))
+                     (if v "add" "remove")
+                     "locked-scroll"))))
 
 #?(:cljs
     (defn element-top [elem top]

+ 27 - 0
tailwind.config.js

@@ -1,3 +1,5 @@
+const colors = require('tailwindcss/colors')
+
 module.exports = {
   purge: [
     './src/**/*.js',
@@ -6,4 +8,29 @@ module.exports = {
   ],
   plugins: [require('@tailwindcss/ui')],
   darkMode: 'class',
+  theme: {
+    colors: {
+      transparent: 'transparent',
+      current: 'currentColor',
+      black: colors.black,
+      white: colors.white,
+      gray: colors.trueGray,
+      indigo: {
+        50: '#f0f9ff',
+        100: '#e0f2fe',
+        200: '#bae6fd',
+        300: '#7dd3fc',
+        400: '#38bdf8',
+        500: '#0ea5e9',
+        600: '#0284c7',
+        700: '#005b8a',
+        800: '#075985',
+        900: '#0c4a6e',
+      },
+      red: colors.rose,
+      yellow: colors.amber,
+      orange: colors.orange,
+      rose: colors.rose
+    }
+  }
 }