|
|
@@ -1,103 +1,24 @@
|
|
|
(ns frontend.components.reference
|
|
|
- (:require [clojure.string :as string]
|
|
|
- [frontend.config :as config]
|
|
|
- [frontend.components.block :as block]
|
|
|
+ (:require [frontend.components.block :as block]
|
|
|
[frontend.components.content :as content]
|
|
|
[frontend.components.editor :as editor]
|
|
|
+ [frontend.components.reference-filters :as filters]
|
|
|
+ [frontend.config :as config]
|
|
|
[frontend.context.i18n :refer [t]]
|
|
|
[frontend.db :as db]
|
|
|
[frontend.db-mixins :as db-mixins]
|
|
|
+ [frontend.db.async :as db-async]
|
|
|
[frontend.db.utils :as db-utils]
|
|
|
- [frontend.db.model :as model-db]
|
|
|
[frontend.handler.block :as block-handler]
|
|
|
[frontend.handler.page :as page-handler]
|
|
|
+ [frontend.modules.outliner.tree :as tree]
|
|
|
[frontend.search :as search]
|
|
|
[frontend.state :as state]
|
|
|
[frontend.ui :as ui]
|
|
|
- [logseq.shui.ui :as shui]
|
|
|
[frontend.util :as util]
|
|
|
- [rum.core :as rum]
|
|
|
- [frontend.modules.outliner.tree :as tree]
|
|
|
- [frontend.db.async :as db-async]
|
|
|
- [promesa.core :as p]))
|
|
|
-
|
|
|
-(defn- frequencies-sort
|
|
|
- [references]
|
|
|
- (sort-by second #(> %1 %2) references))
|
|
|
-
|
|
|
-(defn filtered-refs
|
|
|
- [page filters filters-atom filtered-references]
|
|
|
- [:div.flex.gap-2.flex-wrap.items-center
|
|
|
- (for [[ref-name ref-count] filtered-references]
|
|
|
- (when ref-name
|
|
|
- (let [lc-reference (string/lower-case ref-name)]
|
|
|
- (ui/button
|
|
|
- [:span
|
|
|
- ref-name
|
|
|
- (when ref-count [:sup " " ref-count])]
|
|
|
- :on-click (fn [e]
|
|
|
- (swap! filters-atom #(if (nil? (get filters lc-reference))
|
|
|
- (assoc % lc-reference (not (.-shiftKey e)))
|
|
|
- (dissoc % lc-reference)))
|
|
|
- (page-handler/save-filter! page @filters-atom))
|
|
|
- :small? true
|
|
|
- :variant :outline
|
|
|
- :key ref-name))))])
|
|
|
-
|
|
|
-(rum/defcs filter-dialog-inner < rum/reactive (rum/local "" ::filterSearch)
|
|
|
- [state page-entity filters-atom *references]
|
|
|
- (let [filter-search (get state ::filterSearch)
|
|
|
- references (rum/react *references)
|
|
|
- filtered-references (frequencies-sort
|
|
|
- (if (= @filter-search "")
|
|
|
- references
|
|
|
- (search/fuzzy-search references @filter-search :limit 500 :extract-fn first)))
|
|
|
- filters (rum/react filters-atom)
|
|
|
- includes (keep (fn [[page include?]]
|
|
|
- (let [page' (model-db/get-page-original-name page)]
|
|
|
- (when include? [page'])))
|
|
|
- filters)
|
|
|
- excludes (keep (fn [[page include?]]
|
|
|
- (let [page' (model-db/get-page-original-name page)]
|
|
|
- (when-not include? [page'])))
|
|
|
- filters)]
|
|
|
- [:div.ls-filters.filters
|
|
|
- [:div.sm:flex.sm:items-start
|
|
|
- [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-gray-200.text-gray-500.sm:mx-0.sm:h-10.sm:w-10
|
|
|
- (ui/icon "filter" {:size 20})]
|
|
|
- [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left.pb-2
|
|
|
- [:h3#modal-headline.text-lg.leading-6.font-medium (t :linked-references/filter-heading)]
|
|
|
- [:span.text-xs
|
|
|
- (t :linked-references/filter-directions)]]]
|
|
|
- (when (seq filters)
|
|
|
- [:div.cp__filters.mb-4.ml-2
|
|
|
- (when (seq includes)
|
|
|
- [:div.flex.flex-row.flex-wrap.center-items
|
|
|
- [:div.mr-1.font-medium.py-1 (t :linked-references/filter-includes)]
|
|
|
- (filtered-refs page-entity filters filters-atom includes)])
|
|
|
- (when (seq excludes)
|
|
|
- [:div.flex.flex-row.flex-wrap
|
|
|
- [:div.mr-1.font-medium.py-1 (t :linked-references/filter-excludes)]
|
|
|
-
|
|
|
- (filtered-refs page-entity filters filters-atom excludes)])])
|
|
|
- [:div.cp__filters-input-panel.flex.focus-within:bg-gray-03
|
|
|
- (ui/icon "search")
|
|
|
- [:input.cp__filters-input.w-full.bg-transparent
|
|
|
- {:placeholder (t :linked-references/filter-search)
|
|
|
- :autofocus true
|
|
|
- :on-change (fn [e]
|
|
|
- (reset! filter-search (util/evalue e)))}]]
|
|
|
- (let [all-filters (set (keys filters))
|
|
|
- refs (remove (fn [[page _]] (all-filters (util/page-name-sanity-lc page)))
|
|
|
- filtered-references)]
|
|
|
- (when (seq refs)
|
|
|
- [:div.mt-4
|
|
|
- (filtered-refs page-entity filters filters-atom refs)]))]))
|
|
|
-
|
|
|
-(defn filter-dialog
|
|
|
- [page-entity filters-atom *references]
|
|
|
- (fn []
|
|
|
- (filter-dialog-inner page-entity filters-atom *references)))
|
|
|
+ [logseq.shui.ui :as shui]
|
|
|
+ [promesa.core :as p]
|
|
|
+ [rum.core :as rum]))
|
|
|
|
|
|
(rum/defc block-linked-references < rum/reactive db-mixins/query
|
|
|
{:init (fn [state]
|
|
|
@@ -138,13 +59,15 @@
|
|
|
(content/content page-name {:hiccup ref-hiccup}))])
|
|
|
|
|
|
(rum/defc references-cp
|
|
|
- [page-entity page-name filters filters-atom filter-state total filter-n filtered-ref-blocks *ref-pages]
|
|
|
- (let [threshold (state/get-linked-references-collapsed-threshold)
|
|
|
+ [page-entity page-name *filters total filter-n filtered-ref-blocks *ref-pages]
|
|
|
+ (let [filters @*filters
|
|
|
+ threshold (state/get-linked-references-collapsed-threshold)
|
|
|
default-collapsed? (>= total threshold)
|
|
|
*collapsed? (atom nil)]
|
|
|
(ui/foldable
|
|
|
[:div.flex.flex-row.flex-1.justify-between.items-center
|
|
|
- [:h2.font-medium (t :linked-references/reference-count (if (seq filters) filter-n nil) total)]
|
|
|
+ [:h2.font-medium (t :linked-references/reference-count (when (or (seq (:included filters))
|
|
|
+ (seq (:excluded filters))) filter-n) total)]
|
|
|
[:a.filter.fade-link
|
|
|
{:title (t :linked-references/filter-heading)
|
|
|
:on-mouse-over (fn [_e]
|
|
|
@@ -153,14 +76,19 @@
|
|
|
(reset! @*collapsed? false)))
|
|
|
:on-pointer-down (fn [e]
|
|
|
(util/stop-propagation e)
|
|
|
- (shui/dialog-open!
|
|
|
- (filter-dialog page-entity filters-atom *ref-pages)))}
|
|
|
+ (shui/popup-show! (.-target e)
|
|
|
+ (fn []
|
|
|
+ [:div.p-4
|
|
|
+ (filters/filter-dialog page-entity *filters *ref-pages)])
|
|
|
+ {:align "end"}))}
|
|
|
(ui/icon "filter" {:class (cond
|
|
|
- (empty? filter-state)
|
|
|
+ (and (empty? (:included filters)) (empty? (:excluded filters)))
|
|
|
"opacity-60 hover:opacity-100"
|
|
|
- (every? true? (vals filter-state))
|
|
|
+
|
|
|
+ (and (seq (:included filters)) (empty? (:excluded filters)))
|
|
|
"text-success"
|
|
|
- (every? false? (vals filter-state))
|
|
|
+
|
|
|
+ (and (empty? (:included filters)) (seq (:excluded filters)))
|
|
|
"text-error"
|
|
|
:else
|
|
|
"text-warning")
|
|
|
@@ -188,41 +116,30 @@
|
|
|
(concat children (rest blocks))
|
|
|
(conj result fb))))))))
|
|
|
|
|
|
-(rum/defc sub-page-properties-changed < rum/static
|
|
|
- [page-entity v filters-atom]
|
|
|
- (rum/use-effect!
|
|
|
- (fn []
|
|
|
- (reset! filters-atom
|
|
|
- (page-handler/get-filters page-entity)))
|
|
|
- [page-entity v filters-atom])
|
|
|
- [:<>])
|
|
|
-
|
|
|
(rum/defcs references* < rum/reactive db-mixins/query
|
|
|
(rum/local nil ::ref-pages)
|
|
|
{:init (fn [state]
|
|
|
- (let [page (first (:rum/args state))
|
|
|
- filters (when page (atom nil))]
|
|
|
- (when page (db-async/<get-block-refs (state/get-current-repo) (:db/id page)))
|
|
|
- (assoc state ::filters filters)))}
|
|
|
+ (let [page (first (:rum/args state))]
|
|
|
+ (when page (db-async/<get-block-refs (state/get-current-repo) (:db/id page))))
|
|
|
+ (assoc state ::filters (atom nil)))}
|
|
|
[state page-entity]
|
|
|
(when page-entity
|
|
|
- (let [repo (state/get-current-repo)]
|
|
|
+ (let [repo (state/get-current-repo)
|
|
|
+ *filters (::filters state)]
|
|
|
(when page-entity
|
|
|
(when-not (state/sub-async-query-loading (str (:db/id page-entity) "-refs"))
|
|
|
- (let [page-name (:block/name page-entity)
|
|
|
- page-props-v (state/sub-page-properties-changed page-name)
|
|
|
+ (let [page-entity (db/sub-block (:db/id page-entity))
|
|
|
+ page-name (:block/name page-entity)
|
|
|
*ref-pages (::ref-pages state)
|
|
|
- filters-atom (get state ::filters)
|
|
|
- filter-state (rum/react filters-atom)
|
|
|
+ filters (page-handler/get-filters page-entity)
|
|
|
+ _ (when-not (= filters @*filters)
|
|
|
+ (reset! *filters filters))
|
|
|
page-id (:db/id page-entity)
|
|
|
ref-blocks (db/get-page-referenced-blocks page-id)
|
|
|
aliases (db/page-alias-set repo page-id)
|
|
|
aliases-exclude-self (set (remove #{page-id} aliases))
|
|
|
top-level-blocks (filter (fn [b] (some aliases (set (map :db/id (:block/refs b))))) ref-blocks)
|
|
|
top-level-blocks-ids (set (map :db/id top-level-blocks))
|
|
|
- filters (when (seq filter-state)
|
|
|
- (-> (group-by second filter-state)
|
|
|
- (update-vals #(map first %))))
|
|
|
filtered-ref-blocks (->> (block-handler/filter-blocks ref-blocks filters)
|
|
|
(block-handler/get-filtered-ref-blocks-with-parents ref-blocks))
|
|
|
total (count top-level-blocks)
|
|
|
@@ -251,11 +168,10 @@
|
|
|
(map :block/original-name)
|
|
|
frequencies)]
|
|
|
(reset! *ref-pages ref-pages)
|
|
|
- (when (or (seq filter-state) (> filter-n 0))
|
|
|
+ (when (or (seq (:included filters)) (seq (:excluded filters)) (> filter-n 0))
|
|
|
[:div.references.page-linked.flex-1.flex-row
|
|
|
- (sub-page-properties-changed page-entity page-props-v filters-atom)
|
|
|
[:div.content.pt-6
|
|
|
- (references-cp page-entity page-name filters filters-atom filter-state total filter-n filtered-ref-blocks' *ref-pages)]])))))))
|
|
|
+ (references-cp page-entity page-name *filters total filter-n filtered-ref-blocks' *ref-pages)]])))))))
|
|
|
|
|
|
(rum/defc references
|
|
|
[page-entity]
|