mirror of
https://github.com/penpot/penpot.git
synced 2025-03-18 10:41:29 -05:00
🎉 Picker color palettes interactions
This commit is contained in:
parent
568f7f5b3d
commit
a0627efffe
7 changed files with 409 additions and 199 deletions
|
@ -68,8 +68,8 @@
|
|||
(s/def :internal.shape/collapsed boolean?)
|
||||
(s/def :internal.shape/content any?)
|
||||
(s/def :internal.shape/fill-color string?)
|
||||
(s/def :internal.shape/fill-color-ref-file uuid?)
|
||||
(s/def :internal.shape/fill-color-ref-id uuid?)
|
||||
(s/def :internal.shape/fill-color-ref-file (s/nilable uuid?))
|
||||
(s/def :internal.shape/fill-color-ref-id (s/nilable uuid?))
|
||||
(s/def :internal.shape/fill-opacity number?)
|
||||
(s/def :internal.shape/font-family string?)
|
||||
(s/def :internal.shape/font-size number?)
|
||||
|
@ -85,8 +85,8 @@
|
|||
(s/def :internal.shape/rx number?)
|
||||
(s/def :internal.shape/ry number?)
|
||||
(s/def :internal.shape/stroke-color string?)
|
||||
(s/def :internal.shape/stroke-color-ref-file uuid?)
|
||||
(s/def :internal.shape/stroke-color-ref-id uuid?)
|
||||
(s/def :internal.shape/stroke-color-ref-file (s/nilable uuid?))
|
||||
(s/def :internal.shape/stroke-color-ref-id (s/nilable uuid?))
|
||||
(s/def :internal.shape/stroke-opacity number?)
|
||||
(s/def :internal.shape/stroke-style #{:solid :dotted :dashed :mixed :none})
|
||||
(s/def :internal.shape/stroke-width number?)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -123,6 +123,10 @@
|
|||
width: 100%;
|
||||
height: 4.8rem;
|
||||
padding: 0.25rem;
|
||||
|
||||
&.size-small {
|
||||
height: 3.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.color-palette-inside {
|
||||
|
@ -141,15 +145,37 @@
|
|||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
flex-basis: 66px;
|
||||
|
||||
&.cell-big {
|
||||
flex-basis: 66px;
|
||||
}
|
||||
|
||||
&.cell-small {
|
||||
flex-basis: 52px;
|
||||
}
|
||||
|
||||
.color {
|
||||
background-color: $color-gray-10;
|
||||
border: 2px solid $color-gray-60;
|
||||
border-radius: 50%;
|
||||
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: $color-gray-20;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -107,3 +107,25 @@
|
|||
(update-in [:workspace-file :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)))))
|
||||
|
|
|
@ -100,7 +100,9 @@
|
|||
:draw-interaction-to nil
|
||||
:left-sidebar? true
|
||||
:right-sidebar? true
|
||||
:color-for-rename nil})
|
||||
:color-for-rename nil
|
||||
:selected-palette :recent
|
||||
:selected-palette-size :big})
|
||||
|
||||
(def initialize-layout
|
||||
(ptk/reify ::initialize-layout
|
||||
|
|
|
@ -13,16 +13,19 @@
|
|||
[goog.events :as events]
|
||||
[okulary.core :as l]
|
||||
[rumext.alpha :as mf]
|
||||
[cuerdas.core :as str]
|
||||
[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.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.keyboard :as kbd]
|
||||
[app.util.color :refer [hex->rgb]]
|
||||
[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
|
||||
|
||||
|
@ -31,7 +34,11 @@
|
|||
(l/derived st/state)))
|
||||
|
||||
(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)))
|
||||
|
||||
(defn- make-selected-palette-item-ref
|
||||
|
@ -40,41 +47,40 @@
|
|||
(l/derived st/state)))
|
||||
|
||||
;; --- Components
|
||||
|
||||
(mf/defc palette-item
|
||||
[{:keys [color] :as props}]
|
||||
(let [rgb-vec (hex->rgb color)
|
||||
|
||||
select-color
|
||||
[{:keys [color size]}]
|
||||
(let [select-color
|
||||
(fn [event]
|
||||
(if (kbd/shift? event)
|
||||
(st/emit! (udw/update-color-on-selected-shapes {:stroke-color color}))
|
||||
(st/emit! (udw/update-color-on-selected-shapes {:fill-color color}))))]
|
||||
(st/emit! (udw/update-color-on-selected-shapes {:stroke-color (:value 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}
|
||||
[:span.color {:style {:background color}}]
|
||||
[:span.color-text color]]))
|
||||
[:span.color {:style {:background (:value color)}}]
|
||||
(when (= size :big) [:span.color-text (or (:name color) (:value color))])]))
|
||||
|
||||
(mf/defc palette
|
||||
[{:keys [palettes selected left-sidebar?] :as props}]
|
||||
(let [items-ref (mf/use-memo
|
||||
(mf/deps selected)
|
||||
(partial make-selected-palette-item-ref selected))
|
||||
|
||||
items (mf/deref items-ref)
|
||||
state (mf/use-state {:show-menu false })
|
||||
[{:keys [left-sidebar? current-colors recent-colors file-colors shared-libs selected size]}]
|
||||
(let [state (mf/use-state {:show-menu false })
|
||||
|
||||
width (:width @state 0)
|
||||
visible (mth/round (/ width 66))
|
||||
|
||||
offset (:offset @state 0)
|
||||
max-offset (- (count items)
|
||||
max-offset (- (count current-colors)
|
||||
visible)
|
||||
|
||||
close-fn #(st/emit! (udw/toggle-layout-flags :colorpalette))
|
||||
container (mf/use-ref nil)
|
||||
|
||||
locale (mf/deref i18n/locale)
|
||||
|
||||
on-left-arrow-click
|
||||
(mf/use-callback
|
||||
(mf/deps max-offset visible)
|
||||
|
@ -108,12 +114,8 @@
|
|||
(fn [event]
|
||||
(let [dom (mf/ref-val container)
|
||||
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
|
||||
#(let [dom (mf/ref-val container)
|
||||
|
@ -125,48 +127,116 @@
|
|||
(fn []
|
||||
(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")}
|
||||
[:& context-menu
|
||||
{:selectable true
|
||||
:selected (->> palettes
|
||||
(filter #(= (:id %) selected))
|
||||
first
|
||||
:name)
|
||||
:show (:show-menu @state)
|
||||
:on-close #(swap! state assoc :show-menu false)
|
||||
:options (mapv #(vector (:name %) (partial handle-click %)) palettes)}]
|
||||
[:& dropdown {:show (:show-menu @state)
|
||||
:on-close #(swap! state assoc :show-menu false)}
|
||||
[:ul.workspace-context-menu.palette-menu
|
||||
(for [cur-library (vals shared-libs)]
|
||||
(let [colors (-> cur-library (get-in [:data :colors]) vals)]
|
||||
[:li.palette-library
|
||||
{:on-click #(st/emit! (mdc/change-palette-selected (:id cur-library)))}
|
||||
(when (= selected (:id cur-library)) i/tick)
|
||||
[: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
|
||||
{:on-click #(swap! state assoc :show-menu true)}
|
||||
[:div.color-palette-actions-button i/actions]]
|
||||
|
||||
[: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"
|
||||
:right (str (* 66 offset) "px")}}
|
||||
(for [item items]
|
||||
[:& palette-item {:color (:content item) :key (:id item)}])]]
|
||||
(for [[idx item] (map-indexed vector current-colors)]
|
||||
[:& palette-item {:size size
|
||||
:color item
|
||||
:key idx}])]]
|
||||
|
||||
[: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
|
||||
[{:keys [left-sidebar? team-id] :as props}]
|
||||
(let [palettes (->> (mf/deref palettes-ref)
|
||||
(vals)
|
||||
(mapcat identity))
|
||||
selected (or (mf/deref selected-palette-ref)
|
||||
(:id (first palettes)))]
|
||||
[{:keys [left-sidebar? team-id]}]
|
||||
(let [recent-colors (mf/deref refs/workspace-recent-colors)
|
||||
file-colors (mf/deref refs/workspace-file-colors)
|
||||
shared-libs (mf/deref refs/workspace-libraries)
|
||||
selected (or (mf/deref selected-palette-ref) :recent)
|
||||
size (or (mf/deref selected-palette-size-ref) :big)
|
||||
|
||||
current-library-colors (mf/use-state [])]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps team-id)
|
||||
(fn []))
|
||||
;; (st/emit! (dlib/retrieve-libraries :palettes)
|
||||
;; (dlib/retrieve-libraries :palettes team-id))))
|
||||
(mf/deps selected)
|
||||
(fn []
|
||||
(reset! current-library-colors
|
||||
(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?
|
||||
:current-colors @current-library-colors
|
||||
:recent-colors recent-colors
|
||||
:file-colors file-colors
|
||||
:shared-libs shared-libs
|
||||
:selected selected
|
||||
:palettes palettes}]))
|
||||
:size size}]))
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
[app.common.math :as math]
|
||||
[app.common.uuid :refer [uuid]]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.colors :as dwc]
|
||||
[app.main.ui.modal :as modal]
|
||||
[okulary.core :as l]
|
||||
[app.main.refs :as refs]))
|
||||
[app.main.refs :as refs]
|
||||
[app.util.i18n :as i18n :refer [t]]))
|
||||
|
||||
;; --- Color Picker Modal
|
||||
|
||||
|
@ -100,9 +102,16 @@
|
|||
shared-libs (mf/deref refs/workspace-libraries)
|
||||
recent-colors (mf/deref refs/workspace-recent-colors)
|
||||
|
||||
locale (mf/deref i18n/locale)
|
||||
|
||||
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
|
||||
(mf/use-effect
|
||||
|
@ -140,7 +149,8 @@
|
|||
(mf/use-effect
|
||||
(mf/deps file-colors)
|
||||
(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
|
||||
(mf/use-effect
|
||||
|
@ -263,8 +273,8 @@
|
|||
(let [val (-> e dom/get-target dom/get-value)]
|
||||
(reset! selected-library val)))
|
||||
:value @selected-library}
|
||||
[:option {:value "recent"} "Recent colors"]
|
||||
[:option {:value "file"} "File library"]
|
||||
[:option {:value "recent"} (t locale "workspace.libraries.colors.recent-colors")]
|
||||
[:option {:value "file"} (t locale "workspace.libraries.colors.file-library")]
|
||||
(for [[_ {:keys [name id]}] shared-libs]
|
||||
[:option {:key id
|
||||
:value id} name])]
|
||||
|
@ -275,7 +285,8 @@
|
|||
:on-click #(st/emit! (dwl/add-color (:hex @current-color)))}
|
||||
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]
|
||||
|
||||
(for [[idx {:keys [id file-id value]}] (map-indexed vector @current-library-colors)]
|
||||
|
@ -298,7 +309,7 @@
|
|||
{:on-click (fn []
|
||||
(on-accept @value-ref)
|
||||
(modal/hide!))}
|
||||
"Save color"]])])
|
||||
(t locale "workspace.libraries.colors.save-color")]])])
|
||||
)
|
||||
|
||||
(mf/defc colorpicker-modal
|
||||
|
|
Loading…
Add table
Reference in a new issue