diff --git a/resources/day8/re_frame/trace/main.css b/resources/day8/re_frame/trace/main.css index 3a51c71..0be1a55 100644 --- a/resources/day8/re_frame/trace/main.css +++ b/resources/day8/re_frame/trace/main.css @@ -77,12 +77,16 @@ font-family: "courier new", monospace; font-size: 100%; padding: 3px 3px 1px 3px; - border: 1px solid black; + border: 1px solid #999999; } #--re-frame-trace-- button, #--re-frame-trace-- input { overflow: visible; } +#--re-frame-trace-- button:focus, +#--re-frame-trace-- select:focus { + outline: #999999 dotted 1px; +} #--re-frame-trace-- button, #--re-frame-trace-- html [type="button"], #--re-frame-trace-- [type="reset"], @@ -155,13 +159,8 @@ -webkit-border-horizontal-spacing: 0; -webkit-border-vertical-spacing: 0; } -#--re-frame-trace-- th, -#--re-frame-trace-- td { - display: table-cell; - padding: 0 5px; -} -#--re-frame-trace-- tr { - display: table-row; +#--re-frame-trace-- table { + display: table; } #--re-frame-trace-- thead { display: table-header-group; @@ -169,20 +168,115 @@ #--re-frame-trace-- tbody { display: table-row-group; } +#--re-frame-trace-- th, +#--re-frame-trace-- td { + display: table-cell; +} +#--re-frame-trace-- tr { + display: table-row; +} #--re-frame-trace-- table { - display: table; width: 100%; + font-size: 14px; } #--re-frame-trace-- tbody { - color: #aaaaaa; + color: #222222; } -#--re-frame-trace-- tr:hover { - transition: all 0.1s ease-out; - background: aliceblue; - filter: brightness(90%); +#--re-frame-trace-- thead { + font-weight: bold; } -#--re-frame-trace-- tr:nth-child(even) { - background: aliceblue; +#--re-frame-trace-- tr th, +#--re-frame-trace-- tr td { + padding: 6px; +} +#--re-frame-trace-- tr th:first-child { + text-align: right; +} +#--re-frame-trace-- tr.trace--trace-even, +#--re-frame-trace-- tr.trace--trace-even + .trace--details { + background: #fafafa; +} +#--re-frame-trace-- tr.trace--sub-create .trace--op { + color: #008766; +} +#--re-frame-trace-- tr.trace--sub-run .trace--op { + color: #762cff; +} +#--re-frame-trace-- tr.trace--event .trace--op { + color: #a66900; +} +#--re-frame-trace-- tr.trace--render .trace--op { + color: #007cc2; +} +#--re-frame-trace-- tr.trace--fsm-trigger .trace--op { + color: #284694; +} +#--re-frame-trace-- tr.trace--details { + color: #8f8f8f; +} +#--re-frame-trace-- tr.trace--details:hover, +#--re-frame-trace-- tr.trace--details:focus { + color: #5c5c5c; +} +#--re-frame-trace-- tr.trace--details:hover .trace--details-icon:before, +#--re-frame-trace-- tr.trace--details:focus .trace--details-icon:before { + color: #222222; + cursor: pointer; + content: "🖶"; +} +#--re-frame-trace-- tr.trace--details:focus .trace--details-tags-text { + border-left: 1px dotted #999999; + padding-left: 7px; +} +#--re-frame-trace-- tr td.trace--toggle { + color: #a8a8a8; + padding: 0; + text-align: right; +} +#--re-frame-trace-- tr td.trace--toggle button:focus { + color: #222222; + outline: none; +} +#--re-frame-trace-- tr td.trace--op { + color: #8f8f8f; + padding-left: 0; + white-space: nowrap; +} +#--re-frame-trace-- tr td.trace--op-string { + word-break: break-all; +} +#--re-frame-trace-- tr td.trace--details-tags { + padding: 0; + cursor: pointer; +} +#--re-frame-trace-- tr td.trace--details-tags .trace--details-tags-text { + padding: 8px 5px; + padding-left: 8px; + margin-bottom: 5px; +} +#--re-frame-trace-- tr td.trace--meta { + color: #8f8f8f; + white-space: nowrap; + text-align: right; +} +#--re-frame-trace-- tr td .op-string { + cursor: pointer; + padding: 1px; +} +#--re-frame-trace-- tr td .op-string:hover { + border-bottom: 1px dotted #616cdb; + padding-bottom: 0; +} +#--re-frame-trace-- tr:hover .trace--toggle { + color: #222222; +} +#--re-frame-trace-- tr th:first-child, +#--re-frame-trace-- tr td:first-child { + padding-left: 7px; +} +#--re-frame-trace-- tr th:last-child, +#--re-frame-trace-- tr td:last-child { + padding-right: 7px; } #--re-frame-trace-- .button { padding: 5px 5px 3px; @@ -194,12 +288,8 @@ border-bottom: 1px dotted #888; font-weight: normal; } -#--re-frame-trace-- .button:focus, #--re-frame-trace-- .text-button:focus { - border-radius: 2px 2px 0 0; - -webkit-box-shadow: inset 0px -5px 0px 0px rgba(0, 0, 0, 0.3); - -moz-box-shadow: inset 0px -5px 0px 0px rgba(0, 0, 0, 0.3); - box-shadow: inset 0px -5px 0px 0px rgba(0, 0, 0, 0.3); + outline: #999999 dotted 1px; } #--re-frame-trace-- .icon-button { font-size: 10px; @@ -216,25 +306,28 @@ } #--re-frame-trace-- .tab.active { background: transparent; - border-bottom: 3px solid #add8e6; + border-bottom: 3px solid #808080; border-radius: 0; padding-bottom: 1px; } #--re-frame-trace-- ul.filter-items { list-style-type: none; - padding: 0; - margin: 0 -5px; - margin-top: 10px; + margin: 0 5px; } -#--re-frame-trace-- .filter-items li { - color: #333; - background: #efeef1; +#--re-frame-trace-- ul.filter-items .filter-item { + color: #8f8f8f; + background: #fafafa; + border: 1px solid #efeef1; display: inline-block; font-size: 0.9em; - margin: 5px; + margin: 10px 5px; } -#--re-frame-trace-- .filter-items li .filter-item-string { - color: #616cdb; +#--re-frame-trace-- ul.filter-items .filter-item .filter-item-string { + color: #222222; + background: #ffff00; +} +#--re-frame-trace-- ul.filter-items .filter-item:hover { + text-decoration: line-through; } #--re-frame-trace-- .icon { display: inline-block; @@ -247,8 +340,15 @@ #--re-frame-trace-- .icon-remove { margin-left: 10px; } -#--re-frame-trace-- select { +#--re-frame-trace-- .filter { + box-shadow: -7px 15px 6px -15px rgba(0, 0, 0, 0.3); + z-index: 1001; +} +#--re-frame-trace-- .filter .filter-control select { + border: none; + border-bottom: 1px solid #8f8f8f; background: white; + display: inline-block; font-family: 'courier new', monospace; font-size: 1em; padding: 2px 0 0 0; @@ -256,19 +356,29 @@ -webkit-appearance: menulist; appearance: menulist; } +#--re-frame-trace-- .filter .filter-control .filter-control-input { + border-bottom: 1px solid #8f8f8f; + display: inline-block; +} +#--re-frame-trace-- .filter .filter-control .filter-control-input:before { + display: inline-block; + color: #8f8f8f; + content: "⚲"; + transform: rotate(-45deg); +} +#--re-frame-trace-- .filter .filter-control .filter-control-input input { + border: none; +} #--re-frame-trace-- .nav { background: #efeef1; color: #222222; } #--re-frame-trace-- .panel-content-scrollable { - margin: 0 10px; flex: 1 1 auto; height: 100%; overflow: auto; padding-top: 10px; - -webkit-box-shadow: inset -1px 18px 13px -22px rgba(0, 0, 0, 0.7); - -moz-box-shadow: inset -1px 18px 13px -22px rgba(0, 0, 0, 0.7); - box-shadow: inset -1px 18px 13px -22px rgba(0, 0, 0, 0.7); + z-index: 1000; } #--re-frame-trace-- .tab-contents { display: flex; @@ -278,6 +388,9 @@ #--re-frame-trace-- .filter-control { margin: 10px 0 0 10px; } -#--re-frame-trace-- .trace-details { - cursor: pointer; +#--re-frame-trace-- .filter-items-count.active { + background: #ffff00; +} +#--re-frame-trace-- .filter-items-count.active:hover { + text-decoration: line-through; } diff --git a/resources/day8/re_frame/trace/main.less b/resources/day8/re_frame/trace/main.less index 7633f2f..9189b4d 100644 --- a/resources/day8/re_frame/trace/main.less +++ b/resources/day8/re_frame/trace/main.less @@ -1,8 +1,19 @@ +@background-blue: #e7f1ff; +@background-gray: #a8a8a8; +@background-gray-hint: #fafafa; +@dark-green: #008766; +@dark-gold: #A66900; +@dark-purple: #762cff; +@dark-blue: #284694; +@dark-gray: gray; +@dark-skyblue: #007CC2; +@medium-gray: #999; @light-purple: #616cdb; @light-blue: lightblue; @light-gray: #efeef1; +@yellow: yellow; @text-color: #222; -@text-color-muted: #aaa; +@text-color-muted: #8f8f8f; #--re-frame-trace-- { @@ -87,7 +98,7 @@ font-size: 100%; // line-height: 1.15; padding: 3px 3px 1px 3px; - border: 1px solid black; + border: 1px solid @medium-gray; } button, // Show the overflow in IE. @@ -95,6 +106,13 @@ overflow: visible; } + button, + select { + &:focus { + outline: @medium-gray dotted 1px; + } + } + /** * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` * controls in Android 4. @@ -193,12 +211,8 @@ -webkit-border-horizontal-spacing: 0; -webkit-border-vertical-spacing: 0; } - th, td { - display: table-cell; - padding: 0 5px; - } - tr { - display: table-row; + table { + display: table; } thead { display: table-header-group; @@ -206,9 +220,11 @@ tbody { display: table-row-group; } - table { - display: table; - width: 100%; + th, td { + display: table-cell; + } + tr { + display: table-row; } @@ -219,16 +235,140 @@ background: white; font-family: 'courier new', monospace; + table { + width: 100%; + font-size: 14px; + } tbody { - color: @text-color-muted; + color: @text-color; } - tr:hover { - transition: all 0.1s ease-out; - background: aliceblue; - filter: brightness(90%); + thead { + font-weight: bold; } - tr:nth-child(even) { - background: aliceblue; + + tr { + th, td { + padding: 6px; + } + + th:first-child { + text-align: right; + } + + &.trace--trace { + } + + &.trace--trace-even, + &.trace--trace-even + .trace--details { + background: @background-gray-hint; + } + + &.trace--sub-create { + .trace--op{ + color: @dark-green; + } + } + &.trace--sub-run { + .trace--op{ + color: @dark-purple; + } + } + &.trace--event { + .trace--op{ + color: @dark-gold; + } + } + &.trace--render { + .trace--op{ + color: @dark-skyblue; + } + } + &.trace--fsm-trigger { + .trace--op{ + color: @dark-blue; + } + } + &.trace--details { + color: @text-color-muted; + + &:hover, + &:focus { + color: darken(@text-color-muted, 20); + + .trace--details-icon:before { + color: @text-color; + cursor: pointer; + content: "🖶"; + } + } + + &:focus { + .trace--details-tags-text { + border-left: 1px dotted @medium-gray; + padding-left: 7px; + } + } + } + + td { + &.trace--toggle { + color: @background-gray; + padding: 0; + text-align: right; + + button:focus { + color: @text-color; + outline: none; + } + } + &.trace--op { + color: @text-color-muted; + padding-left: 0; + white-space: nowrap; + } + &.trace--op-string { + word-break: break-all; + } + &.trace--details-tags { + padding: 0; + cursor: pointer; + + .trace--details-tags-text { + padding: 8px 5px; + padding-left: 8px; + margin-bottom: 5px; + } + } + &.trace--meta { + color: @text-color-muted; + white-space: nowrap; + text-align: right; + } + .op-string { + cursor: pointer; + padding: 1px; + + &:hover { + border-bottom: 1px dotted @light-purple; + padding-bottom: 0; + } + } + } + + &:hover { + .trace--toggle { + color: @text-color; + } + } + + th, td { + &:first-child { + padding-left: 7px; + } + &:last-child { + padding-right: 7px; + } + } } .button { padding: 5px 5px 3px; @@ -239,12 +379,9 @@ .text-button { border-bottom: 1px dotted #888; font-weight: normal; - } - .button:focus, .text-button:focus { - border-radius: 2px 2px 0 0; - -webkit-box-shadow: inset 0px -5px 0px 0px rgba(0,0,0,0.3); - -moz-box-shadow: inset 0px -5px 0px 0px rgba(0,0,0,0.3); - box-shadow: inset 0px -5px 0px 0px rgba(0,0,0,0.3); + &:focus { + outline: @medium-gray dotted 1px; + } } .icon-button { font-size: 10px; @@ -264,30 +401,31 @@ } .tab.active { background: transparent; - border-bottom: 3px solid @light-blue; + border-bottom: 3px solid @dark-gray; border-radius: 0; padding-bottom: 1px; } ul.filter-items { list-style-type: none; - padding: 0; - margin: 0 -5px; - margin-top: 10px; - } - .filter-items li { - color: #333; - background: @light-gray; - display: inline-block; - font-size: 0.9em; - margin: 5px; - } - .filter-items { - li { + margin: 0 5px; + + .filter-item { + color: @text-color-muted; + background: @background-gray-hint; + border: 1px solid @light-gray; + display: inline-block; + font-size: 0.9em; + margin: 10px 5px; + .filter-item-string { - color: @light-purple; + color: @text-color; + background: @yellow; + } + + &:hover { + text-decoration: line-through; } } - } .icon { display: inline-block; @@ -300,14 +438,38 @@ .icon-remove { margin-left: 10px; } - select { - background: white; - font-family: 'courier new', monospace; - font-size: 1em; - padding: 2px 0 0 0; - -moz-appearance: menulist; - -webkit-appearance: menulist; - appearance: menulist; + .filter { + box-shadow: -7px 15px 6px -15px rgba(0, 0, 0, 0.3); + z-index: 1001; + + .filter-control { + select { + border: none; + border-bottom: 1px solid @text-color-muted; + background: white; + display: inline-block; + font-family: 'courier new', monospace; + font-size: 1em; + padding: 2px 0 0 0; + -moz-appearance: menulist; + -webkit-appearance: menulist; + appearance: menulist; + } + .filter-control-input { + border-bottom: 1px solid @text-color-muted; + display: inline-block; + + &:before { + display: inline-block; + color: @text-color-muted; + content: "⚲"; + transform: rotate(-45deg); + } + input { + border: none; + } + } + } } .nav { background: @light-gray; @@ -316,14 +478,12 @@ .panel-content-top { } .panel-content-scrollable { - margin: 0 10px; + padding-top: 10px; flex: 1 1 auto; height: 100%; overflow: auto; padding-top: 10px; - -webkit-box-shadow: inset -1px 18px 13px -22px rgba(0,0,0,0.7); - -moz-box-shadow: inset -1px 18px 13px -22px rgba(0,0,0,0.7); - box-shadow: inset -1px 18px 13px -22px rgba(0,0,0,0.7); + z-index: 1000; } .tab-contents { display: flex; @@ -333,7 +493,14 @@ .filter-control { margin: 10px 0 0 10px; } - .trace-details { - cursor: pointer; + + .filter-items-count { + &.active { + background: @yellow; + + &:hover { + text-decoration: line-through; + } + } } } diff --git a/src/day8/re_frame/trace.cljs b/src/day8/re_frame/trace.cljs index 7a7d8f8..1849a13 100644 --- a/src/day8/re_frame/trace.cljs +++ b/src/day8/re_frame/trace.cljs @@ -126,8 +126,7 @@ (when (pos? (count v)) (on-save v)))] (fn [] - [:input {:style {:margin-left 7} - :type "text" + [:input {:type "text" :value @val :auto-focus true :on-change #(do (reset! val (-> % .-target .-value)) @@ -161,58 +160,61 @@ (js/parseFloat filter-input)) :filter-type filter-type}))) -(defn render-traces [showing-traces filter-items filter-input trace-detail-expansions] +(defn render-traces [visible-traces filter-items filter-input trace-detail-expansions] (doall - (for [{:keys [op-type id operation tags duration] :as trace} showing-traces] - (let [row-style {:border-top (case op-type :event "1px solid lightgrey" nil)} - show-row? (get-in @trace-detail-expansions [:overrides id] - (:show-all? @trace-detail-expansions)) - op-name (if (vector? operation) - (second operation) - operation) - #_#__ (js/console.log (devtools/header-api-call tags))] - (list [:tr {:key id - :on-click (fn [ev] - (swap! trace-detail-expansions update-in [:overrides id] - #(if show-row? false (not %)))) - :style {:color (case op-type - :sub/create "green" - :sub/run "#fd701e" - :event "blue" - :render "purple" - :re-frame.router/fsm-trigger "#fd701e" - nil)}} - [:td {:style row-style} - [:button (if show-row? "▼" "▶")]] - [:td {:style row-style} - [:div.op-string - [:span {:on-click (fn [ev] - (add-filter filter-items (name op-type) :contains) - (.stopPropagation ev))} - (str op-type)]]] - [:td {:style row-style} - [:div.op-string - [:span {:on-click (fn [ev] - (add-filter filter-items (name op-name) :contains) - (.stopPropagation ev))} - op-name]]] - [:td - {:style (merge row-style { - ; :font-weight (if (< slower-than-bold-int duration) - ; "bold" - ; "") - :white-space "nowrap"})} + (->> + visible-traces + (map-indexed (fn [index {:keys [op-type id operation tags duration] :as trace}] + (let [show-row? (get-in @trace-detail-expansions [:overrides id] + (:show-all? @trace-detail-expansions)) + op-name (if (vector? operation) + (second operation) + operation) + #_#__ (js/console.log (devtools/header-api-call tags))] + (list [:tr {:key id + :on-click (fn [ev] + (swap! trace-detail-expansions update-in [:overrides id] + #(if show-row? false (not %)))) + :class (str/join " " ["trace--trace" + (case op-type + :sub/create "trace--sub-create" + :sub/run "trace--sub-run" + :event "trace--event" + :render "trace--render" + :re-frame.router/fsm-trigger "trace--fsm-trigger" + nil) + (if (even? index) + "trace--trace-even" + "trace--trace-odd")])} - (.toFixed duration 1) " ms"]] - (when show-row? - [:tr {:key (str id "-details")} - [:td.trace-details {:col-span 4 - :on-click #(.log js/console tags)} - (let [tag-str (with-out-str (pprint/pprint tags)) - string-size-limit 400] - (if (< string-size-limit (count tag-str)) - (str (subs tag-str 0 string-size-limit) " ...") - tag-str))]])))))) + [:td.trace--toggle + [:button (if show-row? "▼" "▶")]] + [:td.trace--op + [:span.op-string {:on-click (fn [ev] + (add-filter filter-items (name op-type) :contains) + (.stopPropagation ev))} + (str op-type)]] + [:td.trace--op-string + [:span.op-string {:on-click (fn [ev] + (add-filter filter-items (name op-name) :contains) + (.stopPropagation ev))} + op-name]] + [:td.trace--meta + (.toFixed duration 1) " ms"]] + (when show-row? + [:tr.trace--details {:key (str id "-details") + :tab-index 0} + [:td] + [:td.trace--details-tags {:col-span 2 + :on-click #(.log js/console tags)} + [:div.trace--details-tags-text + (let [tag-str (with-out-str (pprint/pprint tags)) + string-size-limit 400] + (if (< string-size-limit (count tag-str)) + (str (subs tag-str 0 string-size-limit) " ...") + tag-str))]] + [:td.trace--meta.trace--details-icon + {:on-click #(.log js/console tags)}]])))))))) (defn render-trace-panel [] (let [filter-input (r/atom "") filter-items (r/atom (localstorage/get "filter-items" [])) @@ -224,7 +226,7 @@ (fn [_ _ _ new-state] (localstorage/save! "filter-items" new-state))) (fn [] - (let [showing-traces (if (= @filter-items []) + (let [visible-traces (if (= @filter-items []) @traces (filter (apply every-pred (map query->fn @filter-items)) @traces)) save-query (fn [_] @@ -237,36 +239,33 @@ [:div.tab-contents - [:div.filter-control - [:div.filter-control-input - [:select {:value @filter-type - :on-change #(reset! filter-type (keyword (.. % -target -value)))} - [:option {:value "contains"} "contains"] - [:option {:value "slower-than"} "slower than"]] - [search-input {:on-save save-query - :on-change #(reset! filter-input (.. % -target -value))}] - [:button.button.icon-button {:on-click save-query - :style {:margin 0}} - [components/icon-add]] - (if @input-error - [:div.input-error {:style {:color "red" :margin-top 5}} - "Please enter a valid number."])] - [:ul.filter-items - (map (fn [item] - ^{:key (:id item)} - [:li.filter-item - [:button.button - {:style {:margin 0} - :on-click (fn [event] (swap! filter-items #(remove (comp (partial = (:query item)) :query) %)))} - (:filter-type item) ": " [:span.filter-item-string (:query item)] - [:span.icon-button [components/icon-remove]]]]) - @filter-items)]] + [:div.filter + [:div.filter-control + [:select {:value @filter-type + :on-change #(reset! filter-type (keyword (.. % -target -value)))} + [:option {:value "contains"} "contains"] + [:option {:value "slower-than"} "slower than"]] + [:div.filter-control-input {:style {:margin-left 10}} + [search-input {:on-save save-query + :on-change #(reset! filter-input (.. % -target -value))}] + [components/icon-add] + (if @input-error + [:div.input-error {:style {:color "red" :margin-top 5}} + "Please enter a valid number."])]] + [:ul.filter-items + (map (fn [item] + ^{:key (:id item)} + [:li.filter-item + [:button.button + {:style {:margin 0} + :on-click (fn [event] (swap! filter-items #(remove (comp (partial = (:query item)) :query) %)))} + (:filter-type item) ": " [:span.filter-item-string (:query item)]]]) + @filter-items)]] [components/autoscroll-list {:class "panel-content-scrollable" :scroll? true} [:table - {:style {:margin-bottom 10} - :cell-spacing "0" :width "100%"} [:thead>tr - [:th [:button.text-button + [:th {:style {:padding 0}} + [:button.text-button {:style {:cursor "pointer"} :on-click (fn [ev] ;; Always reset expansions @@ -276,15 +275,17 @@ (if (:show-all? @trace-detail-expansions) "-" "+")]] [:th "operations"] [:th - (when (pos? (count @filter-items)) - (str (count showing-traces) " of ")) - (when (pos? (count @traces)) - (str (count @traces))) + [:button {:class (str/join " " ["filter-items-count" + (when (pos? (count @filter-items)) "active")]) + :on-click #(reset! filter-items [])} + (when (pos? (count @filter-items)) + (str (count visible-traces) " of ")) + (str (count @traces))] " events " (when (pos? (count @traces)) [:span "(" [:button.text-button {:on-click #(do (trace/reset-tracing!) (reset! traces []))} "clear"] ")"])] - [:th "meta"]] - [:tbody (render-traces showing-traces filter-items filter-input trace-detail-expansions)]]]])))) + [:th {:style {:text-align "right"}} "meta"]] + [:tbody (render-traces visible-traces filter-items filter-input trace-detail-expansions)]]]])))) (defn resizer-style [draggable-area] {:position "absolute" :z-index 2 :opacity 0