|
1 | 1 | (ns app.main |
2 | 2 | (:gen-class) |
3 | 3 | (:require [hyperlith.core :as h :refer [defaction defview]] |
4 | | - [hyperlith.extras.sqlite :as d])) |
| 4 | + [hyperlith.extras.sqlite :as d] |
| 5 | + [app.virtual-scroll :as vs])) |
5 | 6 |
|
6 | 7 | (def row-height 20) |
7 | | -(def view-rows 300) |
8 | 8 |
|
9 | 9 | (def css |
10 | 10 | (h/static-css |
|
28 | 28 | :gap :5px |
29 | 29 | :flex-direction :column}] |
30 | 30 |
|
31 | | - [:.view |
32 | | - {:overflow-y :scroll |
33 | | - :scroll-behavior :smooth |
34 | | - :overflow-anchor :none |
35 | | - :height "min(100% - 2rem , 60rem)"}] |
36 | | - |
37 | | - [:.table |
38 | | - {:background :white |
39 | | - :pointer-events :none}] |
40 | | - |
41 | | - [:table-view |
42 | | - ;; Using implicit rows here (not specifying the row template) prevents a |
43 | | - ;; layout shift. |
44 | | - {:position :relative |
45 | | - :display :grid}] |
46 | | - |
47 | 31 | [:.row |
48 | | - {;; Set row height explicitly |
49 | | - :height (str row-height "px") |
50 | | - :display :grid |
| 32 | + {:display :grid |
51 | 33 | :grid-template-columns (str "repeat(" 4 ", auto)")}]])) |
52 | 34 |
|
53 | 35 | (defn get-session-data [db sid] |
|
73 | 55 | :data ?new-data}]} |
74 | 56 | {:sid sid :new-data new-data})))) |
75 | 57 |
|
76 | | -(defn row->offset [row-cursor] |
77 | | - (max (- row-cursor 100) 0)) |
78 | | - |
79 | 58 | (defaction handler-scroll |
80 | | - [{:keys [sid tabid tx-batch!] {:keys [y]} :body}] |
| 59 | + [{:keys [sid tabid tx-batch!] {:strs [y]} :query-params}] |
81 | 60 | ;; We don't actually care about the number of rows only their height |
82 | 61 | ;; this makes the maths simpler |
83 | | - (let [row-cursor (int (/ y row-height))] |
| 62 | + (when-let [y (int (parse-long y))] |
84 | 63 | (tx-batch! |
85 | 64 | (fn [db] |
86 | 65 | (update-tab-data! db sid tabid |
87 | | - #(assoc % :row-cursor (max (int row-cursor) 0))))))) |
| 66 | + #(assoc % :y (max y 0))))))) |
88 | 67 |
|
89 | 68 | (defn Row [id [a b c :as _data]] |
90 | | - (h/html [:div.row |
91 | | - [:div id] [:div a] [:div b] [:div c]])) |
92 | | - |
93 | | -(defn UserView [{:keys [row-cursor] :or {row-cursor 0}} db] |
94 | | - (let [current-offset (row->offset row-cursor)] |
95 | | - (h/html |
96 | | - [:div#table-view.table-view |
97 | | - {:style |
98 | | - {:transform (str "translateY(" (* current-offset row-height) "px)")}} |
99 | | - (->> (d/q db |
100 | | - '{select [id data] |
101 | | - from row |
102 | | - offset ?offset |
103 | | - limit ?limit} |
104 | | - {:offset current-offset |
105 | | - :limit view-rows}) |
106 | | - (mapv (fn [[id row]] (Row id row))))]))) |
107 | | - |
108 | | -(def on-scroll-js |
109 | | - (str "$y = el.scrollTop; @post(`" handler-scroll "`)")) |
| 69 | + (h/html [:div.row {:id id} |
| 70 | + [:div nil id] [:div nil a] [:div nil b] [:div nil c]])) |
| 71 | + |
| 72 | +(defn row-builder [db offset limit] |
| 73 | + (->> (d/q db |
| 74 | + '{select [id data] |
| 75 | + from row |
| 76 | + offset ?offset |
| 77 | + limit ?limit} |
| 78 | + {:offset offset |
| 79 | + :limit limit}) |
| 80 | + (mapv (fn [[id row]] (Row id row))))) |
| 81 | + |
| 82 | +(defn row-count [db] |
| 83 | + (-> (d/q db '{select [[[count *]]] from row}) |
| 84 | + first)) |
110 | 85 |
|
111 | 86 | (def shim-headers |
112 | 87 | (h/html |
|
117 | 92 | (defview handler-root |
118 | 93 | {:path "/" :shim-headers shim-headers :br-window-size 19} |
119 | 94 | [{:keys [db sid tabid] :as _req}] |
120 | | - (let [;; TODO: make this dynamic |
121 | | - row-count 200000 |
122 | | - tab-data (get-tab-data db sid tabid) |
123 | | - content (UserView (assoc tab-data :row-count row-count) db)] |
| 95 | + (let [tab-data (get-tab-data db sid tabid)] |
124 | 96 | (h/html |
125 | 97 | [:link#css {:rel "stylesheet" :type "text/css" :href css}] |
126 | 98 | [:main#morph.main |
127 | | - [:div#view.view |
128 | | - {:data-ref "_view" |
129 | | - :data-on-scroll__throttle.100ms.trail.noleading on-scroll-js} |
130 | | - [:div#table.table |
131 | | - {:style {:height (str (* row-count row-height) "px")}} |
132 | | - content]]]))) |
| 99 | + [:pre {:data-json-signals true} nil] |
| 100 | + [::vs/Virtual#view |
| 101 | + {:v/row-height 20 |
| 102 | + :v/view-height 1000 |
| 103 | + :v/max-rendered-rows 1000 |
| 104 | + :v/row-fn (partial row-builder db) |
| 105 | + :v/row-count-fn (partial row-count db) |
| 106 | + :v/scroll-handler-path handler-scroll |
| 107 | + :v/scroll-pos (:y tab-data)}]]))) |
133 | 108 |
|
134 | 109 | (defn initial-table-db-state! [db] |
135 | 110 | (let [number-of-rows 200000 |
|
203 | 178 |
|
204 | 179 | (def db (-> @app_ :ctx :db)) |
205 | 180 |
|
| 181 | + (user/bench |
| 182 | + (html/html->str |
| 183 | + (html/html |
| 184 | + [::vs/Virtual#view |
| 185 | + {:v/row-height 20 |
| 186 | + :v/view-height 1000 |
| 187 | + :v/max-rendered-rows 300 |
| 188 | + :v/row-fn (partial row-builder db) |
| 189 | + :v/row-count-fn (partial row-count db) |
| 190 | + :v/scroll-handler-path handler-scroll |
| 191 | + :v/scroll-pos (:y 10)}]))) |
| 192 | + |
206 | 193 | ,) |
0 commit comments