From cc4863b25a6dce9970b9e23fe843aa02fb05ddaf Mon Sep 17 00:00:00 2001 From: Kimo Knowles Date: Sat, 20 Jul 2024 19:44:59 +0200 Subject: [PATCH] [error-modal] Add more args --- src/re_com/box.cljs | 2 +- src/re_com/error_modal.cljs | 105 +++++++++++++++++++++++------- src/re_com/text.cljs | 74 ++++++++++++--------- src/re_com/theme.cljs | 39 ++++++----- src/re_com/theme/blue_modern.cljs | 28 +++++--- src/re_com/theme/default.cljs | 19 ++++-- src/re_com/util.cljs | 23 +++++-- src/re_com/validate.cljs | 2 +- src/re_demo/core.cljs | 13 +++- src/re_demo/line.cljs | 2 +- src/re_demo/modal_panel.cljs | 20 +++--- src/re_demo/nested_grid.cljs | 8 +-- 12 files changed, 224 insertions(+), 111 deletions(-) diff --git a/src/re_com/box.cljs b/src/re_com/box.cljs index fcc4e0ce..b477a941 100644 --- a/src/re_com/box.cljs +++ b/src/re_com/box.cljs @@ -541,4 +541,4 @@ :style style :attr attr :src src - :debug-as debug-as)))) \ No newline at end of file + :debug-as debug-as)))) diff --git a/src/re_com/error_modal.cljs b/src/re_com/error_modal.cljs index 9887593f..0e7c22ba 100644 --- a/src/re_com/error_modal.cljs +++ b/src/re_com/error_modal.cljs @@ -6,26 +6,42 @@ [re-com.box :as box] [re-com.modal-panel :as mp] [re-com.theme :as theme] + [re-com.theme.blue-modern :as blue-modern] [re-com.buttons :as button] [re-com.text :as text] [re-com.util :as u :refer [deref-or-value px]])) +(swap! theme/registry update :main vector blue-modern/theme) + +(defn close-button [props] + (let [hover? (r/atom nil)] + [:div {:on-mouse-enter (partial reset! hover? true) + :on-mouse-leave (partial reset! hover? false) + :style {:padding "12px 7px 7px 7px"}} + [u/x-button (merge props {:hover? hover? :stroke-width "1.2px"})]])) + (defn error-modal [& {:keys [severity title - what-happened what-happened-label - implications implications-label - what-to-do what-to-do-label + what-happened what-happened-title + implications implications-title + what-to-do what-to-do-title + details details-title + error error-title action instructions + proceedable? + undone? backdrop-on-click on-close closeable? + theme header footer heading] :or {title "Sorry, you've hit a bug" - what-happened-label "What Happened?" - implications-label "Implications" - what-to-do-label "What Should I Do?" + what-happened-title "What Happened?" + implications-title "Implications" + what-to-do-title "What Should I Do?" + details-title "Low-level Details (for developers):" severity :error closeable? true} :as args}] - (let [themed (fn [part & [props]] + (let [themed (fn [part props] (theme/apply props {:part part :state {:severity severity}} @@ -35,7 +51,11 @@ arrow-side-length (* 2 arrow-midpoint) arrow-points (str arrow-midpoint "," arrow-midpoint " " arrow-side-length "," 0 " " - "0,0")] + "0,0") + error (if (string? error) + (fn [props] [:div props error]) error) + details (if (string? details) + (fn [props] [:div props details]) details)] [mp/modal-panel (themed ::modal {:backdrop-on-click backdrop-on-click @@ -48,23 +68,58 @@ (themed ::title-wrapper {:src (at) :children - [[text/title (themed ::title {:level :level2 :label title})] - (when closeable? [u/x-button {:on-click on-close}])]})] - [:svg (themed ::triangle {:style {:width (px arrow-side-length) - :height (px arrow-midpoint) - :transform (str "translateX(" (-> panel-padding (- arrow-midpoint) px) ")")}}) + [[text/title (themed ::title {:label title})] + (when closeable? [close-button {:on-click on-close + :height "12px" + :width "12px"}])]})] + [:svg (themed ::triangle + {:style {:width (px arrow-side-length) + :height (px arrow-midpoint) + :transform (str "translateX(" + (-> panel-padding (- arrow-midpoint) px) ")")}}) [:polygon {:points arrow-points}]] [box/v-box (themed ::body - {:children - [[u/part header args] - (when what-happened - [u/part heading (themed ::heading {:label what-happened-label :level :level2}) text/title]) - [u/part what-happened args] - (when implications - [u/part heading (themed ::heading {:label implications-label :level :level2}) text/title]) - [u/part implications args] - (when what-to-do - [u/part heading (themed ::heading {:label what-to-do-label :level :level2}) text/title]) - [u/part what-to-do args] - [u/part footer args]]})]]})]})])) + {:gap [:<> + [box/gap :size "19px"] + [box/line] + [box/gap :size "7px"]] + :children + [(when header + [:<> + [box/gap :size "19px"] + [u/part header args]]) + [:<> + (when action + [u/part heading + (themed ::sub-title-2 {:label action :level :level2}) + text/title]) + (when instructions + [text/p instructions]) + (when what-happened + [:<> + [u/part heading + (themed ::sub-title-2 {:label what-happened-title :level :level3}) text/title] + [u/part what-happened args]]) + + (when implications + [:<> + [u/part heading + (themed ::sub-title {:label implications-title :level :level3}) text/title] + [u/part implications args]]) + + (when what-to-do + [:<> + [u/part heading (themed ::sub-title {:label what-to-do-title :level :level3}) text/title] + [u/part what-to-do args]])] + + (when (or details error) + [:<> + [u/part heading + (themed ::sub-title {:label details-title :level :level3}) text/title] + [u/part details args] + + [u/part error (themed ::error args)]]) + + (when footer + [u/part footer args])]})]]})]})])) diff --git a/src/re_com/text.cljs b/src/re_com/text.cljs index 8e202bbe..25d88dd4 100644 --- a/src/re_com/text.cljs +++ b/src/re_com/text.cljs @@ -1,13 +1,14 @@ -(ns re-com.text - (:require-macros - [re-com.core :refer [handler-fn at reflect-current-component]] - [re-com.validate :refer [validate-args-macro]]) - (:require - [re-com.config :refer [include-args-desc?]] - [re-com.debug :refer [->attr]] - [re-com.box :refer [v-box box line flex-child-style]] - [re-com.util :refer [deep-merge]] - [re-com.validate :refer [title-levels-list title-level-type? css-style? html-attr? parts? string-or-hiccup?]])) + (ns re-com.text + (:require-macros + [re-com.core :refer [handler-fn at reflect-current-component]] + [re-com.validate :refer [validate-args-macro]]) + (:require + [re-com.config :refer [include-args-desc?]] + [re-com.debug :refer [->attr]] + [re-com.box :refer [v-box box line flex-child-style]] + [re-com.theme :as theme] + [re-com.util :refer [deep-merge]] + [re-com.validate :refer [title-levels-list title-level-type? css-style? html-attr? parts? string-or-hiccup?]])) ;; ------------------------------------------------------------------------------------ ;; Component: label @@ -83,37 +84,46 @@ {:name :style :required false :type "CSS style map" :validate-fn css-style? :description "CSS styles to add or override (applies to the title, not the wrapping div)"} {:name :attr :required false :type "HTML attr map" :validate-fn html-attr? :description [:span "HTML attributes, like " [:code ":on-mouse-move"] [:br] "No " [:code ":class"] " or " [:code ":style"] "allowed (applies to the title, not the wrapping div)"]} {:name :parts :required false :type "map" :validate-fn (parts? title-parts) :description "See Parts section below."} + {:name :theme :required false :type "map" :description "alpha"} {:name :src :required false :type "map" :validate-fn map? :description [:span "Used in dev builds to assist with debugging. Source code coordinates map containing keys" [:code ":file"] "and" [:code ":line"] ". See 'Debugging'."]} {:name :debug-as :required false :type "map" :validate-fn map? :description [:span "Used in dev builds to assist with debugging, when one component is used implement another component, and we want the implementation component to masquerade as the original component in debug output, such as component stacks. A map optionally containing keys" [:code ":component"] "and" [:code ":args"] "."]}])) (defn title "A title with four preset levels" - [& {:keys [label level underline? margin-top margin-bottom class style attr parts src debug-as] + [& {:keys [label level underline? margin-top margin-bottom class style attr parts src debug-as theme] :or {margin-top "0.6em" margin-bottom "0.3em"} :as args}] (or (validate-args-macro title-args-desc args) - (let [preset-class (if (nil? level) "" (name level))] + (let [preset-class (if (nil? level) "" (name level)) + this-theme (theme/defaults args) + themed (fn [part props] + (theme/apply props + {:part part} + this-theme))] [v-box - :src src - :debug-as (or debug-as (reflect-current-component)) - :class (str "rc-title-wrapper " preset-class " " (get-in parts [:wrapper :class])) - :style (get-in parts [:wrapper :style]) - :attr (get-in parts [:wrapper :attr]) - :children [[:span (merge {:class (str "display-flex rc-title " preset-class " " class) - :style (merge (flex-child-style "none") - {:margin-top margin-top} - {:line-height 1} ;; so that the margins are correct - (when-not underline? {:margin-bottom margin-bottom}) - style)} - attr) - label] - (when underline? [line - :src (at) - :size "1px" - :class (str "rc-title-underline " (get-in parts [:underline :class])) - :style (merge {:margin-bottom margin-bottom} (get-in parts [:underline :style])) - :attr (get-in parts [:underline :attr])])]]))) + (themed ::title-wrapper + {:src src + :debug-as (or debug-as (reflect-current-component)) + :class (str "rc-title-wrapper " preset-class " " (get-in parts [:wrapper :class])) + :style (get-in parts [:wrapper :style]) + :attr (get-in parts [:wrapper :attr]) + :children [[:span + (themed ::title-label + (merge {:class (str "display-flex rc-title " preset-class " " class) + :style (merge (flex-child-style "none") + {:margin-top margin-top} + {:line-height 1} ;; so that the margins are correct + (when-not underline? {:margin-bottom margin-bottom}) + style)} + attr)) + label] + (when underline? [line + :src (at) + :size "1px" + :class (str "rc-title-underline " (get-in parts [:underline :class])) + :style (merge {:margin-bottom margin-bottom} (get-in parts [:underline :style])) + :attr (get-in parts [:underline :attr])])]})]))) ;; ------------------------------------------------------------------------------------ ;; Component: p @@ -153,4 +163,4 @@ [:span.rc-p m (into [:span] children)])) ;; Alias for backwards compatibility; p and p-span used to be different implementations. -(def p-span p) \ No newline at end of file +(def p-span p) diff --git a/src/re_com/theme.cljs b/src/re_com/theme.cljs index 769feefa..2cab9255 100644 --- a/src/re_com/theme.cljs +++ b/src/re_com/theme.cljs @@ -3,6 +3,7 @@ (:require [reagent.core :as r] [re-com.theme.util :as tu] + [re-com.util :as u] [re-com.theme.default :as theme.default])) (def registry (r/atom {:base-variables theme.default/base-variables @@ -14,7 +15,7 @@ (def named->vec (memoize - (juxt :base-variables :main-variables :user-variables :base :main :user))) + (juxt :re-com/system :base-variables :main-variables :user-variables :base :main :user))) (def global (r/reaction (flatten (named->vec @registry)))) @@ -22,12 +23,9 @@ (def parts tu/parts) -(defn rf [[props ctx] theme] - (let [result (theme props ctx)] - (if (vector? result) result [result ctx]))) - -(defn merge [a {:keys [base main user main-variables user-variables base-variables] :as b}] +(defn merge [a {:re-com/keys [system] :keys [base main user main-variables user-variables base-variables] :as b}] (cond-> a + system (update :re-com/system conj system) base-variables (assoc :base-variables base-variables) main-variables (assoc :main-variables main-variables) user-variables (update :user-variables conj user-variables) @@ -35,17 +33,22 @@ main (assoc :main main) user (update :user conj user))) +(defn rf [[props ctx] theme] + (let [result (theme props ctx)] + (if (vector? result) result [result ctx]))) + (defn apply ([props ctx themes] (->> (if-not (map? themes) - (update @registry :user conj themes) + (update @registry :usder conj themes) (merge @registry themes)) named->vec flatten (remove nil?) (reduce rf [props ctx]) - first))) + first + (#(dissoc % :re-com/system))))) (defn props [ctx themes] (apply {} ctx themes)) @@ -74,10 +77,16 @@ (update :attr clojure.core/merge (select-keys outer-props outer-attr-keys))))))) -(defn defaults [{:keys [theme-vars base-theme main-theme theme parts]} & themes] - (apply re-com.theme/merge - {:variables theme-vars - :base base-theme - :main main-theme - :user [theme (re-com.theme/parts parts)]} - themes)) +(defn add-parts-path [path] + (fn parts-pather [props {:keys [part] :as ctx}] + [(update props :theme conj (add-parts-path (conj path part))) + (assoc ctx :parts-path (conj path part))])) + +(defn defaults [{:re-com/keys [system] :keys [theme-vars base-theme main-theme theme parts]} & themes] + (re-com.theme/merge + {:re-com/system [] + :variables theme-vars + :base base-theme + :main main-theme + :user [theme (re-com.theme/parts parts)]} + themes)) diff --git a/src/re_com/theme/blue_modern.cljs b/src/re_com/theme/blue_modern.cljs index bce26257..b787a6ec 100644 --- a/src/re_com/theme/blue_modern.cljs +++ b/src/re_com/theme/blue_modern.cljs @@ -1,14 +1,24 @@ (ns re-com.theme.blue-modern (:require [re-com.theme :as theme] + [re-com.text :as text] [re-com.dropdown :as dropdown] - [re-com.tree-select :as tree-select])) + [re-com.tree-select :as tree-select] + [re-com.error-modal :as-alias error-modal])) -(defn theme [attr {:keys [state part] $ :variables}] - (->> {} - (case part - - ::dropdown/anchor-wrapper - {:style {:height "25px" - :line-height "23px"}}) - (theme/merge-props attr))) +(defn theme [props {:keys [state part part-path] + $ :variables + :as ctx}] + (->> (or + (case part-path + [:re-com.error-modal/sub-title-2 + ::text/title-label] + {:style {:color "red"}} + nil) + (case part + ::dropdown/anchor-wrapper + {:style {:height "25px" + :line-height "23px"}} + nil) + {}) + (theme/merge-props props))) diff --git a/src/re_com/theme/default.cljs b/src/re_com/theme/default.cljs index 9ee90c6f..4d30df5d 100644 --- a/src/re_com/theme/default.cljs +++ b/src/re_com/theme/default.cljs @@ -150,7 +150,7 @@ (defn main [props {:keys [state part] {:as $ - :keys [sm-1 sm-2 sm-3 sm-4 sm-6 md-1 md-2 + :keys [sm-1 sm-2 sm-3 sm-4 sm-5 sm-6 md-1 md-2 dark shadow light light-background border border-dark foreground]} :variables @@ -302,7 +302,6 @@ ::error-modal/inner-wrapper {:style {:background-color (:white $) :box-shadow "2.82843px 2.82843px 4px rgba(1,1,1,0.2)" - :color (:error $) :font-size (:font-size/medium $) :min-width (px 474) :min-height (px 300)}} @@ -317,14 +316,14 @@ "#1e1e1e") :color "#FFFFFF" :padding-left md-2 - :padding-right md-1} + :padding-right sm-6} :height (px 50)}) ::error-modal/title - {:style {:font-size (:font-size/heading $) - :color (:white $) - :margin "0px" - :padding-bottom "3px"}} + {:style {:font-size 25 + :color (:white $) + :padding 0 + :margin "0px"}} ::error-modal/triangle (let [{:keys [severity]} state] @@ -333,6 +332,12 @@ :warning (:warning $) "#1e1e1e")}}) + ::error-modal/error + {:style {:font-family "monospace" + :white-space "pre" + :font-size :font-size/small + :color (:neutral $)}} + ::error-modal/body {:style {:padding (str sm-4 " " md-2)}}) (merge-props props))) diff --git a/src/re_com/util.cljs b/src/re_com/util.cljs index 25783262..d767fe3e 100644 --- a/src/re_com/util.cljs +++ b/src/re_com/util.cljs @@ -249,6 +249,9 @@ default (part default props) :else nil)) +(defn themed-part [x props & [default]] + [x props default]) + (def reduce-> #(reduce %2 %1 %3)) (defn triangle [& {:keys [width height fill direction] @@ -262,11 +265,21 @@ :fill fill}]]) (defn x-button [& {:as props}] - (let [hover? (r/atom nil)] - (fn [& {:as props}] + (let [hover-internal? (r/atom nil)] + (fn [& {:keys [hover? width height stroke-width] + :or {width "9px" + height "9px" + hover? hover-internal? + stroke-width "1px"} + :as props}] [:svg (merge {:on-mouse-enter (partial reset! hover? true) :on-mouse-leave (partial reset! hover? false) - :width "9px" :height "9px" :viewBox "0 0 9 9" :xmlns "http://www.w3.org/2000/svg" :stroke (if @hover? "#767a7c" "currentColor")} + :width width + :height height + :viewBox (str "0 0 " (<-px width) " " (<-px height)) + :xmlns "http://www.w3.org/2000/svg" + :stroke (if (deref-or-value hover?) "#767a7c" "currentColor") + :stroke-width stroke-width} props) - [:line {:x1 "1" :y1 "1" :x2 "9" :y2 "9" :stroke-width "1"}] - [:line {:x1 "1" :y1 "9" :x2 "9" :y2 "1" :stroke-width "1"}]]))) + [:line {:x1 0 :y1 0 :x2 (<-px width) :y2 (<-px height)}] + [:line {:x1 0 :y1 (<-px height) :x2 (<-px width) :y2 0}]]))) diff --git a/src/re_com/validate.cljs b/src/re_com/validate.cljs index ed07edb7..2b4945db 100644 --- a/src/re_com/validate.cljs +++ b/src/re_com/validate.cljs @@ -147,7 +147,7 @@ [arg-defs passed-args] (if-not debug? nil - (let [passed-arg-keys (set (keys passed-args)) + (let [passed-arg-keys (set (remove #{:theme} (set (keys passed-args)))) problems (->> [] (arg-names-known? (:arg-names arg-defs) passed-arg-keys) (required-args? (:required-args arg-defs) passed-arg-keys) diff --git a/src/re_demo/core.cljs b/src/re_demo/core.cljs index ff23b70f..50e8ecc1 100644 --- a/src/re_demo/core.cljs +++ b/src/re_demo/core.cljs @@ -8,7 +8,7 @@ [reagent.dom :as rdom] [alandipert.storage-atom :refer [local-storage]] [secretary.core :as secretary] - [re-com.core :refer [at h-box v-box box gap line scroller border label p title alert-box h-split] :refer-macros [handler-fn]] + [re-com.core :as rc :refer [at h-box v-box box gap line scroller border label p title alert-box h-split] :refer-macros [handler-fn]] [re-com.config :refer [version]] [re-com.util :refer [get-element-by-id item-for-id]] [re-demo.utils :refer [panel-title scroll-to-top]] @@ -259,9 +259,18 @@ :padding "0px 0px 0px 50px" :child [(:panel (item-for-id @selected-tab-id tabs-definition))]]]]]]))) ;; the tab panel to show, for the selected tab +(defn main2 [] + [rc/error-modal + {:src (at) + :what-happened "Something happened" + :implications "Implications" + :what-to-do "Do something." + :footer [:div + [rc/title :level :level3 :label :error-log]]}]) + (defn ^:dev/after-load mount-root [] - (rdom/render [main] (get-element-by-id "app"))) + (rdom/render [main2] (get-element-by-id "app"))) (defn ^:export mount-demo [] diff --git a/src/re_demo/line.cljs b/src/re_demo/line.cljs index d6801312..61f1d903 100644 --- a/src/re_demo/line.cljs +++ b/src/re_demo/line.cljs @@ -45,7 +45,7 @@ :padding "20px"} :child "Box 1"] [line :src (at) - :size "3px" + `pf :size "3px" :color "red"] [box :src (at) :style {:background-color "lightgrey" diff --git a/src/re_demo/modal_panel.cljs b/src/re_demo/modal_panel.cljs index cc3f90f1..872e7bdc 100644 --- a/src/re_demo/modal_panel.cljs +++ b/src/re_demo/modal_panel.cljs @@ -1,5 +1,5 @@ (ns re-demo.modal-panel - (:require [re-com.core :refer [at h-box v-box box gap line border title label modal-panel error-modal progress-bar input-text checkbox button p]] + (:require [re-com.core :as rc :refer [at h-box v-box box gap line border title label modal-panel error-modal progress-bar input-text checkbox button p]] [re-com.error-modal :refer [error-modal]] [re-com.modal-panel :refer [modal-panel-parts-desc modal-panel-args-desc]] [re-demo.utils :refer [panel-title title2 title3 parts-table args-table github-hyperlink status-text]] @@ -139,14 +139,16 @@ :on-click (fn [] (reset! show? true) #_(js/setTimeout #(reset! show? false) 3000))] - (when @show? - [error-modal - {:src (at) - :what-happened "Something happened" - :implications "Implications" - :what-to-do "Do something." - :backdrop-on-click #(reset! show? false) - :on-close #(reset! show? false)}])]]))) + (when true #_@show? + [error-modal + {:src (at) + :what-happened "Something happened" + :implications "Implications" + :what-to-do "Do something." + :footer [:div + [rc/title :level :level3 :label :error-log]] + :backdrop-on-click #(reset! show? false) + :on-close #(reset! show? false)}])]]))) (defn panel2 [] [v-box :src (at) diff --git a/src/re_demo/nested_grid.cljs b/src/re_demo/nested_grid.cljs index 027aa561..66cdf7f9 100644 --- a/src/re_demo/nested_grid.cljs +++ b/src/re_demo/nested_grid.cljs @@ -52,14 +52,14 @@ [p "A " [:code ":column-spec"] " describes a single column."] [:ul [:li "For instance, the " [:strong "Basic Demo"] " uses " - [:code ":a"] " as a " [:code ":column-spec"] "."] - [:li "You can use " [:i "almost any"] " type of value (not just keywords)."] + [:code "2"] " as a " [:code ":column-spec"] "."] + [:li "You can use " [:i "almost any"] " type of value."] [:li "You " [:i "can't"] " use vectors or lists (these are reserved for the " [:code ":column-tree"] ")."] [:li "At Day8, we tend to use maps. For instance, " [:pre {:style {:width 400}} "{:id :a :column-label \"A\" - :special-business-logic ::xyz}"]]] + :special-business-logic {::xyz \"abc\"}}"]]] [title2 "Column Tree"] [p "A " [:code ":column-tree"] "describes a nested arrangement of columns." [:ul @@ -421,7 +421,7 @@ :cell (fn [{:keys [column-path row-path]}] (* (last column-path) (last row-path)))]"]]] - [p "A simple times table. the " [:code ":cell"] " function receives " + [p "A simple times table. The " [:code ":cell"] " function gets called once for each cell, getting passed a " [:code ":column-path"] " and " [:code ":row-path"] ". In this case, each path is a vector of one number. For instance, " "the bottom cells each have a " [:code ":row-path"] " of " [:code "[5]"] "."]