|
48 | 48 | [:code ":column-tree"] ","
|
49 | 49 | [:code ":column-spec"] ","
|
50 | 50 | [:code ":column-path"] ", etc..."]
|
51 |
| - [:ul {:style {:width 400}} |
52 |
| - [:li [p "A " [:code ":column-spec"] " describes a single column."] |
53 |
| - [:ul |
54 |
| - [:li "For instance, the " [:strong "Basic Demo"] " uses " |
55 |
| - [:code ":a"] " as a " [:code ":column-spec"] "."] |
56 |
| - [:li "Besides keywords, you can use " [:i "almost any"] " type of value."] |
57 |
| - [:li "You " [:i "can't"] " use vectors or lists (these are reserved for the " |
58 |
| - [:code ":column-tree"] ")."] |
59 |
| - [:li "At Day8, we tend to use maps. For instance, " |
60 |
| - [:pre "{:id :a |
| 51 | + [title2 "Column Spec"] |
| 52 | + [p "A " [:code ":column-spec"] " describes a single column."] |
| 53 | + [:ul |
| 54 | + [:li "For instance, the " [:strong "Basic Demo"] " uses " |
| 55 | + [:code ":a"] " as a " [:code ":column-spec"] "."] |
| 56 | + [:li "You can use " [:i "almost any"] " type of value (not just keywords)."] |
| 57 | + [:li "You " [:i "can't"] " use vectors or lists (these are reserved for the " |
| 58 | + [:code ":column-tree"] ")."] |
| 59 | + [:li "At Day8, we tend to use maps. For instance, " |
| 60 | + [:pre {:style {:width 400}} "{:id :a |
61 | 61 | :column-label \"A\"
|
62 |
| - :special-business-logic ::xyz}"]]]] |
63 |
| - [:br] |
64 |
| - [:li "A " [:code ":column-tree"] "describes a nested arrangement of columns." |
65 |
| - [:ul |
66 |
| - [:li "There are parent columns, and they can have child columns, " |
67 |
| - "which can have their own child columns, etc..."] |
68 |
| - [:li "In practice, a " [:code ":column-tree"] " is a vector (or list) of " |
69 |
| - [:code ":column-spec"] "values."] |
70 |
| - [:li "The most basic case is a flat tree: " [:code "[:a :b :c]"] "."] |
71 |
| - [:li "A nested tree looks like: " [:code "[:a [1 2] :b [3 4]]"] "."] |
72 |
| - [:li "In that case: " |
73 |
| - [:ul |
74 |
| - [:li [:code ":a"] " and " [:code ":b"] " are siblings, each with two children."] |
75 |
| - [:li [:code "1"] " and " [:code "2"] " are siblings, both children of " [:code ":a"]]]]]] |
76 |
| - [:br] |
77 |
| - [:li "A " [:code ":column-path"] " describes a distinct location within a " |
78 |
| - [:code ":column-tree"] "." |
79 |
| - [:ul |
80 |
| - [:li ""] |
81 |
| - [:li "Given a " [:code ":column-tree"] ", " [:code ":nested-grid"] |
82 |
| - " derives all the " [:code ":column-path"] "s it contains, mapping the " |
83 |
| - [:code ":cell"] " function over all of them."]]] |
84 |
| - [:br] |
85 |
| - [:li [:code ":row-spec"] ", " [:code ":row-tree"] " and " [:code ":row-paths"] |
86 |
| - " have all the same properties as their column equivalents."] |
87 |
| - [:br] |
88 |
| - [:li "A " [:i "position"] " combines one " [:code ":row-path"] |
89 |
| - " with one " [:code ":column-path"] "." |
90 |
| - [:ul |
91 |
| - [:li "Rendering one cell means evaluating the " [:code ":cell"] "function, " |
92 |
| - "by passing in keyword arguments " |
93 |
| - [:code ":row-path"] " and " [:code ":column-path"] |
94 |
| - " (i.e., the " [:i "position"] ")."]]]]]]) |
| 62 | + :special-business-logic ::xyz}"]]] |
| 63 | + [title2 "Column Tree"] |
| 64 | + [p "A " [:code ":column-tree"] "describes a nested arrangement of columns." |
| 65 | + [:ul |
| 66 | + [:li "In practice, a " [:code ":column-tree"] " is a vector (or list) of " |
| 67 | + [:code ":column-spec"] "values."] |
| 68 | + [:li "There are parent columns, and they can have child columns, " |
| 69 | + "which can have their own child columns, etc..."] |
| 70 | + [:li "The most basic case is a flat tree: " [:code "[:a :b :c]"] "."] |
| 71 | + [:li "A nested tree looks like: " [:code "[:a [1 2] :b [3 4]]"] "."] |
| 72 | + [:li "In that case: " |
| 73 | + [:ul |
| 74 | + [:li [:code ":a"] " and " [:code ":b"] " are siblings, each with two children."] |
| 75 | + [:li [:code "1"] " and " [:code "2"] " are siblings, both children of " [:code ":a"]]]]]] |
| 76 | + [title2 "Column Path"] |
| 77 | + [p "A " [:code ":column-path"] " describes a distinct ancestry within a " |
| 78 | + [:code ":column-tree"] "." |
| 79 | + [:ul |
| 80 | + [:li "For the " [:code ":column-tree"] " above, " [:code "[:a [1 2] :b [3 4]]"] ", its " [:code ":column-path"] "s are: " |
| 81 | + [:pre "[[:a] [:a 1] [:a 2] [:b] [:b 1] [:b 2]]"]]]] |
| 82 | + [title2 "Row"] |
| 83 | + [p "Everything described above applies to rows, as well. " [:code ":row-spec"] ", " [:code ":row-tree"] " and " [:code ":row-path"] |
| 84 | + " have all the same properties as their column equivalents."] |
| 85 | + [title2 "Cell & Header Functions"] |
| 86 | + [p [:code "nested-grid"] " accepts " [:code ":column-header"] ", " [:code ":row-header"] ", " [:code ":header-spacer"] " and " [:code ":cell"] " props. Each is a function." [:code "nested-grid"] " calls each function to render the following locations:" |
| 87 | + [nested-grid |
| 88 | + :header-spacer (constantly [:div {:style {:color "grey"}} ":header-spacer"]) |
| 89 | + :column-width 100 |
| 90 | + :column-tree [":column-header" [{:id (gensym) :label ":column-header"} |
| 91 | + {:id (gensym) :label ":column-header"}]] |
| 92 | + :row-tree [":row-header" [{:id (gensym) :label ":row-header"} |
| 93 | + {:id (gensym) :label "row-header"}]] |
| 94 | + :cell (constantly ":cell")] |
| 95 | + [p "Each prop has a reasonable default, except for " [:code ":cell"] "." |
| 96 | + "Your " [:code ":cell"] " function will be passed two keyword arguments, " |
| 97 | + [:code ":column-path"] " and " [:code ":row-path"] ". It can return either a string or a hiccup."]]]]) |
95 | 98 |
|
96 | 99 | (defn intro-column []
|
97 | 100 | [v-box
|
|
256 | 259 | "for above nested-grid"
|
257 | 260 | "src/re_demo/nested_grid.cljs"]
|
258 | 261 | [p "Here, we use " [:i "header specs"] " like " [:code "multiply"]
|
259 |
| - " and " [:code "lookup"] " to build a multi-modal view of the source data."] |
| 262 | + " and " [:code "lookup"] " to build a multi-modal view of the source data." |
| 263 | + " In other words, the combined " [:code ":column-path"] " and " [:code ":row-path"] " express not just " [:i "what"] " to show in the cell, but also " [:i "how"] " to show it."] |
260 | 264 | [:pre "(def lookup-table [[\"🚓\" \"🛵\" \"🚲\" \"🛻\" \"🚚\"]
|
261 | 265 | [\"🍐\" \"🍎\" \"🍌\" \"🥝\" \"🍇\"]
|
262 | 266 | [\"🐕\" \"🐎\" \"🧸\" \"🐈\" \"🐟\"]])
|
|
282 | 286 | (apply merge))]
|
283 | 287 | (operator left right)))]"]]])
|
284 | 288 |
|
285 |
| -(defn basic-demo [] |
| 289 | +(defn header-demo [] |
| 290 | + [:hi]) |
| 291 | + |
| 292 | +(defn internals-demo [] |
286 | 293 | [v-box
|
287 | 294 | :children
|
288 |
| - [[h-box |
| 295 | + [[nested-grid |
| 296 | + :column-tree [{:id "Tree" :width 130} |
| 297 | + {:id "Leaf Paths" :width 155} |
| 298 | + {:id "All Paths" :width 180}] |
| 299 | + :row-tree [{:label "Basic" :tree [:a :b :c]} |
| 300 | + {:label "Nested" :tree [:a [:b :c]]} |
| 301 | + {:label "Branching" :tree [:a [:b] :c [:d]]} |
| 302 | + {:label "Explicit" :tree [[:a [:b :c]] |
| 303 | + [:d [:e :f]]]} |
| 304 | + {:label "Typed" :tree [:kw 42 "str" {:k :map}]}] |
| 305 | + :cell (fn [{:keys [column-path] [{:keys [tree]}] :row-path}] |
| 306 | + (case (:id (last column-path)) |
| 307 | + "Tree" (str tree) |
| 308 | + "Leaf Paths" (str (vec (nested-grid/leaf-paths |
| 309 | + (nested-grid/header-spec->header-paths tree)))) |
| 310 | + "All Paths" (str (nested-grid/header-spec->header-paths tree))))] |
| 311 | + [p "This table demonstrates how " [:code "nested-grid"] " derives a vector of " [:code ":column-path"] "s from a " [:code ":column-tree"] "."] |
| 312 | + [h-box |
289 | 313 | :justify :between
|
290 | 314 | :children
|
291 | 315 | [[nested-grid
|
|
302 | 326 | :row-tree [1 2 3]
|
303 | 327 | :cell (fn [{:keys [column-path row-path]}]
|
304 | 328 | (str column-path row-path))]"]]]
|
| 329 | + [p "Here, the " [:code ":cell"] " function simply prints the " [:code ":column-path"] " and " [:code ":row-path"] " it gets passed."] |
305 | 330 | [h-box
|
306 | 331 | :justify :between
|
307 | 332 | :children
|
|
320 | 345 | 2 [:x :y]]
|
321 | 346 | :cell (fn [{:keys [column-path row-path]}]
|
322 | 347 | (str column-path row-path))]"]]]
|
| 348 | + [p "Same " [:code ":cell"] " function, but with a nested " [:code ":row-tree"] "."] |
323 | 349 | [h-box
|
324 | 350 | :justify :between
|
325 | 351 | :children
|
|
338 | 364 | :row-tree [:x [5 6] :y [7 8]]
|
339 | 365 | :cell (fn [{:keys [column-path row-path]}]
|
340 | 366 | [:i {:style {:color \"grey\"}}
|
341 |
| - (str column-path row-path)])]"]]]]]) |
342 |
| - |
343 |
| -(defn header-demo [] |
344 |
| - [:hi]) |
| 367 | + (str column-path row-path)])]"]]] |
| 368 | + [p "This " [:code ":cell"] " function returns a hiccup, not just a string."] |
| 369 | + [h-box |
| 370 | + :justify :between |
| 371 | + :children |
| 372 | + [[nested-grid |
| 373 | + :column-tree [:a :b :c] |
| 374 | + :row-tree [[1 [:x :y]] |
| 375 | + [2 [:x :y]]] |
| 376 | + :column-width 55 |
| 377 | + :column-header-height 25 |
| 378 | + :row-header-width 30 |
| 379 | + :show-branch-paths? true |
| 380 | + :cell (fn [{:keys [column-path row-path]}] |
| 381 | + (str column-path row-path))] |
| 382 | + [:pre {:style {:margin-top 19}} "[nested-grid |
| 383 | + :show-branch-paths? true |
| 384 | + :column-tree [:a :b :c] |
| 385 | + :row-tree [1 [:x :y] |
| 386 | + 2 [:x :y]] |
| 387 | + :cell (fn [{:keys [column-path row-path]}] |
| 388 | + (str column-path row-path))]"]]] |
| 389 | + [p "When passed " [:code ":show-branch-paths? true"] |
| 390 | + ", more cells get rendered. " [:code "[1]"] " and " [:code "[2]"] " count as " |
| 391 | + "branch paths, since they have children in the " [:code ":row-tree"] ". By default, these are not shown by default."]]]) |
345 | 392 |
|
346 |
| -(defn internals-demo [] |
| 393 | +(defn basic-demo [] |
347 | 394 | [v-box
|
348 | 395 | :children
|
349 |
| - [[p "This table demonstrates how " [:code "nested-grid"] " derives a vector of " [:code ":column-path"] "s from a " [:code ":column-tree"] ":"] |
350 |
| - [nested-grid |
351 |
| - :column-tree [{:id "Tree" :width 130} |
352 |
| - {:id "Leaf Paths" :width 155} |
353 |
| - {:id "All Paths" :width 180}] |
354 |
| - :row-tree [{:label "Basic" :tree [:a :b :c]} |
355 |
| - {:label "Nested" :tree [:a [:b :c]]} |
356 |
| - {:label "Branching" :tree [:a [:b] :c [:d]]} |
357 |
| - {:label "Explicit" :tree [[:a [:b :c]] |
358 |
| - [:d [:e :f]]]} |
359 |
| - {:label "Typed" :tree [:kw 42 "str" {:k :map}]}] |
360 |
| - :cell (fn [{:keys [column-path] [{:keys [tree]}] :row-path}] |
361 |
| - (case (:id (last column-path)) |
362 |
| - "Tree" (str tree) |
363 |
| - "Leaf Paths" (str (vec (nested-grid/leaf-paths |
364 |
| - (nested-grid/header-spec->header-paths tree)))) |
365 |
| - "All Paths" (str (nested-grid/header-spec->header-paths tree))))]]]) |
| 396 | + [[h-box |
| 397 | + :justify :between |
| 398 | + :children |
| 399 | + [[nested-grid |
| 400 | + :column-tree [2 4 6] |
| 401 | + :row-tree [1 3 5] |
| 402 | + :cell (fn [{:keys [column-path row-path]}] |
| 403 | + (* (last column-path) (last row-path)))] |
| 404 | + [:pre {:style {:margin-top "19px"}} "[nested-grid |
| 405 | + :column-tree [2 4 6] |
| 406 | + :row-tree [1 3 5] |
| 407 | + :cell (fn [{:keys [column-path row-path]}] |
| 408 | + (* (last column-path) |
| 409 | + (last row-path)))]"]]] |
| 410 | + [p "A simple times table. the " [:code ":cell"] " function receives " |
| 411 | + [:code ":column-path"] " and " [:code ":row-path"] |
| 412 | + ". In this case, each path is a vector of one number, for instance, " |
| 413 | + [:code "[5]"] "."] |
| 414 | + [h-box |
| 415 | + :justify :between |
| 416 | + :children |
| 417 | + [[nested-grid |
| 418 | + :column-tree [0 1 2] |
| 419 | + :row-tree [2 3 4] |
| 420 | + :cell (fn [{:keys [column-path row-path]}] |
| 421 | + (get-in lookup-table [(last column-path) |
| 422 | + (last row-path)]))] |
| 423 | + [:pre {:style {:margin-top "19px"}} "(def lookup-table [[\"🚓\" \"🛵\" \"🚲\" \"🛻\" \"🚚\"] |
| 424 | + [\"🍐\" \"🍎\" \"🍌\" \"🥝\" \"🍇\"] |
| 425 | + [\"🐕\" \"🐎\" \"🧸\" \"🐈\" \"🐟\"]]) |
| 426 | +[nested-grid |
| 427 | + :column-tree [0 1 2] |
| 428 | + :row-tree [2 3 4] |
| 429 | + :cell (fn [{:keys [column-path row-path]}] |
| 430 | + (get-in lookup-table [(last column-path) |
| 431 | + (last row-path)]))]"]]] |
| 432 | + [p "Here, instead of multiplying the path values, we use them to access an " |
| 433 | + "external lookup table. This is a common use-case: prepare a data frame independently from " |
| 434 | + [:code "nested-grid"] ", but with the intention of using " |
| 435 | + [:code "nested-grid"] " as a simple display layer."]]]) |
366 | 436 |
|
367 | 437 | (defn demos []
|
368 | 438 | (let [tabs [{:id :basic :label "Basic Demo" :view basic-demo}
|
369 |
| - {:id :color :label "Color" :view color-demo} |
370 |
| - {:id :shade :label "Shade" :view color-shade-demo} |
| 439 | + #_#_{:id :color :label "Color" :view color-demo} |
| 440 | + {:id :shade :label "Shade" :view color-shade-demo} |
371 | 441 | {:id :internals :label "Internals" :view internals-demo}
|
372 |
| - {:id :spec :label "Spec" :view header-spec-demo}] |
| 442 | + {:id :spec :label "Multimodal" :view header-spec-demo}] |
373 | 443 | !tab-id (r/atom (:id (first tabs)))
|
374 | 444 | !tab (r/reaction (u/item-for-id @!tab-id tabs))]
|
375 | 445 | (fn []
|
|
467 | 537 | ;; core holds a reference to panel, so need one level of indirection to get figwheel updates
|
468 | 538 | (defn panel
|
469 | 539 | []
|
470 |
| - (let [tabs [{:id :intro :label "Introduction" :view intro-column} |
471 |
| - {:id :concepts :label "Concepts" :view concepts-column} |
472 |
| - {:id :more :label "More" :view more-column} |
473 |
| - {:id :parameters :label "Parameters" :view args-column}] |
| 540 | + (let [tabs [{:id :intro :label "Introduction" :view intro-column} |
| 541 | + {:id :concepts :label "Concepts" :view concepts-column} |
| 542 | + {:id :more :label "More" :view more-column} |
| 543 | + {:id :parameters :label "Parameters" :view args-column}] |
474 | 544 | !tab-id (r/atom (:id (first tabs)))
|
475 | 545 | !tab (r/reaction (u/item-for-id @!tab-id tabs))]
|
476 | 546 | (fn []
|
|
0 commit comments