mirror of
https://github.com/penpot/penpot.git
synced 2026-09-09 13:39:02 +00:00
Merge pull request #2 from uxbox/sort-and-filter-projects
Sort and filter projects
This commit is contained in:
commit
bb1222116d
@ -28,22 +28,44 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-search {
|
.dashboard-search {
|
||||||
cursor: pointer;
|
align-items: center;
|
||||||
margin-left: $big;
|
display: flex;
|
||||||
|
margin-left: $small;
|
||||||
|
|
||||||
svg {
|
.input-text {
|
||||||
fill: $color-gray-dark;
|
background: rgba(255,255,255,.4);
|
||||||
height: 20px;
|
border: 0;
|
||||||
width: 20px;
|
color: $dark-ui-text;
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin: 0;
|
||||||
|
max-width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-search {
|
||||||
|
align-items: center;
|
||||||
|
background: rgba(255,255,255,.4);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
height: 28px;
|
||||||
|
padding: 0 5px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $light-ui-icons;
|
||||||
|
height: 15px;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
width: 15px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
fill: $color-danger;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
|
||||||
fill: $color-gray-darker;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
&.library-gap {
|
&.library-gap {
|
||||||
padding: $small $medium $small 270px;
|
padding: $small $medium $small 270px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,6 +62,39 @@
|
|||||||
(-pr-writer [mv writer _]
|
(-pr-writer [mv writer _]
|
||||||
(-write writer "#<event:u.d.d/initialize>"))))
|
(-write writer "#<event:u.d.d/initialize>"))))
|
||||||
|
|
||||||
|
(defn set-project-ordering
|
||||||
|
[order]
|
||||||
|
(reify
|
||||||
|
rs/UpdateEvent
|
||||||
|
(-apply-update [_ state]
|
||||||
|
(assoc-in state [:dashboard :project-order] order))
|
||||||
|
|
||||||
|
IPrintWithWriter
|
||||||
|
(-pr-writer [mv writer _]
|
||||||
|
(-write writer "#<event:u.d.d/set-project-ordering>"))))
|
||||||
|
|
||||||
|
(defn set-project-filtering
|
||||||
|
[term]
|
||||||
|
(reify
|
||||||
|
rs/UpdateEvent
|
||||||
|
(-apply-update [_ state]
|
||||||
|
(assoc-in state [:dashboard :project-filter] term))
|
||||||
|
|
||||||
|
IPrintWithWriter
|
||||||
|
(-pr-writer [mv writer _]
|
||||||
|
(-write writer "#<event:u.d.d/set-project-filtering>"))))
|
||||||
|
|
||||||
|
(defn clear-project-filtering
|
||||||
|
[]
|
||||||
|
(reify
|
||||||
|
rs/UpdateEvent
|
||||||
|
(-apply-update [_ state]
|
||||||
|
(assoc-in state [:dashboard :project-filter] ""))
|
||||||
|
|
||||||
|
IPrintWithWriter
|
||||||
|
(-pr-writer [mv writer _]
|
||||||
|
(-write writer "#<event:u.d.d/clear-project-filtering>"))))
|
||||||
|
|
||||||
(defn set-collection-type
|
(defn set-collection-type
|
||||||
[type]
|
[type]
|
||||||
{:pre [(contains? #{:builtin :own} type)]}
|
{:pre [(contains? #{:builtin :own} type)]}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
(ns uxbox.data.projects
|
(ns uxbox.data.projects
|
||||||
(:require [bouncer.validators :as v]
|
(:require [bouncer.validators :as v]
|
||||||
|
[cuerdas.core :as str]
|
||||||
[uxbox.rstore :as rs]
|
[uxbox.rstore :as rs]
|
||||||
[uxbox.router :as r]
|
[uxbox.router :as r]
|
||||||
[uxbox.state :as st]
|
[uxbox.state :as st]
|
||||||
@ -57,6 +58,23 @@
|
|||||||
(sort-by :created)
|
(sort-by :created)
|
||||||
(into [])))
|
(into [])))
|
||||||
|
|
||||||
|
(defn sort-projects-by
|
||||||
|
[ordering projs]
|
||||||
|
(case ordering
|
||||||
|
:name (sort-by :name projs)
|
||||||
|
:created (reverse (sort-by :created projs))
|
||||||
|
projs))
|
||||||
|
|
||||||
|
(defn contains-term?
|
||||||
|
[phrase term]
|
||||||
|
(str/contains? (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)))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Events
|
;; Events
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|||||||
@ -34,7 +34,14 @@
|
|||||||
(let [value (get-in +locales+ [+locale+ t] (name t))
|
(let [value (get-in +locales+ [+locale+ t] (name t))
|
||||||
plural (first (filter c? args))
|
plural (first (filter c? args))
|
||||||
args (mapv #(if (c? %) @% %) args)
|
args (mapv #(if (c? %) @% %) args)
|
||||||
value (if vector?
|
value (cond
|
||||||
|
(and (vector? value)
|
||||||
|
(= 3 (count value)))
|
||||||
|
(nth value (min 2 @plural))
|
||||||
|
|
||||||
|
(vector? value)
|
||||||
(if (= @plural 1) (first value) (second value))
|
(if (= @plural 1) (first value) (second value))
|
||||||
|
|
||||||
|
:else
|
||||||
value)]
|
value)]
|
||||||
(apply str/format value args))))
|
(apply str/format value args))))
|
||||||
|
|||||||
@ -2,6 +2,15 @@
|
|||||||
|
|
||||||
(defonce +locales+
|
(defonce +locales+
|
||||||
{"ds.projects" "PROJECTS"
|
{"ds.projects" "PROJECTS"
|
||||||
|
"ds.num-projects" ["No projects"
|
||||||
|
"%s project"
|
||||||
|
"%s projects"]
|
||||||
|
"ds.project-ordering" "Sort by"
|
||||||
|
"ds.project-ordering.by-name" "name"
|
||||||
|
"ds.project-ordering.by-last-update" "last update"
|
||||||
|
"ds.project-ordering.by-creation-date" "creation date"
|
||||||
|
"ds.project-search.placeholder" "Search..."
|
||||||
|
|
||||||
"ds.elements" "ELEMENTS"
|
"ds.elements" "ELEMENTS"
|
||||||
"ds.icons" "ICONS"
|
"ds.icons" "ICONS"
|
||||||
"ds.colors" "COLORS"
|
"ds.colors" "COLORS"
|
||||||
|
|||||||
@ -7,7 +7,8 @@
|
|||||||
(defonce stream
|
(defonce stream
|
||||||
(rs/init {:user {:fullname "Cirilla Fiona"
|
(rs/init {:user {:fullname "Cirilla Fiona"
|
||||||
:avatar "http://lorempixel.com/50/50/"}
|
:avatar "http://lorempixel.com/50/50/"}
|
||||||
:dashboard {}
|
:dashboard {:project-order :name
|
||||||
|
:project-filter ""}
|
||||||
:workspace {}
|
:workspace {}
|
||||||
:shapes-by-id {}
|
:shapes-by-id {}
|
||||||
:elements-by-id {}
|
:elements-by-id {}
|
||||||
|
|||||||
@ -3,10 +3,12 @@
|
|||||||
[rum.core :as rum]
|
[rum.core :as rum]
|
||||||
[cats.labs.lens :as l]
|
[cats.labs.lens :as l]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
|
[uxbox.locales :as t :refer (tr)]
|
||||||
[uxbox.router :as r]
|
[uxbox.router :as r]
|
||||||
[uxbox.rstore :as rs]
|
[uxbox.rstore :as rs]
|
||||||
[uxbox.state :as s]
|
[uxbox.state :as s]
|
||||||
[uxbox.time :as time]
|
[uxbox.time :as time]
|
||||||
|
[uxbox.data.dashboard :as dd]
|
||||||
[uxbox.data.projects :as dp]
|
[uxbox.data.projects :as dp]
|
||||||
[uxbox.data.workspace :as dw]
|
[uxbox.data.workspace :as dw]
|
||||||
[uxbox.ui.icons :as i]
|
[uxbox.ui.icons :as i]
|
||||||
@ -20,9 +22,8 @@
|
|||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
;; FIXME rename
|
;; FIXME rename
|
||||||
(def +ordering-options+ {:name "name"
|
(def +ordering-options+ {:name "ds.project-ordering.by-name"
|
||||||
:last-updated "date updated"
|
:created "ds.project-ordering.by-creation-date"})
|
||||||
:created "date created"})
|
|
||||||
|
|
||||||
(def +layouts+ {:mobile {:name "Mobile"
|
(def +layouts+ {:mobile {:name "Mobile"
|
||||||
:id "mobile"
|
:id "mobile"
|
||||||
@ -149,32 +150,75 @@
|
|||||||
;; Menu
|
;; Menu
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
;; (def ^:static menu-l
|
(def ^:static menu-l
|
||||||
;; (as-> (l/select-keys [:projects]) $
|
(as-> (l/select-keys [:projects-by-id]) $
|
||||||
;; (l/focus-atom $ s/state)))
|
(l/focus-atom $ s/state)))
|
||||||
|
|
||||||
(rum/defc project-sort-selector < rum/reactive
|
(def ^:static project-ordering-l
|
||||||
[sort-order]
|
(as-> (l/in [:dashboard :project-order]) $
|
||||||
nil)
|
(l/focus-atom $ s/state)))
|
||||||
;; (let [sort-name (get project-orderings (rum/react sort-order))]
|
|
||||||
;; [:select.input-select
|
(def ^:static project-filtering-l
|
||||||
;; {:on-change #(reset! sort-order (name->order (.-value (.-target %))))
|
(as-> (l/in [:dashboard :project-filter]) $
|
||||||
;; :value sort-name}
|
(l/focus-atom $ s/state)))
|
||||||
;; (for [order (keys project-orderings)
|
|
||||||
;; :let [name (get project-orderings order)]]
|
(defn project-sort-render
|
||||||
;; [:option {:key name} name])]))
|
[]
|
||||||
|
(let [ordering (rum/react project-ordering-l)
|
||||||
|
change-order #(rs/emit! (dd/set-project-ordering (keyword (.-value (.-target %)))))]
|
||||||
|
(html
|
||||||
|
[:div
|
||||||
|
[:span (tr "ds.project-ordering")]
|
||||||
|
[:select.input-select
|
||||||
|
{:on-change change-order
|
||||||
|
:value (name ordering)}
|
||||||
|
(for [option (keys +ordering-options+)
|
||||||
|
:let [option-id (get +ordering-options+ option)
|
||||||
|
option-value (name option)
|
||||||
|
option-text (tr option-id)]]
|
||||||
|
[:option
|
||||||
|
{:key option-id
|
||||||
|
:value option-value}
|
||||||
|
option-text])]])))
|
||||||
|
|
||||||
|
(def project-sorting
|
||||||
|
(mx/component
|
||||||
|
{:render project-sort-render
|
||||||
|
:name "project-sort-order"
|
||||||
|
:mixins [rum/reactive]}))
|
||||||
|
|
||||||
|
(defn project-search-render
|
||||||
|
[]
|
||||||
|
(let [change-term #(rs/emit! (dd/set-project-filtering (.-value (.-target %))))
|
||||||
|
clear-term #(rs/emit! (dd/clear-project-filtering))]
|
||||||
|
(html
|
||||||
|
[:form.dashboard-search
|
||||||
|
[:input.input-text
|
||||||
|
{:type "text"
|
||||||
|
:on-change change-term
|
||||||
|
:auto-focus true
|
||||||
|
:placeholder (tr "ds.project-search.placeholder")
|
||||||
|
:value (rum/react project-filtering-l)}]
|
||||||
|
[:div.clear-search
|
||||||
|
{:on-click clear-term}
|
||||||
|
i/close]])))
|
||||||
|
|
||||||
|
(def project-search
|
||||||
|
(mx/component
|
||||||
|
{:render project-search-render
|
||||||
|
:name "project-search"
|
||||||
|
:mixins [rum/reactive]}))
|
||||||
|
|
||||||
(defn menu-render
|
(defn menu-render
|
||||||
[]
|
[]
|
||||||
(let [state {:projects []} #_(rum/react menu-l)
|
(let [projects (rum/react menu-l)
|
||||||
pcount (count (:projects state))]
|
pcount (count (:projects-by-id projects))] ;; FIXME: redundant project-by-id key
|
||||||
(html
|
(html
|
||||||
[:section#dashboard-bar.dashboard-bar
|
[:section#dashboard-bar.dashboard-bar
|
||||||
[:div.dashboard-info
|
[:div.dashboard-info
|
||||||
[:span.dashboard-projects pcount " projects"]
|
[:span.dashboard-projects (tr "ds.num-projects" (t/c pcount))]
|
||||||
[:span "Sort by"]]
|
(project-sorting)
|
||||||
[:div.dashboard-search
|
(project-search)]])))
|
||||||
i/search]])))
|
|
||||||
|
|
||||||
(def menu
|
(def menu
|
||||||
(mx/component
|
(mx/component
|
||||||
@ -235,14 +279,17 @@
|
|||||||
(letfn [(on-click [e]
|
(letfn [(on-click [e]
|
||||||
(dom/prevent-default e)
|
(dom/prevent-default e)
|
||||||
(lightbox/open! :new-project))]
|
(lightbox/open! :new-project))]
|
||||||
(let [state (rum/react grid-l)]
|
(let [state (rum/react grid-l)
|
||||||
|
ordering (rum/react project-ordering-l)
|
||||||
|
filtering (rum/react project-filtering-l)
|
||||||
|
projects (dp/filter-projects-by filtering (vals (:projects-by-id state)))]
|
||||||
(html
|
(html
|
||||||
[:section.dashboard-grid
|
[:section.dashboard-grid
|
||||||
[:h2 "Your projects"]
|
[:h2 "Your projects"]
|
||||||
[:div.dashboard-grid-content
|
[:div.dashboard-grid-content
|
||||||
[:div.grid-item.add-project {:on-click on-click}
|
[:div.grid-item.add-project {:on-click on-click}
|
||||||
[:span "+ New project"]]
|
[:span "+ New project"]]
|
||||||
(for [item (vals (:projects-by-id state))]
|
(for [item (dp/sort-projects-by ordering projects)]
|
||||||
(rum/with-key (project-item item) (:id item)))]]))))
|
(rum/with-key (project-item item) (:id item)))]]))))
|
||||||
|
|
||||||
(def grid
|
(def grid
|
||||||
@ -250,4 +297,3 @@
|
|||||||
{:render grid-render
|
{:render grid-render
|
||||||
:name "grid"
|
:name "grid"
|
||||||
:mixins [rum/reactive]}))
|
:mixins [rum/reactive]}))
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user