🎉 Picker color palettes interactions

This commit is contained in:
alonso.torres 2020-09-08 12:30:35 +02:00 committed by Hirunatan
parent 568f7f5b3d
commit a0627efffe
7 changed files with 409 additions and 199 deletions

View file

@ -68,8 +68,8 @@
(s/def :internal.shape/collapsed boolean?) (s/def :internal.shape/collapsed boolean?)
(s/def :internal.shape/content any?) (s/def :internal.shape/content any?)
(s/def :internal.shape/fill-color string?) (s/def :internal.shape/fill-color string?)
(s/def :internal.shape/fill-color-ref-file uuid?) (s/def :internal.shape/fill-color-ref-file (s/nilable uuid?))
(s/def :internal.shape/fill-color-ref-id uuid?) (s/def :internal.shape/fill-color-ref-id (s/nilable uuid?))
(s/def :internal.shape/fill-opacity number?) (s/def :internal.shape/fill-opacity number?)
(s/def :internal.shape/font-family string?) (s/def :internal.shape/font-family string?)
(s/def :internal.shape/font-size number?) (s/def :internal.shape/font-size number?)
@ -85,8 +85,8 @@
(s/def :internal.shape/rx number?) (s/def :internal.shape/rx number?)
(s/def :internal.shape/ry number?) (s/def :internal.shape/ry number?)
(s/def :internal.shape/stroke-color string?) (s/def :internal.shape/stroke-color string?)
(s/def :internal.shape/stroke-color-ref-file uuid?) (s/def :internal.shape/stroke-color-ref-file (s/nilable uuid?))
(s/def :internal.shape/stroke-color-ref-id uuid?) (s/def :internal.shape/stroke-color-ref-id (s/nilable uuid?))
(s/def :internal.shape/stroke-opacity number?) (s/def :internal.shape/stroke-opacity number?)
(s/def :internal.shape/stroke-style #{:solid :dotted :dashed :mixed :none}) (s/def :internal.shape/stroke-style #{:solid :dotted :dashed :mixed :none})
(s/def :internal.shape/stroke-width number?) (s/def :internal.shape/stroke-width number?)

File diff suppressed because it is too large Load diff

View file

@ -123,6 +123,10 @@
width: 100%; width: 100%;
height: 4.8rem; height: 4.8rem;
padding: 0.25rem; padding: 0.25rem;
&.size-small {
height: 3.5rem;
}
} }
.color-palette-inside { .color-palette-inside {
@ -141,15 +145,37 @@
flex-direction: column; flex-direction: column;
flex-shrink: 0; flex-shrink: 0;
position: relative; position: relative;
&.cell-big {
flex-basis: 66px; flex-basis: 66px;
}
&.cell-small {
flex-basis: 52px;
}
.color { .color {
background-color: $color-gray-10; background-color: $color-gray-10;
border: 2px solid $color-gray-60; border: 2px solid $color-gray-60;
border-radius: 50%; border-radius: 50%;
flex-shrink: 0; flex-shrink: 0;
padding: 1.5rem;
} }
&.cell-big .color {
width: 50px;
height: 50px;
}
&.cell-small .color {
width: 40px;
height: 40px;
}
.color.color-big {
width: 50px;
height: 50px;
}
.color-text { .color-text {
color: $color-gray-20; color: $color-gray-20;
font-size: $fs12; font-size: $fs12;
@ -263,3 +289,52 @@
} }
} }
} }
ul.palette-menu {
left: 8px;
top: auto;
bottom: 4.5rem;
color: $color-black;
li {
position: relative;
padding: 5px 1.5rem;
}
hr {
margin: 0.5rem 0;
}
svg {
width: 9px;
height: 9px;
position: absolute;
left: 0.5rem;
top: 10px;
}
hr {
border-color: $color-gray-20;
}
.palette-library {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.color-sample {
display: flex;
flex-direction: row;
margin-top: 0.5rem;
}
.color-bullet {
width: 20px;
height: 20px;
border-radius: 12px;
border: 1px solid $color-gray-10;
margin-right: 5px;
}
}

View file

@ -107,3 +107,25 @@
(update-in [:workspace-file :colors] (update-in [:workspace-file :colors]
(fn [colors] (filter #(not= (:id %) color-id) colors))))))) (fn [colors] (filter #(not= (:id %) color-id) colors)))))))
(defn change-palette-size [size]
(s/assert #{:big :small} size)
(ptk/reify ::change-palette-size
ptk/UpdateEvent
(update [_ state]
(-> state
(assoc-in [:workspace-local :selected-palette-size] size)))))
(defn change-palette-selected [selected]
(ptk/reify ::change-palette-selected
ptk/UpdateEvent
(update [_ state]
(-> state
(assoc-in [:workspace-local :selected-palette] selected)))))
(defn show-palette [selected]
(ptk/reify ::change-palette-selected
ptk/UpdateEvent
(update [_ state]
(-> state
(update :workspace-layout conj :colorpalette)
(assoc-in [:workspace-local :selected-palette] selected)))))

View file

@ -100,7 +100,9 @@
:draw-interaction-to nil :draw-interaction-to nil
:left-sidebar? true :left-sidebar? true
:right-sidebar? true :right-sidebar? true
:color-for-rename nil}) :color-for-rename nil
:selected-palette :recent
:selected-palette-size :big})
(def initialize-layout (def initialize-layout
(ptk/reify ::initialize-layout (ptk/reify ::initialize-layout

View file

@ -13,16 +13,19 @@
[goog.events :as events] [goog.events :as events]
[okulary.core :as l] [okulary.core :as l]
[rumext.alpha :as mf] [rumext.alpha :as mf]
[cuerdas.core :as str]
[app.common.math :as mth] [app.common.math :as mth]
;; [app.main.data.library :as dlib] [app.main.data.colors :as mdc]
[app.main.data.workspace :as udw] [app.main.data.workspace :as udw]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.context-menu :refer [context-menu]] [app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd] [app.main.ui.keyboard :as kbd]
[app.util.color :refer [hex->rgb]] [app.util.color :refer [hex->rgb]]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.object :as obj])) [app.util.object :as obj]
[app.main.refs :as refs]
[app.util.i18n :as i18n :refer [t]]))
;; --- Refs ;; --- Refs
@ -31,7 +34,11 @@
(l/derived st/state))) (l/derived st/state)))
(def selected-palette-ref (def selected-palette-ref
(-> (l/in [:library-selected :palettes]) (-> (l/in [:workspace-local :selected-palette])
(l/derived st/state)))
(def selected-palette-size-ref
(-> (l/in [:workspace-local :selected-palette-size])
(l/derived st/state))) (l/derived st/state)))
(defn- make-selected-palette-item-ref (defn- make-selected-palette-item-ref
@ -40,41 +47,40 @@
(l/derived st/state))) (l/derived st/state)))
;; --- Components ;; --- Components
(mf/defc palette-item (mf/defc palette-item
[{:keys [color] :as props}] [{:keys [color size]}]
(let [rgb-vec (hex->rgb color) (let [select-color
select-color
(fn [event] (fn [event]
(if (kbd/shift? event) (if (kbd/shift? event)
(st/emit! (udw/update-color-on-selected-shapes {:stroke-color color})) (st/emit! (udw/update-color-on-selected-shapes {:stroke-color (:value color)
(st/emit! (udw/update-color-on-selected-shapes {:fill-color color}))))] :stroke-color-ref-file (:file-id color)
:stroke-color-ref-id (:id color)}))
(st/emit! (udw/update-color-on-selected-shapes {:fill-color (:value color)
:fill-color-ref-file (:file-id color)
:fill-color-ref-id (:id color)}))))]
[:div.color-cell {:key (str color) [:div.color-cell {:class (str "cell-"(name size))
:key (or (str (:id color)) (:value color))
:on-click select-color} :on-click select-color}
[:span.color {:style {:background color}}] [:span.color {:style {:background (:value color)}}]
[:span.color-text color]])) (when (= size :big) [:span.color-text (or (:name color) (:value color))])]))
(mf/defc palette (mf/defc palette
[{:keys [palettes selected left-sidebar?] :as props}] [{:keys [left-sidebar? current-colors recent-colors file-colors shared-libs selected size]}]
(let [items-ref (mf/use-memo (let [state (mf/use-state {:show-menu false })
(mf/deps selected)
(partial make-selected-palette-item-ref selected))
items (mf/deref items-ref)
state (mf/use-state {:show-menu false })
width (:width @state 0) width (:width @state 0)
visible (mth/round (/ width 66)) visible (mth/round (/ width 66))
offset (:offset @state 0) offset (:offset @state 0)
max-offset (- (count items) max-offset (- (count current-colors)
visible) visible)
close-fn #(st/emit! (udw/toggle-layout-flags :colorpalette)) close-fn #(st/emit! (udw/toggle-layout-flags :colorpalette))
container (mf/use-ref nil) container (mf/use-ref nil)
locale (mf/deref i18n/locale)
on-left-arrow-click on-left-arrow-click
(mf/use-callback (mf/use-callback
(mf/deps max-offset visible) (mf/deps max-offset visible)
@ -108,12 +114,8 @@
(fn [event] (fn [event]
(let [dom (mf/ref-val container) (let [dom (mf/ref-val container)
width (obj/get dom "clientWidth")] width (obj/get dom "clientWidth")]
(swap! state assoc :width width)))) (swap! state assoc :width width))))]
handle-click
(mf/use-callback
(fn [library]))]
;; (st/emit! (dlib/select-library :palettes (:id library)))))]
(mf/use-layout-effect (mf/use-layout-effect
#(let [dom (mf/ref-val container) #(let [dom (mf/ref-val container)
@ -125,48 +127,116 @@
(fn [] (fn []
(events/unlistenByKey key1)))) (events/unlistenByKey key1))))
(mf/use-effect
(mf/deps selected)
(fn []
(when selected)))
;; (st/emit! (dlib/retrieve-library-data :palettes selected)))))
[:div.color-palette {:class (when left-sidebar? "left-sidebar-open")} [:div.color-palette {:class (when left-sidebar? "left-sidebar-open")}
[:& context-menu [:& dropdown {:show (:show-menu @state)
{:selectable true :on-close #(swap! state assoc :show-menu false)}
:selected (->> palettes [:ul.workspace-context-menu.palette-menu
(filter #(= (:id %) selected)) (for [cur-library (vals shared-libs)]
first (let [colors (-> cur-library (get-in [:data :colors]) vals)]
:name) [:li.palette-library
:show (:show-menu @state) {:on-click #(st/emit! (mdc/change-palette-selected (:id cur-library)))}
:on-close #(swap! state assoc :show-menu false) (when (= selected (:id cur-library)) i/tick)
:options (mapv #(vector (:name %) (partial handle-click %)) palettes)}] [:div.library-name (str (:name cur-library) " " (str/format "(%s)" (count colors)))]
[:div.color-sample
(for [[idx {:keys [id value]}] (map-indexed vector (take 7 colors))]
[:div.color-bullet {:key (str "color-" idx)
:style {:background-color value}}])]]))
[:li.palette-library
{:on-click #(st/emit! (mdc/change-palette-selected :file))}
(when (= selected :file) i/tick)
[:div.library-name (str (t locale "workspace.libraries.colors.file-library")
(str/format " (%s)" (count file-colors)))]
[:div.color-sample
(for [[idx {:keys [value]}] (map-indexed vector (take 7 (vals file-colors))) ]
[:div.color-bullet {:key (str "color-" idx)
:style {:background-color value}}])]]
[:li.palette-library
{:on-click #(st/emit! (mdc/change-palette-selected :recent))}
(when (= selected :recent) i/tick)
[:div.library-name (str (t locale "workspace.libraries.colors.recent-colors")
(str/format " (%s)" (count recent-colors)))]
[:div.color-sample
(for [[idx value] (map-indexed vector (take 7 (reverse recent-colors))) ]
[:div.color-bullet {:key (str "color-" idx)
:style {:background-color value}}])]]
[:hr.dropdown-separator]
[:li
{:on-click #(st/emit! (mdc/change-palette-size :big))}
(when (= size :big) i/tick)
(t locale "workspace.libraries.colors.big-thumbnails")]
[:li
{:on-click #(st/emit! (mdc/change-palette-size :small))}
(when (= size :small) i/tick)
(t locale "workspace.libraries.colors.small-thumbnails")]]]
[:div.color-palette-actions [:div.color-palette-actions
{:on-click #(swap! state assoc :show-menu true)} {:on-click #(swap! state assoc :show-menu true)}
[:div.color-palette-actions-button i/actions]] [:div.color-palette-actions-button i/actions]]
[:span.left-arrow {:on-click on-left-arrow-click} i/arrow-slide] [:span.left-arrow {:on-click on-left-arrow-click} i/arrow-slide]
[:div.color-palette-content {:ref container :on-wheel on-scroll} [:div.color-palette-content {:class (if (= size :big) "size-big" "size-small")
:ref container :on-wheel on-scroll}
[:div.color-palette-inside {:style {:position "relative" [:div.color-palette-inside {:style {:position "relative"
:right (str (* 66 offset) "px")}} :right (str (* 66 offset) "px")}}
(for [item items] (for [[idx item] (map-indexed vector current-colors)]
[:& palette-item {:color (:content item) :key (:id item)}])]] [:& palette-item {:size size
:color item
:key idx}])]]
[:span.right-arrow {:on-click on-right-arrow-click} i/arrow-slide]])) [:span.right-arrow {:on-click on-right-arrow-click} i/arrow-slide]]))
(defn recent->colors [recent-colors]
(map #(hash-map :value %) (reverse (or recent-colors []))))
(defn file->colors [file-colors]
(map #(select-keys % [:id :value :name]) (vals file-colors)))
(defn library->colors [shared-libs selected]
(map #(merge {:file-id selected} (select-keys % [:id :value :name]))
(vals (get-in shared-libs [selected :data :colors]))))
(mf/defc colorpalette (mf/defc colorpalette
[{:keys [left-sidebar? team-id] :as props}] [{:keys [left-sidebar? team-id]}]
(let [palettes (->> (mf/deref palettes-ref) (let [recent-colors (mf/deref refs/workspace-recent-colors)
(vals) file-colors (mf/deref refs/workspace-file-colors)
(mapcat identity)) shared-libs (mf/deref refs/workspace-libraries)
selected (or (mf/deref selected-palette-ref) selected (or (mf/deref selected-palette-ref) :recent)
(:id (first palettes)))] size (or (mf/deref selected-palette-size-ref) :big)
current-library-colors (mf/use-state [])]
(mf/use-effect (mf/use-effect
(mf/deps team-id) (mf/deps selected)
(fn [])) (fn []
;; (st/emit! (dlib/retrieve-libraries :palettes) (reset! current-library-colors
;; (dlib/retrieve-libraries :palettes team-id)))) (into []
(cond
(= selected :recent) (recent->colors recent-colors)
(= selected :file) (file->colors file-colors)
:else (library->colors shared-libs selected))))))
(mf/use-effect
(mf/deps recent-colors)
(fn []
(when (= selected :recent)
(reset! current-library-colors (into [] (recent->colors recent-colors))))))
(mf/use-effect
(mf/deps file-colors)
(fn []
(when (= selected :file)
(reset! current-library-colors (into [] (file->colors file-colors))))))
[:& palette {:left-sidebar? left-sidebar? [:& palette {:left-sidebar? left-sidebar?
:current-colors @current-library-colors
:recent-colors recent-colors
:file-colors file-colors
:shared-libs shared-libs
:selected selected :selected selected
:palettes palettes}])) :size size}]))

View file

@ -18,9 +18,11 @@
[app.common.math :as math] [app.common.math :as math]
[app.common.uuid :refer [uuid]] [app.common.uuid :refer [uuid]]
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.main.data.colors :as dwc]
[app.main.ui.modal :as modal] [app.main.ui.modal :as modal]
[okulary.core :as l] [okulary.core :as l]
[app.main.refs :as refs])) [app.main.refs :as refs]
[app.util.i18n :as i18n :refer [t]]))
;; --- Color Picker Modal ;; --- Color Picker Modal
@ -100,9 +102,16 @@
shared-libs (mf/deref refs/workspace-libraries) shared-libs (mf/deref refs/workspace-libraries)
recent-colors (mf/deref refs/workspace-recent-colors) recent-colors (mf/deref refs/workspace-recent-colors)
locale (mf/deref i18n/locale)
value-ref (mf/use-var value) value-ref (mf/use-var value)
on-change (or on-change identity)] on-change (or on-change identity)
parse-selected (fn [selected]
(if (#{"recent" "file"} selected)
(keyword selected)
(uuid selected)) )]
;; Update state when there is a change in the props upstream ;; Update state when there is a change in the props upstream
(mf/use-effect (mf/use-effect
@ -140,7 +149,8 @@
(mf/use-effect (mf/use-effect
(mf/deps file-colors) (mf/deps file-colors)
(fn [] (when (= @selected-library "file") (fn [] (when (= @selected-library "file")
(reset! current-library-colors (into [] (map :value (vals file-colors))))))) (let [colors (map #(select-keys % [:id :value]) (vals file-colors))]
(reset! current-library-colors (into [] colors))))))
;; When closing the modal we update the recent-color list ;; When closing the modal we update the recent-color list
(mf/use-effect (mf/use-effect
@ -263,8 +273,8 @@
(let [val (-> e dom/get-target dom/get-value)] (let [val (-> e dom/get-target dom/get-value)]
(reset! selected-library val))) (reset! selected-library val)))
:value @selected-library} :value @selected-library}
[:option {:value "recent"} "Recent colors"] [:option {:value "recent"} (t locale "workspace.libraries.colors.recent-colors")]
[:option {:value "file"} "File library"] [:option {:value "file"} (t locale "workspace.libraries.colors.file-library")]
(for [[_ {:keys [name id]}] shared-libs] (for [[_ {:keys [name id]}] shared-libs]
[:option {:key id [:option {:key id
:value id} name])] :value id} name])]
@ -275,7 +285,8 @@
:on-click #(st/emit! (dwl/add-color (:hex @current-color)))} :on-click #(st/emit! (dwl/add-color (:hex @current-color)))}
i/plus]) i/plus])
[:div.color-bullet.button {:style {:background-color "white"}} [:div.color-bullet.button {:style {:background-color "white"}
:on-click #(st/emit! (dwc/show-palette (parse-selected @selected-library)))}
i/palette] i/palette]
(for [[idx {:keys [id file-id value]}] (map-indexed vector @current-library-colors)] (for [[idx {:keys [id file-id value]}] (map-indexed vector @current-library-colors)]
@ -298,7 +309,7 @@
{:on-click (fn [] {:on-click (fn []
(on-accept @value-ref) (on-accept @value-ref)
(modal/hide!))} (modal/hide!))}
"Save color"]])]) (t locale "workspace.libraries.colors.save-color")]])])
) )
(mf/defc colorpicker-modal (mf/defc colorpicker-modal