diff --git a/src/looped_in/components.cljs b/src/looped_in/components.cljs new file mode 100644 index 0000000..0e5a75a --- /dev/null +++ b/src/looped_in/components.cljs @@ -0,0 +1,6 @@ +(ns looped-in.components + (:require [goog.dom :as dom] + [looped-in.logging :as log])) + +(defn card [& children] + (apply dom/createDom "div" "card" children)) diff --git a/src/looped_in/macros.clj b/src/looped_in/macros.clj new file mode 100644 index 0000000..0becc80 --- /dev/null +++ b/src/looped_in/macros.clj @@ -0,0 +1,3 @@ +(ns looped-in.macros) + +(defmacro get-in-items [m ks] `(get-in ~m (vec (interpose :children ~ks)))) diff --git a/src/looped_in/sidebar.cljs b/src/looped_in/sidebar.cljs index d09d539..35e896a 100644 --- a/src/looped_in/sidebar.cljs +++ b/src/looped_in/sidebar.cljs @@ -4,8 +4,10 @@ [goog.html.sanitizer.HtmlSanitizer :as Sanitizer] [cljs.core.async :refer [go channel]] [looped-in.logging :as log]) + (:require-macros [looped-in.macros :refer [get-in-items]]) (:import (goog.ui Zippy))) (enable-console-print!) @@ -62,19 +64,28 @@ (defn model "Returns initial sidebar state" [] - {:items ()}) + {:items () + :depth [] + :loading false}) (defn update-state "Given a message and the old state, returns the new state" [msg state] (case (:type msg) :items (assoc state :items (:items msg)) + :loading (assoc state :loading (:loading msg)) state)) (defn view "Given a callback to dispatch an update message and the sidebar state, returns the sidebar DOM" [dispatch-message state] - ()) + (log/debug state) + (if (:loading state) + "Loading..." + (let [current-item (get-in-items (:items state) (:depth state))] + (if (> (count current-item) 1) + (map #(components/card (:title %)) current-item) + ())))) (defn render "Renders the new DOM @@ -85,16 +96,14 @@ (dom/removeChildren $container) (apply dom/append $container $sidebar-dom))) -(defn main +(defn run-render-loop "Runs the model-update-view loop" [state] (let [dispatch-message (fn [msg] (let [new-state (update-state msg state)] - (main new-state)))] + (run-render-loop new-state)))] (render (view dispatch-message state)))) -(main (model)) - (defn obj->clj [obj] (into {} (for [k (.keys js/Object obj)] [(keyword k) @@ -104,18 +113,34 @@ (.isArray js/Array v) (map obj->clj (array-seq v)) :default (js->clj v)))]))) -(go (-> js/browser - (.-runtime) - (.sendMessage (clj->js {:type "fetchItems"})) - (promise->channel) - (clj %)} (model))) - (main))) - (defn handle-close-button [e] (.postMessage js/window.parent (clj->js {:type "closeSidebar"}) "*")) -(events/listen (dom/getElement "closeSidebar") "click" handle-close-button) +(defn fetch-items + "Fetch items matching the URL" + [] + (go (-> js/browser + (.-runtime) + (.sendMessage (clj->js {:type "fetchItems"})) + (promise->channel) + (clj items))) + ((fn [items] (sort-by :points #(compare %2 %1) items)))))) + +(defn init + "Initializes the sidebar" + [] + (events/listen (dom/getElement "closeSidebar") "click" handle-close-button) + (let [initial-state (update-state {:type :loading :loading true} (model))] + (run-render-loop initial-state) + (go (-> (fetch-items) + (