From f5789bd4f9cb1a0704bfe2a53dfd6786d3ff57ad Mon Sep 17 00:00:00 2001 From: Andelf Date: Sat, 3 Dec 2022 02:40:42 +0800 Subject: [PATCH] refactor(ui): use pagination component for All pages --- src/main/frontend/components/page.cljs | 323 +++++++++++++------------ src/main/frontend/components/page.css | 21 -- 2 files changed, 169 insertions(+), 175 deletions(-) diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index e8fe2db21..c3ccd8080 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -818,6 +818,36 @@ (notification/show! (str (t :tips/all-done) "!") :success) (js/setTimeout #(refresh-fn) 200)))]])) +(rum/defc pagination + "Pagination component, like `<< >>`. + +- current: current page number +- total: total number of items +- per-page: number of items per page +- on-change: callback function when page number changes" + [& {:keys [current total per-page on-change] + :or {current 1 per-page 40}}] + (let [total-pages (int (Math/ceil (/ total per-page))) + has-prev? (> current 1) + has-next? (< current total-pages) + prev-page (if (= 1 current) 1 (dec current)) + next-page (if (= total-pages current) total-pages (inc current))] + [:div.flex.items-center.noselect + (when has-prev? + [[:a.fade-link.flex + {:on-click #(on-change 1)} + (ui/icon "chevrons-left")] + [:a.fade-link.flex.items-center {:on-click #(on-change prev-page)} + (ui/icon "caret-left") (t :paginates/prev)]]) + [:div.px-2 + [:span (str current "/" total-pages)]] + (when has-next? + [[:a.fade-link.flex.items-center {:on-click #(on-change next-page)} + (t :paginates/next) (ui/icon "caret-right")] + [:a.fade-link.flex + {:on-click #(on-change total-pages)} + (ui/icon "chevrons-right")]])])) + (rum/defcs ^:large-vars/cleanup-todo all-pages < rum/reactive (rum/local nil ::pages) (rum/local nil ::search-key) @@ -847,15 +877,17 @@ *search-input (rum/create-ref) *indeterminate (rum/derived-atom - [*checks] ::indeterminate - (fn [checks] - (when-let [checks (vals checks)] - (if (every? true? checks) - 1 (if (some true? checks) -1 0))))) + [*checks] ::indeterminate + (fn [checks] + (when-let [checks (vals checks)] + (if (every? true? checks) + 1 (if (some true? checks) -1 0))))) mobile? (util/mobile?) + total-items (count @*results-all) + ;; FIXME: "pages" is ambiguous here, it can be either "Logseq pages" or "result pages" total-pages (if-not @*results-all 0 - (js/Math.ceil (/ (count @*results-all) per-page-num))) + (js/Math.ceil (/ total-items per-page-num))) to-page (fn [page] (when (> total-pages 1) (if (and (> page 0) @@ -878,7 +910,7 @@ [:div.flex-1.cp__all_pages [:h1.title (t :all-pages)] - [:div.text-sm.ml-1.opacity-70.mb-4 (t :paginates/pages (count @*results-all))] + [:div.text-sm.ml-1.opacity-70.mb-4 (t :paginates/pages total-items)] (when current-repo @@ -918,168 +950,151 @@ [idx (boolean (get @*checks idx))]))) (reset! *results pages))) - (let [has-prev? (> @*current-page 1) - has-next? (not= @*current-page total-pages)] - [:div - [:div.actions - {:class (util/classnames [{:has-selected (or (nil? @*indeterminate) - (not= 0 @*indeterminate))}])} - [:div.l.flex.items-center - [:div.actions-wrap - (ui/button - [(ui/icon "trash" {:style {:font-size 15}}) (t :delete)] - :on-click (fn [] - (let [selected (filter (fn [[_ v]] v) @*checks) - selected (and (seq selected) - (into #{} (for [[k _] selected] k)))] - (when-let [pages (and selected (filter #(contains? selected (:block/idx %)) @*results))] - (state/set-modal! (batch-delete-dialog pages false #(do - (reset! *checks nil) - (refresh-pages))))))) - :class "fade-link" - :small? true)] + [:div + [:div.actions + {:class (util/classnames [{:has-selected (or (nil? @*indeterminate) + (not= 0 @*indeterminate))}])} + [:div.l.flex.items-center + [:div.actions-wrap + (ui/button + [(ui/icon "trash" {:style {:font-size 15}}) (t :delete)] + :on-click (fn [] + (let [selected (filter (fn [[_ v]] v) @*checks) + selected (and (seq selected) + (into #{} (for [[k _] selected] k)))] + (when-let [pages (and selected (filter #(contains? selected (:block/idx %)) @*results))] + (state/set-modal! (batch-delete-dialog pages false #(do + (reset! *checks nil) + (refresh-pages))))))) + :class "fade-link" + :small? true)] - [:div.search-wrap.flex.items-center.pl-2 - (let [search-fn (fn [] - (let [^js input (rum/deref *search-input)] - (search-key (.-value input)) - (reset! *current-page 1))) - reset-fn (fn [] + [:div.search-wrap.flex.items-center.pl-2 + (let [search-fn (fn [] (let [^js input (rum/deref *search-input)] - (set! (.-value input) "") - (reset! *search-key nil)))] + (search-key (.-value input)) + (reset! *current-page 1))) + reset-fn (fn [] + (let [^js input (rum/deref *search-input)] + (set! (.-value input) "") + (reset! *search-key nil)))] - [(ui/button (ui/icon "search") - :on-click search-fn - :small? true) - [:input.form-input {:placeholder (t :search/page-names) - :on-key-up (fn [^js e] - (let [^js target (.-target e)] - (if (string/blank? (.-value target)) - (reset! *search-key nil) - (cond - (= 13 (.-keyCode e)) (search-fn) - (= 27 (.-keyCode e)) (reset-fn))))) - :ref *search-input - :default-value ""}] + [(ui/button (ui/icon "search") + :on-click search-fn + :small? true) + [:input.form-input {:placeholder (t :search/page-names) + :on-key-up (fn [^js e] + (let [^js target (.-target e)] + (if (string/blank? (.-value target)) + (reset! *search-key nil) + (cond + (= 13 (.-keyCode e)) (search-fn) + (= 27 (.-keyCode e)) (reset-fn))))) + :ref *search-input + :default-value ""}] - (when (not (string/blank? @*search-key)) - [:a.cancel {:on-click reset-fn} - (ui/icon "x")])])]] + (when (not (string/blank? @*search-key)) + [:a.cancel {:on-click reset-fn} + (ui/icon "x")])])]] - [:div.r.flex.items-center.justify-between - [:div - (ui/tippy - {:html [:small (str (t :page/show-whiteboards) " ?")] - :arrow true} - [:a.button.whiteboard - {:class (util/classnames [{:active (boolean @*whiteboard?)}]) - :on-click #(reset! *whiteboard? (not @*whiteboard?))} - (ui/icon "whiteboard" {:extension? true :style {:fontSize ui/icon-size}})])] - [:div - (ui/tippy - {:html [:small (str (t :page/show-journals) " ?")] - :arrow true} - [:a.button.journal - {:class (util/classnames [{:active (boolean @*journal?)}]) - :on-click #(reset! *journal? (not @*journal?))} - (ui/icon "calendar" {:size ui/icon-size})])] + [:div.r.flex.items-center.justify-between + [:div + (ui/tippy + {:html [:small (str (t :page/show-whiteboards) " ?")] + :arrow true} + [:a.button.whiteboard + {:class (util/classnames [{:active (boolean @*whiteboard?)}]) + :on-click #(reset! *whiteboard? (not @*whiteboard?))} + (ui/icon "whiteboard" {:extension? true :style {:fontSize ui/icon-size}})])] + [:div + (ui/tippy + {:html [:small (str (t :page/show-journals) " ?")] + :arrow true} + [:a.button.journal + {:class (util/classnames [{:active (boolean @*journal?)}]) + :on-click #(reset! *journal? (not @*journal?))} + (ui/icon "calendar" {:size ui/icon-size})])] - [:div.paginates - [:span.flex.items-center - {:class (util/classnames [{:is-first (= 1 @*current-page) - :is-last (= @*current-page total-pages)}])} - (when has-prev? - [:a.py-4.pr-2.fade-link.flex.items-center - {:on-click #(to-page (dec @*current-page))} - (ui/icon "caret-left") (str " " (t :paginates/prev))]) - [:span.opacity-60 (str @*current-page "/" total-pages)] - (when has-next? - [:a.py-4.pl-2.fade-link.flex.items-center - {:on-click #(to-page (inc @*current-page))} (str (t :paginates/next) " ") - (ui/icon "caret-right")])]] + [:div.paginates + (pagination :current @*current-page + :total total-items + :per-page per-page-num + :on-change #(to-page %))] - (ui/dropdown-with-links - (fn [{:keys [toggle-fn]}] - [:a.button.fade-link - {:on-click toggle-fn} - (ui/icon "dots" {:size ui/icon-size})]) - [{:title (t :remove-orphaned-pages) - :options {:on-click (fn [] - (let [orphaned-pages (model/get-orphaned-pages {}) - orphaned-pages? (seq orphaned-pages)] - (if orphaned-pages? - (state/set-modal! - (batch-delete-dialog - orphaned-pages true - #(do - (reset! *checks nil) - (refresh-pages)))) - (notification/show! "Congratulations, no orphaned pages in your graph!" :success))))} - :icon (ui/icon "file-x")} - {:title (t :all-files) - :options {:href (rfe/href :all-files)} - :icon (ui/icon "files")}] - {})]] + (ui/dropdown-with-links + (fn [{:keys [toggle-fn]}] + [:a.button.fade-link + {:on-click toggle-fn} + (ui/icon "dots" {:size ui/icon-size})]) + [{:title (t :remove-orphaned-pages) + :options {:on-click (fn [] + (let [orphaned-pages (model/get-orphaned-pages {}) + orphaned-pages? (seq orphaned-pages)] + (if orphaned-pages? + (state/set-modal! + (batch-delete-dialog + orphaned-pages true + #(do + (reset! *checks nil) + (refresh-pages)))) + (notification/show! "Congratulations, no orphaned pages in your graph!" :success))))} + :icon (ui/icon "file-x")} + {:title (t :all-files) + :options {:href (rfe/href :all-files)} + :icon (ui/icon "files")}] + {})]] - [:table.table-auto.cp__all_pages_table - [:thead - [:tr - [:th.selector - (checkbox-opt "all-pages-select-all" - (= 1 @*indeterminate) - {:on-change (fn [] - (let [indeterminate? (= -1 @*indeterminate) - all? (= 1 @*indeterminate)] - (doseq [{:block/keys [idx]} @*results] - (swap! *checks assoc idx (or indeterminate? (not all?)))))) - :indeterminate (= -1 @*indeterminate)})] + [:table.table-auto.cp__all_pages_table + [:thead + [:tr + [:th.selector + (checkbox-opt "all-pages-select-all" + (= 1 @*indeterminate) + {:on-change (fn [] + (let [indeterminate? (= -1 @*indeterminate) + all? (= 1 @*indeterminate)] + (doseq [{:block/keys [idx]} @*results] + (swap! *checks assoc idx (or indeterminate? (not all?)))))) + :indeterminate (= -1 @*indeterminate)})] - (sortable-title (t :block/name) :block/name *sort-by-item *desc?) - (when-not mobile? - [(sortable-title (t :page/backlinks) :block/backlinks *sort-by-item *desc?) - (sortable-title (t :page/created-at) :block/created-at *sort-by-item *desc?) - (sortable-title (t :page/updated-at) :block/updated-at *sort-by-item *desc?)])]] + (sortable-title (t :block/name) :block/name *sort-by-item *desc?) + (when-not mobile? + [(sortable-title (t :page/backlinks) :block/backlinks *sort-by-item *desc?) + (sortable-title (t :page/created-at) :block/created-at *sort-by-item *desc?) + (sortable-title (t :page/updated-at) :block/updated-at *sort-by-item *desc?)])]] - [:tbody - (for [{:block/keys [idx name created-at updated-at backlinks] :as page} @*results] - (when-not (string/blank? name) - [:tr {:key name} - [:td.selector - (checkbox-opt (str "label-" idx) - (get @*checks idx) - {:on-change (fn [] - (swap! *checks update idx not))})] + [:tbody + (for [{:block/keys [idx name created-at updated-at backlinks] :as page} @*results] + (when-not (string/blank? name) + [:tr {:key name} + [:td.selector + (checkbox-opt (str "label-" idx) + (get @*checks idx) + {:on-change (fn [] + (swap! *checks update idx not))})] - [:td.name [:a {:on-click (fn [e] + [:td.name [:a {:on-click (fn [e] (.preventDefault e) - (let [repo (state/get-current-repo)] - (when (gobj/get e "shiftKey") - (state/sidebar-add-block! - repo - (:db/id page) - :page)))) - :href (rfe/href :page {:name (:block/name page)})} - (component-block/page-cp {} page)]] + (let [repo (state/get-current-repo)] + (when (gobj/get e "shiftKey") + (state/sidebar-add-block! + repo + (:db/id page) + :page)))) + :href (rfe/href :page {:name (:block/name page)})} + (component-block/page-cp {} page)]] - (when-not mobile? - [:td.backlinks [:span backlinks]]) - - (when-not mobile? + (when-not mobile? + [[:td.backlinks [:span backlinks]] [:td.created-at [:span (if created-at (date/int->local-time-2 created-at) - "Unknown")]]) - (when-not mobile? + "Unknown")]] [:td.updated-at [:span (if updated-at (date/int->local-time-2 updated-at) - "Unknown")]])]))]] + "Unknown")]]])]))]] - [:div.paginates - [:span] - [:span.flex.items-center - (when has-prev? - [:a.py-4.text-sm.fade-link.flex.items-center {:on-click #(to-page (dec @*current-page))} - (ui/icon "caret-left") (str " " (t :paginates/prev))]) - (when has-next? - [:a.py-4.pl-2.text-sm.fade-link.flex.items-center {:on-click #(to-page (inc @*current-page))} (str (t :paginates/next) " ") - (ui/icon "caret-right")])]]]))])) + [:div.flex.justify-end.py-4 + (pagination :current @*current-page + :total total-items + :per-page per-page-num + :on-change #(to-page %))]])])) diff --git a/src/main/frontend/components/page.css b/src/main/frontend/components/page.css index 3aa704d43..25c1355ac 100644 --- a/src/main/frontend/components/page.css +++ b/src/main/frontend/components/page.css @@ -195,27 +195,6 @@ } } } - - .paginates { - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 4px; - - > span { - color: var(--ls-primary-text-color); - - &:last-child { - a { - user-select: none; - - &:active { - opacity: .6; - } - } - } - } - } } .cp__vertical-menu-button {