diff --git a/src/re_demo/nested_grid.cljs b/src/re_demo/nested_grid.cljs index e8c2b63e..88ffb7dd 100644 --- a/src/re_demo/nested_grid.cljs +++ b/src/re_demo/nested_grid.cljs @@ -2,6 +2,7 @@ (:require [clojure.string :as str] [re-com.core :as rc :refer [at h-box v-box box gap line label p p-span hyperlink-href]] + [re-com.util :as u] [reagent.core :as r] [re-com.nested-grid :as nested-grid :refer [nested-grid nested-grid-args-desc nested-grid-parts-desc]] [re-demo.utils :refer [source-reference panel-title title2 title3 args-table parts-table github-hyperlink status-text new-in-version]])) @@ -22,100 +23,11 @@ :red "🔴" :white "⚪"}) -(def color-mixer - {:red {:red :red - :blue :purple - :yellow :orange} - :yellow {:red :orange - :blue :green - :yellow :yellow} - :blue {:red :purple - :blue :blue - :yellow :green}}) - -(def special-colors - {"lightred" "pink" - "lightorange" "peachpuff" - "lightpurple" "lavender" - "darkpurple" "brown" - "darkyellow" "gold"}) - -(defn mix-colors [color1 color2] - (name (get-in color-mixer [(keyword color1) (keyword color2)]))) - -(mix-colors :red :yellow) - -(defn color-explainer [] - [rc/v-box - :children - [[p "Here's a grid with flat columns and rows." - " The " [:code ":cell"] " function closes over some external business logic (" - [:code "mix-colors"] ") to express a string." - " Since there is only one level of nesting, " [:code "column-path"] - " contains a single " [:i "header value"] " - for instance, " - [:code "[:red]"] "."] - [:pre "[nested-grid - :columns [\"red\" \"yellow\" \"blue\"] - :rows [\"red\" \"yellow\" \"blue\"] - :cell (fn color-cell [{:keys [column-path row-path]}] - (mix-colors (last column-path) - (last row-path)))]"]]]) - -(defn color-demo [] - [nested-grid - :columns ["red" "yellow" "blue"] - :rows ["red" "yellow" "blue"] - :cell (fn color-cell [{:keys [row-path column-path]}] - (mix-colors (last row-path) - (last column-path)))]) - -(defn color-shade-explainer [] - [rc/v-box - :children - [[p "Here, " [:code ":columns"] "is a nested " [:i "configuration"] " of " [:i "header values."]] - [p "Since the " [:i "configuration"] " has 2 levels of nesting," - " each " [:code ":column-path"] " is 2-long. For instance, " - [:code "[:medium :yellow]"] ". "] - [p [:code ":cell"] " returns a hiccup."] - [p "Calling " [:code "(color-shade-cell {:column-path [:medium :yellow] :row-path [:blue]})"] - "should return a " [:span {:style {:color "green"}} "green"] " hiccup."] - - [:pre "[nested-grid - :columns [:medium [:red :yellow :blue] - :light [:red :yellow :blue] - :dark [:red :yellow :blue]] - :rows [:red :yellow :blue] - :cell color-shade-cell]"]]]) - -(defn color-shade-cell [{:keys [row-path column-path]}] - (let [[row-hue] row-path - [shade col-hue] column-path - hue (mix-colors row-hue col-hue) - shade (when-not (= :medium shade) (name shade)) - color (str shade hue) - color (get special-colors color color)] - [:div {:style {:height "100%" - :width "100%" - :text-align "center" - :background-color color}} - [:span {:style {:font-size "10px" - :color "white" - :text-shadow "1px 1px 2px black"}} - color]])) - (nested-grid/header-spec->header-paths [:medium [:red :yellow :blue] :light [:red :yellow :blue] :dark [:red :yellow :blue]]) -(defn color-shade-demo [] - [nested-grid - {:columns [:medium [:red :yellow :blue] - :light [:red :yellow :blue] - :dark [:red :yellow :blue]] - :rows [:red :yellow :blue] - :cell color-shade-cell}]) - (def fruit {:dimension "fruit"}) (defn fruit-demo [] @@ -159,51 +71,15 @@ " for layout."] [title3 "Cells are Functions"] [p "Each cell is a " [:i "function"] " of its grid position."] - [nested-grid - :columns ["a" "b" "c"] - :rows ["x" "y" "z"] - :column-width 40 - :column-header-height 25 - :row-header-width 30 - :cell (fn [{:keys [column-path row-path]}] - (str "(" (last column-path) - ", " (last row-path) ")"))] + [title3 "Headers are Nested"] [p "You can declare headers as a nested " [:i "configuration."]] - [nested-grid - :columns [:a [:a1 :a2] :b [:b1 :b2]] - :rows [:x [:x1 :x2] :y [:y1 :y2]] - :column-header-height 25 - :row-header-width 30 - :column-width 90 - :cell (comp str seq (juxt :column-path :row-path))] + [p "Each vertical partition you see is defined by a " [:code ":column-path"] "." "For instance, " [:code "[:a :a1]"] " is the first " [:code ":column-path"] "."] [p "Same goes for rows. For instance, " [:code "[:y :y2]"] " is the last " [:code ":row-path"] "."] [title3 "Cells are Views of Header Paths"] [p "Each cell is a function of its location."] - [h-box - :gap "25px" - :children - [[nested-grid - :columns [:a :b :c] - :rows [:x [:x1 :x2] - :y [:y1 :y2]] - :column-width 70 - :column-header-height 25 - :row-header-width 30 - :cell (fn [{:keys [column-path row-path]}] - [:i (str (list column-path row-path))])] - [v-box - :children - [[gap :size "20px"] - [:pre "[nested-grid - :columns [:a :b :c] - :rows [:x [:x1 :x2] - :y [:y1 :y2]] - :cell - (fn [{:keys [column-path row-path]}] - [:i (str (list column-path row-path))])]"]]]]] [p "Specifically, the " [:code ":cell"] " prop accepts a function " "of two keyword arguments: " [:code ":column-path"] " and " [:code ":row-path"] "."] [p "The function counts as a " @@ -246,6 +122,221 @@ "your data presentation would simply follow along. " "This could be done either programmatically or via a dedicated user interface."]]]) +(def color-mixer + {:red {:red :red + :blue :purple + :yellow :orange} + :yellow {:red :orange + :blue :green + :yellow :yellow} + :blue {:red :purple + :blue :blue + :yellow :green}}) + +(def special-colors + {"lightred" "pink" + "lightorange" "peachpuff" + "lightpurple" "lavender" + "darkpurple" "brown" + "darkyellow" "gold"}) + +(defn mix-colors [color1 color2] + (name (get-in color-mixer [(keyword color1) (keyword color2)]))) + +(defn color-demo [] + [rc/v-box + :children + [[nested-grid + :columns ["red" "yellow" "blue"] + :rows ["red" "yellow" "blue"] + :cell (fn color-cell [{:keys [row-path column-path]}] + (mix-colors (last row-path) + (last column-path)))] + [source-reference + "for above nested-grid" + "src/re_demo/nested_grid.cljs"] + [p "Here's a grid with flat columns and rows." + " The " [:code ":cell"] " function closes over some external business logic (" + [:code "mix-colors"] ") to express a string." + " Since there is only one level of nesting, " [:code "column-path"] + " contains a single " [:i "header value"] " - for instance, " + [:code "[:red]"] "."] + [:pre "[nested-grid + :columns [\"red\" \"yellow\" \"blue\"] + :rows [\"red\" \"yellow\" \"blue\"] + :cell (fn color-cell [{:keys [column-path row-path]}] + (mix-colors (last column-path) + (last row-path)))]"]]]) + +(defn color-shade-cell [{:keys [row-path column-path]}] + (let [[hue-a] row-path + [shade hue-b] column-path + hue (mix-colors hue-a hue-b) + shade (when-not (= :medium shade) (name shade)) + color (str shade hue) + color (get special-colors color color)] + [:div {:style {:height "100%" + :width "100%" + :text-align "center" + :background-color color}} + [:span {:style {:font-size "10px" + :color "white" + :text-shadow "1px 1px 2px black"}} + color]])) + +(defn color-shade-demo [] + [v-box + :children + [[nested-grid + {:columns [:medium [:red :yellow :blue] + :light [:red :yellow :blue] + :dark [:red :yellow :blue]] + :rows [:red :yellow :blue] + :cell color-shade-cell}] + [source-reference + "for above nested-grid" + "src/re_demo/nested_grid.cljs"] + [rc/v-box + :children + [[p "Here, " [:code ":columns"] "is a nested " [:i "configuration"] " of " [:i "header values."]] + [p "Since the " [:i "configuration"] " has 2 levels of nesting," + " each " [:code ":column-path"] " is 2-long. For instance, " + [:code "[:medium :yellow]"] ". "] + [p [:code ":cell"] " returns a hiccup."] + [p "Calling " [:code "(color-shade-cell {:column-path [:medium :yellow] :row-path [:blue]})"] + "should return a " [:span {:style {:color "green"}} "green"] " hiccup."] + [:pre "[nested-grid + :columns [:medium [:red :yellow :blue] + :light [:red :yellow :blue] + :dark [:red :yellow :blue]] + :rows [:red :yellow :blue] + :cell color-shade-cell]"]]]]]) + +(defn header-spec-demo [] + [v-box + :children + [[nested-grid + :columns [add [one two] + multiply [one two] + lookup [one two]] + :rows [three four] + :row-header (comp :label last :row-path) + :column-header (comp :label last :column-path) + :row-header 20 + :column-header-height 25 + :row-header-width 100 + :parts {:cell-wrapper {:style {:text-align "center"}}} + :cell (fn [{:keys [column-path row-path]}] + (let [{:keys [operator left right]} (->> (into row-path column-path) + (apply merge))] + (operator left right)))] + [source-reference + "for above nested-grid" + "src/re_demo/nested_grid.cljs"] + [p "Here, we use " [:i "header specs"] " like " [:code "multiply"] + " and " [:code "lookup"] " to build a multi-modal view of the source data."] + [:pre "(def lookup-table [[\"🚓\" \"🛵\" \"🚲\" \"🛻\" \"🚚\"] + [\"🍐\" \"🍎\" \"🍌\" \"🥝\" \"🍇\"] + [\"🐕\" \"🐎\" \"🧸\" \"🐈\" \"🐟\"]]) +(def add {:label \"Addition\" :operator +}) +(def multiply {:label \"Multiplication\" :operator *}) +(def lookup {:label \"Lookup\" + :operator (fn [l r] (get-in lookup-table [l r]))}) +(def one {:label \"1\" :left 1}) +(def two {:label \"2\" :left 2}) +(def three {:label \"3\" :right 3}) +(def four {:label \"4\" :right 4}) + +[nested-grid + :columns [add [one two] + multiply [one two] + lookup [one two]] + :rows [three four] + :column-header (comp :label last :column-path) + :row-header (comp :label last :row-path) + :cell (fn [{:keys [column-path row-path]}] + (let [{:keys [operator left right]} (->> column-path + (into row-path) + (apply merge))] + (operator left right)))]"]]]) + +(defn basic-demo [] + [v-box + :children + [[h-box + :justify :between + :children + [[nested-grid + :columns [:a :b :c] + :rows [1 2 3] + :column-width 40 + :column-header-height 25 + :row-header-width 30 + :cell (fn [{:keys [column-path row-path]}] + (str column-path row-path))] + [:pre {:style {:margin-top 19}} "[nested-grid + :columns [:a :b :c] + :rows [1 2 3] + :cell (fn [{:keys [column-path row-path]}] + (str column-path row-path))]"]]] + [h-box + :justify :between + :children + [[nested-grid + :columns [:a :b :c] + :rows [1 [:x :y] + 2 [:x :y]] + :column-width 55 + :column-header-height 25 + :row-header-width 30 + :cell (fn [{:keys [column-path row-path]}] + (str column-path row-path))] + [:pre {:style {:margin-top 19}} "[nested-grid + :columns [:a :b :c] + :rows [1 [:x :y] + 2 [:x :y]] + :cell (fn [{:keys [column-path row-path]}] + (str column-path row-path))]"]]] + [h-box + :justify :between + :children + [[nested-grid + :columns [:a [1 2] :b [3 4]] + :rows [:x [5 6] :y [7 8]] + :column-header-height 25 + :row-header-width 30 + :column-width 65 + :cell (fn [{:keys [column-path row-path]}] + [:i {:style {:color "grey"}} + (str column-path row-path)])] + [:pre {:style {:margin-top 19}} + "[nested-grid + :columns [:a [1 2] :b [3 4]] + :rows [:x [5 6] :y [7 8]] + :cell (fn [{:keys [column-path row-path]}] + [:i {:style {:color \"grey\"}} + (str column-path row-path)])]"]]]]]) + +(defn demos [] + (let [tabs [{:id :basic :label "Basic" :view basic-demo} + {:id :color :label "Color" :view color-demo} + {:id :shade :label "Shade" :view color-shade-demo} + {:id :spec :label "Spec" :view header-spec-demo}] + !tab-id (r/atom (:id (first tabs))) + !tab (r/reaction (u/item-for-id @!tab-id tabs))] + (fn [] + (let [{:keys [view label]} @!tab] + [v-box + :children + [[rc/horizontal-tabs + :src (at) + :model !tab-id + :tabs tabs + :style {:margin-top "12px"} + :on-change #(reset! !tab-id %)] + [title2 (str label " Demo")] + [view]]])))) + ;; core holds a reference to panel, so need one level of indirection to get figwheel updates (defn panel [] @@ -280,74 +371,5 @@ nested-grid-args-desc {:total-width "550px" :name-column-width "180px"}])]] - [v-box - :src (at) - :children - [[title2 "Demo #1: Flat Headers"] - [gap - :src (at) - :size "15px"] - [color-demo] - [source-reference - "for above nested-grid" - "src/re_demo/nested_grid.cljs"] - [color-explainer] - [gap - :src (at) - :size "40px"] - [line :src (at)] - [title2 "Demo #2: Nested Headers"] - [gap - :src (at) - :size "15px"] - [color-shade-demo] - [source-reference - "for above nested-grid" - "src/re_demo/nested_grid.cljs"] - [color-shade-explainer] - [title2 "Demo #3: Header Specifications"] - [nested-grid - :columns [add [one two] - multiply [one two] - lookup [one two]] - :rows [three four] - :row-header (comp :label last :row-path) - :column-header (comp :label last :column-path) - :row-header 20 - :column-header-height 25 - :row-header-width 100 - :parts {:cell-wrapper {:style {:text-align "center"}}} - :cell (fn [{:keys [column-path row-path]}] - (let [{:keys [operator left right]} (->> (into row-path column-path) - (apply merge))] - (operator left right)))] - [source-reference - "for above nested-grid" - "src/re_demo/nested_grid.cljs"] - [p "Here, we use " [:i "header specs"] " like " [:code "multiply"] - " and " [:code "lookup"] " to build a multi-modal view of the source data."] - [:pre "(def lookup-table [[\"🚓\" \"🛵\" \"🚲\" \"🛻\" \"🚚\"] - [\"🍐\" \"🍎\" \"🍌\" \"🥝\" \"🍇\"] - [\"🐕\" \"🐎\" \"🧸\" \"🐈\" \"🐟\"]]) -(def add {:label \"Addition\" :operator +}) -(def multiply {:label \"Multiplication\" :operator *}) -(def lookup {:label \"Lookup\" - :operator (fn [l r] (get-in lookup-table [l r]))}) -(def one {:label \"1\" :left 1}) -(def two {:label \"2\" :left 2}) -(def three {:label \"3\" :right 3}) -(def four {:label \"4\" :right 4}) - -[nested-grid - :columns [add [one two] - multiply [one two] - lookup [one two]] - :rows [three four] - :column-header (comp :label last :column-path) - :row-header (comp :label last :row-path) - :cell (fn [{:keys [column-path row-path]}] - (let [{:keys [operator left right]} (->> column-path - (into row-path) - (apply merge))] - (operator left right)))]"]]]]] + [demos]]] #_[parts-table "nested-grid" nested-grid-grid-parts-desc]]])))