      [:a.close {:href "#"
                 :on-click #(do (dom/prevent-default %)
                                (udl/close!))}
-      i/close]])))
-
-(def new-project-lightbox
-  (mx/component
-   {:render new-project-lightbox-render
-    :name "new-project-lightbox"
-    :mixins [(rum/local +project-defaults+)]}))
+      i/close]]))
 
 (defmethod lbx/render-lightbox :new-project
   [_]

          (on-delete [event]
            (dom/stop-propagation event)
            (udl/open! :confirm {:on-accept delete}))]
    (html
     [:div.grid-item.project-th {:on-click on-navigate
                                 :key (:id project)}
      [:h3 (:name project)]
      [:span.project-th-update
       (str "Updated " (dt/timeago (:modified-at project)))]
      [:div.project-th-actions
       [:div.project-th-icon.pages
        i/page
        [:span (:total-pages project)]]
       #_[:div.project-th-icon.comments
        i/chat
        [:span "0"]]
       #_[:div.project-th-icon.edit
          i/pencil]
       [:div.project-th-icon.delete
        {:on-click on-delete}
        i/trash]]])))

(def ^:private grid-item
  (mx/component
   {:render grid-item-render
    :name "grid-item"
    :mixins [rum/static]}))

;; --- Grid

(defn grid-render
  [own]
  (let [projects (mx/react projects-by-id-ref)
        ordering (mx/react project-ordering-ref)
        filtering (mx/react project-filtering-ref)]
    (letfn [(on-click [e]
              (dom/prevent-default e)
              (udl/open! :new-project))]
      (html
       [:section.dashboard-grid
        [:h2 "Your projects"]
         [:div.dashboard-grid-content
          [:div.dashboard-grid-row
            [:div.grid-item.add-project
             {:on-click on-click}
             [:span "+ New project"]]
            (for [item (->> (vals projects)
                            (dp/filter-projects-by filtering)
                            (dp/sort-projects-by ordering))]
              (-> (grid-item item)
                  (rum/with-key (:id item))))]]]))))

(def grid
  (mx/component
   {:render grid-render
    :name "grid"
    :mixins [mx/reactive]}))

;; --- Page

(defn projects-page-render
  [own]
  (html
   [:main.dashboard-main
    (uum/messages)
    (header)
    [:section.dashboard-content
     (menu)
     (grid)]]))

(defn projects-page-will-mount
  [own]
  (rs/emit! (dd/initialize :dashboard/projects)
            (dp/initialize))
  own)

(defn projects-page-did-remount
  [old-state state]
  (rs/emit! (dd/initialize :dashboard/projects))
  state)

(def projects-page
  (mx/component
   {:render projects-page-render
    :will-mount projects-page-will-mount
    :did-remount projects-page-did-remount
    :name "projects-page"
    :mixins [rum/static]}))

;; --- Lightbox: Layout input

(defn- layout-input
  [local layout-id]
  (let [layout (get-in +layouts+ [layout-id])
        id (:id layout)
        name (:name layout)
        width (:width layout)
        height (:height layout)]
    (html
     [:div
      [:input
       {:type "radio"
        :key id
        :id id
        :name "project-layout"
        :value name
        :checked (= layout-id (:layout @local))
        :on-change #(swap! local merge {:layout layout-id
                                        :width width
                                        :height height})}]
      [:label {:value (:name @local) :for id} name]])))

;; --- Lightbox: Layout selector

(defn- layout-selector
  [local]
  (html
   [:div.input-radio.radio-primary
    (layout-input local "mobile")
    (layout-input local "tablet")
    (layout-input local "notebook")
    (layout-input local "desktop")]))

;; -- New Project Lightbox

(defn- new-project-lightbox-render
  [own]
  (let [local (:rum/local own)
        name (:name @local)
        width (:width @local)
        height (:height @local)]
   (html
    [:div.lightbox-body
     [:h3 "New project"]
     [:form {:on-submit (constantly nil)}

  {:name "ds.project-ordering.by-name"
   :created "ds.project-ordering.by-creation-date"})

;; --- Refs

(def projects-map-ref
  (-> (l/key :projects-by-id)
      (l/derive st/state)))

(def dashboard-ref
  (-> (l/in [:dashboard :projects])
      (l/derive st/state)))

(def project-ordering-ref
  (-> (l/key :project-order)
      (l/derive dashboard-ref)))

(def project-filtering-ref
  (-> (l/in [:project-filter])
      (l/derive dashboard-ref)))

;; --- Helpers

(defn sort-projects-by
  [ordering projs]
  (case ordering
    :name (sort-by :name projs)
    :created (reverse (sort-by :created-at projs))
    projs))

(defn contains-term?
  [phrase term]
  (let [term (name term)]
    (str/includes? (str/lower phrase) (str/trim (str/lower term)))))

(defn filter-projects-by
  [term projs]
  (if (str/blank? term)
    projs
    (filter #(contains-term? (:name %) term) projs)))

;; --- Menu (Filter & Sort)

(mx/defc menu
  {:mixins [mx/static]}
  [state projects]
  (let [ordering (:order state :name)
        filtering (:filter state "")
        count (count projects)]
    (letfn [(on-term-change [event]
              (let [term (-> (dom/get-target event)
                             (dom/get-value))]
                (rs/emit! (dp/update-opts :filter term))))
            (on-ordering-change [event]
              (let [value (dom/event->value event)
                    value (read-string value)]
                (rs/emit! (dp/update-opts :order value))))
            (on-clear [event]
              (rs/emit! (dp/update-opts :filter "")))]
      [:section.dashboard-bar
       [:div.dashboard-info

        ;; Counter
        [:span.dashboard-images (tr "ds.num-projects" (t/c count))]

        ;; Sorting
        [:div
         [:span (tr "ds.project-ordering")]
         [:select.input-select
          {:on-change on-ordering-change
           :value (pr-str ordering)}
          (for [[key value] (seq +ordering-options+)
                :let [ovalue (pr-str key)
                      olabel (tr value)]]
            [:option {:key ovalue :value ovalue} olabel])]]
        ;; Search
        [:form.dashboard-search
         [:input.input-text
          {:key :images-search-box
           :type "text"
           :on-change on-term-change
           :auto-focus true
           :placeholder (tr "ds.project-search.placeholder")
           :value (or filtering "")}]
         [:div.clear-search {:on-click on-clear} i/close]]]])))

;; --- Grid Item

(mx/defc  grid-item
  {:mixins [mx/static]}
  [project]
  (letfn [(on-navigate [event]
            (rs/emit! (dp/go-to (:id project))))
          (delete []
