root
function is what gets added to our markup for the page. q/db
is a query that just returns our entire re-frame db.
Some example styling for the inspector.
.inspector { | |
cursor: pointer; | |
} | |
@media screen and (max-width: 1024px) { | |
.inspector { | |
display: none !important; | |
} | |
} | |
body.local .inspector { | |
max-height: 80%; | |
overflow: auto; | |
padding: 5px 20px 5px 0; | |
text-transform: none; | |
position: fixed; | |
right: 100px; | |
bottom: 30px; | |
z-index: 100; | |
color: #fff; | |
background: rgba(30, 28, 65, 0.97); | |
} | |
body.local .inspector > div > span > span { | |
color: #FF7B7B !important; | |
} | |
body.local .inspector hr { | |
display: none; | |
} |
(ns lumanu.ui.tags.inspector | |
(:require [reagent.core :refer [atom]] | |
[re-frame.core :as rf] | |
[goog.format :as format] | |
[lumanu.ui.queries :as q])) | |
(defn map-sorter [m] | |
(into (sorted-map) m)) | |
(defn set-sorter [s] | |
(apply sorted-set s)) | |
(declare literal coll-view assoc-view) | |
(defprotocol IInspect | |
(-inspect [this] | |
"Return a React or Om compatible representation of this.")) | |
(extend-protocol IInspect | |
Keyword | |
(-inspect [this] (literal "keyword" this)) | |
Symbol | |
(-inspect [this] (literal "symbol" this)) | |
PersistentArrayMap | |
(-inspect [this] | |
(assoc-view "{" "}" "map persistent-array-map" map-sorter)) | |
PersistentHashMap | |
(-inspect [this] | |
(assoc-view "{" "}" "map persistent-hash-map" map-sorter)) | |
PersistentVector | |
(-inspect [this] (coll-view "[" "]" "vector")) | |
PersistentHashSet | |
(-inspect [this] (coll-view "#{" "}" "set persistent-hash-set" identity)) | |
PersistentTreeSet | |
(-inspect [this] (coll-view "#{" "}" "set persistent-tree-set" identity)) | |
List | |
(-inspect [this] (coll-view "(" ")" "list")) | |
LazySeq | |
(-inspect [this] (coll-view "(" ")" "seq lazy-seq")) | |
KeySeq | |
(-inspect [this] (coll-view "(" ")" "seq key-seq")) | |
ValSeq | |
(-inspect [this] (coll-view "(" ")" "seq val-seq")) | |
PersistentArrayMapSeq | |
(-inspect [this] (coll-view "(" ")" "seq persistent-array-map-seq")) | |
Range | |
(-inspect [this] (coll-view "(" ")" "seq range")) | |
UUID | |
(-inspect [this] (literal "uuid" this)) | |
js/RegExp | |
(-inspect [this] (literal "regexp" this)) | |
js/Date | |
(-inspect [this] (literal "date" this)) | |
Atom | |
(-inspect [this] (-inspect @this)) | |
ExceptionInfo | |
(-inspect [this] (assoc-view "#error {" "}" "object" (comp map-sorter | |
#(hash-map :message (.-message %) | |
:data (ex-data %))))) | |
function | |
(-inspect [this] (literal "function" this)) | |
number | |
(-inspect [this] (literal "number" this)) | |
string | |
(-inspect [this] (literal "string" this)) | |
boolean | |
(-inspect [this] (literal "boolean" this)) | |
array | |
(-inspect [this] (coll-view "#js [" "]" "array")) | |
object | |
(-inspect [this] (assoc-view "#js {" "}" "object" (comp map-sorter js->clj))) | |
nil | |
(-inspect [this] (literal "nil" this))) | |
(defn inspect [thing] | |
(-inspect thing)) | |
(defn literal [class v] | |
[:span (pr-str v)]) | |
(defn assoc-view [start end class sorter] | |
(let [open (atom false)] | |
(fn [coll] | |
[:div {:style {:padding-left "25px"} | |
:on-click (fn [e] (swap! open not) (.stopPropagation e))} | |
start | |
(if @open | |
(for [[k v] (sorter coll)] | |
[:span {:key k} | |
[:span {:style {:color "red"}} | |
[inspect k]] | |
[:div | |
[inspect v]]]) | |
(if (satisfies? ICounted coll) | |
(str "...[" (count coll) "]...") | |
"...")) | |
end]))) | |
(defn coll-view [start end class sorter] | |
(let [open (atom false)] | |
(fn [coll] | |
[:div | |
{:style {:padding-left "25px"} | |
:on-click (fn [e] (swap! open not) (.stopPropagation e))} | |
start | |
(if @open | |
(for [[idx i] (map-indexed vector ((or sorter identity) coll))] | |
[:div {:key idx} [inspect i]]) | |
(if (satisfies? ICounted coll) | |
(str "...[" (count coll) "]...") | |
"...")) | |
end]))) | |
(defn root [] | |
[:div.inspector {:style {:text-transform "none"}} | |
[:hr] | |
[inspect @q/db]]) | |