diff --git a/ext/sidebar.html b/ext/sidebar.html index afff724..f713948 100644 --- a/ext/sidebar.html +++ b/ext/sidebar.html @@ -9,16 +9,7 @@ - + diff --git a/src/looped_in/components.cljs b/src/looped_in/components.cljs index ded571f..d11aeba 100644 --- a/src/looped_in/components.cljs +++ b/src/looped_in/components.cljs @@ -24,6 +24,9 @@ (dom/appendChild el child) el) +(defn sidebar-content [& body] + (apply dom/createDom "div" (clj->js {:id "sidebarContent"}) body)) + (defn comments-indicator [num-comments] (let [text (caption30 (str num-comments " comment" (when (not= num-comments 1) "s")))] (dom/createDom "div" @@ -105,6 +108,22 @@ (for [i (range 1 6)] (dom/createDom "div" (str "rect" i))))) +(defn sidebar-header [icon-src] + (dom/createDom "div" "sidebarHeader" + (dom/createDom "img" + (clj->js {:class "headerIcon" + :src icon-src + :width "16px" + :height "16px"})) + (dom/createDom "span" "body30 headerTitle" "Looped In") + (dom/createDom "button" + (clj->js {:class "iconButton" + :id "closeSidebar"}) + (dom/createDom "img" + (clj->js {:src "icons/stop-16.svg" + :width "16px" + :height "16px"}))))) + (defn with-classes [el & classes] (doseq [class (filter #(not (string/blank? %)) classes)] (classes/add el class)) diff --git a/src/looped_in/sidebar.cljs b/src/looped_in/sidebar.cljs index 628ab61..b85c350 100644 --- a/src/looped_in/sidebar.cljs +++ b/src/looped_in/sidebar.cljs @@ -76,117 +76,129 @@ [dispatch-message state] (log/debug state) (cond - (:loading state) (components/loader) - (:item state) (let [current-item (get-in-item - (:item state) - (:depth state))] - (cons - (case (:type current-item) - "story" (components/card + (:loading state) (list (components/sidebar-header "icons/icon48.png") + (components/sidebar-content (components/loader))) + (:item state) (list + (components/sidebar-header "icons/back-16.svg") + (apply + components/sidebar-content + (let [current-item (get-in-item + (:item state) + (:depth state))] + (cons + (case (:type current-item) + "story" (components/card + (dom/createDom + "div" + "storyHeader" + (components/body30 (:title current-item)) + (components/item-link (:id current-item))) + (components/story-caption (:points current-item) + (:author current-item) + (* (:created_at_i current-item) 1000))) + "comment" (components/card + (dom/createDom + "div" + "commentHeader" + (components/comment-caption (:author current-item) + (* (:created_at_i current-item) + 1000)) + (components/item-link (:id current-item))) + (components/comment-text (:text current-item)))) + (map-indexed (fn [index child] + (-> (components/card + (dom/createDom + "div" + "commentHeader" + (components/comment-caption + (:author child) + (* (:created_at_i child) 1000)) + (components/item-link (:id child))) + (components/comment-text (:text child)) + (-> (components/replies-indicator (count (:children child))) + ((fn [indicator] + (if (> (count (:children child)) 0) + (-> indicator + (components/with-classes "clickable") + (components/with-listener + "click" + (fn [e] + (dispatch-message + {:type :enq-depth + :index index})))) + indicator))))) + (components/with-classes "child") + ((fn [card] + (if (> (count (:children child)) 0) + (components/with-classes card "clickable") + card))))) + (->> (:children current-item) + (filter #(contains? % :text)) + (sort-by #(count (:children %)) #(compare %2 %1)))))))) + (:hits state) (list + (components/sidebar-header "icons/icon48.png") + (apply + components/sidebar-content + (map (fn [hit] + (-> (components/card (dom/createDom "div" "storyHeader" - (components/body30 (:title current-item)) - (components/item-link (:id current-item))) - (components/story-caption (:points current-item) - (:author current-item) - (* (:created_at_i current-item) 1000))) - "comment" (components/card - (dom/createDom - "div" - "commentHeader" - (components/comment-caption (:author current-item) - (* (:created_at_i current-item) 1000)) - (components/item-link (:id current-item))) - (components/comment-text (:text current-item)))) - (map-indexed (fn [index child] - (-> (components/card - (dom/createDom - "div" - "commentHeader" - (components/comment-caption - (:author child) - (* (:created_at_i child) 1000)) - (components/item-link (:id child))) - (components/comment-text (:text child)) - (-> (components/replies-indicator (count (:children child))) - ((fn [indicator] - (if (> (count (:children child)) 0) - (-> indicator - (components/with-classes "clickable") - (components/with-listener - "click" - (fn [e] - (dispatch-message - {:type :enq-depth - :index index})))) - indicator))))) - (components/with-classes "child") - ((fn [card] - (if (> (count (:children child)) 0) - (components/with-classes card "clickable") - card))))) - (->> (:children current-item) - (filter #(contains? % :text)) - (sort-by #(count (:children %)) #(compare %2 %1)))))) - (:hits state) (map (fn [hit] - (-> (components/card - (dom/createDom - "div" - "storyHeader" - (components/body30 (:title hit)) - (components/item-link (:objectID hit))) - (components/story-caption (:points hit) - (:author hit) - (* (:created_at_i hit) 1000)) - (-> (components/comments-indicator (:num_comments hit)) - ((fn [indicator] - (if (> (:num_comments hit) 0) - (-> indicator - (components/with-classes "clickable") - (components/with-listener - "click" - (fn [e] - (dispatch-message {:type :loading :loading true}) - (go - (-> (fetch-item (:objectID hit)) - ( (:num_comments hit) 0) - (components/with-classes card "clickable") - card))))) - (:hits state)) - #_(let [current-item (get-in-items (:items state) (:depth state))] - (if (> (count current-item) 1) - (map #(components/card (:title %)) current-item) - ())))) + (components/body30 (:title hit)) + (components/item-link (:objectID hit))) + (components/story-caption (:points hit) + (:author hit) + (* (:created_at_i hit) 1000)) + (-> (components/comments-indicator (:num_comments hit)) + ((fn [indicator] + (if (> (:num_comments hit) 0) + (-> indicator + (components/with-classes "clickable") + (components/with-listener + "click" + (fn [e] + (dispatch-message {:type :loading :loading true}) + (go + (-> (fetch-item (:objectID hit)) + ( (:num_comments hit) 0) + (components/with-classes card "clickable") + card))))) + (:hits state)))))) (defn render "Renders the new DOM This is where clever diffing algorithms would go if this was React" [$sidebar-dom] - (let [$container (dom/getElement "sidebarContent")] + (let [$container (dom/getElement "sidebar")] (dom/removeChildren $container) (.scrollTo js/window 0 0) (if (seqable? $sidebar-dom) (apply dom/append $container $sidebar-dom) (dom/append $container $sidebar-dom)))) +(defn handle-close-button [e] + (.postMessage js/window.parent (clj->js {:type "closeSidebar"}) "*")) + +(defn handle-events + "Registers event listeners" + [state] + (events/listen (dom/getElement "closeSidebar") "click" handle-close-button)) + (defn run-render-loop "Runs the model-update-view loop" [state] (let [dispatch-message (fn [msg] (let [new-state (update-state msg state)] (run-render-loop new-state)))] - (render (view dispatch-message state)))) - -(defn handle-close-button [e] - (.postMessage js/window.parent (clj->js {:type "closeSidebar"}) "*")) + (render (view dispatch-message state)) + (handle-events state))) (defn fetch-hits "Fetch hits in the Algolia API matching the URL" @@ -202,7 +214,6 @@ (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-hits)