mirror of
https://github.com/logseq/logseq.git
synced 2026-06-01 19:01:22 +00:00
Merge branch 'feat/db' into refactor/tag-as-type
This commit is contained in:
@@ -761,11 +761,15 @@
|
||||
|
||||
(defn- input-placeholder
|
||||
[sidebar?]
|
||||
(let [search-mode (:search/mode @state/state)]
|
||||
(let [search-mode (:search/mode @state/state)
|
||||
search-args (:search/args @state/state)]
|
||||
(cond
|
||||
(and (= search-mode :graph) (not sidebar?))
|
||||
"Add graph filter"
|
||||
|
||||
(= search-args :new-page)
|
||||
"Type a page name to create"
|
||||
|
||||
:else
|
||||
"What are you looking for?")))
|
||||
|
||||
@@ -949,6 +953,7 @@
|
||||
::input (atom (or (:initial-input opts) "")))))
|
||||
:will-unmount (fn [state]
|
||||
(state/set-state! :search/mode nil)
|
||||
(state/set-state! :search/args nil)
|
||||
state)}
|
||||
(mixins/event-mixin
|
||||
(fn [state]
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
[dommy.core :as d]
|
||||
[frontend.components.content :as cp-content]
|
||||
[frontend.config :as config]
|
||||
[frontend.context.i18n :refer [t]]
|
||||
[frontend.context.i18n :refer [t tt]]
|
||||
[frontend.db :as db]
|
||||
[electron.ipc :as ipc]
|
||||
[frontend.db-mixins :as db-mixins]
|
||||
@@ -59,18 +59,24 @@
|
||||
[frontend.extensions.fsrs :as fsrs]
|
||||
[logseq.common.util.namespace :as ns-util]))
|
||||
|
||||
(rum/defc nav-content-item < rum/reactive
|
||||
[name {:keys [class count]} child]
|
||||
(rum/defc sidebar-content-group < rum/reactive
|
||||
[name {:keys [class count more header-props enter-show-more? collapsable?]} child]
|
||||
(let [collapsed? (state/sub [:ui/navigation-item-collapsed? class])]
|
||||
[:div.nav-content-item
|
||||
[:div.sidebar-content-group
|
||||
{:class (util/classnames [class {:is-expand (not collapsed?)
|
||||
:has-children (and (number? count) (> count 0))}])}
|
||||
[:div.nav-content-item-inner
|
||||
[:div.header.items-center
|
||||
{:on-click (fn [^js/MouseEvent _e]
|
||||
(state/toggle-navigation-item-collapsed! class))}
|
||||
[:div.a name]
|
||||
[:div.b (ui/icon "chevron-left" {:class "more" :size 14})]]
|
||||
[:div.sidebar-content-group-inner
|
||||
[:div.hd.items-center
|
||||
(cond-> (merge header-props
|
||||
{:class (util/classnames [(:class header-props)
|
||||
{:non-collapsable (false? collapsable?)
|
||||
:enter-show-more (true? enter-show-more?)}])})
|
||||
|
||||
(not (false? collapsable?))
|
||||
(assoc :on-click (fn [^js/MouseEvent _e]
|
||||
(state/toggle-navigation-item-collapsed! class))))
|
||||
[:span.a name]
|
||||
[:span.b (or more (ui/icon "chevron-right" {:class "more" :size 15}))]]
|
||||
(when child [:div.bd child])]]))
|
||||
|
||||
(rum/defc page-name
|
||||
@@ -119,7 +125,7 @@
|
||||
(x-menu-shortcut (shortcut-utils/decorate-binding "shift+click")))]))]
|
||||
|
||||
;; TODO: move to standalone component
|
||||
[:a.flex.items-center.justify-between.relative.group.h-6
|
||||
[:a.link-item.group
|
||||
(cond->
|
||||
{:on-click
|
||||
(fn [e]
|
||||
@@ -134,7 +140,7 @@
|
||||
(util/stop e))}
|
||||
(ldb/object? page)
|
||||
(assoc :title (block-handler/block-unique-title page)))
|
||||
[:span.page-icon.ml-3.justify-center icon]
|
||||
[:span.page-icon icon]
|
||||
[:span.page-title {:class (when untitled? "opacity-50")
|
||||
:style {:display "ruby"}}
|
||||
(cond
|
||||
@@ -151,25 +157,174 @@
|
||||
(shui/button
|
||||
{:size :sm
|
||||
:variant :ghost
|
||||
:class "absolute right-2 top-0 px-1.5 scale-75 opacity-30 hidden group-hover:block hover:opacity-80 active:opacity-100"
|
||||
:class "absolute !bg-transparent right-0 top-0 px-1.5 scale-75 opacity-40 hidden group-hover:block hover:opacity-80 active:opacity-100"
|
||||
:on-click #(do
|
||||
(shui/popup-show! (.-target %) (x-menu-content)
|
||||
{:as-dropdown? true
|
||||
:content-props {:on-click (fn [] (shui/popup-hide!))
|
||||
:class "w-60"}})
|
||||
(util/stop %))}
|
||||
[:i.relative {:style {:top "1px"}} (shui/tabler-icon "dots")])]))
|
||||
[:i.relative {:style {:top "4px"}} (shui/tabler-icon "dots")])]))
|
||||
|
||||
;; Fall back to default if icon is undefined or empty
|
||||
(defn sidebar-item
|
||||
[{:keys [on-click-handler class title icon icon-extension? active href shortcut more]}]
|
||||
[:div
|
||||
{:class (util/classnames [class {:active active}])}
|
||||
[:a.item.group.flex.items-center.text-sm.font-medium.rounded-md
|
||||
{:on-click on-click-handler
|
||||
:class (when active "active")
|
||||
:href href}
|
||||
(ui/icon (str icon) {:extension? icon-extension?})
|
||||
[:span.flex-1 title]
|
||||
(when shortcut
|
||||
[:span.ml-1
|
||||
(ui/render-keyboard-shortcut
|
||||
(ui/keyboard-shortcut-from-config shortcut {:pick-first? true}))])
|
||||
more]])
|
||||
|
||||
(rum/defc favorites < rum/reactive
|
||||
[t]
|
||||
(rum/defc sidebar-graphs
|
||||
[]
|
||||
[:div.sidebar-graphs
|
||||
(repo/graphs-selector)])
|
||||
|
||||
(rum/defc sidebar-navigations-edit-content
|
||||
[{:keys [_id navs checked-navs set-checked-navs!]}]
|
||||
(let [[local-navs set-local-navs!] (rum/use-state checked-navs)]
|
||||
|
||||
(rum/use-effect!
|
||||
(fn []
|
||||
(set-checked-navs! local-navs))
|
||||
[local-navs])
|
||||
|
||||
(for [nav navs
|
||||
:let [name' (name nav)]]
|
||||
(shui/dropdown-menu-checkbox-item
|
||||
{:checked (contains? (set local-navs) nav)
|
||||
:onCheckedChange (fn [v] (set-local-navs!
|
||||
(fn []
|
||||
(if v
|
||||
(conj local-navs nav)
|
||||
(filterv #(not= nav %) local-navs)))))}
|
||||
(tt (keyword "left-side-bar" name')
|
||||
(keyword "right-side-bar" name'))))))
|
||||
|
||||
(rum/defc ^:large-vars/cleanup-todo sidebar-navigations
|
||||
[{:keys [default-home route-match route-name srs-open? db-based? enable-whiteboards?]}]
|
||||
(let [navs [:whiteboards :flashcards :graph-view :all-pages :tag/tasks :tag/assets]
|
||||
[checked-navs set-checked-navs!] (rum/use-state (or (storage/get :ls-sidebar-navigations)
|
||||
[:whiteboards :flashcards :graph-view :all-pages :tag/tasks]))]
|
||||
|
||||
(rum/use-effect!
|
||||
(fn []
|
||||
(when (vector? checked-navs)
|
||||
(storage/set :ls-sidebar-navigations checked-navs)))
|
||||
[checked-navs])
|
||||
|
||||
(sidebar-content-group
|
||||
[:a.wrap-th [:strong.flex-1 "Navigations"]]
|
||||
{:collapsable? false
|
||||
:enter-show-more? true
|
||||
:header-props {:on-click (fn [^js e] (when-let [^js _el (some-> (.-target e) (.closest ".as-edit"))]
|
||||
(shui/popup-show! _el
|
||||
#(sidebar-navigations-edit-content
|
||||
{:id (:id %) :navs navs
|
||||
:checked-navs checked-navs
|
||||
:set-checked-navs! set-checked-navs!})
|
||||
{:as-dropdown? false})))}
|
||||
:more [:a.as-edit {:class "!opacity-60 hover:!opacity-80 relative -top-0.5 right-0"}
|
||||
(shui/tabler-icon "filter-edit" {:size 15})]}
|
||||
[:div.sidebar-navigations.flex.flex-col.mt-1
|
||||
;; required custom home page
|
||||
(let [page (:page default-home)]
|
||||
(if (and page (not (state/enable-journals? (state/get-current-repo))))
|
||||
(sidebar-item
|
||||
{:class "home-nav"
|
||||
:title page
|
||||
:on-click-handler route-handler/redirect-to-home!
|
||||
:active (and (not srs-open?)
|
||||
(= route-name :page)
|
||||
(= page (get-in route-match [:path-params :name])))
|
||||
:icon "home"
|
||||
:shortcut :go/home})
|
||||
|
||||
(sidebar-item
|
||||
{:class "journals-nav"
|
||||
:active (and (not srs-open?)
|
||||
(or (= route-name :all-journals) (= route-name :home)))
|
||||
:title (t :left-side-bar/journals)
|
||||
:on-click-handler (fn [e]
|
||||
(if (gobj/get e "shiftKey")
|
||||
(route-handler/sidebar-journals!)
|
||||
(route-handler/go-to-journals!)))
|
||||
:icon "calendar"
|
||||
:shortcut :go/journals})))
|
||||
|
||||
(for [nav checked-navs]
|
||||
(cond
|
||||
(= nav :whiteboards)
|
||||
(when enable-whiteboards?
|
||||
(when (or config/dev? (not db-based?))
|
||||
(sidebar-item
|
||||
{:class "whiteboard"
|
||||
:title (t :right-side-bar/whiteboards)
|
||||
:href (rfe/href :whiteboards)
|
||||
:on-click-handler (fn [_e] (whiteboard-handler/onboarding-show))
|
||||
:active (and (not srs-open?) (#{:whiteboard :whiteboards} route-name))
|
||||
:icon "whiteboard"
|
||||
:icon-extension? true
|
||||
:shortcut :go/whiteboards})))
|
||||
|
||||
(= nav :flashcards)
|
||||
(when (state/enable-flashcards? (state/get-current-repo))
|
||||
(let [num (state/sub :srs/cards-due-count)]
|
||||
(sidebar-item
|
||||
{:class "flashcards-nav"
|
||||
:title (t :right-side-bar/flashcards)
|
||||
:icon "infinity"
|
||||
:shortcut :go/flashcards
|
||||
:active srs-open?
|
||||
:on-click-handler #(do (fsrs/update-due-cards-count)
|
||||
(state/pub-event! [:modal/show-cards]))
|
||||
:more (when (and num (not (zero? num)))
|
||||
[:span.ml-1.inline-block.py-0.5.px-3.text-xs.font-medium.rounded-full.fade-in num])})))
|
||||
|
||||
(= nav :graph-view)
|
||||
(sidebar-item
|
||||
{:class "graph-view-nav"
|
||||
:title (t :right-side-bar/graph-view)
|
||||
:href (rfe/href :graph)
|
||||
:active (and (not srs-open?) (= route-name :graph))
|
||||
:icon "hierarchy"
|
||||
:shortcut :go/graph-view})
|
||||
|
||||
(= nav :all-pages)
|
||||
(sidebar-item
|
||||
{:class "all-pages-nav"
|
||||
:title (t :right-side-bar/all-pages)
|
||||
:href (rfe/href :all-pages)
|
||||
:active (and (not srs-open?) (= route-name :all-pages))
|
||||
:icon "files"})
|
||||
|
||||
(= (namespace nav) "tag")
|
||||
(when db-based?
|
||||
(let [name'' (name nav)
|
||||
name' (get {"assets" "Asset" "tasks" "Task"} name'')]
|
||||
(when-let [tag-uuid (and name' (:block/uuid (db/entity (keyword "logseq.class" name'))))]
|
||||
(sidebar-item
|
||||
{:class (str "tag-view-nav " name'')
|
||||
:title (tt (keyword "left-side-bar" name'')
|
||||
(keyword "right-side-bar" name''))
|
||||
:href (rfe/href :page {:name tag-uuid})
|
||||
:active (= (str tag-uuid) (get-in route-match [:path-params :name]))
|
||||
:icon "hash"}))))))])))
|
||||
|
||||
(rum/defc sidebar-favorites < rum/reactive
|
||||
[]
|
||||
(let [_favorites-updated? (state/sub :favorites/updated?)
|
||||
favorite-entities (page-handler/get-favorites)]
|
||||
(nav-content-item
|
||||
[:a.flex.items-center.text-sm.font-medium.rounded-md.wrap-th
|
||||
(ui/icon "star" {:size 16})
|
||||
[:strong.flex-1.ml-2 (string/upper-case (t :left-side-bar/nav-favorites))]]
|
||||
(sidebar-content-group
|
||||
[:a.wrap-th
|
||||
[:strong.flex-1 (t :left-side-bar/nav-favorites)]]
|
||||
|
||||
{:class "favorites"
|
||||
:count (count favorite-entities)
|
||||
@@ -180,7 +335,7 @@
|
||||
(when (seq favorite-entities)
|
||||
(let [favorite-items (map
|
||||
(fn [e]
|
||||
(let [icon (icon/get-node-icon-cp e {})]
|
||||
(let [icon (icon/get-node-icon-cp e {:size 16})]
|
||||
{:id (str (:db/id e))
|
||||
:value (:block/uuid e)
|
||||
:content [:li.favorite-item (page-name e icon false)]}))
|
||||
@@ -190,14 +345,11 @@
|
||||
(page-handler/<reorder-favorites! favorites'))
|
||||
:parent-node :ul.favorites.text-sm}))))))
|
||||
|
||||
(rum/defc recent-pages < rum/reactive db-mixins/query
|
||||
[t]
|
||||
(rum/defc sidebar-recent-pages < rum/reactive db-mixins/query
|
||||
[]
|
||||
(let [pages (recent-handler/get-recent-pages)]
|
||||
(nav-content-item
|
||||
[:a.flex.items-center.text-sm.font-medium.rounded-md.wrap-th
|
||||
(ui/icon "history" {:size 16})
|
||||
[:strong.flex-1.ml-2
|
||||
(string/upper-case (t :left-side-bar/nav-recent-pages))]]
|
||||
(sidebar-content-group
|
||||
[:a.wrap-th [:strong.flex-1 (t :left-side-bar/nav-recent-pages)]]
|
||||
|
||||
{:class "recent"
|
||||
:count (count pages)}
|
||||
@@ -210,23 +362,7 @@
|
||||
:draggable true
|
||||
:on-drag-start (fn [event] (editor-handler/block->data-transfer! (:block/name page) event true))
|
||||
:data-ref name}
|
||||
(page-name page (icon/get-node-icon-cp page {}) true)])])))
|
||||
|
||||
(rum/defc flashcards < db-mixins/query rum/reactive
|
||||
[srs-open?]
|
||||
(let [num (state/sub :srs/cards-due-count)]
|
||||
[:a.item.group.flex.items-center.px-2.py-2.text-sm.font-medium.rounded-md
|
||||
{:class (util/classnames [{:active srs-open?}])
|
||||
:on-click #(do
|
||||
(fsrs/update-due-cards-count)
|
||||
(state/pub-event! [:modal/show-cards]))}
|
||||
(ui/icon "infinity")
|
||||
[:span.flex-1 (t :right-side-bar/flashcards)]
|
||||
[:span.ml-1 (ui/render-keyboard-shortcut
|
||||
(ui/keyboard-shortcut-from-config :go/flashcards
|
||||
{:pick-first? true}))]
|
||||
(when (and num (not (zero? num)))
|
||||
[:span.ml-1.inline-block.py-0.5.px-3.text-xs.font-medium.rounded-full.fade-in num])]))
|
||||
(page-name page (icon/get-node-icon-cp page {:size 16}) true)])])))
|
||||
|
||||
(defn get-default-home-if-valid
|
||||
[]
|
||||
@@ -239,37 +375,24 @@
|
||||
default-home
|
||||
(dissoc default-home :page)))))
|
||||
|
||||
(defn sidebar-item
|
||||
[{:keys [on-click-handler class title icon icon-extension? active href shortcut]}]
|
||||
[:div
|
||||
{:class class}
|
||||
[:a.item.group.flex.items-center.text-sm.font-medium.rounded-md
|
||||
{:on-click on-click-handler
|
||||
:class (when active "active")
|
||||
:href href}
|
||||
(ui/icon (str icon) {:extension? icon-extension?})
|
||||
[:span.flex-1 title]
|
||||
(when shortcut
|
||||
[:span.ml-1 (ui/render-keyboard-shortcut (ui/keyboard-shortcut-from-config shortcut))])]])
|
||||
|
||||
(rum/defc ^:large-vars/cleanup-todo sidebar-nav
|
||||
(rum/defc ^:large-vars/cleanup-todo sidebar-container
|
||||
[route-match close-modal-fn left-sidebar-open? enable-whiteboards? srs-open?
|
||||
*closing? close-signal touching-x-offset]
|
||||
(let [[local-closing? set-local-closing?] (rum/use-state false)
|
||||
[el-rect set-el-rect!] (rum/use-state nil)
|
||||
ref-el (rum/use-ref nil)
|
||||
ref-open? (rum/use-ref left-sidebar-open?)
|
||||
db-based? (config/db-based-graph? (state/get-current-repo))
|
||||
default-home (get-default-home-if-valid)
|
||||
route-name (get-in route-match [:data :name])
|
||||
on-contents-scroll #(when-let [^js el (.-target %)]
|
||||
(let [top (.-scrollTop el)
|
||||
cls (.-classList el)
|
||||
cls' "is-scrolled"]
|
||||
(if (> top 2)
|
||||
(.add cls cls')
|
||||
(.remove cls cls'))))
|
||||
close-fn #(set-local-closing? true)
|
||||
ref-el (rum/use-ref nil)
|
||||
ref-open? (rum/use-ref left-sidebar-open?)
|
||||
db-based? (config/db-based-graph? (state/get-current-repo))
|
||||
default-home (get-default-home-if-valid)
|
||||
route-name (get-in route-match [:data :name])
|
||||
on-contents-scroll #(when-let [^js el (.-target %)]
|
||||
(let [top (.-scrollTop el)
|
||||
cls (.-classList el)
|
||||
cls' "is-scrolled"]
|
||||
(if (> top 2)
|
||||
(.add cls cls')
|
||||
(.remove cls cls'))))
|
||||
close-fn #(set-local-closing? true)
|
||||
touching-x-offset (when (number? touching-x-offset)
|
||||
(if-not left-sidebar-open?
|
||||
(when (> touching-x-offset 0)
|
||||
@@ -306,109 +429,46 @@
|
||||
|
||||
[:<>
|
||||
[:div.left-sidebar-inner.flex-1.flex.flex-col.min-h-0
|
||||
{:ref ref-el
|
||||
:style (cond-> {}
|
||||
(and (number? offset-ratio)
|
||||
(> touching-x-offset 0))
|
||||
(assoc :transform (str "translate3d(calc(" touching-x-offset "px - 100%), 0, 0)"))
|
||||
{:ref ref-el
|
||||
:style (cond-> {}
|
||||
(and (number? offset-ratio)
|
||||
(> touching-x-offset 0))
|
||||
(assoc :transform (str "translate3d(calc(" touching-x-offset "px - 100%), 0, 0)"))
|
||||
|
||||
(and (number? offset-ratio)
|
||||
(< touching-x-offset 0))
|
||||
(assoc :transform (str "translate3d(" (* offset-ratio 100) "%, 0, 0)")))
|
||||
(and (number? offset-ratio)
|
||||
(< touching-x-offset 0))
|
||||
(assoc :transform (str "translate3d(" (* offset-ratio 100) "%, 0, 0)")))
|
||||
:on-transition-end (fn []
|
||||
(when local-closing?
|
||||
(reset! *closing? false)
|
||||
(set-local-closing? false)
|
||||
(close-modal-fn)))
|
||||
:on-click #(when-let [^js target (and (util/sm-breakpoint?) (.-target %))]
|
||||
(when (some (fn [sel] (boolean (.closest target sel)))
|
||||
[".favorites .bd" ".recent .bd" ".dropdown-wrapper" ".nav-header"])
|
||||
(close-fn)))}
|
||||
:on-click #(when-let [^js target (and (util/sm-breakpoint?) (.-target %))]
|
||||
(when (some (fn [sel] (boolean (.closest target sel)))
|
||||
[".favorites .bd" ".recent .bd" ".dropdown-wrapper" ".nav-header"])
|
||||
(close-fn)))}
|
||||
|
||||
[:div.flex.flex-col.wrap.gap-1.relative
|
||||
[:nav.px-4.flex.flex-col.gap-1.cp__menubar-repos
|
||||
{:aria-label "Navigation menu"}
|
||||
(repo/repos-dropdown)
|
||||
[:div.wrap
|
||||
[:div.sidebar-header-container
|
||||
;; sidebar graphs
|
||||
(sidebar-graphs)
|
||||
|
||||
[:div.nav-header.flex.flex-col.mt-1
|
||||
(let [page (:page default-home)]
|
||||
(if (and page (not (state/enable-journals? (state/get-current-repo))))
|
||||
(sidebar-item
|
||||
{:class "home-nav"
|
||||
:title page
|
||||
:on-click-handler route-handler/redirect-to-home!
|
||||
:active (and (not srs-open?)
|
||||
(= route-name :page)
|
||||
(= page (get-in route-match [:path-params :name])))
|
||||
:icon "home"
|
||||
:shortcut :go/home})
|
||||
(sidebar-item
|
||||
{:class "journals-nav"
|
||||
:active (and (not srs-open?)
|
||||
(or (= route-name :all-journals) (= route-name :home)))
|
||||
:title (t :left-side-bar/journals)
|
||||
:on-click-handler (fn [e]
|
||||
(if (gobj/get e "shiftKey")
|
||||
(route-handler/sidebar-journals!)
|
||||
(route-handler/go-to-journals!)))
|
||||
:icon "calendar"
|
||||
:shortcut :go/journals})))
|
||||
;; sidebar sticky navigations
|
||||
(sidebar-navigations
|
||||
{:default-home default-home
|
||||
:route-match route-match
|
||||
:db-based? db-based?
|
||||
:enable-whiteboards? enable-whiteboards?
|
||||
:route-name route-name
|
||||
:srs-open? srs-open?})]
|
||||
|
||||
(when db-based?
|
||||
(let [tag-uuid (:block/uuid (db/entity :logseq.class/Task))]
|
||||
(sidebar-item
|
||||
{:class "task-view-nav"
|
||||
:title (t :left-side-bar/tasks)
|
||||
:href (rfe/href :page {:name tag-uuid})
|
||||
:active (= (str tag-uuid) (get-in route-match [:path-params :name]))
|
||||
:icon "hash"})))
|
||||
|
||||
(when db-based?
|
||||
(let [tag-uuid (:block/uuid (db/entity :logseq.class/Asset))]
|
||||
(sidebar-item
|
||||
{:class "asset-view-nav"
|
||||
:title (t :left-side-bar/assets)
|
||||
:href (rfe/href :page {:name tag-uuid})
|
||||
:active (= (str tag-uuid) (get-in route-match [:path-params :name]))
|
||||
:icon "hash"})))
|
||||
|
||||
(when enable-whiteboards?
|
||||
(when (or config/dev? (not db-based?))
|
||||
(sidebar-item
|
||||
{:class "whiteboard"
|
||||
:title (t :right-side-bar/whiteboards)
|
||||
:href (rfe/href :whiteboards)
|
||||
:on-click-handler (fn [_e] (whiteboard-handler/onboarding-show))
|
||||
:active (and (not srs-open?) (#{:whiteboard :whiteboards} route-name))
|
||||
:icon "whiteboard"
|
||||
:icon-extension? true
|
||||
:shortcut :go/whiteboards})))
|
||||
|
||||
(when (state/enable-flashcards? (state/get-current-repo))
|
||||
[:div.flashcards-nav
|
||||
(flashcards srs-open?)])
|
||||
|
||||
(sidebar-item
|
||||
{:class "graph-view-nav"
|
||||
:title (t :right-side-bar/graph-view)
|
||||
:href (rfe/href :graph)
|
||||
:active (and (not srs-open?) (= route-name :graph))
|
||||
:icon "hierarchy"
|
||||
:shortcut :go/graph-view})
|
||||
|
||||
(sidebar-item
|
||||
{:class "all-pages-nav"
|
||||
:title (t :right-side-bar/all-pages)
|
||||
:href (rfe/href :all-pages)
|
||||
:active (and (not srs-open?) (= route-name :all-pages))
|
||||
:icon "files"})]]
|
||||
|
||||
[:div.nav-contents-container.flex.flex-col.gap-1.pt-1
|
||||
[:div.sidebar-contents-container
|
||||
{:on-scroll on-contents-scroll}
|
||||
(favorites t)
|
||||
(sidebar-favorites)
|
||||
|
||||
(when (not config/publishing?)
|
||||
(recent-pages t))]]]
|
||||
(sidebar-recent-pages))]]]
|
||||
|
||||
[:span.shade-mask
|
||||
(cond-> {:on-click close-fn}
|
||||
(number? offset-ratio)
|
||||
@@ -459,22 +519,22 @@
|
||||
(rum/local -1 ::close-signal)
|
||||
(rum/local nil ::touch-state)
|
||||
[s {:keys [left-sidebar-open? route-match]}]
|
||||
(let [close-fn #(state/set-left-sidebar-open! false)
|
||||
*closing? (::closing? s)
|
||||
*touch-state (::touch-state s)
|
||||
*close-signal (::close-signal s)
|
||||
enable-whiteboards? (state/enable-whiteboards?)
|
||||
touch-point-fn (fn [^js e] (some-> (gobj/get e "touches") (aget 0) (#(hash-map :x (.-clientX %) :y (.-clientY %)))))
|
||||
srs-open? (= :srs (state/sub :modal/id))
|
||||
touching-x-offset (and (some-> @*touch-state :after)
|
||||
(some->> @*touch-state
|
||||
((juxt :after :before))
|
||||
(map :x) (apply -)))
|
||||
touch-pending? (> (abs touching-x-offset) 20)]
|
||||
(let [close-fn #(state/set-left-sidebar-open! false)
|
||||
*closing? (::closing? s)
|
||||
*touch-state (::touch-state s)
|
||||
*close-signal (::close-signal s)
|
||||
enable-whiteboards? (state/enable-whiteboards?)
|
||||
touch-point-fn (fn [^js e] (some-> (gobj/get e "touches") (aget 0) (#(hash-map :x (.-clientX %) :y (.-clientY %)))))
|
||||
srs-open? (= :srs (state/sub :modal/id))
|
||||
touching-x-offset (and (some-> @*touch-state :after)
|
||||
(some->> @*touch-state
|
||||
((juxt :after :before))
|
||||
(map :x) (apply -)))
|
||||
touch-pending? (> (abs touching-x-offset) 20)]
|
||||
|
||||
[:div#left-sidebar.cp__sidebar-left-layout
|
||||
{:class (util/classnames [{:is-open left-sidebar-open?
|
||||
:is-closing @*closing?
|
||||
{:class (util/classnames [{:is-open left-sidebar-open?
|
||||
:is-closing @*closing?
|
||||
:is-touching touch-pending?}])
|
||||
:on-touch-start
|
||||
(fn [^js e]
|
||||
@@ -495,8 +555,9 @@
|
||||
(reset! *touch-state nil))}
|
||||
|
||||
;; sidebar contents
|
||||
(sidebar-nav route-match close-fn left-sidebar-open? enable-whiteboards? srs-open? *closing?
|
||||
@*close-signal (and touch-pending? touching-x-offset))
|
||||
(sidebar-container route-match close-fn left-sidebar-open? enable-whiteboards? srs-open? *closing?
|
||||
@*close-signal (and touch-pending? touching-x-offset))
|
||||
|
||||
;; resizer
|
||||
(sidebar-resizer)]))
|
||||
|
||||
@@ -539,13 +600,13 @@
|
||||
onboarding-and-home? (and (or (nil? (state/get-current-repo)) (config/demo-graph?))
|
||||
(not config/publishing?)
|
||||
(= :home route-name))
|
||||
margin-less-pages? (or (and (mobile-util/native-platform?) onboarding-and-home?) margin-less-pages?)]
|
||||
margin-less-pages? (or (and (mobile-util/native-platform?) onboarding-and-home?) margin-less-pages?)]
|
||||
[:div#main-container.cp__sidebar-main-layout.flex-1.flex
|
||||
{:class (util/classnames [{:is-left-sidebar-open left-sidebar-open?}])}
|
||||
|
||||
;; desktop left sidebar layout
|
||||
(left-sidebar {:left-sidebar-open? left-sidebar-open?
|
||||
:route-match route-match})
|
||||
:route-match route-match})
|
||||
|
||||
[:div#main-content-container.scrollbar-spacing.w-full.flex.justify-center.flex-row.outline-none.relative
|
||||
|
||||
@@ -557,8 +618,8 @@
|
||||
|
||||
[:div.cp__sidebar-main-content
|
||||
{:data-is-margin-less-pages margin-less-pages?
|
||||
:data-is-full-width (or margin-less-pages?
|
||||
(contains? #{:all-files :all-pages :my-publishing} route-name))}
|
||||
:data-is-full-width (or margin-less-pages?
|
||||
(contains? #{:all-files :all-pages :my-publishing} route-name))}
|
||||
|
||||
(when show-recording-bar?
|
||||
(recording-bar))
|
||||
@@ -584,10 +645,10 @@
|
||||
:else
|
||||
[:div
|
||||
{:class (if (or onboarding-and-home? margin-less-pages?) "" (util/hiccup->class "mx-auto.pb-24"))
|
||||
:style {:margin-bottom (cond
|
||||
margin-less-pages? 0
|
||||
onboarding-and-home? 0
|
||||
:else 120)}}
|
||||
:style {:margin-bottom (cond
|
||||
margin-less-pages? 0
|
||||
onboarding-and-home? 0
|
||||
:else 120)}}
|
||||
main-content])
|
||||
|
||||
(comment
|
||||
@@ -714,7 +775,7 @@
|
||||
[: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"]]
|
||||
[: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))]
|
||||
@@ -761,7 +822,7 @@
|
||||
|
||||
;; default
|
||||
[:a.it.flex.items-center.px-4.py-1.select-none
|
||||
{:key title
|
||||
{:key title
|
||||
:on-click (fn []
|
||||
(cond
|
||||
(fn? on-click) (on-click)
|
||||
@@ -774,12 +835,12 @@
|
||||
|
||||
(rum/defc help-button < rum/reactive
|
||||
[]
|
||||
(let [help-open? (state/sub :ui/help-open?)
|
||||
(let [help-open? (state/sub :ui/help-open?)
|
||||
handbooks-open? (state/sub :ui/handbooks-open?)]
|
||||
[:<>
|
||||
[:div.cp__sidebar-help-btn
|
||||
[:div.inner
|
||||
{:title (t :help-shortcut-title)
|
||||
{:title (t :help-shortcut-title)
|
||||
:on-click #(state/toggle! :ui/help-open?)}
|
||||
[:svg.scale-125 {:stroke "currentColor", :fill "none", :stroke-linejoin "round", :width "24", :view-box "0 0 24 24", :xmlns "http://www.w3.org/2000/svg", :stroke-linecap "round", :stroke-width "2", :class "icon icon-tabler icon-tabler-help-small", :height "24"}
|
||||
[:path {:stroke "none", :d "M0 0h24v24H0z", :fill "none"}]
|
||||
@@ -862,7 +923,7 @@
|
||||
(if (and (state/modal-opened?)
|
||||
(not
|
||||
(and
|
||||
;; FIXME: this does not work on CI tests
|
||||
;; FIXME: this does not work on CI tests
|
||||
util/node-test?
|
||||
(state/editing?))))
|
||||
(state/close-modal!)
|
||||
@@ -879,9 +940,9 @@
|
||||
editor-font (some-> (state/sub :ui/editor-font) (name))
|
||||
system-theme? (state/sub :ui/system-theme?)
|
||||
light? (= "light" (state/sub :ui/theme))
|
||||
sidebar-open? (state/sub :ui/sidebar-open?)
|
||||
sidebar-open? (state/sub :ui/sidebar-open?)
|
||||
settings-open? (state/sub :ui/settings-open?)
|
||||
left-sidebar-open? (state/sub :ui/left-sidebar-open?)
|
||||
left-sidebar-open? (state/sub :ui/left-sidebar-open?)
|
||||
wide-mode? (state/sub :ui/wide-mode?)
|
||||
ls-block-hl-colored? (state/sub :pdf/block-highlight-colored?)
|
||||
onboarding-state (state/sub :file-sync/onboarding-state)
|
||||
@@ -903,14 +964,14 @@
|
||||
show-recording-bar? (state/sub :mobile/show-recording-bar?)
|
||||
preferred-language (state/sub [:preferred-language])]
|
||||
(theme/container
|
||||
{:t t
|
||||
:theme theme
|
||||
:accent-color accent-color
|
||||
:editor-font editor-font
|
||||
:route route-match
|
||||
:current-repo current-repo
|
||||
:edit? edit?
|
||||
:nfs-granted? granted?
|
||||
{:t t
|
||||
:theme theme
|
||||
:accent-color accent-color
|
||||
:editor-font editor-font
|
||||
:route route-match
|
||||
:current-repo current-repo
|
||||
:edit? edit?
|
||||
:nfs-granted? granted?
|
||||
:db-restoring? db-restoring?
|
||||
:sidebar-open? sidebar-open?
|
||||
:settings-open? settings-open?
|
||||
@@ -918,9 +979,9 @@
|
||||
:system-theme? system-theme?
|
||||
:onboarding-state onboarding-state
|
||||
:preferred-language preferred-language
|
||||
:on-click (fn [e]
|
||||
(editor-handler/unhighlight-blocks!)
|
||||
(util/fix-open-external-with-shift! e))}
|
||||
:on-click (fn [e]
|
||||
(editor-handler/unhighlight-blocks!)
|
||||
(util/fix-open-external-with-shift! e))}
|
||||
|
||||
[:main.theme-container-inner#app-container-wrapper
|
||||
{:class (util/classnames
|
||||
@@ -945,26 +1006,26 @@
|
||||
[:div.#app-container
|
||||
[:div#left-container
|
||||
{:class (if (state/sub :ui/sidebar-open?) "overflow-hidden" "w-full")}
|
||||
(header/header {:light? light?
|
||||
:current-repo current-repo
|
||||
:logged? logged?
|
||||
:page? page?
|
||||
:route-match route-match
|
||||
:default-home default-home
|
||||
(header/header {:light? light?
|
||||
:current-repo current-repo
|
||||
:logged? logged?
|
||||
:page? page?
|
||||
:route-match route-match
|
||||
:default-home default-home
|
||||
:new-block-mode new-block-mode})
|
||||
(when (util/electron?)
|
||||
(find-in-page/search))
|
||||
|
||||
(main {:route-match route-match
|
||||
:margin-less-pages? margin-less-pages?
|
||||
:logged? logged?
|
||||
:home? home?
|
||||
:route-name route-name
|
||||
:indexeddb-support? indexeddb-support?
|
||||
:light? light?
|
||||
:db-restoring? db-restoring?
|
||||
:main-content main-content'
|
||||
:show-action-bar? show-action-bar?
|
||||
(main {:route-match route-match
|
||||
:margin-less-pages? margin-less-pages?
|
||||
:logged? logged?
|
||||
:home? home?
|
||||
:route-name route-name
|
||||
:indexeddb-support? indexeddb-support?
|
||||
:light? light?
|
||||
:db-restoring? db-restoring?
|
||||
:main-content main-content'
|
||||
:show-action-bar? show-action-bar?
|
||||
:show-recording-bar? show-recording-bar?})]
|
||||
|
||||
(when window-controls?
|
||||
|
||||
@@ -58,32 +58,18 @@
|
||||
@apply py-4 sm:pl-8 sm:pr-4;
|
||||
}
|
||||
|
||||
#main-content-container[data-is-margin-less-pages=true] {
|
||||
padding: 0 !important;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.left-sidebar-inner {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
padding-top: 12px;
|
||||
width: var(--ls-left-sidebar-sm-width);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
background-color: var(--left-sidebar-bg-color);
|
||||
border-right: 1px solid or(--ls-left-sidebar-border-color, --lx-gray-03, --ls-tertiary-background-color);
|
||||
transition: transform .3s;
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
z-index: 3;
|
||||
@apply relative h-full pt-3 overflow-y-auto overflow-x-hidden transition-transform;
|
||||
@apply transform-gpu translate-x-[-100%] z-[3] antialiased;
|
||||
|
||||
-webkit-font-smoothing: antialiased;
|
||||
width: var(--ls-left-sidebar-sm-width);
|
||||
background-color: var(--left-sidebar-bg-color);
|
||||
border-right: 1px solid var(--lx-gray-03, var(--ls-tertiary-background-color));
|
||||
|
||||
> .wrap {
|
||||
@apply flex flex-col relative w-full mt-6;
|
||||
|
||||
height: calc(100vh - var(--ls-headbar-inner-top-padding) - 50px);
|
||||
margin-top: 30px;
|
||||
width: 100%;
|
||||
padding-top: var(--ls-win32-title-bar-height);
|
||||
|
||||
> .fake-bar {
|
||||
@apply w-full px-5 pt-1 sm:hidden;
|
||||
@@ -106,7 +92,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.nav-header {
|
||||
.sidebar-navigations {
|
||||
@apply gap-0.5;
|
||||
|
||||
a {
|
||||
@@ -126,58 +112,47 @@
|
||||
}
|
||||
|
||||
.page-icon {
|
||||
@apply flex items-center text-center mr-1 align-baseline;
|
||||
|
||||
width: 20px;
|
||||
flex-shrink: 0;
|
||||
line-height: 1em;
|
||||
@apply flex items-center mr-2 text-center align-baseline leading-none;
|
||||
}
|
||||
|
||||
a.item {
|
||||
@apply px-2 py-2 sm:py-1.5;
|
||||
|
||||
user-select: none;
|
||||
transition: background-color .3s;
|
||||
@apply flex items-center pl-1.5 pr-0.5 h-8 select-none;
|
||||
|
||||
.ui__icon {
|
||||
@apply flex justify-center;
|
||||
width: 20px;
|
||||
font-size: 16px;
|
||||
margin-right: 8px;
|
||||
opacity: .7;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.graph-icon .ui__icon {
|
||||
padding: 0;
|
||||
width: unset;
|
||||
margin-right: 0px;
|
||||
@apply relative flex justify-center w-[20px] text-base mr-2 opacity-80;
|
||||
}
|
||||
|
||||
.graph-icon {
|
||||
margin-left: 3px;
|
||||
margin-right: 11px;
|
||||
}
|
||||
|
||||
&:hover, &.active {
|
||||
background-color: var(--lx-gray-04, var(--color-level-3, var(--rx-gray-04)));
|
||||
color: var(--lx-gray-12, var(--rx-gray-12));
|
||||
@apply ml-[3px] mr-[11px];
|
||||
|
||||
.ui__icon {
|
||||
opacity: .9;
|
||||
@apply p-0 w-auto mr-0;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover, &.active, > .thumb {
|
||||
background-color: var(--lx-gray-04, var(--ls-quaternary-background-color, var(--rx-gray-04)));
|
||||
|
||||
.ui__icon {
|
||||
@apply opacity-100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-contents-container {
|
||||
@apply relative h-full flex-grow-0 overflow-x-hidden overflow-y-auto;
|
||||
.sidebar-header-container {
|
||||
@apply flex flex-col gap-1 px-3 mb-1;
|
||||
}
|
||||
|
||||
.sidebar-contents-container {
|
||||
@apply flex flex-col gap-1 pt-1;
|
||||
@apply px-3 relative h-full flex-grow-0 overflow-x-hidden overflow-y-auto;
|
||||
|
||||
&.is-scrolled {
|
||||
border-top: 1px solid var(--ls-tertiary-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
.nav-content-item {
|
||||
.sidebar-content-group {
|
||||
&:not(:hover) {
|
||||
::-webkit-scrollbar-thumb,
|
||||
::-webkit-scrollbar,
|
||||
@@ -186,168 +161,116 @@
|
||||
}
|
||||
}
|
||||
|
||||
.nav-content-item-inner {
|
||||
&-inner {
|
||||
@apply flex flex-col;
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply pl-6 pr-4 py-1 flex justify-between items-center select-none sticky top-[-4px];
|
||||
@apply cursor-pointer z-[2] active:opacity-80;
|
||||
> .hd {
|
||||
@apply pl-2 pr-1 h-[32px] flex justify-between items-center select-none sticky top-[-4px];
|
||||
@apply cursor-pointer z-[2] active:opacity-80 rounded-md;
|
||||
|
||||
background-color: var(--left-sidebar-bg-color);
|
||||
background-color: var(--left-sidebar-bg-color);
|
||||
|
||||
.ui__icon {
|
||||
@apply flex justify-center;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.more {
|
||||
opacity: 0;
|
||||
transition: .15s transform;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--lx-gray-04, var(--ls-tertiary-background-color, var(--rx-gray-04)));
|
||||
|
||||
* {
|
||||
opacity: 1 !important;
|
||||
.ui__icon {
|
||||
@apply flex justify-center w-[20px];
|
||||
}
|
||||
|
||||
.more {
|
||||
opacity: .8 !important;
|
||||
}
|
||||
}
|
||||
&.non-collapsable {
|
||||
@apply cursor-default active:opacity-100;
|
||||
|
||||
.wrap-th {
|
||||
@apply opacity-50;
|
||||
|
||||
> .ui__icon {
|
||||
@apply relative top-[-1px];
|
||||
}
|
||||
|
||||
> strong {
|
||||
@apply text-[11px] font-semibold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bd {
|
||||
@apply py-1 overflow-y-auto;
|
||||
|
||||
display: none;
|
||||
min-height: 40px;
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
width: 100%;
|
||||
padding: 4px 24px;
|
||||
opacity: .8;
|
||||
transition: background-color .3s, opacity .3s;
|
||||
|
||||
.page-title {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
flex-grow: 1;
|
||||
.wrap-th {
|
||||
@apply cursor-default;
|
||||
}
|
||||
}
|
||||
|
||||
.page-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
&:not(.non-collapsable) {
|
||||
|
||||
&:hover {
|
||||
background-color: var(--lx-gray-04, var(--ls-quaternary-background-color, var(--rx-gray-04)));
|
||||
opacity: 1;
|
||||
|
||||
* {
|
||||
@apply !opacity-100;
|
||||
}
|
||||
|
||||
.more {
|
||||
@apply opacity-80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wrap-th {
|
||||
@apply flex items-center text-sm font-medium opacity-50;
|
||||
|
||||
> .ui__icon {
|
||||
@apply relative top-[-1px];
|
||||
}
|
||||
|
||||
> strong {
|
||||
@apply text-xs font-medium;
|
||||
}
|
||||
}
|
||||
|
||||
&.enter-show-more {
|
||||
> .b {
|
||||
@apply transition-opacity opacity-0 delay-300;
|
||||
}
|
||||
|
||||
&:hover > .b {
|
||||
@apply opacity-80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .bd {
|
||||
@apply overflow-y-auto hidden;
|
||||
|
||||
ul {
|
||||
@apply list-none p-0 m-0;
|
||||
|
||||
li {
|
||||
@apply m-0;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply px-2 flex items-center justify-between relative h-[32px] w-full rounded-md;
|
||||
|
||||
.page-title {
|
||||
@apply whitespace-nowrap hidden text-ellipsis flex-grow overflow-hidden pr-2;
|
||||
}
|
||||
|
||||
.page-icon {
|
||||
@apply flex items-center;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--lx-gray-04, var(--ls-quaternary-background-color, var(--rx-gray-04)));
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hd .more {
|
||||
@apply transition-transform;
|
||||
}
|
||||
|
||||
&.is-expand {
|
||||
.header .more {
|
||||
opacity: 0;
|
||||
transform: rotate(-90deg);
|
||||
.hd .more {
|
||||
@apply opacity-40 rotate-90;
|
||||
}
|
||||
|
||||
.bd {
|
||||
display: block;
|
||||
@apply block;
|
||||
}
|
||||
}
|
||||
|
||||
&.has-children:not(.is-expand) {
|
||||
.header .more {
|
||||
opacity: .4;
|
||||
.hd .more {
|
||||
@apply opacity-50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.create {
|
||||
width: 100%;
|
||||
padding: 4px 14px 14px;
|
||||
background-image: linear-gradient(transparent, var(--ls-primary-background-color));
|
||||
user-select: none;
|
||||
|
||||
@screen sm {
|
||||
background-image: linear-gradient(transparent, or(--ls-left-sidebar-bottom-gradient, --lx-gray-02, --ls-secondary-background-color));
|
||||
|
||||
.dark & {
|
||||
background-image: linear-gradient(transparent, or(--ls-left-sidebar-bottom-gradient, --lx-gray-01, --ls-secondary-background-color));
|
||||
}
|
||||
}
|
||||
|
||||
&-link {
|
||||
background-color: var(--ls-primary-background-color);
|
||||
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
|
||||
}
|
||||
|
||||
.dropdown-wrapper {
|
||||
top: initial;
|
||||
right: initial;
|
||||
bottom: calc(100% + 6px);
|
||||
left: 0;
|
||||
width: max-content;
|
||||
|
||||
@screen sm {
|
||||
bottom: 0;
|
||||
left: calc(100% + 6px);
|
||||
}
|
||||
}
|
||||
|
||||
#create-button {
|
||||
@apply flex items-center justify-center p-2 text-sm font-medium rounded-md w-full border;
|
||||
background-color: or(--ls-create-button-color, --lx-gray-03, --ls-secondary-background-color) !important;
|
||||
border-color: transparent;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
border-color: var(--ls-border-color);
|
||||
background-color: or(--ls-create-button-color-focus, --lx-gray-03, --ls-primary-background-color) !important;
|
||||
}
|
||||
|
||||
@screen sm {
|
||||
background-color: or(--ls-create-button-color-sm, --lx-gray-03, --ls-primary-background-color) !important;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: or(--ls-create-button-color-sm-focus, --lx-gray-04, --ls-secondary-background-color) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark & {
|
||||
--left-sidebar-bg-color: var(--lx-gray-02, var(--ls-secondary-background-color, hsl(var(--secondary, var(--rx-gray-03-hsl)))));
|
||||
}
|
||||
|
||||
@screen sm {
|
||||
padding-top: 0;
|
||||
width: var(--ls-left-sidebar-width);
|
||||
@@ -355,25 +278,14 @@
|
||||
> .wrap {
|
||||
margin-top: 52px;
|
||||
}
|
||||
|
||||
.create {
|
||||
&-link {
|
||||
background-color: var(--ls-primary-background-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cp__sidebar-left-layout {
|
||||
@apply fixed top-0 left-0 w-[10px];
|
||||
|
||||
z-index: var(--ls-z-index-level-5);
|
||||
@apply fixed top-0 left-0 w-[10px] z-[var(--ls-z-index-level-5)];
|
||||
|
||||
a {
|
||||
@apply opacity-90 hover:opacity-100;
|
||||
transition: all 120ms ease-out;
|
||||
|
||||
color: var(--ls-left-sidebar-text-color, var(--ls-header-button-background));
|
||||
@apply opacity-80 hover:opacity-100 text-foreground;
|
||||
}
|
||||
|
||||
> .left-sidebar-inner {
|
||||
@@ -454,10 +366,7 @@
|
||||
|
||||
.left-sidebar-resizer {
|
||||
@apply absolute w-[3px] top-0 right-[-2px] bottom-0 overflow-hidden cursor-col-resize;
|
||||
@apply z-10;
|
||||
|
||||
transition: background-color 300ms;
|
||||
transition-delay: 300ms;
|
||||
@apply z-10 transition-[background-color] duration-200 delay-300;
|
||||
|
||||
&.is-active, &:hover,
|
||||
&:focus, &:active {
|
||||
@@ -466,26 +375,22 @@
|
||||
}
|
||||
|
||||
@screen sm {
|
||||
width: 0;
|
||||
z-index: var(--ls-z-index-level-1);
|
||||
transition: width .3s;
|
||||
@apply w-0 z-[var(--ls-z-index-level-1)] transition-[width];
|
||||
|
||||
&:before {
|
||||
background-color: or(--ls-left-sidebar-container-sm, --lx-gray-02, --ls-secondary-background-color);
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
@apply w-0 overflow-hidden;
|
||||
}
|
||||
|
||||
&.is-open {
|
||||
width: var(--ls-left-sidebar-width);
|
||||
@apply w-[var(--ls-left-sidebar-width)];
|
||||
|
||||
.left-sidebar-inner {
|
||||
overflow: visible;
|
||||
@apply overflow-visible;
|
||||
}
|
||||
}
|
||||
|
||||
> .shade-mask {
|
||||
display: none;
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -601,7 +506,7 @@
|
||||
.resizer {
|
||||
@apply absolute top-0 bottom-0 touch-none left-[1px] w-[3px] select-none;
|
||||
@apply cursor-col-resize hover:bg-primary/90 focus:bg-primary/90 active:bg-primary/90;
|
||||
@apply z-[1000] delay-300 transition-[background-color] duration-300;
|
||||
@apply z-[1000] delay-300 transition-[background-color] duration-200;
|
||||
}
|
||||
|
||||
&.closed {
|
||||
@@ -748,20 +653,6 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.cp__menubar-repos {
|
||||
.title-wrap {
|
||||
line-height: 1.2em;
|
||||
padding: 1px 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Workaround for Linux Intel GPU text rendering issue GH#7233 */
|
||||
.is-electron.is-linux .cp__menubar-repos {
|
||||
.repo-switch, .nav-header .flex-1 {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
@supports not (overflow-y: overlay) {
|
||||
.scrollbar-spacing {
|
||||
overflow-y: auto;
|
||||
@@ -833,11 +724,9 @@ html[data-theme='dark'] {
|
||||
}
|
||||
}
|
||||
|
||||
.blocks-selection-mode .page-title, .blocks-selection-mode .block-content-inner, .blocks-selection-mode .block-body, .blocks-selection-mode .ls-properties-area {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.favorite-item {
|
||||
@apply overflow-hidden;
|
||||
max-height: 24px;
|
||||
.blocks-selection-mode .page-title,
|
||||
.blocks-selection-mode .block-content-inner,
|
||||
.blocks-selection-mode .block-body,
|
||||
.blocks-selection-mode .ls-properties-area {
|
||||
@apply select-none;
|
||||
}
|
||||
|
||||
@@ -265,12 +265,6 @@ html.is-native-ipad {
|
||||
}
|
||||
}
|
||||
|
||||
.left-sidebar-inner {
|
||||
> .wrap {
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.cp__right-sidebar {
|
||||
&-settings {
|
||||
margin-top: -4px;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
[frontend.util.text :as text-util]
|
||||
[goog.object :as gobj]
|
||||
[logseq.shui.ui :as shui]
|
||||
[medley.core :as medley]
|
||||
[promesa.core :as p]
|
||||
[rum.core :as rum]))
|
||||
|
||||
@@ -293,39 +294,79 @@
|
||||
:on-click #(route-handler/redirect-to-all-graphs)}
|
||||
(shui/tabler-icon "layout-2") [:span (t :all-graphs)]))])
|
||||
|
||||
(rum/defcs repos-dropdown-content < rum/reactive
|
||||
[_state & {:keys [contentid] :as opts}]
|
||||
(let [multiple-windows? false
|
||||
current-repo (state/sub :git/current-repo)
|
||||
login? (boolean (state/sub :auth/id-token))
|
||||
repos (state/sub [:me :repos])
|
||||
remotes (state/sub [:file-sync/remote-graphs :graphs])
|
||||
rtc-graphs (state/sub :rtc/graphs)
|
||||
downloading-graph-id (state/sub :rtc/downloading-graph-uuid)
|
||||
remotes-loading? (state/sub [:file-sync/remote-graphs :loading])
|
||||
db-based? (config/db-based-graph? current-repo)
|
||||
repos (sort-repos-with-metadata-local repos)
|
||||
repos (distinct
|
||||
(if (and (or (seq remotes) (seq rtc-graphs)) login?)
|
||||
(repo-handler/combine-local-&-remote-graphs repos (concat remotes rtc-graphs)) repos))
|
||||
items-fn #(repos-dropdown-links repos current-repo downloading-graph-id opts)
|
||||
header-fn #(when (> (count repos) 1) ; show switch to if there are multiple repos
|
||||
[:div.font-medium.text-sm.opacity-50.px-1.py-1.flex.flex-row.justify-between.items-center
|
||||
[:h4.pb-1 (t :left-side-bar/switch)]
|
||||
|
||||
(when (and (file-sync/enable-sync?) login?)
|
||||
(if remotes-loading?
|
||||
(ui/loading "")
|
||||
(shui/button
|
||||
{:variant :ghost
|
||||
:size :sm
|
||||
:title "Refresh remote graphs"
|
||||
:class "!h-6 !px-1 relative right-[-4px]"
|
||||
:on-click (fn []
|
||||
(file-sync/load-session-graphs)
|
||||
(rtc-handler/<get-remote-graphs))}
|
||||
(ui/icon "refresh" {:size 15}))))])
|
||||
_remote? (and current-repo (:remote? (first (filter #(= current-repo (:url %)) repos))))
|
||||
_repo-name (when current-repo (db/get-repo-name current-repo))]
|
||||
|
||||
[:div
|
||||
{:class (when (<= (count repos) 1) "no-repos")}
|
||||
(header-fn)
|
||||
[:div.cp__repos-list-wrap
|
||||
(for [{:keys [hr item hover-detail title options icon]} (items-fn)]
|
||||
(let [on-click' (:on-click options)
|
||||
href' (:href options)]
|
||||
(if hr
|
||||
(shui/dropdown-menu-separator)
|
||||
(shui/dropdown-menu-item
|
||||
(assoc options
|
||||
:title hover-detail
|
||||
:on-click (fn [^js e]
|
||||
(when on-click'
|
||||
(when-not (false? (on-click' e))
|
||||
(shui/popup-hide! contentid)))))
|
||||
(or item
|
||||
(if href'
|
||||
[:a.flex.items-center.w-full
|
||||
{:href href' :on-click #(shui/popup-hide! contentid)
|
||||
:style {:color "inherit"}} title]
|
||||
[:span.flex.items-center.gap-1.w-full
|
||||
icon [:div title]]))))))]
|
||||
(repos-footer multiple-windows? db-based?)]))
|
||||
|
||||
(rum/defcs repos-dropdown < rum/reactive
|
||||
(rum/local false ::electron-multiple-windows?)
|
||||
[state & {:as opts}]
|
||||
(let [multiple-windows? (::electron-multiple-windows? state)
|
||||
current-repo (state/sub :git/current-repo)
|
||||
login? (boolean (state/sub :auth/id-token))
|
||||
remotes-loading? (state/sub [:file-sync/remote-graphs :loading])]
|
||||
(let [current-repo (state/sub :git/current-repo)
|
||||
login? (boolean (state/sub :auth/id-token))]
|
||||
(let [repos (state/sub [:me :repos])
|
||||
remotes (state/sub [:file-sync/remote-graphs :graphs])
|
||||
rtc-graphs (state/sub :rtc/graphs)
|
||||
downloading-graph-id (state/sub :rtc/downloading-graph-uuid)
|
||||
db-based? (config/db-based-graph? current-repo)
|
||||
repos (sort-repos-with-metadata-local repos)
|
||||
repos (distinct
|
||||
(if (and (or (seq remotes) (seq rtc-graphs)) login?)
|
||||
(repo-handler/combine-local-&-remote-graphs repos (concat remotes rtc-graphs)) repos))
|
||||
items-fn #(repos-dropdown-links repos current-repo downloading-graph-id opts)
|
||||
header-fn #(when (> (count repos) 1) ; show switch to if there are multiple repos
|
||||
[:div.font-medium.text-sm.opacity-50.px-1.py-1.flex.flex-row.justify-between.items-center
|
||||
[:h4.pb-1 (t :left-side-bar/switch)]
|
||||
|
||||
(when (and (file-sync/enable-sync?) login?)
|
||||
(if remotes-loading?
|
||||
(ui/loading "")
|
||||
(shui/button
|
||||
{:variant :ghost
|
||||
:size :sm
|
||||
:title "Refresh remote graphs"
|
||||
:class "!h-6 !px-1 relative right-[-4px]"
|
||||
:on-click (fn []
|
||||
(file-sync/load-session-graphs)
|
||||
(rtc-handler/<get-remote-graphs))}
|
||||
(ui/icon "refresh" {:size 15}))))])]
|
||||
(repo-handler/combine-local-&-remote-graphs repos (concat remotes rtc-graphs)) repos))]
|
||||
(let [remote? (and current-repo (:remote? (first (filter #(= current-repo (:url %)) repos))))
|
||||
repo-name (when current-repo (db/get-repo-name current-repo))
|
||||
short-repo-name (if current-repo
|
||||
@@ -340,36 +381,13 @@
|
||||
(some-> (.-target e)
|
||||
(.closest "a.item")
|
||||
(shui/popup-show!
|
||||
(fn [{:keys [id]}]
|
||||
[:<>
|
||||
(header-fn)
|
||||
[:div.cp__repos-list-wrap
|
||||
(for [{:keys [hr item hover-detail title options icon]} (items-fn)]
|
||||
(let [on-click' (:on-click options)
|
||||
href' (:href options)]
|
||||
(if hr
|
||||
(shui/dropdown-menu-separator)
|
||||
(shui/dropdown-menu-item
|
||||
(assoc options
|
||||
:title hover-detail
|
||||
:on-click (fn [^js e]
|
||||
(when on-click'
|
||||
(when-not (false? (on-click' e))
|
||||
(shui/popup-hide! id)))))
|
||||
(or item
|
||||
(if href'
|
||||
[:a.flex.items-center.w-full
|
||||
{:href href' :on-click #(shui/popup-hide! id)
|
||||
:style {:color "inherit"}} title]
|
||||
[:span.flex.items-center.gap-1.w-full
|
||||
icon [:div title]]))))))]
|
||||
(repos-footer multiple-windows? db-based?)])
|
||||
(fn [{:keys [id]}] (repos-dropdown-content (assoc opts :contentid id)))
|
||||
{:as-dropdown? true
|
||||
:auto-focus? false
|
||||
:align "start"
|
||||
:content-props {:class (str "repos-list " (when (<= (count repos) 1) " no-repos"))
|
||||
:content-props {:class "repos-list"
|
||||
:data-mode (when db-based? "db")}})))
|
||||
:title repo-name} ;; show full path on hover
|
||||
:title repo-name} ;; show full path on hover
|
||||
[:div.flex.relative.graph-icon.rounded
|
||||
(shui/tabler-icon "database" {:size 15})]
|
||||
|
||||
@@ -380,6 +398,29 @@
|
||||
(when remote? [:span.pl-1 (ui/icon "cloud")])]
|
||||
[:span.dropdown-caret]])))))
|
||||
|
||||
(rum/defcs graphs-selector < rum/reactive
|
||||
[_state]
|
||||
(let [current-repo (state/get-current-repo)
|
||||
user-repos (state/get-repos)
|
||||
current-repo' (some->> user-repos (medley/find-first #(= current-repo (:url %))))
|
||||
repo-name (when current-repo (db/get-repo-name current-repo))
|
||||
db-based? (config/db-based-graph? current-repo)
|
||||
remote? (:remote? current-repo')
|
||||
short-repo-name (if current-repo
|
||||
(db/get-short-repo-name repo-name)
|
||||
"Select a Graph")]
|
||||
[:div.cp__graphs-selector.flex.items-center.justify-between
|
||||
[:a.item.flex.items-center.gap-1.select-none
|
||||
{:on-click (fn [^js e]
|
||||
(shui/popup-show! (.closest (.-target e) "a")
|
||||
(fn [{:keys [id]}] (repos-dropdown-content {:contentid id}))
|
||||
{:as-dropdown? true
|
||||
:content-props {:class "repos-list"}
|
||||
:align :start}))}
|
||||
[:span.thumb (shui/tabler-icon (if remote? "cloud" (if db-based? "database" "folder")) {:size 16})]
|
||||
[:strong short-repo-name]
|
||||
(shui/tabler-icon "selector" {:size 18})]]))
|
||||
|
||||
(defn invalid-graph-name-warning
|
||||
[]
|
||||
(notification/show!
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
.ui__dropdown-menu-content {
|
||||
&.repos-list {
|
||||
@apply flex flex-col px-2 relative overflow-hidden min-w-[280px] sm:max-w-[320px];
|
||||
@apply flex flex-col px-2 relative overflow-hidden min-w-[300px] sm:max-w-[400px];
|
||||
|
||||
.ui__dropdown-menu-item {
|
||||
@apply overflow-hidden overflow-ellipsis;
|
||||
@@ -26,7 +26,7 @@
|
||||
@apply max-h-80 overflow-scroll mx-[-8px] px-2 pb-2;
|
||||
}
|
||||
|
||||
&.no-repos {
|
||||
.no-repos {
|
||||
.cp__repos-list-wrap {
|
||||
@apply hidden;
|
||||
}
|
||||
@@ -67,4 +67,37 @@
|
||||
@apply w-full !py-4 !justify-start opacity-70 font-medium hover:opacity-90
|
||||
items-center gap-1.5 hover:bg-gray-03;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cp__graphs-selector {
|
||||
> a.item {
|
||||
@apply flex items-center relative flex-1 overflow-hidden
|
||||
pl-1 py-1 pr-4 opacity-90 active:opacity-70 rounded-md;
|
||||
|
||||
> .thumb {
|
||||
@apply w-6 h-6 overflow-hidden flex flex-shrink-0 items-center
|
||||
justify-center rounded opacity-80 dark:opacity-50;
|
||||
|
||||
> .ui__icon {
|
||||
@apply mr-0;
|
||||
}
|
||||
}
|
||||
|
||||
> strong {
|
||||
@apply whitespace-nowrap overflow-hidden text-ellipsis pl-1
|
||||
font-medium relative pr-4 text-sm;
|
||||
}
|
||||
|
||||
> .ui__icon {
|
||||
@apply absolute -right-1 top-2 opacity-60;
|
||||
}
|
||||
}
|
||||
|
||||
> span {
|
||||
@apply relative flex items-center -mr-1;
|
||||
|
||||
> .ui__button {
|
||||
@apply p-1 opacity-40 hover:opacity-70 active:opacity-100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,6 @@ html[data-theme=light] {
|
||||
height: calc(100vh - 48px);
|
||||
}
|
||||
|
||||
html[data-theme=light] a.toggle:hover {
|
||||
color: var(--ls-primary-text-color);
|
||||
}
|
||||
|
||||
.cp__header {
|
||||
> .r > div:not(.ui__dropdown-trigger) a, button {
|
||||
color: var(--lx-gray-11, var(--ls-header-button-background, var(--rx-gray-11)));
|
||||
|
||||
@@ -156,7 +156,7 @@ main.ls-fold-button-on-right {
|
||||
}
|
||||
|
||||
main.theme-container-inner {
|
||||
--left-sidebar-bg-color: var(--lx-gray-02, hsl(var(--secondary, var(--rx-gray-03-hsl))));
|
||||
--left-sidebar-bg-color: var(--lx-gray-02, var(--ls-secondary-background-color, hsl(var(--secondary, var(--rx-gray-03-hsl)))));
|
||||
}
|
||||
|
||||
html[data-font='serif'] .ls-block, .ls-font-serif {
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
"This ns is a system component that handles translation for the entire
|
||||
application. The ns dependencies for this ns must be small since it is used
|
||||
throughout the application."
|
||||
(:require [frontend.dicts :as dicts]
|
||||
(:require [clojure.string :as string]
|
||||
[frontend.dicts :as dicts]
|
||||
[medley.core :as medley]
|
||||
[tongue.core :as tongue]
|
||||
[frontend.state :as state]
|
||||
[lambdaisland.glogi :as log]))
|
||||
@@ -26,6 +28,14 @@
|
||||
:lang preferred-language}}])
|
||||
(apply translate :en args)))))
|
||||
|
||||
(defn tt
|
||||
[& keys]
|
||||
(some->
|
||||
(medley/find-first
|
||||
#(not (string/starts-with? (t %) "{Missing key"))
|
||||
keys)
|
||||
t))
|
||||
|
||||
(defn- fetch-local-language []
|
||||
(.. js/window -navigator -language))
|
||||
|
||||
|
||||
@@ -201,11 +201,12 @@
|
||||
100)))
|
||||
|
||||
(defn go-to-search!
|
||||
[search-mode]
|
||||
(search-handler/clear-search! false)
|
||||
(when search-mode
|
||||
(state/set-search-mode! search-mode))
|
||||
(state/pub-event! [:go/search]))
|
||||
([search-mode] (go-to-search! search-mode nil))
|
||||
([search-mode args]
|
||||
(search-handler/clear-search! false)
|
||||
(when search-mode
|
||||
(state/set-search-mode! search-mode args))
|
||||
(state/pub-event! [:go/search])))
|
||||
|
||||
(defn sidebar-journals!
|
||||
[]
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
|
||||
:search/q ""
|
||||
:search/mode nil ; nil -> global mode, :graph -> add graph filter, etc.
|
||||
:search/args nil
|
||||
:search/result nil
|
||||
:search/graph-filters []
|
||||
:search/engines {}
|
||||
@@ -1084,8 +1085,10 @@ Similar to re-frame subscriptions"
|
||||
(set-state! :editor/cursor-range range))
|
||||
|
||||
(defn set-search-mode!
|
||||
[value]
|
||||
(set-state! :search/mode value))
|
||||
([value] (set-search-mode! value nil))
|
||||
([value args]
|
||||
(set-state! :search/mode value)
|
||||
(set-state! :search/args args)))
|
||||
|
||||
(defn set-editor-action!
|
||||
[value]
|
||||
|
||||
@@ -236,28 +236,41 @@
|
||||
(= :db.cardinality/many (:db/cardinality k-schema))]))
|
||||
|
||||
(defn- patch-remote-attr-map-by-local-av-coll
|
||||
[attr-map av-coll]
|
||||
[remote-attr-map local-av-coll]
|
||||
(let [a->add->v-set
|
||||
(reduce
|
||||
(fn [m [a v _t add?]]
|
||||
(let [{add-vset true retract-vset false} (get m a {true #{} false #{}})]
|
||||
(assoc m a {true ((if add? conj disj) add-vset v)
|
||||
false ((if add? disj conj) retract-vset v)})))
|
||||
{} av-coll)]
|
||||
(into attr-map
|
||||
(keep
|
||||
(fn [[remote-a remote-v]]
|
||||
(when-let [{add-vset true retract-vset false} (get a->add->v-set remote-a)]
|
||||
[remote-a
|
||||
(if (coll? remote-v)
|
||||
(-> (set remote-v)
|
||||
(set/union add-vset)
|
||||
(set/difference retract-vset)
|
||||
vec)
|
||||
(cond
|
||||
(seq add-vset) (first add-vset)
|
||||
(contains? retract-vset remote-v) nil))])))
|
||||
attr-map)))
|
||||
{} local-av-coll)
|
||||
updated-remote-attr-map1
|
||||
(keep
|
||||
(fn [[remote-a remote-v]]
|
||||
(when-let [{add-vset true retract-vset false} (get a->add->v-set remote-a)]
|
||||
[remote-a
|
||||
(if (coll? remote-v)
|
||||
(-> (set remote-v)
|
||||
(set/union add-vset)
|
||||
(set/difference retract-vset)
|
||||
vec)
|
||||
(cond
|
||||
(seq add-vset) (first add-vset)
|
||||
(contains? retract-vset remote-v) nil))]))
|
||||
remote-attr-map)
|
||||
updated-remote-attr-map2
|
||||
(keep
|
||||
(fn [[a add->v-set]]
|
||||
(when-let [ns (namespace a)]
|
||||
(when (and (not (contains? #{"block"} ns))
|
||||
;; FIXME: only handle non-block/xxx attrs,
|
||||
;; because some :block/xxx attrs are card-one, we only generate card-many values here
|
||||
(not (contains? remote-attr-map a)))
|
||||
(when-let [v-set (not-empty (get add->v-set true))]
|
||||
[a (vec v-set)]))))
|
||||
a->add->v-set)]
|
||||
(into remote-attr-map
|
||||
(concat updated-remote-attr-map1 updated-remote-attr-map2))))
|
||||
|
||||
(defn- update-remote-data-by-local-unpushed-ops
|
||||
"when remote-data request client to move/update/remove/... blocks,
|
||||
|
||||
@@ -112,15 +112,56 @@
|
||||
:user.property/ppp
|
||||
[#uuid "6752bdee-7963-4a6a-84a4-86cd456b470c"
|
||||
#uuid "6752bdf0-ee32-40af-8abb-3f8d179ba888"]}}
|
||||
r))))
|
||||
(testing "case6: toggle status"
|
||||
(let [[uuid1 uuid2 status-value-uuid] (repeatedly random-uuid)
|
||||
affected-blocks-map
|
||||
{uuid1
|
||||
{:op :update-attrs
|
||||
:self uuid1
|
||||
:parents [uuid2]}}
|
||||
unpushed-ops
|
||||
[[:update
|
||||
536872312
|
||||
{:block-uuid uuid1
|
||||
:av-coll
|
||||
[[:logseq.task/status status-value-uuid 536872312 true]]}]]
|
||||
r (#'r.remote/update-remote-data-by-local-unpushed-ops affected-blocks-map unpushed-ops)]
|
||||
(is (= {uuid1
|
||||
{:op :update-attrs
|
||||
:self uuid1
|
||||
:parents [uuid2]
|
||||
:logseq.task/status [status-value-uuid]}}
|
||||
r))))
|
||||
(testing "case7: toggle status(2)"
|
||||
(let [[uuid1 uuid2 status-value-uuid1 status-value-uuid2] (repeatedly random-uuid)
|
||||
affected-blocks-map
|
||||
{uuid1
|
||||
{:op :update-attrs
|
||||
:self uuid1
|
||||
:parents [uuid2]}}
|
||||
unpushed-ops
|
||||
[[:update
|
||||
536872314
|
||||
{:block-uuid uuid1
|
||||
:av-coll
|
||||
[[:logseq.task/status status-value-uuid1 536872312 true]
|
||||
[:logseq.task/status status-value-uuid1 536872312 false]
|
||||
[:logseq.task/status status-value-uuid2 536872314 true]]}]]
|
||||
r (#'r.remote/update-remote-data-by-local-unpushed-ops affected-blocks-map unpushed-ops)]
|
||||
(is (= {uuid1
|
||||
{:op :update-attrs
|
||||
:self uuid1
|
||||
:parents [uuid2]
|
||||
:logseq.task/status [status-value-uuid2]}}
|
||||
r)))))
|
||||
|
||||
(deftest ^:fix-me apply-remote-move-ops-test
|
||||
(deftest apply-remote-move-ops-test
|
||||
(let [repo (state/get-current-repo)
|
||||
conn (conn/get-db repo false)
|
||||
opts {:persist-op? false
|
||||
:transact-opts {:repo repo
|
||||
:conn conn}}
|
||||
date-formatter (common-config/get-date-formatter (worker-state/get-config repo))
|
||||
page-name "apply-remote-move-ops-test"
|
||||
[page-uuid
|
||||
uuid1-client uuid2-client
|
||||
@@ -132,10 +173,10 @@
|
||||
repo
|
||||
conn
|
||||
[{:block/uuid uuid1-client :block/title "uuid1-client"
|
||||
:block/left [:block/uuid page-uuid]
|
||||
:block/order "a1"
|
||||
:block/parent [:block/uuid page-uuid]}
|
||||
{:block/uuid uuid2-client :block/title "uuid2-client"
|
||||
:block/left [:block/uuid uuid1-client]
|
||||
:block/order "a2"
|
||||
:block/parent [:block/uuid page-uuid]}]
|
||||
(ldb/get-page @conn page-name)
|
||||
{:sibling? true :keep-uuid? true}))
|
||||
@@ -147,17 +188,17 @@
|
||||
{uuid1-remote {:op :move
|
||||
:self uuid1-remote
|
||||
:parents [page-uuid]
|
||||
:left page-uuid
|
||||
:content "uuid1-remote"}}}
|
||||
:block/order "a0"}}}
|
||||
move-ops (#'r.remote/move-ops-map->sorted-move-ops
|
||||
(:move-ops-map
|
||||
(#'r.remote/affected-blocks->diff-type-ops
|
||||
repo (:affected-blocks data-from-ws))))]
|
||||
(is (rtc-const/data-from-ws-validator data-from-ws))
|
||||
(#'r.remote/apply-remote-move-ops repo conn date-formatter move-ops)
|
||||
(is (rtc-const/data-from-ws-validator data-from-ws) data-from-ws)
|
||||
(#'r.remote/apply-remote-move-ops repo conn move-ops)
|
||||
(let [page-blocks (ldb/get-page-blocks @conn (:db/id (ldb/get-page @conn page-name)) {})]
|
||||
(is (= #{uuid1-remote uuid1-client uuid2-client} (set (map :block/uuid page-blocks))))
|
||||
(is (= page-uuid (:block/uuid (:block/left (d/entity @conn [:block/uuid uuid1-remote]))))))))
|
||||
(is (= #{uuid1-remote uuid1-client uuid2-client} (set (map :block/uuid page-blocks)))
|
||||
[uuid1-remote uuid1-client uuid2-client])
|
||||
(is (= page-uuid (:block/uuid (:block/parent (d/entity @conn [:block/uuid uuid1-remote]))))))))
|
||||
|
||||
(testing "apply-remote-move-ops-test2"
|
||||
(let [data-from-ws {:req-id "req-id"
|
||||
@@ -167,24 +208,24 @@
|
||||
{uuid2-remote {:op :move
|
||||
:self uuid2-remote
|
||||
:parents [uuid1-client]
|
||||
:left uuid1-client
|
||||
:content "uuid2-remote"}
|
||||
:block/order "a0"}
|
||||
uuid1-remote {:op :move
|
||||
:self uuid1-remote
|
||||
:parents [uuid2-remote]
|
||||
:left uuid2-remote}}}
|
||||
:block/order "a1"}}}
|
||||
move-ops (#'r.remote/move-ops-map->sorted-move-ops
|
||||
(:move-ops-map
|
||||
(#'r.remote/affected-blocks->diff-type-ops
|
||||
repo (:affected-blocks data-from-ws))))]
|
||||
(is (rtc-const/data-from-ws-validator data-from-ws))
|
||||
(#'r.remote/apply-remote-move-ops repo conn date-formatter move-ops)
|
||||
(#'r.remote/apply-remote-move-ops repo conn move-ops)
|
||||
(let [page-blocks (ldb/get-page-blocks @conn (:db/id (ldb/get-page @conn page-name)) {})]
|
||||
(is (= #{uuid1-remote uuid2-remote uuid1-client uuid2-client} (set (map :block/uuid page-blocks))))
|
||||
(is (= uuid1-client (:block/uuid (:block/left (d/entity @conn [:block/uuid uuid2-remote])))))
|
||||
(is (= uuid2-remote (:block/uuid (:block/left (d/entity @conn [:block/uuid uuid1-remote]))))))))))
|
||||
(is (= ["a0" "a1"]
|
||||
(mapv (fn [uuid*] (:block/order (d/entity @conn [:block/uuid uuid*])))
|
||||
[uuid2-remote uuid1-remote]))))))))
|
||||
|
||||
(deftest ^:fix-me apply-remote-remove-ops-test
|
||||
(deftest apply-remote-remove-ops-test
|
||||
(let [repo (state/get-current-repo)
|
||||
conn (conn/get-db repo false)
|
||||
opts {:persist-op? false
|
||||
@@ -292,10 +333,9 @@ result:
|
||||
(let [page-blocks (ldb/get-page-blocks @conn (:db/id (ldb/get-page @conn page-name)))]
|
||||
(is (= [uuid3 uuid1] (map :block/uuid (sort-by :block/order page-blocks)))))))))
|
||||
|
||||
(deftest ^:fix-me apply-remote-update&remove-page-ops-test
|
||||
(deftest apply-remote-update&remove-page-ops-test
|
||||
(let [repo (state/get-current-repo)
|
||||
conn (conn/get-db repo false)
|
||||
date-formatter (common-config/get-date-formatter (worker-state/get-config repo))
|
||||
[page1-uuid ;; page2-uuid page3-uuid page4-uuid
|
||||
](repeatedly random-uuid)]
|
||||
(testing "apply-remote-update-page-ops-test1"
|
||||
@@ -303,13 +343,13 @@ result:
|
||||
:affected-blocks
|
||||
{page1-uuid {:op :update-page
|
||||
:self page1-uuid
|
||||
:page-name (str page1-uuid)
|
||||
:block/title (str page1-uuid)}}}
|
||||
:page-name (ldb/write-transit-str (str "X" page1-uuid))
|
||||
:block/title (ldb/write-transit-str (str "X" page1-uuid))}}}
|
||||
update-page-ops (vals
|
||||
(:update-page-ops-map
|
||||
(#'r.remote/affected-blocks->diff-type-ops repo (:affected-blocks data-from-ws))))]
|
||||
(is (rtc-const/data-from-ws-validator data-from-ws))
|
||||
(#'r.remote/apply-remote-update-page-ops repo conn date-formatter update-page-ops)
|
||||
(#'r.remote/apply-remote-update-page-ops repo conn update-page-ops)
|
||||
(is (= page1-uuid (:block/uuid (d/entity @conn [:block/uuid page1-uuid]))))))
|
||||
|
||||
(testing "apply-remote-update-page-ops-test2"
|
||||
@@ -317,13 +357,13 @@ result:
|
||||
:affected-blocks
|
||||
{page1-uuid {:op :update-page
|
||||
:self page1-uuid
|
||||
:page-name (str page1-uuid "-rename")
|
||||
:block/title (str page1-uuid "-rename")}}}
|
||||
:page-name (ldb/write-transit-str (str page1-uuid "-rename"))
|
||||
:block/title (ldb/write-transit-str (str page1-uuid "-rename"))}}}
|
||||
update-page-ops (vals
|
||||
(:update-page-ops-map
|
||||
(#'r.remote/affected-blocks->diff-type-ops repo (:affected-blocks data-from-ws))))]
|
||||
(is (rtc-const/data-from-ws-validator data-from-ws))
|
||||
(#'r.remote/apply-remote-update-page-ops repo conn date-formatter update-page-ops)
|
||||
(#'r.remote/apply-remote-update-page-ops repo conn update-page-ops)
|
||||
(is (= (str page1-uuid "-rename") (:block/name (d/entity @conn [:block/uuid page1-uuid]))))))
|
||||
|
||||
(testing "apply-remote-remove-page-ops-test1"
|
||||
|
||||
Reference in New Issue
Block a user