mirror of https://github.com/logseq/logseq
cmdk
parent
4e2d980955
commit
6f984d45ef
|
@ -1 +1,2 @@
|
|||
-
|
||||
-
|
|
@ -2,11 +2,27 @@
|
|||
(:require
|
||||
[clojure.string :as str]
|
||||
[logseq.shui.util :as util]
|
||||
[rum.core :as rum]))
|
||||
[rum.core :as rum]
|
||||
[logseq.shui.icon.v2 :as icon]))
|
||||
|
||||
(rum/defc root
|
||||
[{:keys [intent text] :or {intent :primary}} context]
|
||||
[:button.shui__button
|
||||
[:div.shui__border]
|
||||
text])
|
||||
[{:keys [theme text depth size icon shortcut] :or {theme :color depth 1 size :md}} context]
|
||||
(let [theme-class (str "shui__button-theme-" (name theme))
|
||||
depth-class (str "shui__button-depth-" depth)
|
||||
color-class (str "shui__button-color-" (some-> context :state deref :ui/radix-color name))
|
||||
size-class (str "shui__button-size-" (name size))]
|
||||
[:button.shui__button {:class (str theme-class " " depth-class " " color-class " " size-class)}
|
||||
text
|
||||
(when icon
|
||||
(icon/root icon))
|
||||
(when (not-empty shortcut)
|
||||
(for [key shortcut]
|
||||
[:div.shui__button-shortcut-key
|
||||
(case key
|
||||
"cmd" (icon/root "command")
|
||||
"shift" (icon/root "arrow-big-up-filled")
|
||||
"return" (icon/root "arrow-back")
|
||||
key)]))]))
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -2,12 +2,202 @@
|
|||
(:require
|
||||
[clojure.string :as str]
|
||||
[logseq.shui.util :as util]
|
||||
[logseq.shui.button.v2 :as button]
|
||||
[logseq.shui.icon.v2 :as icon]
|
||||
[rum.core :as rum]))
|
||||
|
||||
(rum/defc root
|
||||
[{:keys [intent text] :or {intent :primary}} context]
|
||||
[:button.shui__button
|
||||
[:div.shui__border]
|
||||
text])
|
||||
(def state (atom {:current-engine "All"
|
||||
:highlight-index 0
|
||||
:button {:text "Open" :theme :gray :shortcut ["return"]}}))
|
||||
|
||||
(defn get-results []
|
||||
[])
|
||||
|
||||
(defn get-preview []
|
||||
nil)
|
||||
|
||||
(rum/defc result-heading [text]
|
||||
[:div.text-xs.font-bold.pt-4.pb-1.px-6 {:style {:color "var(--lx-gray-11)"}} text])
|
||||
|
||||
(rum/defc result-item [{:keys [icon icon-theme text info shortcut value-label value title highlighted on-highlight on-highlight-dep]}]
|
||||
(rum/use-effect!
|
||||
(fn []
|
||||
(when highlighted
|
||||
(on-highlight)))
|
||||
[highlighted on-highlight-dep])
|
||||
[:div.flex.px-6.gap-3.py-4 {:style {:background (if highlighted "var(--lx-gray-01)" "var(--lx-gray-02)")}}
|
||||
[:div.w-5.h-5.rounded.flex.items-center.justify-center
|
||||
{:style {:background (case icon-theme :color "var(--lx-accent-09)" :gray "var(--lx-gray-09)" :gradient "linear-gradient(-65deg, #8AE8FF, #5373E7, #369EFF, #00B1CC)")
|
||||
:box-shadow (when (#{:color :gradient} icon-theme) "inset 0 0 0 1px rgba(255,255,255,0.3) ")}}
|
||||
(icon/root icon {:size "14"})]
|
||||
[:div.flex.flex-1.flex-col
|
||||
(when title
|
||||
[:div.text-sm.pb-2.font-bold {:style {:color "var(--lx-gray-11)"}} title])
|
||||
[:div {:class "text-sm font-medium"} text
|
||||
(when info
|
||||
[:span {:style {:color "var(--lx-gray-11)"}} (str " — " info)])]]
|
||||
(when (or value-label value)
|
||||
[:div {:class "text-xs"}
|
||||
[:span {:style {:color "var(--lx-gray-11)"}} (str value-label ": ")]
|
||||
[:span {:style {:color "var(--lx-gray-12)"}} value]])
|
||||
(when shortcut
|
||||
[:div
|
||||
(for [key shortcut]
|
||||
[:span (str key)])])])
|
||||
|
||||
(rum/defc engines < rum/reactive [context]
|
||||
(let [state-value (rum/react state)
|
||||
{:keys [current-engine]} state-value
|
||||
active-themes {"Quick capture" :color "AI" :gradient}]
|
||||
[:div.flex.gap-4.px-6
|
||||
(for [engine ["All" "Pages" "Blocks" "Quick capture" "AI"]
|
||||
:let [theme (if (= engine current-engine) (get active-themes engine :gray) :gray)
|
||||
muted (if (= engine current-engine) "" " opacity-50")]]
|
||||
[:div {:class (str "inline-block text-sm font-medium" muted)}
|
||||
(button/root {:text engine :depth 0 :size :sm :theme theme} context)])]))
|
||||
|
||||
(defn button-updater [text theme & shortcut]
|
||||
(fn []
|
||||
(swap! state assoc :button {:text text :theme theme :shortcut (map name shortcut)})))
|
||||
|
||||
(rum/defc results < rum/reactive []
|
||||
(let [state-value (rum/react state)
|
||||
{:keys [current-engine highlight-index]} state-value
|
||||
filtered-actions (when (#{"All" "Actions"} current-engine)
|
||||
[{:icon-theme :color :icon "plus" :text "Quick capture" :info "Add a block to todays journal page" :on-highlight (button-updater "Quick capture" :color :return)}
|
||||
{:icon-theme :gradient :icon "question-mark" :text "Generate short answer" :on-highlight (button-updater "Generate" :gradient :return)}
|
||||
{:icon-theme :gray :icon "toggle-left" :text "Toggle Logseq Sync" :value-label "Current State" :value "On" :on-highlight (button-updater "Toggle" :gray :return)}
|
||||
{:icon-theme :gray :icon "player-play" :text "Restart Logseq Sync Onboarding" :on-highlight (button-updater "Restart" :gray :return)}])
|
||||
filtered-qc-actions (when (#{"Quick capture"} current-engine)
|
||||
[{:icon-theme :color :icon "block" :text "Create block" :info "Add a block to todays journal page" :on-highlight (button-updater "Create" :color :cmd :return)}
|
||||
{:icon-theme :color :icon "page" :text "Create page" :on-highlight (button-updater "Create" :color :cmd :return)}
|
||||
{:icon-theme :color :icon "whiteboard" :text "Create whiteboard" :info "Create a whiteboard with this block on it" :on-highlight (button-updater "Create" :color :cmd :return)}])
|
||||
filtered-ai-actions (when (#{"AI"} current-engine)
|
||||
[{:icon-theme :gradient :icon "page" :text "Ask about the current page" :on-highlight (button-updater "Query" :gradient :return)}
|
||||
{:icon-theme :gradient :icon "graph" :text "Ask about the current graph" :on-highlight (button-updater "Query" :gradient :return)}
|
||||
{:icon-theme :gradient :icon "messages" :text "Chat" :info "Chat with an AI about any topic" :on-highlight (button-updater "Start chat" :gradient :return)}
|
||||
{:icon-theme :gradient :icon "question-mark" :text "Generate short answer" :on-highlight (button-updater "Generate" :gradient :return)}])
|
||||
filtered-blocks (when (#{"All" "Blocks"} current-engine)
|
||||
[{:icon-theme :gray :icon "block" :title "Not a real document" :on-highlight (button-updater "Open" :gray :return) :text "When working on cmdk, we want to display blocks that appear from search. These can have quite a long body of text, and that body of text should potentially be truncated"}
|
||||
{:icon-theme :gray :icon "block" :title "Not a real document" :on-highlight (button-updater "Open" :gray :return) :text "Of course, that truncated text should be truncated in a way that makes sense, and doesn't cut off in the middle of a word, and contains the search query if there is one"}
|
||||
{:icon-theme :gray :icon "block" :title "Not a real document" :on-highlight (button-updater "Open" :gray :return) :text "We should play around with displaying the blocks hierarchy, currently it's very noisy, and I'm not sure if it's adding much value. It's possible that the preview will be a sufficient replacement"}])
|
||||
filtered-pages (when (#{"All" "Pages"} current-engine)
|
||||
[{:icon-theme :gray :icon "page" :text "Memo/CMDK" :on-highlight (button-updater "Open" :gray :return)}
|
||||
{:icon-theme :gray :icon "page" :text "Logseq Logo Community Contest" :on-highlight (button-updater "Open" :gray :return)}])
|
||||
grouped-items (->> [["Actions" filtered-actions] ["Actions" filtered-qc-actions] ["Actions" filtered-ai-actions] ["Blocks" filtered-blocks] ["Pages" filtered-pages]]
|
||||
(filter #(not-empty (second %))))
|
||||
item-count (count (mapcat second grouped-items))
|
||||
highlight-index-normalized (cond
|
||||
(zero? item-count)
|
||||
nil
|
||||
(<= 0 (mod highlight-index item-count))
|
||||
(mod highlight-index item-count)
|
||||
:else
|
||||
(- item-count (mod highlight-index item-count)))
|
||||
highlight-item (some->> highlight-index-normalized (nth (mapcat second grouped-items)))]
|
||||
[:div.overflow-y-auto {:style {:max-height "50dvh"}}
|
||||
(for [[index [group items]] (map-indexed vector grouped-items)]
|
||||
[:<>
|
||||
(when-not (zero? index)
|
||||
[:div.w-full {:style {:background "var(--lx-gray-07)"}
|
||||
:class "h-px"}])
|
||||
(result-heading group)
|
||||
(for [item items]
|
||||
(result-item (assoc item :highlighted (= item highlight-item) :on-highlight-dep current-engine)))])]))
|
||||
|
||||
(rum/defc preview []
|
||||
[:div "Preview"])
|
||||
|
||||
(rum/defc actions < rum/reactive []
|
||||
(let [state-value (rum/react state)
|
||||
button-props (:button state-value)]
|
||||
[:div.py-4.px-6.flex.justify-end.gap-6.border-t
|
||||
{:style {:background-color "var(--lx-gray-03)"
|
||||
:border-color "var(--lx-gray-07)"}}
|
||||
(button/root {:text "Cancel" :theme :gray} {})
|
||||
(button/root button-props {})]))
|
||||
|
||||
(rum/defc quick-capture []
|
||||
[:div.px-6
|
||||
[:div.flex.items-center
|
||||
[:div.w-4.h-4.flex.items-center.justify-center
|
||||
[:div.w-2.h-2.bg-white.rounded-full.opacity-25]]
|
||||
[:input {:class "w-full border-0 px-6 bg-transparent"
|
||||
:type "text"}]]
|
||||
[:div.flex.items-center
|
||||
(icon/root "circle-plus" {:style {:opacity 0.5}})
|
||||
[:input {:class "w-full border-0 px-6 bg-transparent"
|
||||
:type "text"}]]])
|
||||
|
||||
(rum/defc search []
|
||||
[:input {:class "w-full border-0 px-6"
|
||||
:type "text"
|
||||
:placeholder "Search"}])
|
||||
|
||||
(rum/defc header < rum/reactive
|
||||
[context]
|
||||
(let [state-value (rum/react state)
|
||||
current-engine (:current-engine state-value)]
|
||||
[:div.relative.border-b.flex.flex-col.gap-4.pt-4.pb-1.rounded
|
||||
{:style {:border-color "var(--lx-gray-07)"
|
||||
:background (when (= current-engine "Quick capture") "var(--lx-accent-02")}
|
||||
:class (when (= current-engine "Quick capture") "shui__cmdk-quick-capture-glow")}
|
||||
(engines context)
|
||||
(if (= current-engine "Quick capture")
|
||||
(quick-capture)
|
||||
(search))]))
|
||||
|
||||
(defn prev-engine [current-engine]
|
||||
(->> ["All" "Pages" "Blocks" "Quick capture" "AI" "All"]
|
||||
(reverse)
|
||||
(drop-while (complement #{current-engine}))
|
||||
(second)))
|
||||
|
||||
(defn next-engine [current-engine]
|
||||
(->> ["All" "Pages" "Blocks" "Quick capture" "AI" "All"]
|
||||
(drop-while (complement #{current-engine}))
|
||||
(second)))
|
||||
|
||||
(defonce keydown-handler
|
||||
(fn [e]
|
||||
(case (.-key e)
|
||||
; "Escape" (rum/dispatch! :close)
|
||||
"ArrowDown" (swap! state update :highlight-index inc)
|
||||
"ArrowUp" (swap! state update :highlight-index dec)
|
||||
"j" (when (.-metaKey e)
|
||||
(if (.-shiftKey e)
|
||||
(swap! state update :current-engine prev-engine)
|
||||
(swap! state update :current-engine next-engine)))
|
||||
; "ArrowUp" (rum/dispatch! :highlight-prev)
|
||||
; "Enter" (rum/dispatch! :select)
|
||||
(println (.-key e)))))
|
||||
|
||||
(defn use-cmdk-keyboard-bindings! []
|
||||
(rum/use-effect!
|
||||
(fn []
|
||||
(js/window.addEventListener "keydown" keydown-handler)
|
||||
#(js/window.removeEventListener "keydown" keydown-handler))
|
||||
[]))
|
||||
|
||||
(rum/defc root < rum/reactive
|
||||
{:did-mount (fn [_]
|
||||
(js/window.removeEventListener "keydown" keydown-handler)
|
||||
(js/window.addEventListener "keydown" keydown-handler))
|
||||
:will-unmount (fn [_] (js/window.removeEventListener "keydown" keydown-handler))}
|
||||
[props context]
|
||||
; (use-cmdk-keyboard-bindings!)
|
||||
(let [preview-data (get-preview)]
|
||||
[:div.-m-8 {:style {:background-color "var(--lx-gray-02)"
|
||||
:width "75vw"
|
||||
:max-width 800}}
|
||||
(header context)
|
||||
(if preview-data
|
||||
[:div.grid.grid-cols-2
|
||||
(results)
|
||||
(preview)]
|
||||
[:div.grid.grid-cols-1
|
||||
(results)])
|
||||
[:div
|
||||
(actions)]]))
|
||||
|
||||
|
||||
|
|
|
@ -42,4 +42,5 @@
|
|||
:color-gradient (state/get-color-gradient)
|
||||
:sub-color-gradient-bg-styles state/sub-color-gradient-bg-styles
|
||||
:sub-color-gradient-text-styles state/sub-color-gradient-text-styles
|
||||
:linear-gradient colors/linear-gradient})
|
||||
:linear-gradient colors/linear-gradient
|
||||
:state state/state})
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
(ns logseq.shui.icon.v2
|
||||
(:require
|
||||
[camel-snake-kebab.core :as csk]
|
||||
[cljs-bean.core :as bean]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as string]
|
||||
[clojure.walk :as w]
|
||||
[daiquiri.interpreter :as interpreter]
|
||||
[goog.object :as gobj]
|
||||
[goog.string :as gstring]
|
||||
[rum.core :as rum]))
|
||||
|
||||
;; this is taken from frontend.rum, and should be properly abstracted
|
||||
(defn kebab-case->camel-case
|
||||
"Converts from kebab case to camel case, eg: on-click to onClick"
|
||||
[input]
|
||||
(string/replace input #"-([a-z])" (fn [[_ c]] (string/upper-case c))))
|
||||
|
||||
;; this is taken from frontend.rum, and should be properly abstracted
|
||||
(defn map-keys->camel-case
|
||||
"Stringifys all the keys of a cljs hashmap and converts them
|
||||
from kebab case to camel case. If :html-props option is specified,
|
||||
then rename the html properties values to their dom equivalent
|
||||
before conversion"
|
||||
[data & {:keys [html-props]}]
|
||||
(let [convert-to-camel (fn [[key value]]
|
||||
[(kebab-case->camel-case (name key)) value])]
|
||||
(w/postwalk (fn [x]
|
||||
(if (map? x)
|
||||
(let [new-map (if html-props
|
||||
(set/rename-keys x {:class :className :for :htmlFor})
|
||||
x)]
|
||||
(into {} (map convert-to-camel new-map)))
|
||||
x))
|
||||
data)))
|
||||
|
||||
;; this is taken from frontend.rum, and should be properly abstracted
|
||||
(defn adapt-class
|
||||
([react-class]
|
||||
(adapt-class react-class false))
|
||||
([react-class skip-opts-transform?]
|
||||
(fn [& args]
|
||||
(let [[opts children] (if (map? (first args))
|
||||
[(first args) (rest args)]
|
||||
[{} args])
|
||||
type# (first children)
|
||||
;; we have to make sure to check if the children is sequential
|
||||
;; as a list can be returned, eg: from a (for)
|
||||
new-children (if (sequential? type#)
|
||||
(let [result (interpreter/interpret children)]
|
||||
(if (sequential? result)
|
||||
result
|
||||
[result]))
|
||||
children)
|
||||
;; convert any options key value to a react element, if
|
||||
;; a valid html element tag is used, using sablono
|
||||
vector->react-elems (fn [[key val]]
|
||||
(if (sequential? val)
|
||||
[key (interpreter/interpret val)]
|
||||
[key val]))
|
||||
new-options (into {}
|
||||
(if skip-opts-transform?
|
||||
opts
|
||||
(map vector->react-elems opts)))]
|
||||
(apply js/React.createElement react-class
|
||||
;; sablono html-to-dom-attrs does not work for nested hashmaps
|
||||
(bean/->js (map-keys->camel-case new-options :html-props true))
|
||||
new-children)))))
|
||||
|
||||
(def get-adapt-icon-class
|
||||
(memoize (fn [klass] (adapt-class klass))))
|
||||
|
||||
(rum/defc root
|
||||
([name] (root name nil))
|
||||
([name {:keys [extension? font? class] :as opts}]
|
||||
(when-not (string/blank? name)
|
||||
(let [^js jsTablerIcons (gobj/get js/window "tablerIcons")]
|
||||
(if (or extension? font? (not jsTablerIcons))
|
||||
[:span.ui__icon (merge {:class
|
||||
(gstring/format
|
||||
(str "%s-" name
|
||||
(when (:class opts)
|
||||
(str " " (string/trim (:class opts)))))
|
||||
(if extension? "tie tie" "ti ti"))}
|
||||
(dissoc opts :class :extension? :font?))]
|
||||
|
||||
;; tabler svg react
|
||||
(when-let [klass (gobj/get js/tablerIcons (str "Icon" (csk/->PascalCase name)))]
|
||||
(let [f (get-adapt-icon-class klass)]
|
||||
[:span.ui__icon.ti
|
||||
{:class (str "ls-icon-" name " " class)}
|
||||
(f (merge {:size 18} (map-keys->camel-case (dissoc opts :class))))])))))))
|
|
@ -1,5 +1,6 @@
|
|||
.shui__button {
|
||||
@apply bg-gradient-to-br from-red-500 via-green-500 to-blue-500 py-0.5 px-2 rounded-lg text-sm font-medium relative;
|
||||
@apply font-medium relative flex items-center justify-center gap-1;
|
||||
border-radius: 0.25rem;
|
||||
/* box-shadow: inset 0 2px 0 0px rgba(255, 255, 255, 0.2), */
|
||||
/* inset 0 -2px 0 0px rgba(0, 0, 0, 0.1); */
|
||||
/* background-image: linear-gradient(white, white), */
|
||||
|
@ -8,8 +9,29 @@
|
|||
/* background-clip: content-box, border-box; */
|
||||
}
|
||||
|
||||
.shui__button:before {
|
||||
@apply absolute inset-0 rounded-lg;
|
||||
.shui__button-size-sm {
|
||||
@apply text-xs py-1 px-2;
|
||||
}
|
||||
|
||||
.shui__button-size-md {
|
||||
@apply text-sm py-1 px-3;
|
||||
}
|
||||
|
||||
.shui__button-theme-color {
|
||||
background: or(--lx-accent-09, --ls-active-primary-color);
|
||||
}
|
||||
|
||||
.shui__button-theme-gray {
|
||||
background: or(--lx-gray-05, --ls-quaternary-background-color);
|
||||
}
|
||||
|
||||
.shui__button-theme-gradient {
|
||||
background: linear-gradient(-65deg, #8AE8FF, #5373E7, #369EFF, #00B1CC);
|
||||
}
|
||||
|
||||
.shui__button-depth-1:before {
|
||||
@apply absolute inset-0;
|
||||
border-radius: 0.25rem;
|
||||
content: "";
|
||||
padding: 1px;
|
||||
background: linear-gradient(to bottom, rgba(255,255,255,0.3), transparent);
|
||||
|
@ -17,16 +39,11 @@
|
|||
linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
/* background-image: linear-gradient(to bottom, white, transparent); */
|
||||
/* background-clip: border-box, padding-box; */
|
||||
/* padding: 1px; */
|
||||
/* border: 1px solid transparent; */
|
||||
/* border: 1px solid; */
|
||||
/* border-image: linear-gradient(to bottom, black, transparent) 1; */
|
||||
}
|
||||
|
||||
.shui__button:after {
|
||||
@apply absolute inset-0 rounded-lg;
|
||||
.shui__button-depth-1:after {
|
||||
@apply absolute inset-0;
|
||||
border-radius: 0.25rem;
|
||||
content: "";
|
||||
padding: 1px;
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.2), transparent);
|
||||
|
@ -34,8 +51,49 @@
|
|||
linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
/* @apply absolute inset-0 rounded-lg; */
|
||||
/* content: ""; */
|
||||
/* border: 1px solid; */
|
||||
/* border-image: linear-gradient(to top, white, transparent) 1; */
|
||||
}
|
||||
|
||||
.shui__button-depth-2:before {
|
||||
@apply absolute inset-0;
|
||||
border-radius: 0.25rem;
|
||||
content: "";
|
||||
padding: 1px;
|
||||
background: linear-gradient(to bottom, rgba(255,255,255,0.6), transparent);
|
||||
-webkit-mask: linear-gradient(#fff 0 0) content-box,
|
||||
linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
}
|
||||
|
||||
.shui__button-depth-2:after {
|
||||
@apply absolute inset-0;
|
||||
border-radius: 0.25rem;
|
||||
content: "";
|
||||
padding: 1px;
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.4), transparent);
|
||||
-webkit-mask: linear-gradient(#fff 0 0) content-box,
|
||||
linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
}
|
||||
|
||||
.shui__button-shortcut-key:first-of-type {
|
||||
@apply ml-2;
|
||||
}
|
||||
|
||||
.shui__button-shortcut-key {
|
||||
@apply text-xs font-normal bg-white/10 h-5 w-5 flex items-center justify-center rounded;
|
||||
}
|
||||
|
||||
.shui__cmdk-quick-capture-glow::before {
|
||||
@apply absolute inset-0;
|
||||
pointer-events: none;
|
||||
border-radius: 0.25rem;
|
||||
content: "";
|
||||
padding: 1px;
|
||||
background: linear-gradient(to bottom, var(--lx-accent-10), transparent);
|
||||
-webkit-mask: linear-gradient(#fff 0 0) content-box,
|
||||
linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
}
|
||||
|
|
|
@ -412,11 +412,12 @@
|
|||
:label "ls-modal-search"}))
|
||||
|
||||
(defmethod handle :go/cmdk [_]
|
||||
(js/alert "handle cmdk")
|
||||
(state/set-modal! cmdk
|
||||
{:fullscreen? false
|
||||
:close-btn? false
|
||||
:label "ls-modal-cmdk"}))
|
||||
(when-not (= cmdk (:modal/panel-content @state/state))
|
||||
(state/set-modal! cmdk
|
||||
{:fullscreen? false
|
||||
:close-btn? false
|
||||
:label "ls-modal-cmdk"
|
||||
:shui? true})))
|
||||
|
||||
(defmethod handle :go/plugins [_]
|
||||
(plugin/open-plugins-modal!))
|
||||
|
|
|
@ -22,4 +22,5 @@
|
|||
(make-context {:block-config block-config
|
||||
:app-config (state/get-config)
|
||||
:inline inline
|
||||
:int->local-time-2 int->local-time-2}))
|
||||
:int->local-time-2 int->local-time-2
|
||||
:state state/state}))
|
||||
|
|
|
@ -1350,7 +1350,7 @@ Similar to re-frame subscriptions"
|
|||
(set-modal! modal-panel-content
|
||||
{:fullscreen? false
|
||||
:close-btn? true}))
|
||||
([modal-panel-content {:keys [id label fullscreen? close-btn? close-backdrop? center?]}]
|
||||
([modal-panel-content {:keys [id label fullscreen? close-btn? close-backdrop? center? shui?]}]
|
||||
(let [opened? (modal-opened?)]
|
||||
(when opened?
|
||||
(close-modal!))
|
||||
|
@ -1367,7 +1367,8 @@ Similar to re-frame subscriptions"
|
|||
:modal/panel-content modal-panel-content
|
||||
:modal/fullscreen? fullscreen?
|
||||
:modal/close-btn? close-btn?
|
||||
:modal/close-backdrop? (if (boolean? close-backdrop?) close-backdrop? true))))
|
||||
:modal/close-backdrop? (if (boolean? close-backdrop?) close-backdrop? true)
|
||||
:modal/shui? shui?)))
|
||||
nil))
|
||||
|
||||
(defn close-modal!
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
[camel-snake-kebab.core :as csk]
|
||||
[cljs-bean.core :as bean]
|
||||
[clojure.string :as string]
|
||||
[frontend.shui :refer [make-shui-context]]
|
||||
[datascript.core :as d]
|
||||
[electron.ipc :as ipc]
|
||||
[frontend.components.svg :as svg]
|
||||
|
@ -584,11 +585,13 @@
|
|||
|
||||
(rum/defc modal-panel-content <
|
||||
mixins/component-editing-mode
|
||||
[panel-content close-fn]
|
||||
(panel-content close-fn))
|
||||
[panel-content close-fn shui?]
|
||||
(if shui?
|
||||
(panel-content {:close-fn close-fn} (make-shui-context nil nil))
|
||||
(panel-content close-fn)))
|
||||
|
||||
(rum/defc modal-panel
|
||||
[show? panel-content transition-state close-fn fullscreen? close-btn?]
|
||||
[show? panel-content transition-state close-fn fullscreen? close-btn? shui?]
|
||||
[:div.ui__modal-panel.transform.transition-all.sm:min-w-lg.sm
|
||||
{:class (case transition-state
|
||||
"entering" "ease-out duration-300 opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
|
@ -611,7 +614,7 @@
|
|||
|
||||
(when show?
|
||||
[:div {:class (if fullscreen? "" "panel-content")}
|
||||
(modal-panel-content panel-content close-fn)])])
|
||||
(modal-panel-content panel-content close-fn shui?)])])
|
||||
|
||||
(rum/defc modal < rum/reactive
|
||||
(mixins/event-mixin
|
||||
|
@ -637,6 +640,7 @@
|
|||
close-backdrop? (state/sub :modal/close-backdrop?)
|
||||
show? (state/sub :modal/show?)
|
||||
label (state/sub :modal/label)
|
||||
shui? (state/sub :modal/shui?)
|
||||
close-fn (fn []
|
||||
(state/close-modal!)
|
||||
(state/close-settings!))
|
||||
|
@ -651,7 +655,7 @@
|
|||
(css-transition
|
||||
{:in show? :timeout 0}
|
||||
(fn [state]
|
||||
(modal-panel show? modal-panel-content state close-fn fullscreen? close-btn?)))]))
|
||||
(modal-panel show? modal-panel-content state close-fn fullscreen? close-btn? shui?)))]))
|
||||
|
||||
(defn make-confirm-modal
|
||||
[{:keys [tag title sub-title sub-checkbox? on-cancel on-confirm]
|
||||
|
@ -724,7 +728,7 @@
|
|||
(css-transition
|
||||
{:in show? :timeout 0}
|
||||
(fn [state]
|
||||
(modal-panel show? modal-panel-content state close-fn false close-btn?)))]))))
|
||||
(modal-panel show? modal-panel-content state close-fn false close-btn? false)))]))))
|
||||
|
||||
(defn loading
|
||||
([] (loading (t :loading)))
|
||||
|
|
Loading…
Reference in New Issue