diff --git a/deps/db/src/logseq/db/common/sqlite.cljs b/deps/db/src/logseq/db/common/sqlite.cljs index 3c01af14da..34fc2afade 100644 --- a/deps/db/src/logseq/db/common/sqlite.cljs +++ b/deps/db/src/logseq/db/common/sqlite.cljs @@ -330,9 +330,7 @@ views all-files pages-datoms))] - (prn :debug "db-graph?" db-graph?) - (prn :debug "block/journal-day schema" (str (:block/journal-day (:schema db)))) - {:schema (assoc schema :block/journal-day {:db/index true}) + {:schema schema :initial-data data})) (defn restore-initial-data diff --git a/deps/db/src/logseq/db/file_based/schema.cljs b/deps/db/src/logseq/db/file_based/schema.cljs index b111d2565e..00e3beb83e 100644 --- a/deps/db/src/logseq/db/file_based/schema.cljs +++ b/deps/db/src/logseq/db/file_based/schema.cljs @@ -45,7 +45,8 @@ ;; for pages :block/alias {:db/valueType :db.type/ref - :db/cardinality :db.cardinality/many} + :db/cardinality :db.cardinality/many + :db/index true} ;; todo keywords, e.g. "TODO", "DOING", "DONE" :block/marker {} diff --git a/deps/shui/src/logseq/shui/ui.cljs b/deps/shui/src/logseq/shui/ui.cljs index 0acfa454ea..def5f40bbb 100644 --- a/deps/shui/src/logseq/shui/ui.cljs +++ b/deps/shui/src/logseq/shui/ui.cljs @@ -53,6 +53,7 @@ (def tooltip-portal (util/lsui-wrap "TooltipPortal")) (def tooltip-content (util/lsui-wrap "TooltipContent")) (def tooltip-provider (util/lsui-wrap "TooltipProvider")) +(def tooltip-arrow (util/lsui-wrap "TooltipArrow")) (def card (util/lsui-wrap "Card")) (def card-header (util/lsui-wrap "CardHeader")) diff --git a/package.json b/package.json index ee828984d0..26be8c51d7 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,9 @@ "del": "^6.0.0", "glob": "9.0.0", "gulp": "^4.0.2", - "gulp-replace": "^1.1.4", "gulp-postcss": "^10.0.0", + "gulp-replace": "^1.1.4", "ip": "1.1.9", - "semver": "7.5.2", "karma": "^6.4.4", "karma-chrome-launcher": "^3.2.0", "karma-cljs-test": "^0.1.0", @@ -33,6 +32,7 @@ "postcss-import-ext-glob": "2.0.1", "postcss-nested": "6.0.0", "purgecss": "4.0.2", + "semver": "7.5.2", "shadow-cljs": "2.26.0", "stylelint": "^13.8.0", "stylelint-config-standard": "^20.0.0", @@ -161,7 +161,6 @@ "react-intersection-observer": "^9.3.5", "react-resize-context": "3.0.0", "react-textarea-autosize": "8.3.3", - "react-tippy": "1.4.0", "react-transition-group": "4.3.0", "react-virtuoso": "4.12.5", "remove-accents": "0.4.2", diff --git a/src/main/frontend/commands.cljs b/src/main/frontend/commands.cljs index ee19b85269..eda82796bb 100644 --- a/src/main/frontend/commands.cljs +++ b/src/main/frontend/commands.cljs @@ -241,19 +241,16 @@ (if db-based? (db-based-statuses) (file-based-statuses)) - (mapv (fn [m] - (let [command (if db-based? - [:div.flex.flex-row.items-center.gap-2 m [:div.text-xs.opacity-50 "Status"]] - m) - icon (if db-based? - (case m + (mapv (fn [command] + (let [icon (if db-based? + (case command "Canceled" "Cancelled" "Doing" "InProgress50" - m) + command) "square-asterisk")] - [command (->marker m) (str "Set status to " m) icon]))))] + [command (->marker command) (str "Set status to " command) icon]))))] (when (seq result) - (map (fn [v] (conj v "TASK")) result)))) + (map (fn [v] (conj v "TASK STATUS")) result)))) (defn file-based-priorities [] @@ -273,17 +270,17 @@ (db-based-priorities) (file-based-priorities)) (mapv (fn [item] - (let [command (if db-based? - [:div.flex.flex-row.items-center.gap-2 item [:div.text-xs.opacity-50 "Priority"]] - item)] - [command (->priority item) (str "Set priority to " item) + (let [command item] + [command + (->priority item) + (str "Set priority to " item) (if db-based? (str "priorityLvl" item) (str "circle-letter-" (util/safe-lower-case item)))]))) (with-no-priority) (vec))] (when (seq result) - (map (fn [v] (conj v "PRIORITY")) result)))) + (map (fn [v] (into v ["PRIORITY"])) result)))) ;; Credits to roamresearch.com @@ -297,7 +294,7 @@ [] (mapv (fn [level] (let [heading (str "Heading " level)] - [heading (->heading level) heading (str "h-" level)])) (range 1 7))) + [heading (->heading level) heading (str "h-" level) "Heading"])) (range 1 7))) (defonce *matched-commands (atom nil)) (defonce *initial-commands (atom nil)) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index ce750bf85f..d90e63c15d 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -1068,7 +1068,7 @@ (contains? config/video-formats asset-type)))) (declare block-positioned-properties) -(rum/defc page-reference < rum/reactive +(rum/defc page-reference < rum/reactive db-mixins/query "Component for page reference" [html-export? uuid-or-title* {:keys [nested-link? show-brackets? id] :as config} label] (when uuid-or-title* @@ -1077,7 +1077,8 @@ uuid-or-title*) show-brackets? (if (some? show-brackets?) show-brackets? (state/show-brackets?)) contents-page? (= "contents" (string/lower-case (str id))) - block (db/get-page uuid-or-title) + block* (db/get-page uuid-or-title) + block (or (some-> (:db/id block*) db/sub-block) block*) config' (assoc config :label (mldoc/plain->text label) :contents-page? contents-page? diff --git a/src/main/frontend/components/container.cljs b/src/main/frontend/components/container.cljs index c884234aa4..21a5b955bc 100644 --- a/src/main/frontend/components/container.cljs +++ b/src/main/frontend/components/container.cljs @@ -782,19 +782,20 @@ (rum/defc new-block-mode < rum/reactive [] (when (state/sub [:document/mode?]) - (ui/tippy {:html [:div.p-2 - [:p.mb-2 [:b "Document mode"]] - [:ul - [:li - [:div.inline-block.mr-1 (ui/render-keyboard-shortcut (shortcut-dh/gen-shortcut-seq :editor/new-line))] - [:p.inline-block "to create new block"]] - [:li - [:p.inline-block.mr-1 "Click `D` or type"] - [:div.inline-block.mr-1 (ui/render-keyboard-shortcut (shortcut-dh/gen-shortcut-seq :ui/toggle-document-mode))] - [:p.inline-block "to toggle document mode"]]]]} - [:a.block.px-1.text-sm.font-medium.bg-base-2.rounded-md.mx-2 - {:on-click state/toggle-document-mode!} - "D"]))) + (ui/tooltip + [:a.block.px-1.text-sm.font-medium.bg-base-2.rounded-md.mx-2 + {:on-click state/toggle-document-mode!} + "D"] + [:div.p-2 + [:p.mb-2 [:b "Document mode"]] + [:ul + [:li + [:div.inline-block.mr-1 (ui/render-keyboard-shortcut (shortcut-dh/gen-shortcut-seq :editor/new-line))] + [:p.inline-block "to create new block"]] + [:li + [:p.inline-block.mr-1 "Click `D` or type"] + [:div.inline-block.mr-1 (ui/render-keyboard-shortcut (shortcut-dh/gen-shortcut-seq :ui/toggle-document-mode))] + [:p.inline-block "to toggle document mode"]]]]))) (def help-menu-items [{:title "Handbook" :icon "book-2" :on-click #(handbooks/toggle-handbooks)} diff --git a/src/main/frontend/components/editor.cljs b/src/main/frontend/components/editor.cljs index 0fd6f1ca2e..9ce0cd5e26 100644 --- a/src/main/frontend/components/editor.cljs +++ b/src/main/frontend/components/editor.cljs @@ -45,7 +45,7 @@ (or (= "Add new property" (first item)) (when (= (count item) 5) - (contains? #{"TASK" "PRIORITY"} (last item))))) commands) + (contains? #{"TASK STATUS" "PRIORITY"} (last item))))) commands) commands)) (rum/defcs commands < rum/reactive @@ -56,63 +56,59 @@ _ (when (state/get-editor-action) (reset! *matched matched')) page? (db/page? (db/entity (:db/id (state/get-edit-block)))) - matched (filter-commands page? @*matched)] + matched (filter-commands page? @*matched) + filtered? (not= matched @commands/*initial-commands)] (ui/auto-complete matched - {:get-group-name - (fn [item] - (when (= (count item) 5) (last item))) + (cond-> + {:item-render + (fn [item] + (let [command-name (first item) + command-doc (get item 2) + plugin-id (get-in item [1 1 1 :pid]) + doc (when (state/show-command-doc?) command-doc) + options (some-> item (get 3)) + icon-name (some-> (if (map? options) (:icon options) options) (name)) + command-name (if icon-name + [:span.flex.items-center.gap-1 + (shui/tabler-icon icon-name) + [:strong.font-normal command-name]] + command-name)] + (cond + (or plugin-id (vector? doc)) + [:div.has-help + {:title plugin-id} + command-name + (when doc (ui/tooltip [:small (svg/help-circle)] doc))] - :item-render - (fn [item] - (let [command-name (first item) - command-doc (get item 2) - plugin-id (get-in item [1 1 1 :pid]) - doc (when (state/show-command-doc?) command-doc) - options (some-> item (get 3)) - icon-name (some-> (if (map? options) (:icon options) options) (name)) - command-name (if icon-name - [:span.flex.items-center.gap-1 - (shui/tabler-icon icon-name) - [:strong.font-normal command-name]] - command-name)] - (cond - (or plugin-id (vector? doc)) - [:div.has-help - {:title plugin-id} - command-name - (when doc (ui/tippy - {:html doc - :interactive true - :fixed-position? true - :position "right"} + (string? doc) + [:div {:title doc} + command-name] - [:small (svg/help-circle)]))] + :else + [:div command-name]))) - (string? doc) - [:div {:title doc} - command-name] - - :else - [:div command-name]))) - - :on-chosen - (fn [chosen-item] - (let [command (first chosen-item)] - (reset! commands/*current-command command) - (let [command-steps (get (into {} matched) command) - restore-slash? (or - (contains? #{"Today" "Yesterday" "Tomorrow" "Current time"} command) - (and - (not (fn? command-steps)) - (not (contains? (set (map first command-steps)) :editor/input)) - (not (contains? #{"Date picker" "Template" "Deadline" "Scheduled" "Upload an image"} command))))] - (editor-handler/insert-command! id command-steps - format - {:restore? restore-slash? - :command command})))) - :class - "cp__commands-slash"}))) + :on-chosen + (fn [chosen-item] + (let [command (first chosen-item)] + (reset! commands/*current-command command) + (let [command-steps (get (into {} matched) command) + restore-slash? (or + (contains? #{"Today" "Yesterday" "Tomorrow" "Current time"} command) + (and + (not (fn? command-steps)) + (not (contains? (set (map first command-steps)) :editor/input)) + (not (contains? #{"Date picker" "Template" "Deadline" "Scheduled" "Upload an image"} command))))] + (editor-handler/insert-command! id command-steps + format + {:restore? restore-slash? + :command command})))) + :class + "cp__commands-slash"} + (not filtered?) + (assoc :get-group-name + (fn [item] + (when (= (count item) 5) (last item)))))))) (defn- page-on-chosen-handler [embed? input id q pos format] diff --git a/src/main/frontend/components/file_based/block.cljs b/src/main/frontend/components/file_based/block.cljs index 47f435d2f3..cb54f1c39d 100644 --- a/src/main/frontend/components/file_based/block.cljs +++ b/src/main/frontend/components/file_based/block.cljs @@ -81,10 +81,9 @@ (defn priority-cp [{:block/keys [pre-block? priority] :as block}] (when (and (not pre-block?) priority) - (ui/tippy - {:interactive true - :html (set-priority block priority)} - (priority-text priority)))) + (ui/tooltip + (priority-text priority) + (set-priority block priority)))) (defn clock-summary-cp [block body] @@ -96,22 +95,20 @@ (not= summary "0m") (not (string/blank? summary))) [:div {:style {:max-width 100}} - (ui/tippy {:html (fn [] - (when-let [logbook (drawer/get-logbook body)] - (let [clocks (->> (last logbook) - (filter #(string/starts-with? % "CLOCK:")) - (remove string/blank?))] - [:div.p-4 - [:div.font-bold.mb-2 "LOGBOOK:"] - [:ul - (for [clock (take 10 (reverse clocks))] - [:li clock])]]))) - :interactive true - :in-editor? true - :delay [1000, 100]} - [:div.text-sm.time-spent.ml-1 {:style {:padding-top 3}} - [:a.fade-link - summary]])])))) + (ui/tooltip + [:div.text-sm.time-spent.ml-1 {:style {:padding-top 3}} + [:a.fade-link + summary]] + + (when-let [logbook (drawer/get-logbook body)] + (let [clocks (->> (last logbook) + (filter #(string/starts-with? % "CLOCK:")) + (remove string/blank?))] + [:div.p-4 + [:div.font-bold.mb-2 "LOGBOOK:"] + [:ul + (for [clock (take 10 (reverse clocks))] + [:li clock])]])))])))) (rum/defc timestamp-editor [ast *show-datapicker?] diff --git a/src/main/frontend/components/file_based/query.cljs b/src/main/frontend/components/file_based/query.cljs index ff04e3dcef..57337980b3 100644 --- a/src/main/frontend/components/file_based/query.cljs +++ b/src/main/frontend/components/file_based/query.cljs @@ -10,22 +10,17 @@ (rum/defc query-refresh-button [query-time {:keys [on-pointer-down full-text-search?]}] - (ui/tippy - {:html [:div - [:p - (if full-text-search? - [:span "Full-text search results will not be refreshed automatically."] - [:span (str "This query takes " (int query-time) "ms to finish, it's a bit slow so that auto refresh is disabled.")])] - [:p - "Click the refresh button instead if you want to see the latest result."]] - :interactive true - :popperOptions {:modifiers {:preventOverflow - {:enabled true - :boundariesElement "viewport"}}} - :arrow true} - [:a.fade-link.flex - {:on-pointer-down on-pointer-down} - (ui/icon "refresh" {:style {:font-size 20}})])) + (ui/tooltip + [:a.fade-link.flex + {:on-pointer-down on-pointer-down} + (ui/icon "refresh" {:style {:font-size 20}})] + [:div + [:p + (if full-text-search? + [:span "Full-text search results will not be refreshed automatically."] + [:span (str "This query takes " (int query-time) "ms to finish, it's a bit slow so that auto refresh is disabled.")])] + [:p + "Click the refresh button instead if you want to see the latest result."]])) ;; Custom query header only used by file graphs (rum/defc custom-query-header diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index 7cc014175e..d5feabca84 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -908,30 +908,35 @@ (reset! *excluded-pages? value) (set-setting! :excluded-pages? value))) true)]] + (when (config/db-based-graph? (state/get-current-repo)) [:div.flex.flex-col.mb-2 [:p "Created before"] (when created-at-filter [:div (.toDateString (js/Date. (+ created-at-filter (get-in graph [:all-pages :created-at-min]))))]) - (ui/tippy {:html [:div.pr-3 (str (js/Date. (+ created-at-filter (get-in graph [:all-pages :created-at-min]))))]} - ;; Slider keeps track off the range from min created-at to max created-at - ;; because there were bugs with setting min and max directly - (ui/slider created-at-filter - {:min 0 - :max (- (get-in graph [:all-pages :created-at-max]) - (get-in graph [:all-pages :created-at-min])) - :on-change #(do - (reset! *created-at-filter (int %)) - (set-setting! :created-at-filter (int %)))}))]) + + (ui/tooltip + ;; Slider keeps track off the range from min created-at to max created-at + ;; because there were bugs with setting min and max directly + (ui/slider created-at-filter + {:min 0 + :max (- (get-in graph [:all-pages :created-at-max]) + (get-in graph [:all-pages :created-at-min])) + :on-change #(do + (reset! *created-at-filter (int %)) + (set-setting! :created-at-filter (int %)))}) + [:div.px-1 (str (js/Date. (+ created-at-filter (get-in graph [:all-pages :created-at-min]))))])]) + (when (seq focus-nodes) [:div.flex.flex-col.mb-2 [:p {:title "N hops from selected nodes"} "N hops from selected nodes"] - (ui/tippy {:html [:div.pr-3 n-hops]} - (ui/slider (or n-hops 10) - {:min 1 - :max 10 - :on-change #(reset! *n-hops (int %))}))]) + (ui/tooltip + (ui/slider (or n-hops 10) + {:min 1 + :max 10 + :on-change #(reset! *n-hops (int %))}) + [:div n-hops])]) [:a.opacity-70.opacity-100 {:on-click (fn [] (swap! *graph-reset? not) @@ -977,39 +982,45 @@ [:div.flex.flex-col.mb-2 [:p {:title "Link Distance"} "Link Distance"] - (ui/tippy {:html [:div.pr-3 link-dist]} - (ui/slider (/ link-dist 10) - {:min 1 ;; 10 - :max 18 ;; 180 - :on-change #(let [value (int %)] - (reset! *link-dist (* value 10)) - (set-forcesetting! :link-dist (* value 10)))}))] + (ui/tooltip + (ui/slider (/ link-dist 10) + {:min 1 ;; 10 + :max 18 ;; 180 + :on-change #(let [value (int %)] + (reset! *link-dist (* value 10)) + (set-forcesetting! :link-dist (* value 10)))}) + [:div link-dist])] + [:div.flex.flex-col.mb-2 [:p {:title "Charge Strength"} "Charge Strength"] - (ui/tippy {:html [:div.pr-3 charge-strength]} - (ui/slider (/ charge-strength 100) - {:min -10 ;;-1000 - :max 10 ;;1000 - :on-change #(let [value (int %)] - (reset! *charge-strength (* value 100)) - (set-forcesetting! :charge-strength (* value 100)))}))] + (ui/tooltip + (ui/slider (/ charge-strength 100) + {:min -10 ;;-1000 + :max 10 ;;1000 + :on-change #(let [value (int %)] + (reset! *charge-strength (* value 100)) + (set-forcesetting! :charge-strength (* value 100)))}) + [:div charge-strength])] + [:div.flex.flex-col.mb-2 [:p {:title "Charge Range"} "Charge Range"] - (ui/tippy {:html [:div.pr-3 charge-range]} - (ui/slider (/ charge-range 100) - {:min 5 ;;500 - :max 40 ;;4000 - :on-change #(let [value (int %)] - (reset! *charge-range (* value 100)) - (set-forcesetting! :charge-range (* value 100)))}))] + (ui/tooltip + (ui/slider (/ charge-range 100) + {:min 5 ;;500 + :max 40 ;;4000 + :on-change #(let [value (int %)] + (reset! *charge-range (* value 100)) + (set-forcesetting! :charge-range (* value 100)))}) + [:div charge-range])] - [:a.opacity-70.opacity-100 {:on-click (fn [] - (swap! *graph-forcereset? not) - (reset! *link-dist 70) - (reset! *charge-strength -600) - (reset! *charge-range 600))} + [:a + {:on-click (fn [] + (swap! *graph-forcereset? not) + (reset! *link-dist 70) + (reset! *charge-strength -600) + (reset! *charge-range 600))} "Reset Forces"]]])) {}) (graph-filter-section diff --git a/src/main/frontend/components/plugins.cljs b/src/main/frontend/components/plugins.cljs index ac67dd6b2d..80e1add4f3 100644 --- a/src/main/frontend/components/plugins.cljs +++ b/src/main/frontend/components/plugins.cljs @@ -585,14 +585,14 @@ (when (and develop-mode? (util/electron?) (not market?)) [:div - (ui/tippy {:html [:div (t :plugin/unpacked-tips)] - :arrow true} - (ui/button - (t :plugin/load-unpacked) - {:icon "upload" - :intent "link" - :class "load-unpacked" - :on-click plugin-handler/load-unpacked-plugin})) + (ui/tooltip + (ui/button + (t :plugin/load-unpacked) + {:icon "upload" + :intent "link" + :class "load-unpacked" + :on-click plugin-handler/load-unpacked-plugin}) + [:div (t :plugin/unpacked-tips)]) (when (util/electron?) (unpacked-plugin-loader selected-unpacked-pkg))])] @@ -1075,9 +1075,7 @@ [:div.px-4 (when-not (string/blank? notes) - (ui/tippy - {:html [:p notes]} - [:span.opacity-30.hover:opacity-80 (ui/icon "info-circle")]))]])] + (ui/tooltip [:span.opacity-30.hover:opacity-80 (ui/icon "info-circle")] [:p notes]))]])] ;; all done [:div.py-4 [:strong.text-4xl (str "\uD83C\uDF89 " (t :plugin/all-updated))]]) diff --git a/src/main/frontend/components/property.cljs b/src/main/frontend/components/property.cljs index d6795e3364..ec3078505c 100644 --- a/src/main/frontend/components/property.cljs +++ b/src/main/frontend/components/property.cljs @@ -145,11 +145,8 @@ (when (= "Enter" (.-key e)) (util/stop-propagation e)))} label))))) (when show-type-change-hints? - (ui/tippy {:html "Changing the property type clears some property configurations." - :class "tippy-hover ml-2" - :interactive true - :disabled false} - (svg/info)))])) + (ui/tooltip (svg/info) + [:span "Changing the property type clears some property configurations."]))])) (rum/defc property-select [exclude-properties select-opts] diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index 939317a404..a542623bb3 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -601,19 +601,17 @@ (dropdown-editor-menuitem {:icon :letter-t :title "Property type" :desc (if disabled?' - (ui/tippy {:html [:div.w-96 - "The type of this property is locked once you start using it. This is to make sure all your existing information stays correct if the property type is changed later. To unlock, all uses of a property must be deleted."] - :class "tippy-hover ml-2" - :interactive true - :disabled false} - (str property-type-label')) + (ui/tooltip + [:span (str property-type-label')] + [:div.w-96 + "The type of this property is locked once you start using it. This is to make sure all your existing information stays correct if the property type is changed later. To unlock, all uses of a property must be deleted."]) (str property-type-label')) :disabled? disabled?' :submenu-content (fn [ops] (property-type-sub-pane property ops))})) (when (and (= property-type :node) - (not (contains? #{:logseq.property/parent} (:db/ident property)))) + (not (contains? #{:logseq.property/parent} (:db/ident property)))) (dropdown-editor-menuitem {:icon :hash :disabled? disabled? :title "Specify node tags" diff --git a/src/main/frontend/components/settings.cljs b/src/main/frontend/components/settings.cljs index ec633b381f..12b2bf6962 100644 --- a/src/main/frontend/components/settings.cljs +++ b/src/main/frontend/components/settings.cljs @@ -381,13 +381,7 @@ :let [active? (= color color-accent) none? (= color :none)]] [:div.flex.items-center - (ui/tippy - {:html (case color - :none [:p {:style {:max-width "300px"}} - "Cancel accent color. This is currently in beta stage and mainly used for compatibility with custom themes."] - :logseq "Logseq classical color" - (str (name color) " color")) - :delay [1000, 100]} + (ui/tooltip (shui/button {:class "w-5 h-5 px-1 rounded-full flex justify-center items-center transition ease-in duration-100 hover:cursor-pointer hover:opacity-100" :auto-focus (and _in-modal? active?) @@ -402,7 +396,13 @@ {:class (if none? "h-0.5 w-full bg-red-700" "w-2 h-2 rounded-full transition ease-in duration-100") :style {:background-color (if-not none? (str "var(--rx-" (name color) "-07)") "") - :opacity (if (or none? active?) 1 0)}}]))])]] + :opacity (if (or none? active?) 1 0)}}]) + + (case color + :none [:p {:style {:max-width "300px"}} + "Cancel accent color. This is currently in beta stage and mainly used for compatibility with custom themes."] + :logseq "Logseq classical color" + (str (name color) " color")))])]] [:div (row-with-button-action @@ -431,11 +431,8 @@ {:for "custom_date_format"} (t :settings-page/custom-date-format) (when-not (config/db-based-graph? (state/get-current-repo)) - (ui/tippy {:html (t :settings-page/custom-date-format-warning) - :class "tippy-hover ml-2" - :interactive true - :disabled false} - (svg/info)))] + (ui/tooltip [:span.flex.px-2 (svg/info)] + [:span (t :settings-page/custom-date-format-warning)]))] [:div.mt-1.sm:mt-0.sm:col-span-2 [:div.max-w-lg.rounded-md [:select.form-select.is-small @@ -484,11 +481,8 @@ (defn outdenting-row [t logical-outdenting?] (toggle "preferred_outdenting" [(t :settings-page/preferred-outdenting) - (ui/tippy {:html (outdenting-hint) - :class "tippy-hover ml-2" - :interactive true - :disabled false} - (svg/info))] + (ui/tooltip [:span.flex.px-2 (svg/info)] + (outdenting-hint) {:content-props {:side "right"}})] logical-outdenting? config-handler/toggle-logical-outdenting!)) @@ -501,22 +495,16 @@ (defn preferred-pasting-file [t preferred-pasting-file?] (toggle "preferred_pasting_file" [(t :settings-page/preferred-pasting-file) - (ui/tippy {:html (t :settings-page/preferred-pasting-file-hint) - :class "tippy-hover ml-2" - :interactive true - :disabled false} - (svg/info))] + (ui/tooltip [:span.flex.px-2 (svg/info)] + [:span.block.w-64 (t :settings-page/preferred-pasting-file-hint)])] preferred-pasting-file? config-handler/toggle-preferred-pasting-file!)) (defn auto-expand-row [t auto-expand-block-refs?] (toggle "auto_expand_block_refs" [(t :settings-page/auto-expand-block-refs) - (ui/tippy {:html (auto-expand-hint) - :class "tippy-hover ml-2" - :interactive true - :disabled false} - (svg/info))] + (ui/tooltip [:span.flex.px-2 (svg/info)] + (auto-expand-hint))] auto-expand-block-refs? config-handler/toggle-auto-expand-block-refs!)) @@ -866,26 +854,23 @@ (row-with-button-action {:left-label (str (t :settings-page/sync-diff-merge) " (Experimental!)") ;; Not included in i18n to avoid outdating translations :action (sync-diff-merge-enabled-switcher enabled?) - :desc (ui/tippy {:html [:div - [:div (t :settings-page/sync-diff-merge-desc)] - [:div (t :settings-page/sync-diff-merge-warn)]] - :class "tippy-hover ml-2" - :interactive true - :disabled false} - (svg/info))})) + :desc (ui/tooltip [:span.inline-flex.px-1 (svg/info)] + [:div + [:div (t :settings-page/sync-diff-merge-desc)] + [:div (t :settings-page/sync-diff-merge-warn)]])})) (rum/defc rtc-enabled-switcher [enabled?] (ui/toggle enabled? - (fn [] - (let [value (not enabled?)] - (state/set-rtc-enabled! value))) - true)) + (fn [] + (let [value (not enabled?)] + (state/set-rtc-enabled! value))) + true)) (defn rtc-switcher-row [enabled?] (row-with-button-action - {:left-label "RTC" - :action (rtc-enabled-switcher enabled?)})) + {:left-label "RTC" + :action (rtc-enabled-switcher enabled?)})) (rum/defc whiteboards-enabled-switcher [enabled?] diff --git a/src/main/frontend/extensions/srs.cljs b/src/main/frontend/extensions/srs.cljs index bfb387c66d..7c2a236937 100644 --- a/src/main/frontend/extensions/srs.cljs +++ b/src/main/frontend/extensions/srs.cljs @@ -488,16 +488,17 @@ :on-click #(score-and-next-card 5 card card-index finished? phase review-records cb)})]) (when preview? - (ui/tippy {:html [:div.text-sm - (t :flashcards/modal-btn-reset-tip)] - :class "tippy-hover" - :interactive true} - (ui/button [:span (t :flashcards/modal-btn-reset)] - :id "card-reset" - :class (util/hiccup->class "opacity-60.hover:opacity-100.card-reset") - :on-click (fn [e] - (util/stop e) - (operation-reset! card)))))] + (ui/tooltip + (ui/button [:span (t :flashcards/modal-btn-reset)] + :id "card-reset" + :class (util/hiccup->class "opacity-60.hover:opacity-100.card-reset") + :on-click (fn [e] + (util/stop e) + (operation-reset! card))) + + [:div.text-sm + (t :flashcards/modal-btn-reset-tip)] + {:trigger-props {:as-child false}}))] [:div.my-3 (ui/button "Review cards" :small? true)])])))) (rum/defc view-modal < @@ -629,27 +630,20 @@ ;; FIXME: CSS issue (if @*preview-mode? - (ui/tippy {:html [:div.text-sm (t :flashcards/modal-current-total)] - :interactive true} - [:div.opacity-60.text-sm.mr-2 - @*card-index - [:span "/"] - total]) - (ui/tippy {:html [:div.text-sm (t :flashcards/modal-overdue-total)] - ;; :class "tippy-hover" - :interactive true} - [:div.opacity-60.text-sm.mr-2 - (max 0 (- filtered-total @*card-index)) - [:span "/"] - total])) - - (ui/tippy - {:html [:div.text-sm (t :flashcards/modal-toggle-preview-mode)] - :delay [1000, 100] - :class "tippy-hover" - :interactive true - :disabled false} + (ui/tooltip + [:div.opacity-60.text-sm.mr-2 + @*card-index + [:span "/"] + total] + [:div.text-sm (t :flashcards/modal-current-total)]) + (ui/tooltip + [:div.opacity-60.text-sm.mr-2 + (max 0 (- filtered-total @*card-index)) + [:span "/"] + total] + [:div.text-sm (t :flashcards/modal-overdue-total)])) + (ui/tooltip (ui/button (merge {:icon "letter-a" @@ -661,13 +655,11 @@ :button-props {:id "preview-all-cards"} :small? true} (when @*preview-mode? - {:icon-props {:style {:color "var(--ls-button-background)"}}})))) + {:icon-props {:style {:color "var(--ls-button-background)"}}}))) + [:div.text-sm (t :flashcards/modal-toggle-preview-mode)] + {:trigger-props {:as-child false}}) - (ui/tippy - {:html [:div.text-sm (t :flashcards/modal-toggle-random-mode)] - :delay [1000, 100] - :class "tippy-hover" - :interactive true} + (ui/tooltip (ui/button (merge {:icon "arrows-shuffle" @@ -677,7 +669,9 @@ (swap! *random-mode? not)) :small? true} (when @*random-mode? - {:icon-props {:style {:color "var(--ls-button-background)"}}}))))]] + {:icon-props {:style {:color "var(--ls-button-background)"}}}))) + [:div.text-sm (t :flashcards/modal-toggle-random-mode)] + {:trigger-props {:as-child false}})]] [:div.px-1 (when (and (not modal?) (not @*preview-mode?)) {:on-click (fn [] diff --git a/src/main/frontend/handler.cljs b/src/main/frontend/handler.cljs index 3fb2b748f3..347387c5ee 100644 --- a/src/main/frontend/handler.cljs +++ b/src/main/frontend/handler.cljs @@ -17,6 +17,7 @@ [frontend.error :as error] [frontend.handler.command-palette :as command-palette] [frontend.handler.events :as events] + [frontend.handler.events.ui] [frontend.handler.file-based.events] [frontend.handler.file-based.file :as file-handler] [frontend.handler.global-config :as global-config-handler] diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 6a39c91edb..6d629b9383 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -818,7 +818,7 @@ concat-prev-block? (let [children (:block/_parent (db/entity (:db/id block))) db-based? (config/db-based-graph? repo) - prev-block-is-not-parent? (not= (:block/uuid (:block/parent block)) (:block/uuid prev-block)) + prev-block-is-not-parent? (empty? (:block/_parent prev-block)) delete-prev-block? (and db-based? prev-block-is-not-parent? (empty? (:block/tags block)) diff --git a/src/main/frontend/handler/events.cljs b/src/main/frontend/handler/events.cljs index f8ab9bb804..786f016f3f 100644 --- a/src/main/frontend/handler/events.cljs +++ b/src/main/frontend/handler/events.cljs @@ -10,24 +10,7 @@ [clojure.core.async.interop :refer [p->c]] [clojure.string :as string] [frontend.commands :as commands] - [frontend.components.block :as block] - [frontend.components.cmdk.core :as cmdk] - [frontend.components.diff :as diff] - [frontend.components.encryption :as encryption] - [frontend.components.file-based.git :as git-component] - [frontend.components.file-sync :as file-sync] - [frontend.components.page :as component-page] - [frontend.components.plugins :as plugin] - [frontend.components.property.dialog :as property-dialog] - [frontend.components.repo :as repo] - [frontend.components.select :as select] - [frontend.components.selection :as selection] - [frontend.components.settings :as settings] - [frontend.components.shell :as shell] - [frontend.components.user.login :as login] - [frontend.components.whiteboard :as whiteboard] [frontend.config :as config] - [frontend.context.i18n :refer [t]] [frontend.date :as date] [frontend.db :as db] [frontend.db.async :as db-async] @@ -36,10 +19,7 @@ [frontend.db.persist :as db-persist] [frontend.db.transact :as db-transact] [frontend.extensions.fsrs :as fsrs] - [frontend.extensions.srs :as srs] [frontend.fs :as fs] - [frontend.fs.capacitor-fs :as capacitor-fs] - [frontend.fs.nfs :as nfs] [frontend.fs.sync :as sync] [frontend.fs.watcher-handler :as fs-watcher] [frontend.handler.assets :as assets-handler] @@ -50,8 +30,6 @@ [frontend.handler.db-based.rtc-flows :as rtc-flows] [frontend.handler.editor :as editor-handler] [frontend.handler.export :as export] - [frontend.handler.file-based.file :as file-handler] - [frontend.handler.file-based.nfs :as nfs-handler] [frontend.handler.file-sync :as file-sync-handler] [frontend.handler.graph :as graph-handler] [frontend.handler.notification :as notification] @@ -63,12 +41,9 @@ [frontend.handler.search :as search-handler] [frontend.handler.shell :as shell-handler] [frontend.handler.ui :as ui-handler] - [frontend.handler.user :as user-handler] [frontend.mobile.core :as mobile] - [frontend.mobile.graph-picker :as graph-picker] [frontend.mobile.util :as mobile-util] [frontend.modules.instrumentation.posthog :as posthog] - [frontend.modules.instrumentation.sentry :as sentry-event] [frontend.modules.outliner.pipeline :as pipeline] [frontend.modules.outliner.ui :as ui-outliner-tx] [frontend.modules.shortcut.core :as st] @@ -76,16 +51,11 @@ [frontend.quick-capture :as quick-capture] [frontend.search :as search] [frontend.state :as state] - [frontend.ui :as ui] [frontend.util :as util] [frontend.util.persist-var :as persist-var] [goog.dom :as gdom] [lambdaisland.glogi :as log] - [logseq.common.config :as common-config] - [logseq.common.util :as common-util] - [logseq.shui.ui :as shui] - [promesa.core :as p] - [rum.core :as rum])) + [promesa.core :as p])) ;; TODO: should we move all events here? @@ -96,54 +66,10 @@ (async/ (sync/c (persist-var/load-vars))) (async/c (rtc-handler/ - (p/let [exists? (fs/dir-exists? graph-path)] - (let [overwrite? (if exists? - (js/confirm (str "There's already a directory with the name \"" graph-name "\", do you want to overwrite it? Make sure to backup it first if you're not sure about it.")) - true)] - (if overwrite? - (p/let [_ (fs/mkdir-if-not-exists graph-path)] - (nfs-handler/ls-dir-files-with-path! - graph-path - {:ok-handler (fn [] - (file-sync-handler/init-remote-graph graph-path graph) - (js/setTimeout (fn [] (repo-handler/refresh-repos!)) 200))})) - (let [graph-name (-> (js/prompt "Please specify a new directory name to download the graph:") - str - string/trim)] - (when-not (string/blank? graph-name) - (state/pub-event! [:graph/pull-down-remote-graph graph graph-name])))))) - (p/catch (fn [^js e] - (notification/show! (str e) :error) - (js/console.error e))))))))) - (when (:GraphName graph) - (shui/dialog-open! - (file-sync/pick-dest-to-sync-panel graph))))) - -(defmethod handle :graph/pick-page-histories [[_ graph-uuid page-name]] - (shui/dialog-open! - (file-sync/pick-page-histories-panel graph-uuid page-name) - {:id :page-histories :label "modal-page-histories"})) - (defmethod handle :graph/open-new-window [[_ev target-repo]] (p/let [current-repo (state/get-current-repo)] (ui-handler/open-new-window-or-tab! current-repo target-repo))) @@ -261,67 +148,6 @@ (defmethod handle :graph/migrated [[_ _repo]] (js/alert "Graph migrated.")) -(defn get-local-repo - [] - (when-let [repo (state/get-current-repo)] - (when (config/local-file-based-graph? repo) - repo))) - -(defn ask-permission - [repo] - (when - (and (not (util/electron?)) - (not (mobile-util/native-platform?))) - (fn [{:keys [close]}] - [:div - ;; TODO: fn translation with args - [:p - "Grant native filesystem permission for directory: " - [:b (config/get-local-dir repo)]] - (ui/button - (t :settings-permission/start-granting) - :class "ui__modal-enter" - :on-click (fn [] - (nfs/check-directory-permission! repo) - (close)))]))) - -(defmethod handle :modal/nfs-ask-permission [] - (when-let [repo (get-local-repo)] - (some-> (ask-permission repo) - (shui/dialog-open! {:align :top})))) - -(defmethod handle :modal/show-cards [[_ cards-id]] - (let [db-based? (config/db-based-graph? (state/get-current-repo))] - (shui/dialog-open! - (if db-based? (fn [] (fsrs/cards-view cards-id)) srs/global-cards) - {:id :srs - :label "flashcards__cp"}))) - -(defmethod handle :modal/show-instruction [_] - (shui/dialog-open! - capacitor-fs/instruction - {:id :instruction - :label "instruction__cp"})) - -(defmethod handle :modal/show-themes-modal [[_ classic?]] - (if classic? - (plugin/open-select-theme!) - (route-handler/go-to-search! :themes))) - -(defmethod handle :ui/toggle-appearance [_] - (let [popup-id "appearance_settings"] - (if (gdom/getElement popup-id) - (shui/popup-hide! popup-id) - (shui/popup-show! - (js/document.querySelector ".toolbar-dots-btn") - (fn [] - (settings/appearance)) - {:id popup-id - :align :end})))) - -(defmethod handle :modal/set-git-username-and-email [[_ _content]] - (shui/dialog-open! git-component/set-git-username-and-email)) - (defmethod handle :page/create [[_ page-name opts]] (if (= page-name (date/today)) (page-handler/create-today-journal!) @@ -333,26 +159,10 @@ (defmethod handle :page/renamed [[_ repo data]] (page-common-handler/after-page-renamed! repo data)) -(defmethod handle :page/show-delete-dialog [[_ selected-rows ok-handler]] - (shui/dialog-open! - (component-page/batch-delete-dialog - selected-rows false - ok-handler))) - (defmethod handle :page/create-today-journal [[_ _repo]] (p/let [_ (page-handler/create-today-journal!)] (ui-handler/re-render-root!))) -(defmethod handle :file/not-matched-from-disk [[_ path disk-content db-content]] - (when-let [repo (state/get-current-repo)] - (shui/dialog-open! - #(diff/local-file repo path disk-content db-content) - {:label "diff__cp"}))) - -(defmethod handle :modal/display-file-version-selector [[_ versions path get-content]] - (shui/dialog-open! - #(git-component/file-version-selector versions path get-content))) - (defmethod handle :graph/sync-context [] (let [context {:dev? config/dev? :node-test? util/node-test? @@ -391,48 +201,6 @@ (export/auto-db-backup! repo {:backup-now? true}) (fs-watcher/load-graph-files! repo))))) -(defmethod handle :notification/show [[_ {:keys [content status clear?]}]] - (notification/show! content status clear?)) - -(defmethod handle :command/run [_] - (when (util/electron?) - (shui/dialog-open! shell/shell))) - -(defmethod handle :go/search [_] - (shui/dialog-open! - cmdk/cmdk-modal - {:id :ls-dialog-cmdk - :align :top - :content-props {:class "ls-dialog-cmdk"} - :close-btn? false})) - -(defmethod handle :go/plugins [_] - (plugin/open-plugins-modal!)) - -(defmethod handle :go/plugins-waiting-lists [_] - (plugin/open-waiting-updates-modal!)) - -(defmethod handle :go/plugins-from-file [[_ plugins]] - (plugin/open-plugins-from-file-modal! plugins)) - -(defmethod handle :go/install-plugin-from-github [[_]] - (shui/dialog-open! - (plugin/install-from-github-release-container))) - -(defmethod handle :go/plugins-settings [[_ pid nav? title]] - (when pid - (state/set-state! :plugin/focused-settings pid) - (state/set-state! :plugin/navs-settings? (not (false? nav?))) - (plugin/open-focused-settings-modal! title))) - -(defmethod handle :go/proxy-settings [[_ agent-opts]] - (shui/dialog-open! - (plugin/user-proxy-settings-container agent-opts) - {:id :https-proxy-panel :center? true :class "lg:max-w-2xl"})) - -(defmethod handle :redirect-to-home [_] - (page-handler/create-today-journal!)) - (defmethod handle :instrument [[_ {:keys [type payload] :as opts}]] (when-not (empty? (dissoc opts :type :payload)) (js/console.error "instrument data-map should only contains [:type :payload]")) @@ -557,57 +325,12 @@ (file-sync-restart!)))) (state/pub-event! [:graph/ready (state/get-current-repo)]))))) -(defmethod handle :plugin/consume-updates [[_ id prev-pending? updated?]] - (let [downloading? (:plugin/updates-downloading? @state/state) - auto-checking? (plugin-handler/get-auto-checking?)] - (when-let [coming (and (not downloading?) - (get-in @state/state [:plugin/updates-coming id]))] - (let [error-code (:error-code coming) - error-code (if (= error-code (str :no-new-version)) nil error-code) - title (:title coming)] - (when (and prev-pending? (not auto-checking?)) - (if-not error-code - (plugin/set-updates-sub-content! (str title "...") 0) - (notification/show! - (str "[Checked]<" title "> " error-code) :error))))) - - (if (and updated? downloading?) - ;; try to start consume downloading item - (if-let [next-coming (state/get-next-selected-coming-update)] - (plugin-handler/check-or-update-marketplace-plugin! - (assoc next-coming :only-check false :error-code nil) - (fn [^js e] (js/console.error "[Download Err]" next-coming e))) - (plugin-handler/close-updates-downloading)) - - ;; try to start consume pending item - (if-let [next-pending (second (first (:plugin/updates-pending @state/state)))] - (do - (println "Updates: take next pending - " (:id next-pending)) - (js/setTimeout - #(plugin-handler/check-or-update-marketplace-plugin! - (assoc next-pending :only-check true :auto-check auto-checking? :error-code nil) - (fn [^js e] - (notification/show! (.toString e) :error) - (js/console.error "[Check Err]" next-pending e))) 500)) - - ;; try to open waiting updates list - (do (when (and prev-pending? (not auto-checking?) - (seq (state/all-available-coming-updates))) - (plugin/open-waiting-updates-modal!)) - (plugin-handler/set-auto-checking! false)))))) - (defmethod handle :plugin/hook-db-tx [[_ {:keys [blocks tx-data] :as payload}]] (when-let [payload (and (seq blocks) (merge payload {:tx-data (map #(into [] %) tx-data)}))] (plugin-handler/hook-plugin-db :changed payload) (plugin-handler/hook-plugin-block-changes payload))) -(defmethod handle :plugin/loader-perf-tip [[_ {:keys [^js o _s _e]}]] - (when-let [opts (.-options o)] - (notification/show! - (plugin/perf-tip-content (.-id o) (.-name opts) (.-url opts)) - :warning false (.-id o)))) - (defmethod handle :mobile-file-watcher/changed [[_ ^js event]] (let [type (.-event event) payload (js->clj event :keywordize-keys true)] @@ -621,51 +344,6 @@ (defmethod handle :shortcut/refresh [[_]] (st/refresh!)) -(defn- refresh-cb [] - (page-handler/create-today-journal!) - (file-sync-restart!)) - -(defmethod handle :graph/ask-for-re-fresh [_] - (shui/dialog-open! - [:div {:style {:max-width 700}} - [:p (t :sync-from-local-changes-detected)] - [:div.flex.justify-end - (ui/button - (t :yes) - :autoFocus "on" - :class "ui__modal-enter" - :on-click (fn [] - (shui/dialog-close!) - (nfs-handler/refresh! (state/get-current-repo) refresh-cb)))]])) - -(defmethod handle :sync/create-remote-graph [[_ current-repo]] - (let [graph-name (js/decodeURI (util/node-path.basename current-repo))] - (async/go - (async/ opts - editing-block - (assoc :original-block editing-block - :edit-original-block - (fn [{:keys [editing-default-property?]}] - (when editing-block - (let [content (:block/title (db/entity (:db/id editing-block))) - esc? (= "Escape" (state/get-ui-last-key-code)) - [content' pos] (cond - esc? - [nil pos] - (and (>= (count content) pos) - (>= pos 2) - (= (util/nth-safe content (dec pos)) - (util/nth-safe content (- pos 2)) - ";")) - [(str (common-util/safe-subs content 0 (- pos 2)) - (common-util/safe-subs content pos)) - (- pos 2)] - :else - [nil pos])] - (when content' - (if editing-default-property? - (editor-handler/save-block! (state/get-current-repo) (:block/uuid editing-block) content') - (editor-handler/edit-block! editing-block (or pos :max) - (cond-> {} - content' - (assoc :custom-content content'))))))))))] - (when (seq blocks) - (let [target' (or target - (some-> (state/get-edit-input-id) - (gdom/getElement)) - (first (state/get-selection-blocks)))] - (if target' - (shui/popup-show! target' - #(property-dialog/dialog blocks opts') - {:align "start" - :auto-focus? true}) - (shui/dialog-open! #(property-dialog/dialog blocks opts') - {:id :property-dialog - :align "start"})))))) - -(defmethod handle :editor/new-property [[_ {:keys [block target] :as opts}]] - (when-not config/publishing? - (p/do! - (editor-handler/save-current-block!) - (editor-new-property block target opts)))) - (defmethod handle :editor/upsert-type-block [[_ {:keys [block type lang update-current-block?]}]] (p/do! (when-not update-current-block? @@ -1026,25 +466,6 @@ (db/entity [:block/uuid (:block/uuid block)])))] (js/setTimeout #(editor-handler/edit-block! block :max) 100))))) -(rum/defc multi-tabs-dialog - [] - (let [word (if (util/electron?) "window" "tab")] - [:div.flex.p-4.flex-col.gap-4.h-64 - [:span.warning.text-lg - (util/format "Logseq doesn't support multiple %ss access to the same graph yet, please close this %s or switch to another graph." - word word)] - [:div.text-lg - [:p "Switch to another repo: "] - [:div.border.rounded.bg-gray-01.overflow-hidden.w-60 - (repo/repos-dropdown {:on-click (fn [e] - (util/stop e) - (state/set-state! :error/multiple-tabs-access-opfs? false) - (shui/dialog-close!))})]]])) - -(defmethod handle :show/multiple-tabs-error-dialog [_] - (state/set-state! :error/multiple-tabs-access-opfs? true) - (shui/dialog-open! multi-tabs-dialog)) - (defmethod handle :rtc/sync-state [[_ state]] (state/update-state! :rtc/state (fn [old] (merge old state)))) @@ -1075,24 +496,6 @@ (defmethod handle :editor/run-query-command [_] (editor-handler/run-query-command!)) -(defmethod handle :editor/show-action-bar [] - (let [selection (state/get-selection-blocks) - first-visible-block (some #(when (util/el-visible-in-viewport? % true) %) selection)] - (when first-visible-block - (shui/popup-hide! :selection-action-bar) - (shui/popup-show! - first-visible-block - (fn [] - (selection/action-bar)) - {:id :selection-action-bar - :content-props {:side "top" - :class "!py-0 !px-0 !border-none"} - :auto-side? false - :align :start})))) - -(defmethod handle :editor/hide-action-bar [] - (shui/popup-hide! :selection-action-bar)) - (defmethod handle :editor/load-blocks [[_ ids]] (when (seq ids) ;; not using `c]] + [frontend.components.block :as block] + [frontend.components.cmdk.core :as cmdk] + [frontend.components.file-sync :as file-sync] + [frontend.components.page :as component-page] + [frontend.components.plugins :as plugin] + [frontend.components.property.dialog :as property-dialog] + [frontend.components.repo :as repo] + [frontend.components.select :as select] + [frontend.components.selection :as selection] + [frontend.components.settings :as settings] + [frontend.components.shell :as shell] + [frontend.components.user.login :as login] + [frontend.components.whiteboard :as whiteboard] + [frontend.config :as config] + [frontend.context.i18n :refer [t]] + [frontend.db :as db] + [frontend.extensions.fsrs :as fsrs] + [frontend.extensions.srs :as srs] + [frontend.fs.capacitor-fs :as capacitor-fs] + [frontend.fs.nfs :as nfs] + [frontend.fs.sync :as sync] + [frontend.handler.db-based.rtc :as rtc-handler] + [frontend.handler.editor :as editor-handler] + [frontend.handler.events :as events] + [frontend.handler.file-based.nfs :as nfs-handler] + [frontend.handler.file-sync :as file-sync-handler] + [frontend.handler.notification :as notification] + [frontend.handler.page :as page-handler] + [frontend.handler.plugin :as plugin-handler] + [frontend.handler.repo :as repo-handler] + [frontend.handler.route :as route-handler] + [frontend.handler.user :as user-handler] + [frontend.mobile.util :as mobile-util] + [frontend.modules.instrumentation.sentry :as sentry-event] + [frontend.state :as state] + [frontend.ui :as ui] + [frontend.util :as util] + [goog.dom :as gdom] + [logseq.common.util :as common-util] + [logseq.shui.ui :as shui] + [promesa.core :as p] + [rum.core :as rum])) + +(defmethod events/handle :class/configure [[_ page]] + (shui/dialog-open! + #(block/block-container {} page) + {:label "page-configure" + :align :top})) + +(defmethod events/handle :go/search [_] + (shui/dialog-open! + cmdk/cmdk-modal + {:id :ls-dialog-cmdk + :align :top + :content-props {:class "ls-dialog-cmdk"} + :close-btn? false})) + +(defmethod events/handle :command/run [_] + (when (util/electron?) + (shui/dialog-open! shell/shell))) + +(defmethod events/handle :notification/show [[_ {:keys [content status clear?]}]] + (notification/show! content status clear?)) + +(defmethod events/handle :command/run [_] + (when (util/electron?) + (shui/dialog-open! shell/shell))) + +(defmethod events/handle :go/plugins [_] + (plugin/open-plugins-modal!)) + +(defmethod events/handle :go/plugins-waiting-lists [_] + (plugin/open-waiting-updates-modal!)) + +(defmethod events/handle :go/plugins-from-file [[_ plugins]] + (plugin/open-plugins-from-file-modal! plugins)) + +(defmethod events/handle :go/install-plugin-from-github [[_]] + (shui/dialog-open! + (plugin/install-from-github-release-container))) + +(defmethod events/handle :go/plugins-settings [[_ pid nav? title]] + (when pid + (state/set-state! :plugin/focused-settings pid) + (state/set-state! :plugin/navs-settings? (not (false? nav?))) + (plugin/open-focused-settings-modal! title))) + +(defmethod events/handle :go/proxy-settings [[_ agent-opts]] + (shui/dialog-open! + (plugin/user-proxy-settings-container agent-opts) + {:id :https-proxy-panel :center? true :class "lg:max-w-2xl"})) + +(defmethod events/handle :redirect-to-home [_] + (page-handler/create-today-journal!)) + +(defmethod events/handle :page/show-delete-dialog [[_ selected-rows ok-handler]] + (shui/dialog-open! + (component-page/batch-delete-dialog + selected-rows false + ok-handler))) + +(defn ask-permission + [repo] + (when + (and (not (util/electron?)) + (not (mobile-util/native-platform?))) + (fn [{:keys [close]}] + [:div + ;; TODO: fn translation with args + [:p + "Grant native filesystem permission for directory: " + [:b (config/get-local-dir repo)]] + (ui/button + (t :settings-permission/start-granting) + :class "ui__modal-enter" + :on-click (fn [] + (nfs/check-directory-permission! repo) + (close)))]))) + +(defn get-local-repo + [] + (when-let [repo (state/get-current-repo)] + (when (config/local-file-based-graph? repo) + repo))) + +(defmethod events/handle :modal/nfs-ask-permission [] + (when-let [repo (get-local-repo)] + (some-> (ask-permission repo) + (shui/dialog-open! {:align :top})))) + +(defmethod events/handle :modal/show-cards [[_ cards-id]] + (let [db-based? (config/db-based-graph? (state/get-current-repo))] + (shui/dialog-open! + (if db-based? (fn [] (fsrs/cards-view cards-id)) srs/global-cards) + {:id :srs + :label "flashcards__cp"}))) + +(defmethod events/handle :modal/show-instruction [_] + (shui/dialog-open! + capacitor-fs/instruction + {:id :instruction + :label "instruction__cp"})) + +(defmethod events/handle :modal/show-themes-modal [[_ classic?]] + (if classic? + (plugin/open-select-theme!) + (route-handler/go-to-search! :themes))) + +(defmethod events/handle :ui/toggle-appearance [_] + (let [popup-id "appearance_settings"] + (if (gdom/getElement popup-id) + (shui/popup-hide! popup-id) + (shui/popup-show! + (js/document.querySelector ".toolbar-dots-btn") + (fn [] + (settings/appearance)) + {:id popup-id + :align :end})))) + +(defmethod events/handle :plugin/consume-updates [[_ id prev-pending? updated?]] + (let [downloading? (:plugin/updates-downloading? @state/state) + auto-checking? (plugin-handler/get-auto-checking?)] + (when-let [coming (and (not downloading?) + (get-in @state/state [:plugin/updates-coming id]))] + (let [error-code (:error-code coming) + error-code (if (= error-code (str :no-new-version)) nil error-code) + title (:title coming)] + (when (and prev-pending? (not auto-checking?)) + (if-not error-code + (plugin/set-updates-sub-content! (str title "...") 0) + (notification/show! + (str "[Checked]<" title "> " error-code) :error))))) + + (if (and updated? downloading?) + ;; try to start consume downloading item + (if-let [next-coming (state/get-next-selected-coming-update)] + (plugin-handler/check-or-update-marketplace-plugin! + (assoc next-coming :only-check false :error-code nil) + (fn [^js e] (js/console.error "[Download Err]" next-coming e))) + (plugin-handler/close-updates-downloading)) + + ;; try to start consume pending item + (if-let [next-pending (second (first (:plugin/updates-pending @state/state)))] + (do + (println "Updates: take next pending - " (:id next-pending)) + (js/setTimeout + #(plugin-handler/check-or-update-marketplace-plugin! + (assoc next-pending :only-check true :auto-check auto-checking? :error-code nil) + (fn [^js e] + (notification/show! (.toString e) :error) + (js/console.error "[Check Err]" next-pending e))) 500)) + + ;; try to open waiting updates list + (do (when (and prev-pending? (not auto-checking?) + (seq (state/all-available-coming-updates))) + (plugin/open-waiting-updates-modal!)) + (plugin-handler/set-auto-checking! false)))))) + +(defmethod events/handle :plugin/loader-perf-tip [[_ {:keys [^js o _s _e]}]] + (when-let [opts (.-options o)] + (notification/show! + (plugin/perf-tip-content (.-id o) (.-name opts) (.-url opts)) + :warning false (.-id o)))) + +(defn- refresh-cb [] + (page-handler/create-today-journal!) + (events/file-sync-restart!)) + +(defmethod events/handle :graph/ask-for-re-fresh [_] + (shui/dialog-open! + [:div {:style {:max-width 700}} + [:p (t :sync-from-local-changes-detected)] + [:div.flex.justify-end + (ui/button + (t :yes) + :autoFocus "on" + :class "ui__modal-enter" + :on-click (fn [] + (shui/dialog-close!) + (nfs-handler/refresh! (state/get-current-repo) refresh-cb)))]])) + +(defn- editor-new-property [block target {:keys [selected-blocks] :as opts}] + (let [editing-block (state/get-edit-block) + pos (state/get-edit-pos) + edit-block-or-selected (cond + editing-block + [editing-block] + (seq selected-blocks) + selected-blocks + :else + (seq (keep #(db/entity [:block/uuid %]) (state/get-selection-block-ids)))) + current-block (when-let [s (state/get-current-page)] + (when (util/uuid-string? s) + (db/entity [:block/uuid (uuid s)]))) + blocks (or (when block [block]) + edit-block-or-selected + (when current-block [current-block])) + opts' (cond-> opts + editing-block + (assoc :original-block editing-block + :edit-original-block + (fn [{:keys [editing-default-property?]}] + (when editing-block + (let [content (:block/title (db/entity (:db/id editing-block))) + esc? (= "Escape" (state/get-ui-last-key-code)) + [content' pos] (cond + esc? + [nil pos] + (and (>= (count content) pos) + (>= pos 2) + (= (util/nth-safe content (dec pos)) + (util/nth-safe content (- pos 2)) + ";")) + [(str (common-util/safe-subs content 0 (- pos 2)) + (common-util/safe-subs content pos)) + (- pos 2)] + :else + [nil pos])] + (when content' + (if editing-default-property? + (editor-handler/save-block! (state/get-current-repo) (:block/uuid editing-block) content') + (editor-handler/edit-block! editing-block (or pos :max) + (cond-> {} + content' + (assoc :custom-content content'))))))))))] + (when (seq blocks) + (let [target' (or target + (some-> (state/get-edit-input-id) + (gdom/getElement)) + (first (state/get-selection-blocks)))] + (if target' + (shui/popup-show! target' + #(property-dialog/dialog blocks opts') + {:align "start" + :auto-focus? true}) + (shui/dialog-open! #(property-dialog/dialog blocks opts') + {:id :property-dialog + :align "start"})))))) + +(defmethod events/handle :editor/new-property [[_ {:keys [block target] :as opts}]] + (when-not config/publishing? + (p/do! + (editor-handler/save-current-block!) + (editor-new-property block target opts)))) + +(defmethod events/handle :graph/new-db-graph [[_ _opts]] + (shui/dialog-open! + repo/new-db-graph + {:id :new-db-graph + :title [:h2 "Create a new graph"] + :style {:max-width "500px"}})) + +(defmethod events/handle :dialog-select/graph-open [] + (select/dialog-select! :graph-open)) + +(defmethod events/handle :dialog-select/graph-remove [] + (select/dialog-select! :graph-remove)) + +(defmethod events/handle :dialog-select/db-graph-replace [] + (select/dialog-select! :db-graph-replace)) + +(rum/defc multi-tabs-dialog + [] + (let [word (if (util/electron?) "window" "tab")] + [:div.flex.p-4.flex-col.gap-4.h-64 + [:span.warning.text-lg + (util/format "Logseq doesn't support multiple %ss access to the same graph yet, please close this %s or switch to another graph." + word word)] + [:div.text-lg + [:p "Switch to another repo: "] + [:div.border.rounded.bg-gray-01.overflow-hidden.w-60 + (repo/repos-dropdown {:on-click (fn [e] + (util/stop e) + (state/set-state! :error/multiple-tabs-access-opfs? false) + (shui/dialog-close!))})]]])) + +(defmethod events/handle :show/multiple-tabs-error-dialog [_] + (state/set-state! :error/multiple-tabs-access-opfs? true) + (shui/dialog-open! multi-tabs-dialog)) + +(defmethod events/handle :editor/show-action-bar [] + (let [selection (state/get-selection-blocks) + first-visible-block (some #(when (util/el-visible-in-viewport? % true) %) selection)] + (when first-visible-block + (shui/popup-hide! :selection-action-bar) + (shui/popup-show! + first-visible-block + (fn [] + (selection/action-bar)) + {:id :selection-action-bar + :content-props {:side "top" + :class "!py-0 !px-0 !border-none"} + :auto-side? false + :align :start})))) + +(defmethod events/handle :editor/hide-action-bar [] + (shui/popup-hide! :selection-action-bar)) + +(defmethod events/handle :user/logout [[_]] + (file-sync-handler/reset-session-graphs) + (sync/remove-all-pwd!) + (file-sync-handler/reset-user-state!) + (login/sign-out!)) + +(defmethod events/handle :user/login [[_ host-ui?]] + (if (or host-ui? (not util/electron?)) + (js/window.open config/LOGIN-URL) + (if (mobile-util/native-platform?) + (route-handler/redirect! {:to :user-login}) + (login/open-login-modal!)))) + +(defmethod events/handle :whiteboard/onboarding [[_ opts]] + (shui/dialog-open! + (fn [{:keys [close]}] (whiteboard/onboarding-welcome close)) + (merge {:close-btn? false + :center? true + :close-backdrop? false} opts))) + +(defn- enable-beta-features! + [] + (when-not (false? (state/enable-sync?)) ; user turns it off + (file-sync-handler/set-sync-enabled! true))) + +;; TODO: separate rtc and file-based implementation +(defmethod events/handle :user/fetch-info-and-graphs [[_]] + (state/set-state! [:ui/loading? :login] false) + (async/go + (let [result (async/c (rtc-handler/ + (p/let [exists? (fs/dir-exists? graph-path)] + (let [overwrite? (if exists? + (js/confirm (str "There's already a directory with the name \"" graph-name "\", do you want to overwrite it? Make sure to backup it first if you're not sure about it.")) + true)] + (if overwrite? + (p/let [_ (fs/mkdir-if-not-exists graph-path)] + (nfs-handler/ls-dir-files-with-path! + graph-path + {:ok-handler (fn [] + (file-sync-handler/init-remote-graph graph-path graph) + (js/setTimeout (fn [] (repo-handler/refresh-repos!)) 200))})) + (let [graph-name (-> (js/prompt "Please specify a new directory name to download the graph:") + str + string/trim)] + (when-not (string/blank? graph-name) + (state/pub-event! [:graph/pull-down-remote-graph graph graph-name])))))) + (p/catch (fn [^js e] + (notification/show! (str e) :error) + (js/console.error e))))))))) + (when (:GraphName graph) + (shui/dialog-open! + (file-sync/pick-dest-to-sync-panel graph))))) + +(defmethod events/handle :graph/pick-page-histories [[_ graph-uuid page-name]] + (shui/dialog-open! + (file-sync/pick-page-histories-panel graph-uuid page-name) + {:id :page-histories :label "modal-page-histories"})) + +(defmethod events/handle :file-sync/maybe-onboarding-show [[_ type]] + (file-sync/maybe-onboarding-show type)) + +(defmethod events/handle :file-sync/storage-exceed-limit [[_]] + (notification/show! "file sync storage exceed limit" :warning false) + (events/file-sync-stop!)) + +(defmethod events/handle :file-sync/graph-count-exceed-limit [[_]] + (notification/show! "file sync graph count exceed limit" :warning false) + (events/file-sync-stop!)) + +(defmethod events/handle :graph/dir-gone [[_ dir]] + (state/pub-event! [:notification/show + {:content (str "The directory " dir " has been renamed or deleted, the editor will be disabled for this graph, you can unlink the graph.") + :status :error + :clear? false}]) + (state/update-state! :file/unlinked-dirs (fn [dirs] (conj dirs dir)))) + +(defmethod events/handle :graph/dir-back [[_ repo dir]] + (when (contains? (:file/unlinked-dirs @state/state) dir) + (notification/clear-all!) + (state/pub-event! [:notification/show + {:content (str "The directory " dir " has been back, you can edit your graph now.") + :status :success + :clear? true}]) + (state/update-state! :file/unlinked-dirs (fn [dirs] (disj dirs dir))) + (when (= dir (config/get-repo-dir repo)) + (fs/watch-dir! dir)))) + +(defmethod events/handle :ui/notify-skipped-downloading-files [[_ paths]] + (notification/show! + [:div + [:div.mb-4 + [:div.font-semibold.mb-4.text-xl "It seems that some of your filenames are in the outdated format."] + [:p + "The files below that have reserved characters can't be saved on this device."] + [:div.overflow-y-auto.max-h-96 + [:ol.my-2 + (for [path paths] + [:li path])]] + + [:div + [:p + "Check " [:a {:href "https://docs.logseq.com/#/page/logseq%20file%20and%20folder%20naming%20rules" + :target "_blank"} + "Logseq file and folder naming rules"] + " for more details."]]]] + :warning + false)) + +(defmethod events/handle :graph/setup-a-repo [[_ opts]] + (let [opts' (merge {:picked-root-fn #(state/close-modal!) + :native-icloud? (not (string/blank? (state/get-icloud-container-root-url))) + :logged? (user-handler/logged-in?)} opts)] + (if (mobile-util/native-ios?) + (shui/dialog-open! + #(graph-picker/graph-picker-cp opts') + {:label "graph-setup"}) + (page-handler/ls-dir-files! st/refresh! opts')))) + +(defmethod events/handle :file/alter [[_ repo path content]] + (p/let [_ (file-handler/alter-file repo path content {:from-disk? true})] + (ui-handler/re-render-root!))) + +(rum/defcs file-id-conflict-item < + (rum/local false ::resolved?) + [state repo file data] + (let [resolved? (::resolved? state) + id (last (:assertion data))] + [:li {:key file} + [:div + [:a {:on-click #(js/window.apis.openPath file)} file] + (if @resolved? + [:div.flex.flex-row.items-center + (ui/icon "circle-check" {:style {:font-size 20}}) + [:div.ml-1 "Resolved"]] + [:div + [:p + (str "It seems that another whiteboard file already has the ID \"" id + "\". You can fix it by changing the ID in this file with another UUID.")] + [:p + "Or, let me" + (ui/button "Fix" + :on-click (fn [] + (let [dir (config/get-repo-dir repo)] + (p/let [content (fs/read-file dir file)] + (let [new-content (string/replace content (str id) (str (random-uuid)))] + (p/let [_ (fs/write-file! repo + dir + file + new-content + {})] + (reset! resolved? true)))))) + :class "inline mx-1") + "it."]])]])) + +(defmethod events/handle :file/parse-and-load-error [[_ repo parse-errors]] + (state/pub-event! [:notification/show + {:content + [:div + [:h2.title "Oops. These files failed to import to your graph:"] + [:ol.my-2 + (for [[file error] parse-errors] + (let [data (ex-data error)] + (cond + (and (common-config/whiteboard? file) + (= :transact/upsert (:error data)) + (uuid? (last (:assertion data)))) + (rum/with-key (file-id-conflict-item repo file data) file) + + :else + (do + (state/pub-event! [:capture-error {:error error + :payload {:type :file/parse-and-load-error}}]) + [:li.my-1 {:key file} + [:a {:on-click #(js/window.apis.openPath file)} file] + [:p (.-message error)]]))))] + [:p "Don't forget to re-index your graph when all the conflicts are resolved."]] + :status :error}])) + +(defmethod events/handle :file-sync-graph/restore-file [[_ graph page-entity content]] + (when (db/get-db graph) + (let [file (:block/file page-entity)] + (when-let [path (:file/path file)] + (when (and (not= content (:file/content file)) + (:file/content file)) + (sync/add-new-version-file graph path (:file/content file))) + (p/let [_ (file-handler/alter-file graph + path + content + {:re-render-root? true + :skip-compare? true})] + (state/close-modal!) + (route-handler/redirect! {:to :page + :path-params {:name (:block/name page-entity)}})))))) + +(defmethod events/handle :sync/create-remote-graph [[_ current-repo]] + (let [graph-name (js/decodeURI (util/node-path.basename current-repo))] + (async/go + (async/ - (merge {:arrow true - :sticky true - :delay 600 - :theme "customized" - :disabled disabled? - :unmountHTMLWhenHide true - :open (if disabled? false open?) - :trigger (if manual "manual" "mouseenter focus") - ;; See https://github.com/tvkhoa/react-tippy/issues/13 - :popperOptions {:modifiers {:flip {:enabled (not fixed-position?)} - :hide {:enabled false} - :preventOverflow {:enabled false}}} - :onShow #(when-not (or (state/editing?) - @(:ui/scrolling? @state/state)) - (reset! *mounted? true)) - :onHide #(reset! *mounted? false)} - opts) - (assoc :html (or - (when open? - (try - (when html - (if (fn? html) - (html) - [:div.px-2.py-1 - html])) - (catch :default e - (log/error :exception e) - [:div]))) - [:div {:key "tippy"} ""]))) - (rum/fragment {:key "tippy-children"} child)))) - (rum/defcs slider < rum/reactive {:init (fn [state] (assoc state ::value (atom (first (:rum/args state)))))} @@ -911,18 +871,13 @@ (rum/defc with-shortcut < rum/reactive < {:key-fn (fn [key pos] (str "shortcut-" key pos))} - [shortcut-key position content] + [shortcut-key _position content] (let [shortcut-tooltip? (state/sub :ui/shortcut-tooltip?) enabled-tooltip? (state/enable-tooltip?)] (if (and enabled-tooltip? shortcut-tooltip?) - (tippy - {:html [:div.text-sm.font-medium (keyboard-shortcut-from-config shortcut-key)] - :interactive true - :position position - :theme "monospace" - :delay [1000, 100] - :arrow true} - content) + (tooltip content + [:div.text-sm.font-medium (keyboard-shortcut-from-config shortcut-key)] + {:trigger-props {:as-child true}}) content))) (rum/defc progress-bar @@ -1020,11 +975,14 @@ :small? true)]])) (rum/defc tooltip - [trigger tooltip-content & {:keys [trigger-props]}] + [trigger tooltip-content & {:keys [portal? root-props trigger-props content-props]}] (shui/tooltip-provider - (shui/tooltip - (shui/tooltip-trigger trigger-props trigger) - (shui/tooltip-content tooltip-content)))) + (shui/tooltip root-props + (shui/tooltip-trigger (merge {:as-child true} trigger-props) trigger) + (if (not (false? portal?)) + (shui/tooltip-portal + (shui/tooltip-content content-props tooltip-content)) + (shui/tooltip-content content-props tooltip-content))))) (rum/defc DelDateButton [on-delete] diff --git a/src/main/frontend/worker/db/fix.cljs b/src/main/frontend/worker/db/fix.cljs new file mode 100644 index 0000000000..b598ba7235 --- /dev/null +++ b/src/main/frontend/worker/db/fix.cljs @@ -0,0 +1,23 @@ +(ns frontend.worker.db.fix + "fix db" + (:require [datascript.core :as d] + [logseq.db.sqlite.util :as sqlite-util])) + +(defn check-and-fix-schema! + [repo conn] + (let [schema (sqlite-util/get-schema repo) + db-schema (:schema @conn) + diffs (->> (keep (fn [[k v]] + (let [schema-v (-> (get db-schema k) + (dissoc :db/ident)) + schema-v' (cond-> schema-v + (= (:db/cardinality schema-v) :db.cardinality/one) + (dissoc :db/cardinality) + (and (:db/index schema-v) + (nil? (:db/index v))) + (dissoc :db/index))] + (when-not (or (= v schema-v') (= k :db/ident)) + (assoc v :db/ident k)))) + schema))] + (when (seq diffs) + (d/transact! conn diffs)))) diff --git a/src/main/frontend/worker/db_worker.cljs b/src/main/frontend/worker/db_worker.cljs index 4a178832fb..1eddad9456 100644 --- a/src/main/frontend/worker/db_worker.cljs +++ b/src/main/frontend/worker/db_worker.cljs @@ -13,6 +13,7 @@ [frontend.common.graph-view :as graph-view] [frontend.common.thread-api :as thread-api :refer [def-thread-api]] [frontend.worker.db-listener :as db-listener] + [frontend.worker.db.fix :as db-fix] [frontend.worker.db.migrate :as db-migrate] [frontend.worker.db.validate :as worker-db-validate] [frontend.worker.export :as worker-export] @@ -332,6 +333,7 @@ (search/create-tables-and-triggers! search-db) (let [schema (sqlite-util/get-schema repo) conn (sqlite-common-db/get-storage-conn storage schema) + _ (db-fix/check-and-fix-schema! repo conn) _ (when datoms (let [data (map (fn [datom] [:db/add (:e datom) (:a datom) (:v datom)]) datoms)] diff --git a/tailwind.all.css b/tailwind.all.css index 692b862e4c..4bdde8d089 100644 --- a/tailwind.all.css +++ b/tailwind.all.css @@ -17,7 +17,6 @@ @import "codemirror/lib/codemirror.css"; @import "codemirror/theme/solarized.css"; @import "codemirror/addon/hint/show-hint.css"; -@import "react-tippy/dist/tippy.css"; @import "pdfjs-dist/web/pdf_viewer.css"; @import "resources/css/tabler-extension.css"; @import "resources/css/codemirror.lsradix.css"; diff --git a/yarn.lock b/yarn.lock index ac6b528b0b..36af11f49a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6584,11 +6584,6 @@ plugin-error@^2.0.1: dependencies: ansi-colors "^1.0.1" -popper.js@^1.11.1: - version "1.16.1" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" - integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== - posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -7249,13 +7244,6 @@ react-textarea-autosize@8.3.3: use-composed-ref "^1.0.0" use-latest "^1.0.0" -react-tippy@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/react-tippy/-/react-tippy-1.4.0.tgz#e8a8b4085ec985e5c94fe128918b733b588a1465" - integrity sha512-r/hM5XK9Ztr2ZY7IWKuRmISTlUPS/R6ddz6PO2EuxCgW+4JBcGZRPU06XcVPRDCOIiio8ryBQFrXMhFMhsuaHA== - dependencies: - popper.js "^1.11.1" - react-transition-group@4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.3.0.tgz#fea832e386cf8796c58b61874a3319704f5ce683"