217 lines
8.1 KiB
Clojure
217 lines
8.1 KiB
Clojure
(ns auto-ap.views.components.grid
|
|
(:require [reagent.core :as r]
|
|
[auto-ap.views.utils :refer [appearing]]
|
|
[react :as react]))
|
|
|
|
(defonce grid-context (react/createContext "default"))
|
|
(def Provider (.-Provider grid-context))
|
|
(def Consumer (.-Consumer grid-context))
|
|
|
|
(defn toggle-sort-by [params sort-key sort-name]
|
|
(let [[found? sort] (reduce
|
|
(fn [[found? sort] sort-item]
|
|
(if (= sort-key (:sort-key sort-item))
|
|
[true (conj sort
|
|
(update sort-item :asc not))]
|
|
[found? (conj sort sort-item)]))
|
|
[false []]
|
|
(:sort params))
|
|
sort (if found?
|
|
sort
|
|
(conj sort {:sort-key sort-key
|
|
:sort-name sort-name
|
|
:asc true}))]
|
|
|
|
(-> params
|
|
(assoc :sort sort))))
|
|
|
|
(defn sort-icon [which sort]
|
|
(let [sort-item (first (filter #(= which (:sort-key %)) sort))]
|
|
(cond
|
|
(and sort-item (:asc sort-item))
|
|
[:span.icon
|
|
[:i.fa.fa-sort-up]]
|
|
|
|
(and sort-item (not (:asc sort-item)))
|
|
[:span.icon
|
|
[:i.fa.fa-sort-down]]
|
|
|
|
:else
|
|
[:span.icon
|
|
[:i.fa.fa-sort]])))
|
|
|
|
(defn bound [x y z]
|
|
(cond
|
|
(< z x)
|
|
x
|
|
(< y x)
|
|
x
|
|
(> y z)
|
|
z
|
|
:else
|
|
y))
|
|
|
|
(defn paginator [{:keys [start end count total on-change]}]
|
|
(let [per-page 100
|
|
max-buttons 5
|
|
buttons-before (Math/floor (/ max-buttons 2))
|
|
total-pages (Math/ceil (/ total per-page))
|
|
current-page (Math/floor (/ start per-page))
|
|
first-page-button (bound 0 (- current-page buttons-before) (- total-pages max-buttons))
|
|
all-buttons (into [] (for [x (range total-pages)]
|
|
^{:key x}
|
|
[:li
|
|
[:a.pagination-link {:class (when (= current-page x)
|
|
"is-current")
|
|
:on-click (fn [e] (on-change {:start (* x per-page)}))}
|
|
(inc x)]]))
|
|
|
|
|
|
last-page-button (Math/min total-pages (+ max-buttons first-page-button))
|
|
|
|
extended-last-page-button (when (not= last-page-button total-pages)
|
|
(list
|
|
^ {:key -1} [:li [:span.pagination-ellipsis "…"]]
|
|
^ {:key -2} (last all-buttons)))
|
|
|
|
extended-first-page-button (when (not= first-page-button 0)
|
|
(list
|
|
^{:key -1} (first all-buttons)
|
|
^{:key -2} [:li [:span.pagination-ellipsis "…"]]))]
|
|
|
|
|
|
[:nav.pagination {:role "pagination"}
|
|
[:ul.pagination-list
|
|
extended-first-page-button
|
|
(apply list (subvec all-buttons first-page-button last-page-button))
|
|
extended-last-page-button
|
|
"Showing " (Math/min (inc start) total) "-" end "/" total]]))
|
|
|
|
(defn sort-by-list [{:keys [sort on-change]}]
|
|
[:div.field.is-grouped.is-grouped-multiline
|
|
(for [{:keys [sort-key sort-name asc]} sort]
|
|
^{:key sort-key}
|
|
[:div.control
|
|
[:div.tags.has-addons
|
|
[:div.tag.is-medium [:span.icon (if asc
|
|
[:i.fa.fa-sort-up]
|
|
[:i.fa.fa-sort-down])]
|
|
[:span sort-name] ]
|
|
[:a.tag.is-medium.is-delete {:on-click (fn []
|
|
(on-change {:sort (filter #(not= sort-key (:sort-key %)) sort)}))}]]])])
|
|
|
|
(defn controls [{:keys [start end count total] :as para}]
|
|
(let [children (r/children (r/current-component))]
|
|
[:> Consumer {}
|
|
(fn [consume]
|
|
(let [{:strs [on-params-change params] :as consume} (js->clj consume)]
|
|
(r/as-element (into
|
|
[:div {:style {:margin-bottom "1rem"}}
|
|
[:div.level
|
|
(into
|
|
[:div.level-left
|
|
[:div.level-item
|
|
[paginator {:start start :end end :count count :total total
|
|
:on-change on-params-change}]]
|
|
[:div.level-item
|
|
[sort-by-list {:sort (:sort params)
|
|
:on-change on-params-change}]]]
|
|
(mapv (fn [c]
|
|
[:div.level-item c]) children))]]))))]))
|
|
|
|
(defn table [{:keys [fullwidth]}]
|
|
|
|
(into
|
|
[:table.table.compact.grid {:class (if fullwidth
|
|
["is-fullwidth"])}]
|
|
(r/children (r/current-component))))
|
|
|
|
(defn header []
|
|
(into
|
|
[:thead]
|
|
(r/children (r/current-component))))
|
|
|
|
(defn header-cell [{:keys [style class]}]
|
|
(into [:th {:style style
|
|
:class class}]
|
|
(r/children (r/current-component))))
|
|
|
|
(defn row [{:keys [class]}]
|
|
(apply r/create-element "tr" #js {:className class}
|
|
(map r/as-element (r/children (r/current-component)))))
|
|
|
|
(defn button-cell [params]
|
|
(apply r/create-element "td" #js {"style" #js {"overflow" "visible"}}
|
|
(map r/as-element (r/children (r/current-component)))))
|
|
|
|
(defn cell [params]
|
|
(apply r/create-element "td" #js {}
|
|
(map r/as-element (r/children (r/current-component))))
|
|
)
|
|
|
|
(defn body []
|
|
(let [children (r/children (r/current-component))]
|
|
[:> Consumer {}
|
|
(fn [consume]
|
|
(let [{:strs [column-count status]} (js->clj consume)]
|
|
(r/as-element
|
|
(cond (= :loading (:state status))
|
|
^{:key "loading-body"}
|
|
[:tbody.test
|
|
(for [i (range 20)]
|
|
^{:key i}
|
|
[:tr
|
|
(for [x (range column-count)]
|
|
^{:key x}
|
|
[:td #_{:col-span column-count}
|
|
[:div
|
|
[:div.ph-item
|
|
[:div.ph-row
|
|
[:div.ph-col-12.big]]]]])])]
|
|
|
|
(= :error (:state status))
|
|
^{:key "error-body"}
|
|
[:tbody [:tr [:td.has-text-centered {:col-span column-count}
|
|
"An unexpected error has occured. "
|
|
(-> status :error first :message)
|
|
" Please try refreshing the page."]]]
|
|
:else
|
|
(into ^{:key "main-body"}
|
|
[:tbody]
|
|
|
|
children)))))]))
|
|
|
|
(defn sortable-header-cell [{:keys [style class sort-key sort-name asc]}]
|
|
(let [children (r/children (r/current-component))]
|
|
[:> Consumer {}
|
|
(fn [consume]
|
|
(let [{:strs [on-params-change params] :as consume} (js->clj consume)]
|
|
(r/as-element (conj (into
|
|
[:th {:on-click (fn [e]
|
|
(on-params-change
|
|
(toggle-sort-by {:sort (:sort params)} sort-key sort-name)))
|
|
:style (assoc style
|
|
:cursor "pointer")
|
|
:class class}]
|
|
children)
|
|
(sort-icon sort-key (:sort params))))))]))
|
|
|
|
(defn grid [{:keys [on-params-change params status column-count]}]
|
|
(r/create-element Provider
|
|
#js {:value #js {:on-params-change on-params-change
|
|
:params params
|
|
:status status
|
|
:column-count column-count}}
|
|
(r/as-element
|
|
(into
|
|
[:<> ]
|
|
(r/children (r/current-component))))))
|
|
|
|
(defn virtual-paginate [start xs ]
|
|
(take 100 (drop (or start 0) xs)))
|
|
|
|
(defn virtual-paginate-controls [start xs]
|
|
{:start (or start 0) :end (min (+ (or start 0) 100)
|
|
(count xs))
|
|
:total (count xs)})
|