| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679 |
- (ns frontend.components.page
- (:require [rum.core :as rum]
- [frontend.util :as util :refer [profile]]
- [frontend.util.marker :as marker]
- [frontend.tools.html-export :as html-export]
- [frontend.handler.page :as page-handler]
- [frontend.handler.ui :as ui-handler]
- [frontend.handler.common :as common-handler]
- [frontend.commands :as commands]
- [frontend.handler.plugin :as plugin-handler]
- [frontend.handler.route :as route-handler]
- [frontend.handler.graph :as graph-handler]
- [frontend.handler.notification :as notification]
- [frontend.handler.editor :as editor-handler]
- [frontend.handler.config :as config-handler]
- [frontend.state :as state]
- [clojure.string :as string]
- [frontend.components.block :as block]
- [frontend.components.editor :as editor]
- [frontend.components.plugins :as plugins]
- [frontend.components.reference :as reference]
- [frontend.components.svg :as svg]
- [frontend.components.export :as export]
- [frontend.extensions.graph :as graph]
- [frontend.components.hierarchy :as hierarchy]
- [frontend.ui :as ui]
- [frontend.components.content :as content]
- [frontend.config :as config]
- [frontend.db :as db]
- [frontend.db.model :as model]
- [frontend.db.utils :as db-utils]
- [frontend.mixins :as mixins]
- [frontend.db-mixins :as db-mixins]
- [goog.dom :as gdom]
- [goog.object :as gobj]
- [frontend.utf8 :as utf8]
- [frontend.date :as date]
- [frontend.format.mldoc :as mldoc]
- [cljs-time.coerce :as tc]
- [cljs-time.core :as t]
- [cljs.pprint :as pprint]
- [frontend.context.i18n :as i18n]
- [reitit.frontend.easy :as rfe]
- [frontend.text :as text]
- [frontend.modules.shortcut.core :as shortcut]
- [frontend.handler.block :as block-handler]
- [cljs-bean.core :as bean]))
- (defn- get-page-name
- [state]
- (let [route-match (first (:rum/args state))]
- (get-in route-match [:parameters :path :name])))
- (defn- get-blocks
- [repo page-name page-original-name block? block-id]
- (when page-name
- (if block?
- (db/get-block-and-children repo block-id)
- (do
- (page-handler/add-page-to-recent! repo page-original-name)
- (db/get-page-blocks repo page-name)))))
- (defn- open-first-block!
- [state]
- (let [blocks (nth (:rum/args state) 1)
- block (first blocks)
- preview? (nth (:rum/args state) 4)]
- (when (and (= (count blocks) 1)
- (string/blank? (:block/content block))
- (not preview?))
- (editor-handler/edit-block! block :max (:block/format block) (:block/uuid block))))
- state)
- (rum/defc page-blocks-inner <
- {:did-mount open-first-block!
- :did-update open-first-block!}
- [page-name page-blocks hiccup sidebar? preview?]
- [:div.page-blocks-inner
- (rum/with-key
- (content/content page-name
- {:hiccup hiccup
- :sidebar? sidebar?})
- (str page-name "-hiccup"))])
- (declare page)
- (defn- get-page-format
- [page-name]
- (let [block? (util/uuid-string? page-name)
- block-id (and block? (uuid page-name))
- page (if block-id
- (:block/name (:block/page (db/entity [:block/uuid block-id])))
- page-name)]
- (db/get-page-format page)))
- (rum/defc dummy-block
- [page-name]
- [:div.ls-block.flex-1.flex-col.rounded-sm {:style {:width "100%"}}
- [:div.flex.flex-row
- [:div.flex.flex-row.items-center.mr-2.ml-1 {:style {:height 24}}
- [:span.bullet-container.cursor
- [:span.bullet]]]
- [:div.flex.flex-1 {:on-click #(editor-handler/insert-first-page-block-if-not-exists! page-name)}
- [:span.opacity-50
- "Click here to edit..."]]]])
- (rum/defc page-blocks-cp < rum/reactive
- db-mixins/query
- [repo page-e {:keys [sidebar? preview?] :as config}]
- (when page-e
- (let [page-name (or (:block/name page-e)
- (str (:block/uuid page-e)))
- page-original-name (or (:block/original-name page-e) page-name)
- format (get-page-format page-name)
- journal? (db/journal-page? page-name)
- block? (util/uuid-string? page-name)
- block-id (and block? (uuid page-name))
- page-empty? (and (not block?) (db/page-empty? repo (:db/id page-e)))
- page-e (if (and page-e (:db/id page-e))
- {:db/id (:db/id page-e)}
- page-e)
- page-blocks (get-blocks repo page-name page-original-name block? block-id)]
- (if (empty? page-blocks)
- (dummy-block page-name)
- (let [document-mode? (state/sub :document/mode?)
- hiccup-config (merge
- {:id (if block? (str block-id) page-name)
- :block? block?
- :editor-box editor/box
- :page page
- :document/mode? document-mode?}
- config)
- hiccup-config (common-handler/config-with-document-mode hiccup-config)
- hiccup (block/->hiccup page-blocks hiccup-config {})]
- (page-blocks-inner page-name page-blocks hiccup sidebar? preview?))))))
- (defn contents-page
- [page]
- (when-let [repo (state/get-current-repo)]
- (page-blocks-cp repo page {:sidebar? true})))
- (rum/defc today-queries < rum/reactive
- [repo today? sidebar?]
- (when (and today? (not sidebar?))
- (let [queries (state/sub [:config repo :default-queries :journals])]
- (when (seq queries)
- [:div#today-queries.mt-10
- (for [{:keys [title] :as query} queries]
- (rum/with-key
- (block/custom-query {:attr {:class "mt-10"}
- :editor-box editor/box
- :page page} query)
- (str repo "-custom-query-" (:query query))))]))))
- (defn- delete-page!
- [page-name]
- (page-handler/delete! page-name
- (fn []
- (notification/show! (str "Page " page-name " was deleted successfully!")
- :success)))
- (state/close-modal!)
- (route-handler/redirect-to-home!))
- (defn delete-page-dialog
- [page-name]
- (fn [close-fn]
- (rum/with-context [[t] i18n/*tongue-context*]
- [:div
- [:div.sm:flex.sm:items-start
- [:div.mx-auto.flex-shrink-0.flex.items-center.justify-center.h-12.w-12.rounded-full.bg-red-100.sm:mx-0.sm:h-10.sm:w-10
- [:svg.h-6.w-6.text-red-600
- {:stroke "currentColor", :view-box "0 0 24 24", :fill "none"}
- [:path
- {:d
- "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
- :stroke-width "2"
- :stroke-linejoin "round"
- :stroke-linecap "round"}]]]
- [:div.mt-3.text-center.sm:mt-0.sm:ml-4.sm:text-left
- [:h3#modal-headline.text-lg.leading-6.font-medium
- (t :page/delete-confirmation)]]]
- [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
- [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
- [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
- {:type "button"
- :class "ui__modal-enter"
- :on-click (fn []
- (delete-page! page-name))}
- (t :yes)]]
- [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
- [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
- {:type "button"
- :on-click close-fn}
- (t :cancel)]]]])))
- (rum/defcs rename-page-dialog-inner <
- (shortcut/disable-all-shortcuts)
- (rum/local "" ::input)
- [state title page-name close-fn]
- (let [input (get state ::input)]
- (rum/with-context [[t] i18n/*tongue-context*]
- [:div.w-full.sm:max-w-lg.sm:w-96
- [:div.sm:flex.sm:items-start
- [:div.mt-3.text-center.sm:mt-0.sm:text-left
- [:h3#modal-headline.text-lg.leading-6.font-medium
- (t :page/rename-to title)]]]
- [:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2
- {:auto-focus true
- :default-value title
- :on-change (fn [e]
- (reset! input (util/evalue e)))}]
- [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
- [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
- [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
- {:type "button"
- :class "ui__modal-enter"
- :on-click (fn []
- (let [value (string/trim @input)]
- (when-not (string/blank? value)
- (page-handler/rename! page-name value)
- (state/close-modal!))))}
- (t :submit)]]
- [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
- [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
- {:type "button"
- :on-click close-fn}
- (t :cancel)]]]])))
- (defn rename-page-dialog
- [title page-name]
- (fn [close-fn]
- (rename-page-dialog-inner title page-name close-fn)))
- (defn tagged-pages
- [repo tag]
- (let [pages (db/get-tag-pages repo tag)]
- (when (seq pages)
- [:div.references.mt-6.flex-1.flex-row
- [:div.content
- (ui/foldable
- [:h2.font-bold.opacity-50 (util/format "Pages tagged with \"%s\"" tag)]
- [:ul.mt-2
- (for [[original-name name] pages]
- [:li {:key (str "tagged-page-" name)}
- [:a {:href (rfe/href :page {:name name})}
- original-name]])] false)]])))
- ;; A page is just a logical block
- (rum/defcs page < rum/reactive
- [state {:keys [repo page-name preview?] :as option}]
- (when-let [path-page-name (or page-name
- (get-page-name state)
- (state/get-current-page))]
- (let [current-repo (state/sub :git/current-repo)
- repo (or repo current-repo)
- page-name (string/lower-case path-page-name)
- block? (util/uuid-string? page-name)
- block-id (and block? (uuid page-name))
- format (let [page (if block-id
- (:block/name (:block/page (db/entity [:block/uuid block-id])))
- page-name)]
- (db/get-page-format page))
- journal? (db/journal-page? page-name)
- sidebar? (:sidebar? option)]
- (rum/with-context [[t] i18n/*tongue-context*]
- (let [route-page-name path-page-name
- page (if block?
- (->> (:db/id (:block/page (db/entity repo [:block/uuid block-id])))
- (db/entity repo))
- (do
- (when-not (db/entity repo [:block/name page-name])
- (db/transact! repo [{:block/name page-name
- :block/original-name path-page-name
- :block/uuid (db/new-block-id)}]))
- (db/pull [:block/name page-name])))
- {:keys [title] :as properties} (:block/properties page)
- page-name (:block/name page)
- page-original-name (:block/original-name page)
- title (or title page-original-name page-name)
- today? (and
- journal?
- (= page-name (string/lower-case (date/journal-name))))
- developer-mode? (state/sub [:ui/developer-mode?])
- public? (true? (:public properties))]
- [:div.flex-1.page.relative (if (seq (:block/tags page))
- (let [page-names (model/get-page-names-by-ids (map :db/id (:block/tags page)))]
- {:data-page-tags (text/build-data-value page-names)})
- {})
- [:div.relative
- (when (and (not sidebar?)
- (not block?))
- [:div.flex.flex-row.space-between
- [:div.flex-1.flex-row
- [:a.page-title {:on-click (fn [e]
- (.preventDefault e)
- (when (gobj/get e "shiftKey")
- (when-let [page (db/pull repo '[*] [:block/name page-name])]
- (state/sidebar-add-block!
- repo
- (:db/id page)
- :page
- {:page page}))))}
- [:h1.title {:style {:margin-left -2}}
- (if page-original-name
- (if (and (string/includes? page-original-name "[[")
- (string/includes? page-original-name "]]"))
- (let [ast (mldoc/->edn page-original-name (mldoc/default-config format))]
- (block/markup-element-cp {} (ffirst ast)))
- page-original-name)
- (or
- page-name
- path-page-name))]]]
- (when (not config/publishing?)
- (let [contents? (= (string/lower-case (str page-name)) "contents")
- links (fn [] (->>
- [(when-not contents?
- {:title (t :page/add-to-favorites)
- :options {:on-click (fn [] (page-handler/handle-add-page-to-contents! page-original-name))}})
- {:title "Go to presentation mode"
- :options {:on-click (fn []
- (state/sidebar-add-block!
- repo
- (:db/id page)
- :page-presentation
- {:page page}))}}
- (when-not contents?
- {:title (t :page/rename)
- :options {:on-click #(state/set-modal! (rename-page-dialog title page-name))}})
- (when-let [file-path (and (util/electron?) (page-handler/get-page-file-path))]
- [{:title (t :page/open-in-finder)
- :options {:on-click #(js/window.apis.showItemInFolder file-path)}}
- {:title (t :page/open-with-default-app)
- :options {:on-click #(js/window.apis.openPath file-path)}}])
- (when-not contents?
- {:title (t :page/delete)
- :options {:on-click #(state/set-modal! (delete-page-dialog page-name))}})
- (when (state/get-current-page)
- {:title (t :export)
- :options {:on-click #(state/set-modal! export/export-page)}})
- (when (util/electron?)
- {:title (t (if public? :page/make-private :page/make-public))
- :options {:on-click
- (fn []
- (page-handler/update-public-attribute!
- page-name
- (if public? false true))
- (state/close-modal!))}})
- (when plugin-handler/lsp-enabled?
- (for [[_ {:keys [key label] :as cmd} action pid] (state/get-plugins-commands-with-type :page-menu-item)]
- {:title label
- :options {:on-click #(commands/exec-plugin-simple-command!
- pid (assoc cmd :page (state/get-current-page)) action)}}))
- (when developer-mode?
- {:title "(Dev) Show page data"
- :options {:on-click (fn []
- (let [page-data (with-out-str (pprint/pprint (db/pull (:db/id page))))]
- (println page-data)
- (notification/show!
- [:div
- [:pre.code page-data]
- [:br]
- (ui/button "Copy to clipboard"
- :on-click #(.writeText js/navigator.clipboard page-data))]
- :success
- false)))}})]
- (flatten)
- (remove nil?)))]
- [:div.flex.flex-row
- (when plugin-handler/lsp-enabled?
- (plugins/hook-ui-slot :page-head-actions-slotted nil)
- (plugins/hook-ui-items :pagebar))
- [:a.opacity-60.hover:opacity-100.page-op.mr-1
- {:title "Search in current page"
- :on-click #(route-handler/go-to-search! :page)}
- svg/search]
- (ui/dropdown-with-links
- (fn [{:keys [toggle-fn]}]
- [:a.cp__vertical-menu-button
- {:title "More options"
- :on-click toggle-fn}
- (svg/vertical-dots nil)])
- links
- {:modal-class (util/hiccup->class
- "origin-top-right.absolute.right-0.top-10.mt-2.rounded-md.shadow-lg.whitespace-no-wrap.dropdown-overflow-auto.page-drop-options")
- :z-index 1})]))])
- [:div
- (when (and block? (not sidebar?))
- (let [config {:id "block-parent"
- :block? true}]
- [:div.mb-4
- (block/block-parents config repo block-id format)]))
- ;; blocks
- (let [page (if block?
- (db/entity repo [:block/uuid block-id])
- page)]
- (page-blocks-cp repo page {:sidebar? sidebar?}))]]
- (when-not block?
- (today-queries repo today? sidebar?))
- (tagged-pages repo page-name)
- ;; referenced blocks
- [:div {:key "page-references"}
- (rum/with-key
- (reference/references route-page-name false)
- (str route-page-name "-refs"))]
- (when (text/namespace-page? route-page-name)
- (hierarchy/structures route-page-name))
- ;; TODO: or we can lazy load them
- (when-not sidebar?
- [:div {:key "page-unlinked-references"}
- (reference/unlinked-references route-page-name)])])))))
- (defonce layout (atom [js/window.innerWidth js/window.innerHeight]))
- (defonce show-journal? (atom false))
- ;; scrollHeight
- (rum/defcs graph-filter-section < (rum/local false ::open?)
- [state title content {:keys [search-filters]}]
- (let [open? (get state ::open?)]
- (when (and (seq search-filters) (not @open?))
- (reset! open? true))
- [:li.relative
- [:div
- [:button.w-full.px-4.py-2.text-left.focus:outline-none {:on-click #(swap! open? not)}
- [:div.flex.items-center.justify-between
- title
- (if @open? (svg/caret-down) (svg/caret-right))]]
- (content open?)]]))
- (rum/defc filter-expand-area
- [open? content]
- [:div.relative.overflow-hidden.transition-all.max-h-0.duration-700
- {:style {:max-height (if @open? 400 0)}}
- content])
- (defonce *n-hops (atom nil))
- (defonce *focus-nodes (atom []))
- (defonce *graph-reset? (atom false))
- (rum/defc graph-filters < rum/reactive
- [graph settings n-hops]
- (let [{:keys [layout journal? orphan-pages? builtin-pages?]
- :or {layout "gForce"
- orphan-pages? true}} settings
- set-setting! (fn [key value]
- (let [new-settings (assoc settings key value)]
- (config-handler/set-config! :graph/settings new-settings)))
- search-graph-filters (state/sub :search/graph-filters)
- focus-nodes (rum/react *focus-nodes)]
- (rum/with-context [[t] i18n/*tongue-context*]
- [:div.absolute.top-4.right-4.graph-filters
- [:div.flex.flex-col
- [:div.shadow-xl.rounded-sm
- [:ul
- (graph-filter-section
- [:span.font-medium "Nodes"]
- (fn [open?]
- (filter-expand-area
- open?
- [:div
- [:p.text-sm.opacity-70.px-4
- (let [c1 (count (:nodes graph))
- s1 (if (> c1 1) "s" "")
- ;; c2 (count (:links graph))
- ;; s2 (if (> c2 1) "s" "")
- ]
- ;; (util/format "%d page%s, %d link%s" c1 s1 c2 s2)
- (util/format "%d page%s" c1 s1)
- )]
- [:div.p-6
- ;; [:div.flex.items-center.justify-between.mb-2
- ;; [:span "Layout"]
- ;; (ui/select
- ;; (mapv
- ;; (fn [item]
- ;; (if (= (:label item) layout)
- ;; (assoc item :selected "selected")
- ;; item))
- ;; [{:label "gForce"}
- ;; {:label "dagre"}])
- ;; (fn [value]
- ;; (set-setting! :layout value))
- ;; "graph-layout")]
- [:div.flex.items-center.justify-between.mb-2
- [:span "Journals"]
- ;; FIXME: why it's not aligned well?
- [:div.mt-1
- (ui/toggle journal?
- #(set-setting! :journal? (not journal?))
- true)]]
- [:div.flex.items-center.justify-between.mb-2
- [:span "Orphan pages"]
- [:div.mt-1
- (ui/toggle orphan-pages?
- #(set-setting! :orphan-pages? (not orphan-pages?))
- true)]]
- [:div.flex.items-center.justify-between.mb-2
- [:span "Built-in pages"]
- [:div.mt-1
- (ui/toggle builtin-pages?
- #(set-setting! :builtin-pages? (not builtin-pages?))
- true)]]
- (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 %))}))])
- [:a.opacity-70.opacity-100 {:on-click (fn []
- (swap! *graph-reset? not)
- (reset! *focus-nodes [])
- (reset! *n-hops nil)
- (state/clear-search-filters!))}
- "Reset Graph"]]])))
- (graph-filter-section
- [:span.font-medium "Search"]
- (fn [open?]
- (filter-expand-area
- open?
- [:div.p-6
- (if (seq search-graph-filters)
- [:div
- (for [q search-graph-filters]
- [:div.flex.flex-row.justify-between.items-center.mb-2
- [:span.font-medium q]
- [:a.search-filter-close.opacity-70.opacity-100 {:on-click #(state/remove-search-filter! q)}
- svg/close]])
- [:a.opacity-70.opacity-100 {:on-click state/clear-search-filters!}
- "Clear All"]]
- [:a.opacity-70.opacity-100 {:on-click #(route-handler/go-to-search! :graph)}
- "Click to search"])]))
- {:search-filters search-graph-filters})]]]])))
- (defn- graph-register-handlers
- [graph focus-nodes n-hops]
- (.on graph "nodeClick"
- (fn [event node]
- (graph/on-click-handler graph node event focus-nodes n-hops))))
- (rum/defc global-graph-inner < rum/reactive
- [graph settings theme]
- (let [[width height] (rum/react layout)
- dark? (= theme "dark")
- n-hops (rum/react *n-hops)
- reset? (rum/react *graph-reset?)
- focus-nodes (when n-hops (rum/react *focus-nodes))
- graph (if (and (integer? n-hops)
- (seq focus-nodes)
- (not (:orphan-pages? settings)))
- (graph-handler/n-hops graph focus-nodes n-hops)
- graph)
- graph (update graph :links (fn [links]
- (let [nodes (set (map :id (:nodes graph)))]
- (remove (fn [link]
- (and (not (nodes (:source link)))
- (not (nodes (:target link)))))
- links))))]
- (rum/with-context [[t] i18n/*tongue-context*]
- [:div.relative#global-graph
- (graph/graph-2d {:nodes (:nodes graph)
- :links (:links graph)
- :width (- width 24)
- :height (- height 48)
- :dark? dark?
- :register-handlers-fn
- (fn [graph]
- (graph-register-handlers graph *focus-nodes *n-hops))
- :reset? reset?})
- (graph-filters graph settings n-hops)])))
- (defn- filter-graph-nodes
- [nodes filters]
- (if (seq filters)
- (let [filter-patterns (map #(re-pattern (str "(?i)" (util/regex-escape %))) filters)]
- (filter (fn [node] (some #(re-find % (:id node)) filter-patterns)) nodes))
- nodes))
- (rum/defcs global-graph < rum/reactive
- (mixins/event-mixin
- (fn [state]
- (mixins/listen state js/window "resize"
- (fn [e]
- (reset! layout [js/window.innerWidth js/window.innerHeight])))))
- {:will-mount (fn [state]
- (state/set-search-mode! :graph)
- state)
- :will-unmount (fn [state]
- (reset! *n-hops nil)
- (reset! *focus-nodes [])
- (state/set-search-mode! :global)
- state)}
- [state]
- (let [settings (state/sub-graph-config)
- theme (state/sub :ui/theme)
- graph (graph-handler/build-global-graph theme settings)
- search-graph-filters (state/sub :search/graph-filters)
- graph (update graph :nodes #(filter-graph-nodes % search-graph-filters))
- reset? (rum/react *graph-reset?)]
- (global-graph-inner graph settings theme)))
- (rum/defc page-graph < db-mixins/query rum/reactive
- []
- (let [page (or
- (and (= :page (state/sub [:route-match :data :name]))
- (state/sub [:route-match :path-params :name]))
- (date/today))
- theme (:ui/theme @state/state)
- dark? (= theme "dark")
- graph (if (util/uuid-string? page)
- (graph-handler/build-block-graph (uuid page) theme)
- (graph-handler/build-page-graph page theme))]
- (when (seq (:nodes graph))
- [:div.sidebar-item.flex-col
- (graph/graph-2d {:nodes (:nodes graph)
- :links (:links graph)
- :width 600
- :height 600
- :dark? dark?
- :register-handlers-fn
- (fn [graph]
- (graph-register-handlers graph (atom nil) (atom nil)))})])))
- (rum/defc all-pages < rum/reactive
- ;; {:did-mount (fn [state]
- ;; (let [current-repo (state/sub :git/current-repo)]
- ;; (js/setTimeout #(db/remove-orphaned-pages! current-repo) 0))
- ;; state)}
- []
- (let [current-repo (state/sub :git/current-repo)]
- (rum/with-context [[t] i18n/*tongue-context*]
- [:div.flex-1
- [:h1.title (t :all-pages)]
- (when current-repo
- (let [pages (page-handler/get-pages-with-modified-at current-repo)]
- [:table.table-auto
- [:thead
- [:tr
- [:th (t :block/name)]
- [:th (t :file/last-modified-at)]]]
- [:tbody
- (for [page pages]
- [:tr {:key page}
- [:td [:a {:on-click (fn [e]
- (let [repo (state/get-current-repo)
- page (db/pull repo '[*] [:block/name (string/lower-case page)])]
- (when (gobj/get e "shiftKey")
- (state/sidebar-add-block!
- repo
- (:db/id page)
- :page
- {:page page}))))
- :href (rfe/href :page {:name page})}
- page]]
- [:td [:span.text-gray-500.text-sm
- (t :file/no-data)]]])]]))])))
|