Last active
February 20, 2022 16:21
-
-
Save zeitstein/3fc2e1bde5610a8d6fba1c02cca74d2a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns grove.guide | |
(:require | |
[shadow.experiments.grove :as sg :refer (<< defc)] | |
[shadow.experiments.grove.runtime :as rt] | |
[shadow.experiments.grove.db :as db] | |
[shadow.experiments.grove.eql-query :as eql] | |
[shadow.experiments.grove.events :as ev] | |
[shadow.experiments.grove.local :as local])) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; init db | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
(def schema | |
{::dir {:type :entity | |
:primary-key :dir/id | |
:attr {} | |
:joins {:dir/dirs [:many ::dir] | |
:dir/files [:many ::file]}} | |
::file {:type :entity | |
:primary-key :file/id | |
:attr {}}}) | |
(def denormalized-data | |
{:dir/id 0 :dir/name "project" :dir/open? true | |
:dir/files [{:file/id 0 :file/name "deps.edn"} | |
{:file/id 1 :file/name ".nrepl-port" ::hidden? true}] | |
:dir/dirs [{:dir/id 1 :dir/name "src/example" :dir/open? true | |
:dir/files [{:file/id 2 :file/name "ui.cljs"} | |
{:file/id 3 :file/name "db.cljs"}]}]}) | |
(defonce data-ref | |
(-> {} ;; empty db, we'll do a load! on init | |
(db/configure schema) | |
(atom))) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; eql | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
(defmethod eql/attr :dir/contains | |
[env db {:dir/keys [files dirs] :as current} query-part params] | |
(cond->> (concat dirs files) | |
(not (::show-hidden? db)) | |
;; note: this will add these idents to list of things the containing query observes | |
;; i.e. changing something in these idents will cause the query to re-run | |
(filterv (fn [ident] (not (::hidden? (get db ident))))))) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; ui | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
(defc ui-file [ident] | |
(bind {:file/keys [name] ::keys [hidden?]} | |
(sg/query-ident ident)) | |
(render | |
(<< [:div | |
[:span.font-mono {:class (when hidden? "text-gray-300") | |
:on-click {:e ::toggle-hide! :ident ident}} | |
name]]))) | |
(defn expensive-computation [contains] | |
(count (filterv #(= ::file (first %)) contains))) | |
(defc ui-dir [ident] | |
(bind {:dir/keys [name open? contains] ::keys [hidden?] :as query-result} | |
(sg/query-ident ident [:dir/name :dir/open? :dir/contains ::hidden?])) | |
(bind num-visible | |
(expensive-computation contains)) | |
(render | |
(<< [:div.border-l-2.border-black | |
[:span.font-bold.font-mono | |
{:on-click {:e ::dir-click! :ident ident} | |
:class (when hidden? "text-gray-300")} | |
name] | |
[:span.ml-3 (str "(visible loc: " (* num-visible 300) ")")] | |
(when (and open? (seq contains)) | |
(<< [:div.m-3 | |
(sg/keyed-seq contains identity | |
#(if (= (first %) ::dir) | |
(ui-dir %) | |
(ui-file %)))]))])) | |
(event ::dir-click! [env {:keys [ident]} e] | |
(if (.-ctrlKey e) | |
(sg/run-tx env {:e ::toggle-hide! :ident ident}) | |
(sg/run-tx env {:e ::toggle-open! :ident ident})))) | |
(defc ui-root [] | |
(bind {::keys [project-root show-hidden?]} | |
(sg/query-root [::project-root ::show-hidden?])) | |
(render | |
(<< [:h1.font-bold.text-xl | |
"click for open/close, ctrl+click for hide/unhide"] | |
[:button.bg-blue-500.hover:bg-blue-700.text-white.py-2.px-4.rounded | |
{:on-click {:e ::toggle-show-hidden! :show? (not show-hidden?)} | |
:style "margin: 10px 0;"} | |
(str "show hidden? " show-hidden?)] | |
(ui-dir (first project-root)))) | |
(event ::toggle-hide! [env event-map event] | |
(when (.-ctrlKey event) | |
(sg/run-tx env event-map)))) | |
(defonce rt-ref | |
(rt/prepare {} data-ref ::runtime-id)) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; event handlers | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
(ev/reg-event rt-ref ::load! | |
(fn [tx-env ev-map] | |
(-> tx-env | |
(update :db db/add ::dir denormalized-data [::project-root]) | |
(assoc-in [:db ::show-hidden?] true)))) | |
(ev/reg-event rt-ref ::toggle-show-hidden! | |
(fn [tx-env {:keys [show?] :as event}] | |
(-> tx-env | |
(assoc-in [:db ::show-hidden?] show?) | |
(ev/queue-fx ::alert! event)))) | |
(ev/reg-fx rt-ref ::alert! | |
(fn [fx-env {:keys [show?] :as fx-data}] | |
(js/alert (str "Will " (when-not show? "not") " show hidden files.")))) | |
(ev/reg-event rt-ref ::toggle-open! | |
(fn [tx-env {:keys [ident]}] | |
(update-in tx-env [:db ident :dir/open?] not))) | |
(ev/reg-event rt-ref ::toggle-hide! | |
(fn [tx-env {:keys [ident] :as event-map}] | |
(update-in tx-env [:db ident ::hidden?] not))) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; init | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
(def root-el | |
(js/document.getElementById "root")) | |
(defn ^:dev/after-load start [] | |
(sg/render rt-ref root-el (ui-root))) | |
(defn init [] | |
(local/init! rt-ref) | |
(sg/run-tx! rt-ref {:e ::load!}) | |
(start)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment