mirror of
https://github.com/logseq/logseq.git
synced 2026-06-01 19:01:22 +00:00
cmdk2 updates
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -20,11 +20,14 @@
|
||||
[frontend.util :as util]
|
||||
[frontend.util.page :as page-util]
|
||||
[goog.functions :as gfun]
|
||||
[logseq.shui.context :refer [make-context]]
|
||||
[frontend.shui :refer [make-shui-context]]
|
||||
[logseq.shui.core :as shui]
|
||||
[promesa.core :as p]
|
||||
[rum.core :as rum]))
|
||||
|
||||
(def GROUP-LIMIT 5)
|
||||
(def FILTER-ROW-HEIGHT 73)
|
||||
|
||||
;; When CMDK opens, we have some default search actions we make avaialbe for quick access
|
||||
(def default-search-actions
|
||||
[{:text "Search only pages" :info "Add filter to search" :icon-theme :gray :icon "page" :filter {:group :pages}}
|
||||
@@ -36,13 +39,16 @@
|
||||
; {:text "Generate short answer" :info "Ask a language model" :icon "question-mark" :icon-theme :gradient}
|
||||
|
||||
(def default-commands
|
||||
[{:text "Open settings" :icon "settings" :icon-theme :gray}])
|
||||
[{:text "Open settings" :icon "settings" :icon-theme :gray}
|
||||
{:text "Open settings" :icon "settings" :icon-theme :gray}
|
||||
{:text "Open settings" :icon "settings" :icon-theme :gray}])
|
||||
|
||||
;; The results are separated into groups, and loaded/fetched/queried separately
|
||||
(def default-results
|
||||
{:search-actions {:status :success :show-more false :items default-search-actions}
|
||||
:commands {:status :success :show-more false :items default-commands}
|
||||
:history {:status :success :show-more false :items nil}
|
||||
{:search-actions {:status :success :show-more false :items nil}
|
||||
:recents {:status :success :show-more false :items nil}
|
||||
:commands {:status :success :show-more false :items nil}
|
||||
:favorites {:status :success :show-more false :items nil}
|
||||
:current-page {:status :success :show-more false :items nil}
|
||||
:pages {:status :success :show-more false :items nil}
|
||||
:blocks {:status :success :show-more false :items nil}
|
||||
@@ -51,18 +57,20 @@
|
||||
;; Take the results, decide how many items to show, and order the results appropriately
|
||||
(defn state->results-ordered [state]
|
||||
(let [results @(::results state)
|
||||
index (volatile! -1)
|
||||
visible-items (fn [group]
|
||||
(let [{:keys [items show-more]} (get results group)]
|
||||
(if show-more items (take 5 items))))
|
||||
results [["Search actions" :search-actions (visible-items :search-actions)]
|
||||
results [["Recents" :recents (visible-items :recents)]
|
||||
["Search actions" :search-actions (visible-items :search-actions)]
|
||||
["Current page" :current-page (visible-items :current-page)]
|
||||
["Commands" :commands (visible-items :commands)]
|
||||
["Pages" :pages (visible-items :pages)]
|
||||
["Whiteboards" :whiteboards (visible-items :whiteboards)]
|
||||
["Blocks" :blocks (visible-items :blocks)]]]
|
||||
results))
|
||||
; (for [[group-name group-key group-items] results]
|
||||
; [group-name group-key (mapv #(assoc % :item-index (vswap! index inc)) group-items)])))
|
||||
; results
|
||||
(for [[group-name group-key group-items] results]
|
||||
[group-name group-key (mapv #(assoc % :item-index (vswap! index inc)) group-items)])))
|
||||
|
||||
;; Take the ordered results and the highlight index and determine which item is highlighted
|
||||
; (defn state->highlighted-item
|
||||
@@ -81,6 +89,30 @@
|
||||
;; Each result gorup has it's own load-results function
|
||||
(defmulti load-results (fn [group state] group))
|
||||
|
||||
;; Initially we want to load the recents into the results
|
||||
(defmethod load-results :initial [_ state]
|
||||
(let [!results (::results state)
|
||||
recent-searches (mapv (fn [q] {:type :search :data q}) (db/get-key-value :recent/search))
|
||||
recent-pages (mapv (fn [page] {:type :page :data page}) (db/get-key-value :recent/pages))
|
||||
recent-items (->> (concat recent-searches recent-pages)
|
||||
(map #(hash-map :icon (if (= :page (:type %)) "page" "history")
|
||||
:icon-theme :gray
|
||||
:text (:data %)
|
||||
:source-recent %)))
|
||||
command-items (->> (cp-handler/top-commands 1000)
|
||||
(map #(hash-map :icon "command"
|
||||
:icon-theme :gray
|
||||
:text (cp/translate t %)
|
||||
:value-label (pr-str (:id %))
|
||||
:shortcut (:shortcut %)
|
||||
:source-command %)))
|
||||
favorite-pages nil
|
||||
favorite-items nil]
|
||||
(reset! !results (-> default-results (assoc-in [:recents :items] recent-items)
|
||||
(assoc-in [:commands :items] command-items)
|
||||
(assoc-in [:favorites :items] favorite-items)))))
|
||||
|
||||
|
||||
;; The search-actions are only loaded when there is no query present. It's like a quick access to filters
|
||||
(defmethod load-results :search-actions [group state]
|
||||
(let [!input (::input state)
|
||||
@@ -96,7 +128,8 @@
|
||||
(swap! !results assoc-in [group :status] :loading)
|
||||
(if (empty? @!input)
|
||||
(swap! !results assoc group {:status :success :items default-commands})
|
||||
(->> (vals (cp-handler/get-commands-unique))
|
||||
(->> (cp-handler/top-commands 1000)
|
||||
(map #(assoc % :t (cp/translate t %)))
|
||||
(filter #(string/includes? (string/lower-case (pr-str %)) (string/lower-case @!input)))
|
||||
(map #(hash-map :icon "command"
|
||||
:icon-theme :gray
|
||||
@@ -176,15 +209,37 @@
|
||||
(p/let [files (search/file-search @!input 99)]
|
||||
(js/console.log "load-results/files" (clj->js files)))))
|
||||
|
||||
(defmethod load-results :recents [group state]
|
||||
(let [!input (::input state)
|
||||
!results (::results state)
|
||||
recent-searches (mapv (fn [q] {:type :search :data q}) (db/get-key-value :recent/search))
|
||||
recent-pages (mapv (fn [page] {:type :page :data page}) (db/get-key-value :recent/pages))]
|
||||
(js/console.log "recents" (clj->js recent-searches) (clj->js recent-pages))
|
||||
(swap! !results assoc-in [group :status] :loading)
|
||||
(let [items (->> (concat recent-searches recent-pages)
|
||||
(filter #(string/includes? (string/lower-case (:data %)) (string/lower-case @!input)))
|
||||
(map #(hash-map :icon (if (= :page (:type %)) "page" "history")
|
||||
:icon-theme :gray
|
||||
; :header (when-let [page-name])
|
||||
:text (:data %)
|
||||
:source-recent %)))]
|
||||
(swap! !results assoc group {:status :success :items items}))))
|
||||
|
||||
; (swap! !results assoc group {:status :success :items recent-items})))
|
||||
|
||||
;; The default load-results function triggers all the other load-results function
|
||||
(defmethod load-results :default [_ state]
|
||||
(js/console.log "load-results/default" @(::input state))
|
||||
(load-results :search-actions state)
|
||||
(load-results :commands state)
|
||||
(load-results :blocks state)
|
||||
(load-results :pages state)
|
||||
; (load-results :whiteboards state)
|
||||
(load-results :files state))
|
||||
(if-not (some-> state ::input deref seq)
|
||||
(load-results :initial state)
|
||||
(do
|
||||
(load-results :search-actions state)
|
||||
(load-results :commands state)
|
||||
(load-results :blocks state)
|
||||
(load-results :pages state)
|
||||
; (load-results :whiteboards state)
|
||||
(load-results :files state)
|
||||
(load-results :recents state))))
|
||||
|
||||
; (def search [query]
|
||||
; (load-results :search-actions state))
|
||||
@@ -263,10 +318,10 @@
|
||||
(js/console.log
|
||||
"testing-capping-the-highlighted-item"
|
||||
(count items)
|
||||
(clj->js (drop 5 items))
|
||||
(clj->js (drop GROUP-LIMIT items))
|
||||
(clj->js highlighted-item)
|
||||
(.indexOf items highlighted-item))
|
||||
(when (< 4 (.indexOf items highlighted-item))
|
||||
(when (< (dec GROUP-LIMIT) (.indexOf items highlighted-item))
|
||||
(reset! (::highlighted-item state) (nth items 4 nil))))]
|
||||
[:div {:class ""}
|
||||
[:div {:class "text-xs py-1.5 px-6 flex justify-between items-center gap-2"
|
||||
@@ -280,14 +335,16 @@
|
||||
(str "99+")
|
||||
(count items))]
|
||||
[:div {:class "flex-1"}]
|
||||
(if show-more
|
||||
[:div {:on-click (fn [] (cap-highlighted-item) (toggle-show-more))} "Show less"]
|
||||
[:div {:on-click (fn [] (toggle-show-more))} "Show more"])]
|
||||
(cond
|
||||
(<= (count items) GROUP-LIMIT) [:div]
|
||||
show-more [:div {:class "hover:cursor-pointer" :on-click (fn [] (cap-highlighted-item) (toggle-show-more))} "Show less"]
|
||||
:else [:div {:class "hover:cursor-pointer" :on-click (fn [] (toggle-show-more))} "Show more"])]
|
||||
|
||||
[:div {:class ""}
|
||||
(for [item visible-items
|
||||
:let [highlighted? (= item highlighted-item)]]
|
||||
(shui/list-item (assoc item
|
||||
:query @(::input state)
|
||||
:highlighted highlighted?
|
||||
;; for some reason, the highlight effect does not always trigger on a
|
||||
;; boolean value change so manually pass in the dep
|
||||
@@ -298,7 +355,7 @@
|
||||
(handle-action action state item))
|
||||
(reset! (::highlighted-item state) item)))
|
||||
:on-highlight (fn [ref]
|
||||
(when (and ref (.-current ref))
|
||||
(when (and ref (.-current ref) (< 2 (:item-index item)))
|
||||
(.. ref -current (scrollIntoView #js {:block "center"
|
||||
:inline "nearest"
|
||||
:behavior "smooth"})))
|
||||
@@ -307,7 +364,8 @@
|
||||
:commands (reset! (::actions state) [:close :trigger])
|
||||
:pages (reset! (::actions state) [:close :copy-page-ref :open-page-right :open-page])
|
||||
:blocks (reset! (::actions state) [:close :copy-block-ref :open-block-right :open-block])
|
||||
nil)))))]]))
|
||||
nil)))
|
||||
(make-shui-context)))]]))
|
||||
|
||||
(defn move-highlight [state n]
|
||||
(let [items (mapcat last (state->results-ordered state))
|
||||
@@ -317,10 +375,27 @@
|
||||
(reset! (::highlighted-item state) next-highlighted-item)
|
||||
(reset! (::highglighted-item state) nil))))
|
||||
|
||||
(defn handle-input-change
|
||||
([state e] (handle-input-change state e (.. e -target -value)))
|
||||
([state _ input]
|
||||
(let [!input (::input state)
|
||||
!load-results-throttled (::load-results-throttled state)]
|
||||
;; update the input value in the UI
|
||||
(reset! !input input)
|
||||
|
||||
;; ensure that there is a throttled version of the load-results function
|
||||
(when-not @!load-results-throttled
|
||||
(reset! !load-results-throttled (gfun/throttle load-results 1000)))
|
||||
|
||||
;; retreive the laod-results function and update all the results
|
||||
(when-let [load-results-throttled @!load-results-throttled]
|
||||
(load-results-throttled :default state)))))
|
||||
|
||||
(defonce keydown-handler
|
||||
(fn [state e]
|
||||
(let [shift? (.-shiftKey e)
|
||||
alt? (.-altKey e)]
|
||||
(js/console.log "pressing key" @(::input state) (.-key e) (boolean (seq @(::input state))))
|
||||
(reset! (::shift? state) shift?)
|
||||
(reset! (::alt? state) alt?)
|
||||
(when (#{"ArrowDown" "ArrowUp"} (.-key e))
|
||||
@@ -334,6 +409,10 @@
|
||||
(handle-action action state @(::highlighted-item state) e))
|
||||
(when-let [action (some #{:open-block :open-page :filter :trigger} @(::actions state))]
|
||||
(handle-action action state @(::highlighted-item state) e)))
|
||||
"Escape" (when (seq @(::input state))
|
||||
(.preventDefault e)
|
||||
(.stopPropagation e)
|
||||
(handle-input-change state nil ""))
|
||||
; "j" (when (.-metaKey e)
|
||||
; (if (.-shiftKey e)
|
||||
; (swap! state update :current-engine prev-engine)
|
||||
@@ -348,21 +427,11 @@
|
||||
alt? (.-altKey e)]
|
||||
(reset! (::shift? state) shift?)
|
||||
(reset! (::alt? state) alt?))))
|
||||
|
||||
(defn handle-input-change [state e]
|
||||
(let [input (.. e -target -value)
|
||||
!input (::input state)
|
||||
!load-results-throttled (::load-results-throttled state)]
|
||||
;; update the input value in the UI
|
||||
(reset! !input input)
|
||||
|
||||
;; ensure that there is a throttled version of the load-results function
|
||||
(when-not @!load-results-throttled
|
||||
(reset! !load-results-throttled (gfun/throttle load-results 1000)))
|
||||
|
||||
;; retreive the laod-results function and update all the results
|
||||
(when-let [load-results-throttled @!load-results-throttled]
|
||||
(load-results-throttled :all state))))
|
||||
; (when (= "Escape" (.-key e))
|
||||
; (js/console.log "escape intercepted keyup")
|
||||
; (.preventDefault e)
|
||||
; (.stopPropagation e)
|
||||
; (reset! (::input state) nil)))))
|
||||
|
||||
(rum/defc page-preview [state highlighted]
|
||||
(let [page-name (:source-page highlighted)]
|
||||
@@ -407,10 +476,14 @@
|
||||
[:div {:class "text-xs font-bold px-6"} "Filters"]
|
||||
[:div {:class "flex items-center gap-2"}
|
||||
[:div {:class "w-4 h-1"}]
|
||||
(when-let [group (:group filter)]
|
||||
[:div {:class "text-xs py-0.5 px-1.5 rounded bg-blue-500/20 hover:bg-blue-500/50 hover:cursor-pointer"
|
||||
:on-click #(swap! (::filter state) dissoc :group)}
|
||||
(print-group-name group)])]])
|
||||
(for [group [:recents :commands :pages :whiteboards :blocks]]
|
||||
(if (= (:group filter) group)
|
||||
[:div {:class "text-xs py-0.5 px-1.5 rounded bg-accent-06 hover:bg-accent-07 hover:cursor-pointer"
|
||||
:on-click #(swap! (::filter state) dissoc :group)}
|
||||
(print-group-name group)]
|
||||
[:div {:class "text-xs py-0.5 px-1.5 rounded bg-gray-06 hover:bg-gray-07 hover:cursor-pointer"
|
||||
:on-click #(swap! (::filter state) assoc :group group)}
|
||||
(print-group-name group)]))]])
|
||||
|
||||
(rum/defc input-row
|
||||
[state all-items]
|
||||
@@ -423,6 +496,9 @@
|
||||
(when (= -1 (.indexOf all-items highlighted-item))
|
||||
(reset! (::highlighted-item state) nil)))
|
||||
[all-items])
|
||||
(rum/use-effect! (fn []
|
||||
(load-results :default state))
|
||||
[])
|
||||
[:div {:class ""
|
||||
:style {:background "var(--lx-gray-02)"
|
||||
:border-bottom "1px solid var(--lx-gray-07)"}}
|
||||
@@ -445,6 +521,7 @@
|
||||
(rum/local default-results ::results)
|
||||
(rum/local nil ::load-results-throttled)
|
||||
(rum/local [:close :filter] ::actions)
|
||||
(rum/local nil ::scroll-container-ref)
|
||||
{:did-mount (fn [state]
|
||||
(let [next-keydown-handler (partial keydown-handler state)
|
||||
next-keyup-handler (partial keyup-handler state)]
|
||||
@@ -454,8 +531,8 @@
|
||||
(when-let [prev-keyup-handler @(::keyup-handler state)]
|
||||
(js/window.removeEventListener "keyup" prev-keyup-handler))
|
||||
;; add new handlers
|
||||
(js/window.addEventListener "keydown" next-keydown-handler)
|
||||
(js/window.addEventListener "keyup" next-keyup-handler)
|
||||
(js/window.addEventListener "keydown" next-keydown-handler true)
|
||||
(js/window.addEventListener "keyup" next-keyup-handler true)
|
||||
;; save references to functions for cleanup later
|
||||
(reset! (::keydown-handler state) next-keydown-handler)
|
||||
(reset! (::keyup-handler state) next-keyup-handler))
|
||||
@@ -470,6 +547,12 @@
|
||||
(reset! (::keydown-handler state) nil)
|
||||
(reset! (::keyup-handler state) nil)
|
||||
state)}
|
||||
{:did-mount (fn [state]
|
||||
(when-let [ref @(::scroll-container-ref state)]
|
||||
(js/console.log "scrolling")
|
||||
(js/setTimeout #(set! (.-scrollTop ref) FILTER-ROW-HEIGHT)))
|
||||
state)}
|
||||
; (load-results :initial state)))}
|
||||
[state {:keys []}]
|
||||
(let [input @(::input state)
|
||||
actions @(::actions state)
|
||||
@@ -483,12 +566,15 @@
|
||||
preview? (or (:source-page highlighted-item) (:source-block highlighted-item))
|
||||
shift? @(::shift? state)
|
||||
alt? @(::alt? state)]
|
||||
; (rum/use-effect! #(load-results :initial state) [])
|
||||
[:div.cp__cmdk {:class "-m-8 max-w-[90dvw] max-h-[90dvh] w-[60rem] h-[30.7rem] "}
|
||||
(input-row state all-items)
|
||||
(when filter (filter-row state filter))
|
||||
[:div {:class (str "grid" (if preview? " grid-cols-2" " grid-cols-1"))}
|
||||
[:div {:class "pt-1 overflow-y-auto h-96"
|
||||
:id "bendy"
|
||||
:ref #(when % (some-> state ::scroll-container-ref (reset! %)))
|
||||
:style {:background "var(--lx-gray-02)"}}
|
||||
(filter-row state filter)
|
||||
(for [[group-name group-key group-items] results-ordered
|
||||
:when (not-empty group-items)
|
||||
:when (if-not group-filter true (= group-filter group-key))]
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
> .it {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
justify-content: start;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
|
||||
|
||||
@@ -151,13 +151,16 @@
|
||||
:height 500}]]])
|
||||
|
||||
(defn row-with-button-action
|
||||
[{:keys [left-label action button-label href on-click desc -for stretch]}]
|
||||
[:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-center
|
||||
[{:keys [left-label description action button-label href on-click desc -for stretch]}]
|
||||
[:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
|
||||
|
||||
;; left column
|
||||
[:label.block.text-sm.font-medium.leading-5.opacity-70
|
||||
{:for -for}
|
||||
left-label]
|
||||
[:div.flex.flex-col
|
||||
[:label.block.text-sm.font-medium.leading-5.opacity-70
|
||||
{: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
|
||||
@@ -315,68 +318,49 @@
|
||||
:action pick-theme
|
||||
:desc (ui/render-keyboard-shortcut (shortcut-helper/gen-shortcut-seq :ui/toggle-theme))})))
|
||||
|
||||
(defn theme-row [t dark?]
|
||||
(defn accent-color-row [t dark?]
|
||||
(let [color-accent (state/sub :ui/radix-color)
|
||||
pick-theme [:div.grid {:style {:grid-template-columns "repeat(17, 1fr)"
|
||||
pick-theme [:div.grid {:style {:grid-template-columns "repeat(5, 1fr)"
|
||||
:gap "0.75rem"
|
||||
:overflow-x :scroll
|
||||
:width "100%"
|
||||
:padding-left "0.25rem"}}
|
||||
[:div.theme-row--color {:on-click #(state/unset-color-accent!)
|
||||
:class (when (nil? color-accent) "selected")}
|
||||
[:div.theme-row--color-swatch {:style {;; "--background" "#0F2A35"
|
||||
;; "--background-hover" "#163542"
|
||||
;; "--background-active" "#274E5E"
|
||||
"--background" "#0369a1"
|
||||
"--background-hover" "#38bdf8" ;; TODO what is the hover color?
|
||||
"--background-active" "#0ea5e9"} ;; TODO what is the hover color?
|
||||
:border-right "1px solid rgba(255,255,255,0.4)"}]
|
||||
[:div.text-xs {:style {:margin "0 -0.5rem"
|
||||
:opacity 0.5
|
||||
:height "1rem"
|
||||
:padding "0 0.5rem"}}]]
|
||||
[:div.theme-row--color-separator]
|
||||
:max-width "16rem"}}
|
||||
(for [color colors/color-list
|
||||
:let [gray (get colors/gray-pairing-map color)]]
|
||||
[:div.theme-row--color {:on-click #(state/set-color-accent! color)
|
||||
:class (when (= color-accent color) "selected")}
|
||||
[:div.theme-row--color-swatch {:style {"--background" (str "var(--rx-" (name color) "-07)")
|
||||
"--background-hover" (str "var(--rx-" (name color) "-10)")
|
||||
"--background-active" (str "var(--rx-" (name color) "-09) ")}}]])]
|
||||
; "--border-hover" (str "var(--rx-" (name color) "-08)")}}]
|
||||
display-theme [:button {:style {:background "var(--lx-accent-03)"
|
||||
:border "1px solid var(--lx-accent-07)"
|
||||
:color "var(--lx-accent-11)"}}
|
||||
(if color-accent (name color-accent) "default")]]
|
||||
:let [gray (get colors/gray-pairing-map color)
|
||||
active? (= color color-accent)
|
||||
default-classes "w-5 h-5 rounded-full flex justify-center items-center border transition ease-in duration-100 hover:cursor-pointer hover:opacity-100"
|
||||
bg (if active? (str "bg-" (name color) "-09 opacity-100")
|
||||
(str "bg-" (name color) "-09 opacity-50"))
|
||||
border (if active? (str "border-" (name color) "-07 opacity-100")
|
||||
(str "border-" (name color) "-06 opacity-50"))]]
|
||||
[:div.flex.items-center {:style {:height 28}}
|
||||
[:div {;;:class (string/join " " [default-classes bg border])
|
||||
:class "w-5 h-5 rounded-full flex justify-center items-center transition ease-in duration-100 hover:cursor-pointer hover:opacity-100"
|
||||
: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)}
|
||||
:on-click (fn [e] (state/set-color-accent! color))}
|
||||
[:div {:class "w-2 h-2 rounded-full transition ease-in duration-100"
|
||||
:style {:background-color (str "var(--rx-" (name color) "-07)")
|
||||
:opacity (if active? 1 0)}}]]])
|
||||
; (shui/button {:text (name color)
|
||||
; :color color
|
||||
; :muted (not= color-accent color)}
|
||||
; (make-shui-context nil nil)))
|
||||
[:div.col-span-5
|
||||
(shui/button {:text "Use custom theme"
|
||||
:theme :gray
|
||||
:on-click (fn [e] (state/unset-color-accent!))}
|
||||
(make-shui-context nil nil))]]]
|
||||
|
||||
[:<>
|
||||
(row-with-button-action {:left-label "Theme color"
|
||||
(row-with-button-action {:left-label "Accent color"
|
||||
:description "Choosing an accent color will override any theme you have selected. To use a custom theme, click the button below."
|
||||
:-for "toggle_radix_theme"
|
||||
:stretch true
|
||||
:action pick-theme})]))
|
||||
|
||||
(defn theme-gradient-row [t dark? color-accent]
|
||||
(let [color-gradient (state/sub :ui/radix-gradient)
|
||||
pick-gradient [:div {:class "grid grid-cols-7 gap-2 overflow-x-auto"}
|
||||
[:div {:class (cond-> "theme-gradient-row--gradient-swatch"
|
||||
(= 1 color-gradient) (str " selected"))
|
||||
:style {"--background" (str "var(--rx-" (name color-accent) "-07)")
|
||||
"--background-hover" (str "var(--rx-" (name color-accent) "-08)")
|
||||
"--background-active" (str "var(--rx-" (name color-accent) "-09)")}
|
||||
:on-click #(state/unset-color-gradient!)}]
|
||||
(for [n (range 2 8)
|
||||
:let [active? (= n color-gradient)]]
|
||||
[:div {:class (cond-> "bg-white theme-gradient-row--gradient-swatch"
|
||||
active? (str " selected"))
|
||||
:key n
|
||||
:style {"--background" (colors/linear-gradient color-accent :07 n)
|
||||
"--background-hover" (colors/linear-gradient color-accent :08 n)
|
||||
"--background-active" (colors/linear-gradient color-accent :09 n)}
|
||||
:on-click #(state/set-color-gradient! n)}])]]
|
||||
(row-with-button-action {:left-label "Theme gradient"
|
||||
:stretch true
|
||||
:action pick-gradient})))
|
||||
|
||||
|
||||
(defn file-format-row [t preferred-format]
|
||||
[:div.it.sm:grid.sm:grid-cols-3.sm:gap-4.sm:items-start
|
||||
[:label.block.text-sm.font-medium.leading-5.opacity-70
|
||||
@@ -715,8 +699,7 @@
|
||||
(language-row t preferred-language)
|
||||
(theme-modes-row t switch-theme system-theme? dark?)
|
||||
(when (and (util/electron?) (not util/mac?)) (native-titlebar-row t))
|
||||
(when show-radix-themes? (theme-row t dark?))
|
||||
(when (and show-radix-themes? color-accent) (theme-gradient-row t dark? color-accent))
|
||||
(when show-radix-themes? (accent-color-row t dark?))
|
||||
(when (config/global-config-enabled?) (edit-global-config-edn))
|
||||
(when current-repo (edit-config-edn))
|
||||
(when current-repo (edit-custom-css))
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
.cp__settings {
|
||||
&-main {
|
||||
&-inner {
|
||||
@apply flex flex-col md:flex-row;
|
||||
|
||||
> header {
|
||||
padding: 10px;
|
||||
padding-top: 0;
|
||||
@@ -77,47 +79,10 @@
|
||||
}
|
||||
|
||||
.settings-menu-link {
|
||||
@apply px-2 py-1.5 select-none;
|
||||
color: or(--lx-gray-12, --ls-primary-text-color);
|
||||
@apply px-2 py-1.5 select-none;
|
||||
color: var(--ls-primary-text-color);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&-inner {
|
||||
@apply flex flex-col md:flex-row;
|
||||
|
||||
> aside {
|
||||
|
||||
ul {
|
||||
|
||||
> li {
|
||||
|
||||
> a {
|
||||
|
||||
> i {
|
||||
overflow: hidden;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
> strong {
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
padding-left: 5px;
|
||||
margin-top: 2px;
|
||||
opacity: .9;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: or(--lx-gray-06, --ls-quaternary-background-color);
|
||||
|
||||
i {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.no-aside {
|
||||
> article {
|
||||
@@ -137,9 +102,11 @@
|
||||
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 12px;
|
||||
align-items: center;
|
||||
align-items: start;
|
||||
|
||||
label {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -226,7 +193,7 @@
|
||||
cursor: inherit;
|
||||
|
||||
> i {
|
||||
border-color: or(--lx-accent-11, --ls-link-text-color);
|
||||
border-color: var(--ls-link-text-color);
|
||||
border-width: 2px;
|
||||
}
|
||||
}
|
||||
@@ -276,7 +243,7 @@
|
||||
|
||||
.update-state {
|
||||
padding: 6px 10px;
|
||||
background-color: or(--lx-gray-06, --ls-quaternary-background-color);
|
||||
background-color: var(--ls-quaternary-background-color);
|
||||
border-radius: 4px;
|
||||
margin-top: 10px;
|
||||
width: fit-content;
|
||||
@@ -334,7 +301,6 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.cp__assets {
|
||||
@@ -345,7 +311,7 @@
|
||||
@apply m-0 list-none -mx-2;
|
||||
|
||||
> li {
|
||||
border-top: 1px solid or(--lx-accent-08, --ls-secondary-border-color);
|
||||
border-top: 1px solid var(--ls-secondary-border-color);
|
||||
|
||||
&:hover {
|
||||
.ext-label.is-plus {
|
||||
@@ -362,8 +328,8 @@
|
||||
.ext-label {
|
||||
@apply rounded px-1.5 opacity-70 cursor-pointer flex items-center select-none active:opacity-50;
|
||||
|
||||
background-color: or(--lx-accent-08, --ls-secondary-border-color);
|
||||
color: or(--lx-gray-11, --ls-secondary-text-color);
|
||||
background-color: var(--ls-secondary-border-color);
|
||||
color: var(--ls-secondary-text-color);
|
||||
|
||||
&.is-del {
|
||||
i.ti {
|
||||
@@ -387,8 +353,8 @@
|
||||
}
|
||||
|
||||
&.is-plus {
|
||||
background-color: or(--lx-gray-03, --ls-primary-background-color);
|
||||
border: 1px solid or(--lx-gray-07, --ls-border-color);
|
||||
background-color: var(--ls-primary-background-color);
|
||||
border: 1px solid var(--ls-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,7 +381,7 @@
|
||||
z-index: 1;
|
||||
width: 100px;
|
||||
max-height: 180px;
|
||||
border:1px solid or(--lx-gray-07, --ls-border-color);
|
||||
border: 1px solid var(--ls-border-color);
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
overflow: overlay;
|
||||
@@ -454,13 +420,13 @@
|
||||
&-alias-ext-input {
|
||||
width: 80px !important;
|
||||
padding: 1px 4px;
|
||||
border: 2px solid or(--lx-gray-08, --ls-secondary-border-color);
|
||||
border: 2px solid var(--ls-secondary-border-color);
|
||||
font-size: 11px;
|
||||
border-radius: 4px;
|
||||
height: 22px;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--lx-gray-07, --ls-border-color);
|
||||
border-color: var(--ls-border-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -478,6 +444,14 @@ html.is-native-iphone-without-notch {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.theme-row--swatch {
|
||||
@apply w-5 h-5 rounded-full flex justify-center items-center;
|
||||
}
|
||||
|
||||
.theme-row--swatch-active {
|
||||
@apply w-5 h-5 rounded-full flex justify-center items-center;
|
||||
}
|
||||
}
|
||||
|
||||
svg.git {
|
||||
@@ -489,61 +463,6 @@ svg.cmd {
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
.cp__settings-main .theme-row--color {
|
||||
@apply flex flex-col items-center;
|
||||
width: 2rem;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.cp__settings-main .theme-row--color-separator {
|
||||
@apply relative;
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
.cp__settings-main .theme-row--color-separator::before {
|
||||
@apply absolute inset-1/2 h-6 -translate-y-3 -translate-x-px;
|
||||
content: "";
|
||||
width: 2px;
|
||||
background-color: or(--logseq-og-color-theme-separator, --lx-gray-09, --ls-quaternary-background-color);
|
||||
}
|
||||
|
||||
.cp__settings-main .theme-row--color-swatch {
|
||||
@apply rounded-full;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
background: var(--background);
|
||||
/* border: 4px solid var(--border); */
|
||||
/* border: 3px solid orange; */
|
||||
}
|
||||
|
||||
.cp__settings-main .theme-row--color-swatch:hover {
|
||||
background: var(--background-hover);
|
||||
border-color: var(--border-hover);
|
||||
}
|
||||
|
||||
.cp__settings-main .selected .theme-row--color-swatch,
|
||||
.cp__settings-main .selected .theme-row--color-swatch:hover {
|
||||
background: var(--background-active);
|
||||
border-color: var(--border-active);
|
||||
}
|
||||
|
||||
.cp__settings-main .theme-gradient-row--gradient-swatch {
|
||||
@apply rounded-full;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
|
||||
background: var(--background);
|
||||
}
|
||||
|
||||
.cp__settings-main .theme-gradient-row--gradient-swatch:hover {
|
||||
background: var(--background-hover);
|
||||
}
|
||||
|
||||
.cp__settings-main .selected.theme-gradient-row--gradient-swatch,
|
||||
.cp__settings-main .selected.theme-gradient-row--gradient-swatch:hover {
|
||||
background: var(--background-active);
|
||||
}
|
||||
|
||||
body[data-settings-tab=keymap] {
|
||||
.cp__settings-inner {
|
||||
> article {
|
||||
|
||||
@@ -179,15 +179,15 @@
|
||||
.cp__shortcut-conflicts-list {
|
||||
&-wrap {
|
||||
> section {
|
||||
@apply bg-gray-3 border-[2px] mb-3 dark:bg-transparent;
|
||||
@apply bg-gray-03 border-[2px] mb-3 dark:bg-transparent;
|
||||
|
||||
> ul {
|
||||
@apply px-2 pb-2 m-0 list-none;
|
||||
}
|
||||
|
||||
> h2 {
|
||||
@apply flex items-center p-2 text-red-9 text-sm space-x-1 font-extrabold;
|
||||
@apply flex items-center p-2 text-red-600 text-sm space-x-1 font-extrabold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@
|
||||
(state/set-online! js/navigator.onLine)
|
||||
(set-network-watcher!)
|
||||
(when-let [radix-color (state/get-color-accent)]
|
||||
(colors/set-radix radix-color (state/get-color-gradient)))
|
||||
(colors/set-radix radix-color))
|
||||
|
||||
(util/indexeddb-check?
|
||||
(fn [_error]
|
||||
|
||||
@@ -528,9 +528,6 @@
|
||||
:ui/cycle-color {:binding "c c"
|
||||
:fn state/cycle-color!}
|
||||
|
||||
:ui/cycle-gradient {:binding "c g"
|
||||
:fn state/cycle-gradient!}
|
||||
|
||||
:ui/toggle-cards {:binding "t c"
|
||||
:fn ui-handler/toggle-cards!}
|
||||
|
||||
@@ -559,7 +556,7 @@
|
||||
::dicts/commands dicts/abbreviated-commands}]
|
||||
(assert (= (::commands keyboard-commands) (::dicts/commands keyboard-commands))
|
||||
(str "Keyboard commands must have an english label"
|
||||
(data/diff (::commands keyboard-commands) (::commands keyboard-commands)))))
|
||||
(data/diff (::commands keyboard-commands) (::dicts/commands keyboard-commands)))))
|
||||
|
||||
(defn- resolve-fn
|
||||
"Converts a keyword fn to the actual fn. The fn to be resolved needs to be
|
||||
@@ -727,7 +724,6 @@
|
||||
:ui/clear-all-notifications
|
||||
:ui/cycle-color
|
||||
:ui/cycle-color-off
|
||||
:ui/cycle-gradient
|
||||
:ui/goto-plugins
|
||||
:ui/install-plugins-from-file
|
||||
:ui/select-theme-color
|
||||
@@ -854,8 +850,7 @@
|
||||
:ui/toggle-settings
|
||||
:ui/toggle-contents
|
||||
:ui/cycle-color-off
|
||||
:ui/cycle-color
|
||||
:ui/cycle-gradient]
|
||||
:ui/cycle-color]
|
||||
|
||||
:shortcut.category/whiteboard
|
||||
[:editor/new-whiteboard
|
||||
|
||||
@@ -236,15 +236,15 @@
|
||||
(and (set? handler-ids) (contains? handler-ids handler-id'))
|
||||
(and global? (contains? global-handlers handler-id'))))
|
||||
(assoc r id handler-id')
|
||||
r)
|
||||
) {} refs)]]))]
|
||||
r))
|
||||
{} refs)]]))]
|
||||
|
||||
[k' (->> ks-bindings
|
||||
(filterv same-leading-key?)
|
||||
(mapv into-conflict-refs)
|
||||
(remove #(empty? (second (second %1))))
|
||||
(into {}))]
|
||||
))))
|
||||
(into {}))]))))
|
||||
|
||||
(remove #(empty? (vals (second %1))))
|
||||
(into {})))))
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
(ns frontend.shui
|
||||
"Glue between frontend code and deps/shui for convenience"
|
||||
(:require
|
||||
[frontend.colors :as colors]
|
||||
[frontend.date :refer [int->local-time-2]]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.utils :as db-utils]
|
||||
[frontend.handler.search :as search-handler]
|
||||
[frontend.state :as state]
|
||||
[logseq.shui.context :refer [make-context]]
|
||||
[frontend.handler.search :as search-handler]))
|
||||
[logseq.shui.context :refer [make-context]]))
|
||||
|
||||
(def default-versions {:logseq.table.version 1})
|
||||
|
||||
@@ -19,10 +22,22 @@
|
||||
(get-in default-versions [version-key])
|
||||
1))))
|
||||
|
||||
(defn make-shui-context [block-config inline]
|
||||
(make-context {:block-config block-config
|
||||
:app-config (state/get-config)
|
||||
:inline inline
|
||||
:int->local-time-2 int->local-time-2
|
||||
:state state/state
|
||||
:search search-handler/search}))
|
||||
(defn make-shui-context
|
||||
([] (make-shui-context nil nil))
|
||||
([block-config inline]
|
||||
(make-context {:block-config block-config
|
||||
:config (state/get-config)
|
||||
:inline inline
|
||||
:int->local-time-2 int->local-time-2
|
||||
:search search-handler/search
|
||||
;; We need some variable from the state to carry over
|
||||
:state state/state
|
||||
:get-current-repo state/get-current-repo
|
||||
:color-accent (state/get-color-accent)
|
||||
;; Pass over ability to look up entities
|
||||
:entity db-utils/entity
|
||||
:get-block-and-children db/get-block-and-children
|
||||
:get-block-children db/get-block-children
|
||||
:get-page-blocks-no-cache db/get-page-blocks-no-cache
|
||||
:get-page db/get-page})))
|
||||
|
||||
|
||||
@@ -84,7 +84,6 @@
|
||||
:ui/custom-theme (or (storage/get :ui/custom-theme) {:light {:mode "light"} :dark {:mode "dark"}})
|
||||
:ui/wide-mode? (storage/get :ui/wide-mode)
|
||||
:ui/radix-color (storage/get :ui/radix-color)
|
||||
:ui/radix-gradient (storage/get :ui/radix-gradient)
|
||||
|
||||
;; ui/collapsed-blocks is to separate the collapse/expand state from db for:
|
||||
;; 1. right sidebar
|
||||
@@ -2192,28 +2191,16 @@ Similar to re-frame subscriptions"
|
||||
(defn get-color-accent []
|
||||
(get @state :ui/radix-color))
|
||||
|
||||
(defn get-color-gradient []
|
||||
(get @state :ui/radix-gradient 1))
|
||||
|
||||
(defn set-color-accent! [color]
|
||||
(swap! state assoc :ui/radix-color color)
|
||||
(storage/set :ui/radix-color color)
|
||||
(colors/set-radix color (get-color-gradient)))
|
||||
|
||||
(defn set-color-gradient! [steps]
|
||||
(swap! state assoc :ui/radix-gradient steps)
|
||||
(storage/set :ui/radix-gradient steps)
|
||||
(colors/set-radix (get-color-accent) steps))
|
||||
(colors/set-radix color))
|
||||
|
||||
(defn unset-color-accent! []
|
||||
(swap! state assoc :ui/radix-color nil)
|
||||
(storage/remove :ui/radix-color)
|
||||
(colors/unset-radix))
|
||||
|
||||
(defn unset-color-gradient! []
|
||||
(swap! state assoc :ui/radix-gradient nil)
|
||||
(storage/remove :ui/radix-gradient))
|
||||
|
||||
(defn cycle-color! []
|
||||
(let [current-color (get-color-accent)
|
||||
next-color (->> (cons nil colors/color-list)
|
||||
@@ -2223,30 +2210,6 @@ Similar to re-frame subscriptions"
|
||||
(set-color-accent! next-color)
|
||||
(unset-color-accent!))))
|
||||
|
||||
(defn cycle-gradient! []
|
||||
(let [current-gradient (get-color-gradient)]
|
||||
(case current-gradient
|
||||
nil (set-color-gradient! 2)
|
||||
6 (unset-color-gradient!)
|
||||
(set-color-gradient! (inc current-gradient)))))
|
||||
|
||||
|
||||
(defn sub-color-gradient-bg-styles [step]
|
||||
(let [color (sub :ui/radix-color)
|
||||
stops (sub :ui/radix-gradient)]
|
||||
{:background-image (colors/linear-gradient color step stops)
|
||||
:background-attachment :fixed
|
||||
:background-position "0 0"
|
||||
:background-size "100% 100%"}))
|
||||
; :transform "translate3d(0,0,0) "}))
|
||||
|
||||
(defn sub-color-gradient-text-styles [step]
|
||||
(assoc (sub-color-gradient-bg-styles step)
|
||||
:background-clip "text"
|
||||
"-webkit-background-clip" "text"
|
||||
:color :transparent))
|
||||
; (sub-color-gradient-bg-styles step))
|
||||
|
||||
(defn set-page-properties-changed!
|
||||
[page-name]
|
||||
(when-not (string/blank? page-name)
|
||||
|
||||
@@ -810,7 +810,6 @@
|
||||
:ui/toggle-contents "Toggle Contents in sidebar"
|
||||
:ui/cycle-color-off "Cycle color off"
|
||||
:ui/cycle-color "Cycle color"
|
||||
:ui/cycle-gradient "Cycle gradient"
|
||||
;; :ui/open-new-window "Open another window"
|
||||
:command/toggle-favorite "Add to/remove from favorites"
|
||||
:editor/open-file-in-default-app "Open file in default app"
|
||||
|
||||
Reference in New Issue
Block a user