mirror of
https://github.com/penpot/penpot.git
synced 2025-06-21 19:16:59 +02:00
♻️ Add stricter validation for colors, fills and strokes
This commit is contained in:
parent
d08d2f49ac
commit
7160334cb9
42 changed files with 698 additions and 597 deletions
|
@ -16,17 +16,41 @@
|
|||
;; PRE DECODE
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn clean-shape-pre-decode
|
||||
"Applies a pre-decode phase migration to the shape"
|
||||
(defn- pre-clean-bool-content
|
||||
[shape]
|
||||
(if (= "bool" (:type shape))
|
||||
(if-let [content (get shape :bool-content)]
|
||||
(-> shape
|
||||
(assoc :content content)
|
||||
(dissoc :bool-content))
|
||||
shape)
|
||||
shape))
|
||||
|
||||
(defn- pre-clean-shadow-color
|
||||
[shape]
|
||||
(d/update-when shape :shadow
|
||||
(fn [shadows]
|
||||
(mapv (fn [shadow]
|
||||
(update shadow :color
|
||||
(fn [color]
|
||||
(let [ref-id (get color :id)
|
||||
ref-file (get color :file-id)]
|
||||
(-> (d/without-qualified color)
|
||||
(select-keys [:opacity :color :gradient :image :ref-id :ref-file])
|
||||
(cond-> ref-id
|
||||
(assoc :ref-id ref-id))
|
||||
(cond-> ref-file
|
||||
(assoc :ref-file ref-file)))))))
|
||||
shadows))))
|
||||
|
||||
(defn clean-shape-pre-decode
|
||||
"Applies a pre-decode phase migration to the shape"
|
||||
[shape]
|
||||
(cond-> shape
|
||||
(= "bool" (:type shape))
|
||||
(pre-clean-bool-content)
|
||||
|
||||
(contains? shape :shadow)
|
||||
(pre-clean-shadow-color)))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; POST DECODE
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
@ -113,7 +113,7 @@
|
|||
(sm/encoder ::ctc/component sm/json-transformer))
|
||||
|
||||
(def encode-color
|
||||
(sm/encoder ::ctcl/color sm/json-transformer))
|
||||
(sm/encoder ctcl/schema:library-color sm/json-transformer))
|
||||
|
||||
(def encode-typography
|
||||
(sm/encoder ::cty/typography sm/json-transformer))
|
||||
|
@ -142,7 +142,7 @@
|
|||
(sm/decoder ::ctc/component sm/json-transformer))
|
||||
|
||||
(def decode-color
|
||||
(sm/decoder ::ctcl/color sm/json-transformer))
|
||||
(sm/decoder ctcl/schema:library-color sm/json-transformer))
|
||||
|
||||
(def decode-file
|
||||
(sm/decoder schema:file sm/json-transformer))
|
||||
|
@ -186,7 +186,7 @@
|
|||
(sm/check-fn ::ctf/media))
|
||||
|
||||
(def validate-color
|
||||
(sm/check-fn ::ctcl/color))
|
||||
(sm/check-fn ctcl/schema:library-color))
|
||||
|
||||
(def validate-component
|
||||
(sm/check-fn ::ctc/component))
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
[app.common.schema.desc-native :as smd]
|
||||
[app.common.schema.generators :as sg]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.colors-list :as ctcl]
|
||||
[app.common.types.component :as ctk]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.container :as ctn]
|
||||
|
@ -266,7 +265,7 @@
|
|||
[:id ::sm/uuid]
|
||||
;; All props are optional, background can be nil because is the
|
||||
;; way to remove already set background
|
||||
[:background {:optional true} [:maybe ::ctc/rgb-color]]
|
||||
[:background {:optional true} [:maybe ctc/schema:hex-color]]
|
||||
[:name {:optional true} :string]]]
|
||||
|
||||
[:set-plugin-data schema:set-plugin-data-change]
|
||||
|
@ -292,12 +291,12 @@
|
|||
[:add-color
|
||||
[:map {:title "AddColorChange"}
|
||||
[:type [:= :add-color]]
|
||||
[:color ::ctc/color]]]
|
||||
[:color ctc/schema:library-color]]]
|
||||
|
||||
[:mod-color
|
||||
[:map {:title "ModColorChange"}
|
||||
[:type [:= :mod-color]]
|
||||
[:color ::ctc/color]]]
|
||||
[:color ctc/schema:library-color]]]
|
||||
|
||||
[:del-color
|
||||
[:map {:title "DelColorChange"}
|
||||
|
@ -926,15 +925,15 @@
|
|||
|
||||
(defmethod process-change :add-color
|
||||
[data {:keys [color]}]
|
||||
(ctcl/add-color data color))
|
||||
(ctc/add-color data color))
|
||||
|
||||
(defmethod process-change :mod-color
|
||||
[data {:keys [color]}]
|
||||
(ctcl/set-color data color))
|
||||
(ctc/set-color data color))
|
||||
|
||||
(defmethod process-change :del-color
|
||||
[data {:keys [id]}]
|
||||
(ctcl/delete-color data id))
|
||||
(ctc/delete-color data id))
|
||||
|
||||
;; DEPRECATED: remove before 2.3
|
||||
(defmethod process-change :add-recent-color
|
||||
|
|
|
@ -1004,14 +1004,11 @@
|
|||
(update :pages-index d/update-vals update-container)
|
||||
(d/update-when :components d/update-vals update-container))))
|
||||
|
||||
(def ^:private valid-color?
|
||||
(sm/lazy-validator ::ctc/color))
|
||||
|
||||
(defmethod migrate-data "legacy-51"
|
||||
[data _]
|
||||
(let [update-colors
|
||||
(fn [colors]
|
||||
(into {} (filter #(-> % val valid-color?) colors)))]
|
||||
(into {} (filter #(-> % val ctc/valid-color?) colors)))]
|
||||
(update data :colors update-colors)))
|
||||
|
||||
(defmethod migrate-data "legacy-52"
|
||||
|
@ -1328,7 +1325,6 @@
|
|||
(update :pages-index d/update-vals update-container)
|
||||
(d/update-when :components d/update-vals update-container))))
|
||||
|
||||
|
||||
(defmethod migrate-data "0004-add-partial-text-touched-flags"
|
||||
[data _]
|
||||
(letfn [(update-object [page object]
|
||||
|
@ -1369,7 +1365,7 @@
|
|||
object))
|
||||
|
||||
(update-container [container]
|
||||
(d/update-when container :objects update-vals update-object))]
|
||||
(d/update-when container :objects d/update-vals update-object))]
|
||||
|
||||
(-> data
|
||||
(update :pages-index d/update-vals update-container)
|
||||
|
@ -1407,6 +1403,33 @@
|
|||
(update :pages-index d/update-vals update-container)
|
||||
(d/update-when :components d/update-vals update-container))))
|
||||
|
||||
(defmethod migrate-data "0004-clean-shadow-and-colors"
|
||||
[data _]
|
||||
(letfn [(clean-shadow [shadow]
|
||||
(update shadow :color (fn [color]
|
||||
(let [ref-id (get color :id)
|
||||
ref-file (get color :file-id)]
|
||||
(-> (d/without-qualified color)
|
||||
(select-keys [:opacity :color :gradient :image :ref-id :ref-file])
|
||||
(cond-> ref-id
|
||||
(assoc :ref-id ref-id))
|
||||
(cond-> ref-file
|
||||
(assoc :ref-file ref-file)))))))
|
||||
|
||||
(update-object [object]
|
||||
(d/update-when object :shadow #(mapv clean-shadow %)))
|
||||
|
||||
(update-container [container]
|
||||
(d/update-when container :objects d/update-vals update-object))
|
||||
|
||||
(clean-library-color [color]
|
||||
(dissoc color :file-id))]
|
||||
|
||||
(-> data
|
||||
(update :pages-index d/update-vals update-container)
|
||||
(d/update-when :components d/update-vals update-container)
|
||||
(d/update-when :colors d/update-vals clean-library-color))))
|
||||
|
||||
(def available-migrations
|
||||
(into (d/ordered-set)
|
||||
["legacy-2"
|
||||
|
@ -1467,5 +1490,6 @@
|
|||
"0003-fix-root-shape"
|
||||
"0003-convert-path-content"
|
||||
"0004-add-partial-text-touched-flags"
|
||||
"0004-clean-shadow-and-colors"
|
||||
"0005-deprecate-image-type"
|
||||
"0006-fix-old-texts-fills"]))
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
(:refer-clojure :exclude [set subseq uuid filter map let boolean vector keyword int double])
|
||||
#?(:cljs (:require-macros [app.common.schema.generators]))
|
||||
(:require
|
||||
[app.common.math :as mth]
|
||||
[app.common.schema.registry :as sr]
|
||||
[app.common.uri :as u]
|
||||
[app.common.math :as mth]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.core :as c]
|
||||
[clojure.test.check.generators :as tg]
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
(ns app.common.test-helpers.shapes
|
||||
(:require
|
||||
[app.common.colors :as clr]
|
||||
[app.common.data :as d]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.test-helpers.files :as thf]
|
||||
[app.common.test-helpers.ids-map :as thi]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.colors-list :as ctcl]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.types.shape :as cts]
|
||||
|
@ -81,9 +81,16 @@
|
|||
(:id page)
|
||||
#(ctst/set-shape % (ctn/set-shape-attr shape attr val)))))))
|
||||
|
||||
(defn sample-color
|
||||
[label & {:keys [] :as params}]
|
||||
(ctc/make-color (assoc params :id (thi/new-id! label))))
|
||||
(defn sample-library-color
|
||||
[label & {:keys [name path color opacity gradient image]}]
|
||||
(-> {:id (thi/new-id! label)
|
||||
:name (or name color "Black")
|
||||
:path path
|
||||
:color (or color "#000000")
|
||||
:opacity (or opacity 1)
|
||||
:gradient gradient
|
||||
:image image}
|
||||
(d/without-nils)))
|
||||
|
||||
(defn sample-fill-color
|
||||
[& {:keys [fill-color fill-opacity] :as params}]
|
||||
|
@ -101,8 +108,8 @@
|
|||
|
||||
(defn add-sample-library-color
|
||||
[file label & {:keys [] :as params}]
|
||||
(let [color (sample-color label params)]
|
||||
(update file :data ctcl/add-color color)))
|
||||
(let [color (sample-library-color label params)]
|
||||
(update file :data ctc/add-color color)))
|
||||
|
||||
(defn sample-typography
|
||||
[label & {:keys [] :as params}]
|
||||
|
|
|
@ -208,9 +208,13 @@
|
|||
([data] (encode-str data nil))
|
||||
([data opts]
|
||||
#?(:cljs
|
||||
(let [t (:type opts :json)
|
||||
w (t/writer t {:handlers @write-handler-map})]
|
||||
(t/write w data))
|
||||
(let [type (:type opts :json)
|
||||
params {:handlers @write-handler-map}
|
||||
params (if (:with-meta opts)
|
||||
(assoc params :transform t/write-meta)
|
||||
params)
|
||||
writer (t/writer type params)]
|
||||
(t/write writer data))
|
||||
:clj
|
||||
(->> (encode data opts)
|
||||
(bytes->str)))))
|
||||
|
@ -219,9 +223,10 @@
|
|||
([data] (decode-str data nil))
|
||||
([data opts]
|
||||
#?(:cljs
|
||||
(let [t (:type opts :json)
|
||||
r (t/reader t {:handlers @read-handler-map})]
|
||||
(t/read r data))
|
||||
(let [type (:type opts :json)
|
||||
params {:handlers @read-handler-map}
|
||||
reader (t/reader type params)]
|
||||
(t/read reader data))
|
||||
:clj
|
||||
(-> (str->bytes data)
|
||||
(decode opts)))))
|
||||
|
|
|
@ -8,23 +8,36 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.media :as cm]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.schema.generators :as sg]
|
||||
[app.common.schema.openapi :as-alias oapi]
|
||||
[app.common.text :as txt]
|
||||
[app.common.time :as dt]
|
||||
[app.common.types.plugins :as ctpg]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.set :as set]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; SCHEMAS & TYPES
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(def rgb-color-re
|
||||
(def valid-color-attrs
|
||||
"A set used for proper check if color should contain only one of the
|
||||
attrs listed in this set."
|
||||
#{:image :gradient :color})
|
||||
|
||||
(defn has-valid-color-attrs?
|
||||
"Check if color has correct color attrs"
|
||||
[color]
|
||||
(let [attrs (set (keys color))
|
||||
result (set/intersection attrs valid-color-attrs)]
|
||||
(= 1 (count result))))
|
||||
|
||||
(def ^:private hex-color-rx
|
||||
#"^#(?:[0-9a-fA-F]{3}){1,2}$")
|
||||
|
||||
(defn- generate-rgb-color
|
||||
[]
|
||||
(def ^:private hex-color-generator
|
||||
(sg/fmap (fn [_]
|
||||
#?(:clj (format "#%06x" (rand-int 16rFFFFFF))
|
||||
:cljs
|
||||
|
@ -37,38 +50,44 @@
|
|||
(.. b (toString 16) (padStart 2 "0"))))))
|
||||
sg/int))
|
||||
|
||||
(defn rgb-color-string?
|
||||
(defn hex-color-string?
|
||||
[o]
|
||||
(and (string? o) (some? (re-matches rgb-color-re o))))
|
||||
(and (string? o) (some? (re-matches hex-color-rx o))))
|
||||
|
||||
(def schema:rgb-color
|
||||
(def schema:hex-color
|
||||
(sm/register!
|
||||
{:type ::rgb-color
|
||||
:pred rgb-color-string?
|
||||
{:type ::hex-color
|
||||
:pred hex-color-string?
|
||||
:type-properties
|
||||
{:title "rgb-color"
|
||||
:description "RGB Color String"
|
||||
:error/message "expected a valid RGB color"
|
||||
:error/code "errors.invalid-rgb-color"
|
||||
:gen/gen (generate-rgb-color)
|
||||
{:title "hex-color"
|
||||
:description "HEX Color String"
|
||||
:error/message "expected a valid HEX color"
|
||||
:error/code "errors.invalid-hex-color"
|
||||
:gen/gen hex-color-generator
|
||||
::oapi/type "integer"
|
||||
::oapi/format "int64"}}))
|
||||
|
||||
(def schema:plain-color
|
||||
[:map [:color schema:hex-color]])
|
||||
|
||||
(def schema:image
|
||||
[:map {:title "ImageColor"}
|
||||
[:width ::sm/int]
|
||||
[:height ::sm/int]
|
||||
[:mtype ::sm/text]
|
||||
[:map {:title "ImageColor" :closed true}
|
||||
[:width [::sm/int {:min 0 :gen/gen sg/int}]]
|
||||
[:height [::sm/int {:min 0 :gen/gen sg/int}]]
|
||||
[:mtype {:gen/gen (sg/elements cm/image-types)} ::sm/text]
|
||||
[:id ::sm/uuid]
|
||||
[:name {:optional true} ::sm/text]
|
||||
[:keep-aspect-ratio {:optional true} :boolean]])
|
||||
|
||||
(def schema:image-color
|
||||
[:map [:image schema:image]])
|
||||
|
||||
(def gradient-types
|
||||
#{:linear :radial})
|
||||
|
||||
(def schema:gradient
|
||||
[:map {:title "Gradient"}
|
||||
[:type [::sm/one-of #{:linear :radial}]]
|
||||
[:map {:title "Gradient" :closed true}
|
||||
[:type [::sm/one-of gradient-types]]
|
||||
[:start-x ::sm/safe-number]
|
||||
[:start-y ::sm/safe-number]
|
||||
[:end-x ::sm/safe-number]
|
||||
|
@ -77,86 +96,79 @@
|
|||
[:stops
|
||||
[:vector {:min 1 :gen/max 2}
|
||||
[:map {:title "GradientStop"}
|
||||
[:color schema:rgb-color]
|
||||
[:opacity {:optional true} [:maybe ::sm/safe-number]]
|
||||
[:color schema:hex-color]
|
||||
[:opacity {:optional true} [::sm/number {:min 0 :max 1}]]
|
||||
[:offset ::sm/safe-number]]]]])
|
||||
|
||||
(def schema:gradient-color
|
||||
[:map [:gradient schema:gradient]])
|
||||
|
||||
(def schema:color-attrs
|
||||
[:map {:title "ColorAttrs"}
|
||||
[:id {:optional true} ::sm/uuid]
|
||||
[:name {:optional true} :string]
|
||||
[:path {:optional true} [:maybe :string]]
|
||||
[:value {:optional true} [:maybe :string]]
|
||||
[:color {:optional true} [:maybe schema:rgb-color]]
|
||||
[:opacity {:optional true} [:maybe ::sm/safe-number]]
|
||||
[:modified-at {:optional true} ::sm/inst]
|
||||
[:map {:title "ColorAttrs" :closed true}
|
||||
[:opacity {:optional true} [::sm/number {:min 0 :max 1}]]
|
||||
[:ref-id {:optional true} ::sm/uuid]
|
||||
[:ref-file {:optional true} ::sm/uuid]
|
||||
[:gradient {:optional true} [:maybe schema:gradient]]
|
||||
[:image {:optional true} [:maybe schema:image]]
|
||||
[:plugin-data {:optional true} ::ctpg/plugin-data]])
|
||||
[:ref-file {:optional true} ::sm/uuid]])
|
||||
|
||||
(def schema:color
|
||||
[:and schema:color-attrs
|
||||
[::sm/contains-any {:strict true} [:color :gradient :image]]])
|
||||
|
||||
(def schema:recent-color
|
||||
[:and
|
||||
[:map {:title "RecentColor"}
|
||||
[:opacity {:optional true} [:maybe ::sm/safe-number]]
|
||||
[:color {:optional true} [:maybe schema:rgb-color]]
|
||||
[:gradient {:optional true} [:maybe schema:gradient]]
|
||||
[:image {:optional true} [:maybe schema:image]]]
|
||||
[::sm/contains-any {:strict true} [:color :gradient :image]]])
|
||||
[:merge {:title "Color"}
|
||||
schema:color-attrs
|
||||
(sm/optional-keys schema:plain-color)
|
||||
(sm/optional-keys schema:gradient-color)
|
||||
(sm/optional-keys schema:image-color)]
|
||||
[:fn has-valid-color-attrs?]])
|
||||
|
||||
(def schema:library-color-attrs
|
||||
[:map {:title "ColorAttrs" :closed true}
|
||||
[:id ::sm/uuid]
|
||||
[:name ::sm/text]
|
||||
[:path {:optional true} :string]
|
||||
[:opacity {:optional true} [::sm/number {:min 0 :max 1}]]
|
||||
[:modified-at {:optional true} ::sm/inst]
|
||||
[:plugin-data {:optional true} ::ctpg/plugin-data]])
|
||||
|
||||
;; Same as color but with :id prop required
|
||||
(def schema:library-color
|
||||
"Used for in-transit representation of a color (per example when user
|
||||
clicks a color on assets sidebar, the color should be properly identified with
|
||||
the file-id where it belongs)"
|
||||
[:and
|
||||
(sm/required-keys schema:color-attrs [:id])
|
||||
[::sm/contains-any {:strict true} [:color :gradient :image]]])
|
||||
|
||||
;; FIXME: revisit if we really need this all registers
|
||||
(sm/register! ::color schema:color)
|
||||
(sm/register! ::gradient schema:gradient)
|
||||
(sm/register! ::image-color schema:image)
|
||||
(sm/register! ::recent-color schema:recent-color)
|
||||
(sm/register! ::color-attrs schema:color-attrs)
|
||||
[:merge
|
||||
schema:library-color-attrs
|
||||
(sm/optional-keys schema:plain-color)
|
||||
(sm/optional-keys schema:gradient-color)
|
||||
(sm/optional-keys schema:image-color)]
|
||||
[:fn has-valid-color-attrs?]])
|
||||
|
||||
(def valid-color?
|
||||
(sm/lazy-validator schema:color))
|
||||
|
||||
(def valid-library-color?
|
||||
(sm/lazy-validator schema:library-color))
|
||||
|
||||
(def check-color
|
||||
(sm/check-fn schema:color :hint "expected valid color"))
|
||||
|
||||
(def check-library-color
|
||||
(sm/check-fn schema:library-color :hint "expected valid library color"))
|
||||
|
||||
(def check-recent-color
|
||||
(sm/check-fn schema:recent-color :hint "expected valid recent color"))
|
||||
(sm/check-fn schema:library-color :hint "expected valid color"))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; HELPERS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; --- factory
|
||||
|
||||
(defn make-color
|
||||
[{:keys [id name path value color opacity ref-id ref-file gradient image]}]
|
||||
(-> {:id (or id (uuid/next))
|
||||
:name (or name color "Black")
|
||||
:path path
|
||||
:value value
|
||||
:color (or color "#000000")
|
||||
:opacity (or opacity 1)
|
||||
:ref-id ref-id
|
||||
:ref-file ref-file
|
||||
:gradient gradient
|
||||
:image image}
|
||||
(d/without-nils)))
|
||||
(defn library-color->color
|
||||
"Converts a library color data structure to a plain color data structure"
|
||||
[lcolor file-id]
|
||||
(-> lcolor
|
||||
(select-keys [:image :gradient :color :opacity])
|
||||
(assoc :ref-id (get lcolor :id))
|
||||
(assoc :ref-file file-id)
|
||||
(vary-meta assoc
|
||||
:path (get lcolor :path)
|
||||
:name (get lcolor :name))))
|
||||
|
||||
;; --- fill
|
||||
|
||||
(defn fill->shape-color
|
||||
(defn fill->color
|
||||
[fill]
|
||||
(d/without-nils
|
||||
{:color (:fill-color fill)
|
||||
|
@ -178,21 +190,22 @@
|
|||
|
||||
(defn attach-fill-color
|
||||
[shape position ref-id ref-file]
|
||||
(-> shape
|
||||
(assoc-in [:fills position :fill-color-ref-id] ref-id)
|
||||
(assoc-in [:fills position :fill-color-ref-file] ref-file)))
|
||||
(d/update-in-when shape [:fills position]
|
||||
(fn [fill]
|
||||
(-> fill
|
||||
(assoc :fill-color-ref-file ref-file)
|
||||
(assoc :fill-color-ref-id ref-id)))))
|
||||
|
||||
(defn detach-fill-color
|
||||
[shape position]
|
||||
(-> shape
|
||||
(d/dissoc-in [:fills position :fill-color-ref-id])
|
||||
(d/dissoc-in [:fills position :fill-color-ref-file])))
|
||||
(d/update-in-when shape [:fills position] dissoc :fill-color-ref-id :fill-color-ref-file))
|
||||
|
||||
;; stroke
|
||||
|
||||
(defn stroke->shape-color
|
||||
(defn stroke->color
|
||||
[stroke]
|
||||
(d/without-nils {:color (:stroke-color stroke)
|
||||
(d/without-nils
|
||||
{:color (str/lower (:stroke-color stroke))
|
||||
:opacity (:stroke-opacity stroke)
|
||||
:gradient (:stroke-color-gradient stroke)
|
||||
:image (:stroke-image stroke)
|
||||
|
@ -201,103 +214,106 @@
|
|||
|
||||
(defn set-stroke-color
|
||||
[shape position color opacity gradient image]
|
||||
(update-in shape [:strokes position]
|
||||
(d/update-in-when shape [:strokes position]
|
||||
(fn [stroke]
|
||||
(d/without-nils (assoc stroke
|
||||
:stroke-color color
|
||||
:stroke-opacity opacity
|
||||
:stroke-color-gradient gradient
|
||||
:stroke-image image)))))
|
||||
(-> stroke
|
||||
(assoc :stroke-color color)
|
||||
(assoc :stroke-opacity opacity)
|
||||
(assoc :stroke-color-gradient gradient)
|
||||
(assoc :stroke-image image)
|
||||
(d/without-nils)))))
|
||||
|
||||
(defn attach-stroke-color
|
||||
[shape position ref-id ref-file]
|
||||
(-> shape
|
||||
(assoc-in [:strokes position :stroke-color-ref-id] ref-id)
|
||||
(assoc-in [:strokes position :stroke-color-ref-file] ref-file)))
|
||||
(d/update-in-when shape [:strokes position]
|
||||
(fn [stroke]
|
||||
(-> stroke
|
||||
(assoc :stroke-color-ref-id ref-id)
|
||||
(assoc :stroke-color-ref-file ref-file)))))
|
||||
|
||||
(defn detach-stroke-color
|
||||
[shape position]
|
||||
(-> shape
|
||||
(d/dissoc-in [:strokes position :stroke-color-ref-id])
|
||||
(d/dissoc-in [:strokes position :stroke-color-ref-file])))
|
||||
(d/update-in-when shape [:strokes position] dissoc :stroke-color-ref-id :stroke-color-ref-file))
|
||||
|
||||
;; shadow
|
||||
|
||||
(defn shadow->shape-color
|
||||
(defn shadow->color
|
||||
[shadow]
|
||||
(d/without-nils {:color (-> shadow :color :color)
|
||||
:opacity (-> shadow :color :opacity)
|
||||
:gradient (-> shadow :color :gradient)
|
||||
:ref-id (-> shadow :color :id)
|
||||
:ref-file (-> shadow :color :file-id)}))
|
||||
(:color shadow))
|
||||
|
||||
(defn set-shadow-color
|
||||
[shape position color opacity gradient]
|
||||
(update-in shape [:shadow position :color]
|
||||
(d/update-in-when shape [:shadow position :color]
|
||||
(fn [shadow-color]
|
||||
(d/without-nils (assoc shadow-color
|
||||
:color color
|
||||
:opacity opacity
|
||||
:gradient gradient)))))
|
||||
(-> shadow-color
|
||||
(assoc :color color)
|
||||
(assoc :opacity opacity)
|
||||
(assoc :gradient gradient)
|
||||
(d/without-nils)))))
|
||||
|
||||
(defn attach-shadow-color
|
||||
[shape position ref-id ref-file]
|
||||
(-> shape
|
||||
(assoc-in [:shadow position :color :id] ref-id)
|
||||
(assoc-in [:shadow position :color :file-id] ref-file)))
|
||||
(d/update-in-when shape [:shadow position :color]
|
||||
(fn [color]
|
||||
(-> color
|
||||
(assoc :ref-id ref-id)
|
||||
(assoc :ref-file ref-file)))))
|
||||
|
||||
(defn detach-shadow-color
|
||||
[shape position]
|
||||
(-> shape
|
||||
(d/dissoc-in [:shadow position :color :id])
|
||||
(d/dissoc-in [:shadow position :color :file-id])))
|
||||
(d/update-in-when shape [:shadow position :color] dissoc :ref-id :ref-file))
|
||||
|
||||
;; grid
|
||||
|
||||
(defn grid->shape-color
|
||||
;: FIXME: revisit colors...... WTF
|
||||
(defn grid->color
|
||||
[grid]
|
||||
(d/without-nils {:color (-> grid :params :color :color)
|
||||
:opacity (-> grid :params :color :opacity)
|
||||
:gradient (-> grid :params :color :gradient)
|
||||
:ref-id (-> grid :params :color :id)
|
||||
:ref-file (-> grid :params :color :file-id)}))
|
||||
(let [color (-> grid :params :color)]
|
||||
(d/without-nils
|
||||
{:color (-> color :color)
|
||||
:opacity (-> color :opacity)
|
||||
:gradient (-> color :gradient)
|
||||
:ref-id (-> color :id)
|
||||
:ref-file (-> color :file-id)})))
|
||||
|
||||
(defn set-grid-color
|
||||
[shape position color opacity gradient]
|
||||
(update-in shape [:grids position :params :color]
|
||||
(d/update-in-when shape [:grids position :params :color]
|
||||
(fn [grid-color]
|
||||
(d/without-nils (assoc grid-color
|
||||
:color color
|
||||
:opacity opacity
|
||||
:gradient gradient)))))
|
||||
(-> grid-color
|
||||
(assoc :color color)
|
||||
(assoc :opacity opacity)
|
||||
(assoc :gradient gradient)
|
||||
(d/without-nils)))))
|
||||
|
||||
(defn attach-grid-color
|
||||
[shape position ref-id ref-file]
|
||||
(-> shape
|
||||
(assoc-in [:grids position :params :color :id] ref-id)
|
||||
(assoc-in [:grids position :params :color :file-id] ref-file)))
|
||||
(d/update-in-when shape [:grids position :params :color]
|
||||
(fn [color]
|
||||
(-> color
|
||||
(assoc :ref-id ref-id)
|
||||
(assoc :ref-file ref-file)))))
|
||||
|
||||
(defn detach-grid-color
|
||||
[shape position]
|
||||
(-> shape
|
||||
(d/dissoc-in [:grids position :params :color :id])
|
||||
(d/dissoc-in [:grids position :params :color :file-id])))
|
||||
(d/update-in-when shape [:grids position :params :color] dissoc :ref-id :ref-file))
|
||||
|
||||
;; --- Helpers for all colors in a shape
|
||||
|
||||
(defn get-text-node-colors
|
||||
"Get all colors used by a node of a text shape"
|
||||
[node]
|
||||
(concat (map fill->shape-color (:fills node))
|
||||
(map stroke->shape-color (:strokes node))))
|
||||
(concat (map fill->color (:fills node))
|
||||
(map stroke->color (:strokes node))))
|
||||
|
||||
(defn get-all-colors
|
||||
"Get all colors used by a shape, in any section."
|
||||
[shape]
|
||||
(concat (map fill->shape-color (:fills shape))
|
||||
(map stroke->shape-color (:strokes shape))
|
||||
(map shadow->shape-color (:shadow shape))
|
||||
(concat (map fill->color (:fills shape))
|
||||
(map stroke->color (:strokes shape))
|
||||
(map shadow->color (:shadow shape))
|
||||
(when (= (:type shape) :frame)
|
||||
(map grid->shape-color (:grids shape)))
|
||||
(map grid->color (:grids shape)))
|
||||
(when (= (:type shape) :text)
|
||||
(reduce (fn [colors node]
|
||||
(concat colors (get-text-node-colors node)))
|
||||
|
@ -326,7 +342,7 @@
|
|||
(let [process-fill (fn [shape [position fill]]
|
||||
(process-fn shape
|
||||
position
|
||||
(fill->shape-color fill)
|
||||
(fill->color fill)
|
||||
set-fill-color
|
||||
attach-fill-color
|
||||
detach-fill-color))
|
||||
|
@ -334,7 +350,7 @@
|
|||
process-stroke (fn [shape [position stroke]]
|
||||
(process-fn shape
|
||||
position
|
||||
(stroke->shape-color stroke)
|
||||
(stroke->color stroke)
|
||||
set-stroke-color
|
||||
attach-stroke-color
|
||||
detach-stroke-color))
|
||||
|
@ -342,7 +358,7 @@
|
|||
process-shadow (fn [shape [position shadow]]
|
||||
(process-fn shape
|
||||
position
|
||||
(shadow->shape-color shadow)
|
||||
(shadow->color shadow)
|
||||
set-shadow-color
|
||||
attach-shadow-color
|
||||
detach-shadow-color))
|
||||
|
@ -350,7 +366,7 @@
|
|||
process-grid (fn [shape [position grid]]
|
||||
(process-fn shape
|
||||
position
|
||||
(grid->shape-color grid)
|
||||
(grid->color grid)
|
||||
set-grid-color
|
||||
attach-grid-color
|
||||
detach-grid-color))
|
||||
|
@ -407,114 +423,76 @@
|
|||
|
||||
(process-shape-colors shape sync-color)))
|
||||
|
||||
(defn- eq-recent-color?
|
||||
[c1 c2]
|
||||
(or (= c1 c2)
|
||||
(and (some? (:color c1))
|
||||
(some? (:color c2))
|
||||
(= (:color c1) (:color c2)))))
|
||||
|
||||
(defn add-recent-color
|
||||
"Moves the color to the top of the list and then truncates up to 15"
|
||||
[state file-id color]
|
||||
(update state file-id (fn [colors]
|
||||
(let [colors (d/removev (partial eq-recent-color? color) colors)
|
||||
colors (conj colors color)]
|
||||
(cond-> colors
|
||||
(> (count colors) 15)
|
||||
(subvec 1))))))
|
||||
|
||||
(defn stroke->color-att
|
||||
[stroke file-id shared-libs]
|
||||
(let [color-file-id (:stroke-color-ref-file stroke)
|
||||
color-id (:stroke-color-ref-id stroke)
|
||||
shared-libs-colors (dm/get-in shared-libs [color-file-id :data :colors])
|
||||
is-shared? (contains? shared-libs-colors color-id)
|
||||
has-color? (or (not (nil? (:stroke-color stroke))) (not (nil? (:stroke-color-gradient stroke))))
|
||||
attrs (if (or is-shared? (= color-file-id file-id))
|
||||
(d/without-nils {:color (str/lower (:stroke-color stroke))
|
||||
:opacity (:stroke-opacity stroke)
|
||||
:id color-id
|
||||
:file-id color-file-id
|
||||
:gradient (:stroke-color-gradient stroke)})
|
||||
(d/without-nils {:color (str/lower (:stroke-color stroke))
|
||||
:opacity (:stroke-opacity stroke)
|
||||
:gradient (:stroke-color-gradient stroke)}))]
|
||||
(defn- stroke->color-att
|
||||
[stroke file-id libraries]
|
||||
(let [ref-file (:stroke-color-ref-file stroke)
|
||||
ref-id (:stroke-color-ref-id stroke)
|
||||
shared-colors (dm/get-in libraries [ref-file :data :colors])
|
||||
is-shared? (contains? shared-colors ref-id)
|
||||
has-color? (or (:stroke-color stroke)
|
||||
(:stroke-color-gradient stroke))
|
||||
attrs (cond-> (stroke->color stroke)
|
||||
(not (or is-shared? (= ref-file file-id)))
|
||||
(dissoc :ref-id :ref-file))]
|
||||
(when has-color?
|
||||
{:attrs attrs
|
||||
:prop :stroke
|
||||
:shape-id (:shape-id stroke)
|
||||
:index (:index stroke)})))
|
||||
|
||||
(defn shadow->color-att
|
||||
[shadow file-id shared-libs]
|
||||
(let [color-file-id (dm/get-in shadow [:color :file-id])
|
||||
color-id (dm/get-in shadow [:color :id])
|
||||
shared-libs-colors (dm/get-in shared-libs [color-file-id :data :colors])
|
||||
is-shared? (contains? shared-libs-colors color-id)
|
||||
attrs (if (or is-shared? (= color-file-id file-id))
|
||||
(d/without-nils {:color (str/lower (dm/get-in shadow [:color :color]))
|
||||
:opacity (dm/get-in shadow [:color :opacity])
|
||||
:id color-id
|
||||
:file-id (dm/get-in shadow [:color :file-id])
|
||||
:gradient (dm/get-in shadow [:color :gradient])})
|
||||
(d/without-nils {:color (str/lower (dm/get-in shadow [:color :color]))
|
||||
:opacity (dm/get-in shadow [:color :opacity])
|
||||
:gradient (dm/get-in shadow [:color :gradient])}))]
|
||||
|
||||
|
||||
(defn- shadow->color-att
|
||||
[shadow file-id libraries]
|
||||
(let [color (get shadow :color)
|
||||
ref-file (get color :ref-file)
|
||||
ref-id (get color :ref-id)
|
||||
shared-colors (dm/get-in libraries [ref-file :data :colors])
|
||||
is-shared? (contains? shared-colors ref-id)
|
||||
attrs (cond-> (shadow->color shadow)
|
||||
(not (or is-shared? (= ref-file file-id)))
|
||||
(dissoc :ref-file :ref-id))]
|
||||
{:attrs attrs
|
||||
:prop :shadow
|
||||
:shape-id (:shape-id shadow)
|
||||
:index (:index shadow)}))
|
||||
|
||||
(defn text->color-att
|
||||
[fill file-id shared-libs]
|
||||
(let [color-file-id (:fill-color-ref-file fill)
|
||||
color-id (:fill-color-ref-id fill)
|
||||
shared-libs-colors (dm/get-in shared-libs [color-file-id :data :colors])
|
||||
is-shared? (contains? shared-libs-colors color-id)
|
||||
attrs (if (or is-shared? (= color-file-id file-id))
|
||||
(d/without-nils {:color (str/lower (:fill-color fill))
|
||||
:opacity (:fill-opacity fill)
|
||||
:id color-id
|
||||
:file-id color-file-id
|
||||
:gradient (:fill-color-gradient fill)})
|
||||
(d/without-nils {:color (str/lower (:fill-color fill))
|
||||
:opacity (:fill-opacity fill)
|
||||
:gradient (:fill-color-gradient fill)}))]
|
||||
(defn- text->color-att
|
||||
[fill file-id libraries]
|
||||
(let [ref-file (:fill-color-ref-file fill)
|
||||
ref-id (:fill-color-ref-id fill)
|
||||
shared-colors (dm/get-in libraries [ref-file :data :colors])
|
||||
is-shared? (contains? shared-colors ref-id)
|
||||
attrs (cond-> (fill->color fill)
|
||||
(not (or is-shared? (= ref-file file-id)))
|
||||
(dissoc :ref-file :ref-id))]
|
||||
|
||||
{:attrs attrs
|
||||
:prop :content
|
||||
:shape-id (:shape-id fill)
|
||||
:index (:index fill)}))
|
||||
|
||||
(defn treat-node
|
||||
(defn- treat-node
|
||||
[node shape-id]
|
||||
(map-indexed #(assoc %2 :shape-id shape-id :index %1) node))
|
||||
|
||||
(defn extract-text-colors
|
||||
[text file-id shared-libs]
|
||||
(let [content (txt/node-seq txt/is-text-node? (:content text))
|
||||
content-filtered (map :fills content)
|
||||
indexed (mapcat #(treat-node % (:id text)) content-filtered)]
|
||||
(map #(text->color-att % file-id shared-libs) indexed)))
|
||||
(defn- extract-text-colors
|
||||
[text file-id libraries]
|
||||
(->> (txt/node-seq txt/is-text-node? (:content text))
|
||||
(map :fills)
|
||||
(mapcat #(treat-node % (:id text)))
|
||||
(map #(text->color-att % file-id libraries))))
|
||||
|
||||
(defn- fill->color-att
|
||||
[fill file-id libraries]
|
||||
(let [ref-file (:fill-color-ref-file fill)
|
||||
ref-id (:fill-color-ref-id fill)
|
||||
shared-colors (dm/get-in libraries [ref-file :data :colors])
|
||||
is-shared? (contains? shared-colors ref-id)
|
||||
has-color? (or (:fill-color fill)
|
||||
(:fill-color-gradient fill))
|
||||
attrs (cond-> (fill->color fill)
|
||||
(not (or is-shared? (= ref-file file-id)))
|
||||
(dissoc :ref-file :ref-id))]
|
||||
|
||||
(defn fill->color-att
|
||||
[fill file-id shared-libs]
|
||||
(let [color-file-id (:fill-color-ref-file fill)
|
||||
color-id (:fill-color-ref-id fill)
|
||||
shared-libs-colors (dm/get-in shared-libs [color-file-id :data :colors])
|
||||
is-shared? (contains? shared-libs-colors color-id)
|
||||
has-color? (or (not (nil? (:fill-color fill))) (not (nil? (:fill-color-gradient fill))))
|
||||
attrs (if (or is-shared? (= color-file-id file-id))
|
||||
(d/without-nils {:color (str/lower (:fill-color fill))
|
||||
:opacity (:fill-opacity fill)
|
||||
:id color-id
|
||||
:file-id color-file-id
|
||||
:gradient (:fill-color-gradient fill)})
|
||||
(d/without-nils {:color (str/lower (:fill-color fill))
|
||||
:opacity (:fill-opacity fill)
|
||||
:gradient (:fill-color-gradient fill)}))]
|
||||
(when has-color?
|
||||
{:attrs attrs
|
||||
:prop :fill
|
||||
|
@ -522,21 +500,67 @@
|
|||
:index (:index fill)})))
|
||||
|
||||
(defn extract-all-colors
|
||||
[shapes file-id shared-libs]
|
||||
[shapes file-id libraries]
|
||||
(reduce
|
||||
(fn [list shape]
|
||||
(fn [result shape]
|
||||
(let [fill-obj (map-indexed #(assoc %2 :shape-id (:id shape) :index %1) (:fills shape))
|
||||
stroke-obj (map-indexed #(assoc %2 :shape-id (:id shape) :index %1) (:strokes shape))
|
||||
shadow-obj (map-indexed #(assoc %2 :shape-id (:id shape) :index %1) (:shadow shape))]
|
||||
(if (= :text (:type shape))
|
||||
(-> list
|
||||
(into (map #(stroke->color-att % file-id shared-libs)) stroke-obj)
|
||||
(into (map #(shadow->color-att % file-id shared-libs)) shadow-obj)
|
||||
(into (extract-text-colors shape file-id shared-libs)))
|
||||
(-> result
|
||||
(into (map #(stroke->color-att % file-id libraries)) stroke-obj)
|
||||
(into (map #(shadow->color-att % file-id libraries)) shadow-obj)
|
||||
(into (extract-text-colors shape file-id libraries)))
|
||||
|
||||
(-> list
|
||||
(into (map #(fill->color-att % file-id shared-libs)) fill-obj)
|
||||
(into (map #(stroke->color-att % file-id shared-libs)) stroke-obj)
|
||||
(into (map #(shadow->color-att % file-id shared-libs)) shadow-obj)))))
|
||||
(-> result
|
||||
(into (map #(fill->color-att % file-id libraries)) fill-obj)
|
||||
(into (map #(stroke->color-att % file-id libraries)) stroke-obj)
|
||||
(into (map #(shadow->color-att % file-id libraries)) shadow-obj)))))
|
||||
[]
|
||||
shapes))
|
||||
|
||||
(defn colors-seq
|
||||
[file-data]
|
||||
(vals (:colors file-data)))
|
||||
|
||||
(defn- touch
|
||||
[color]
|
||||
(assoc color :modified-at (dt/now)))
|
||||
|
||||
(defn add-color
|
||||
[file-data color]
|
||||
(update file-data :colors assoc (:id color) (touch color)))
|
||||
|
||||
(defn get-color
|
||||
[file-data color-id]
|
||||
(get-in file-data [:colors color-id]))
|
||||
|
||||
(defn get-ref-color
|
||||
[library-data color]
|
||||
(when (= (:ref-file color) (:id library-data))
|
||||
(get-color library-data (:ref-id color))))
|
||||
|
||||
(defn set-color
|
||||
[file-data color]
|
||||
(d/assoc-in-when file-data [:colors (:id color)] (touch color)))
|
||||
|
||||
(defn update-color
|
||||
[file-data color-id f & args]
|
||||
(d/update-in-when file-data [:colors color-id] #(-> (apply f % args)
|
||||
(touch))))
|
||||
|
||||
(defn delete-color
|
||||
[file-data color-id]
|
||||
(update file-data :colors dissoc color-id))
|
||||
|
||||
(defn used-colors-changed-since
|
||||
"Find all usages of any color in the library by the given shape, of colors
|
||||
that have ben modified after the date."
|
||||
[shape library since-date]
|
||||
(->> (get-all-colors shape)
|
||||
(keep #(get-ref-color (:data library) %))
|
||||
(remove #(< (:modified-at %) since-date)) ;; Note that :modified-at may be nil
|
||||
(map (fn [color] {:shape-id (:id shape)
|
||||
:asset-id (:id color)
|
||||
:asset-type :color}))))
|
||||
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.common.types.colors-list
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.time :as dt]
|
||||
[app.common.types.color :as ctc]))
|
||||
|
||||
(defn colors-seq
|
||||
[file-data]
|
||||
(vals (:colors file-data)))
|
||||
|
||||
(defn- touch
|
||||
[color]
|
||||
(assoc color :modified-at (dt/now)))
|
||||
|
||||
(defn add-color
|
||||
[file-data color]
|
||||
(update file-data :colors assoc (:id color) (touch color)))
|
||||
|
||||
(defn get-color
|
||||
[file-data color-id]
|
||||
(get-in file-data [:colors color-id]))
|
||||
|
||||
(defn get-ref-color
|
||||
[library-data color]
|
||||
(when (= (:ref-file color) (:id library-data))
|
||||
(get-color library-data (:ref-id color))))
|
||||
|
||||
(defn set-color
|
||||
[file-data color]
|
||||
(d/assoc-in-when file-data [:colors (:id color)] (touch color)))
|
||||
|
||||
(defn update-color
|
||||
[file-data color-id f & args]
|
||||
(d/update-in-when file-data [:colors color-id] #(-> (apply f % args)
|
||||
(touch))))
|
||||
|
||||
(defn delete-color
|
||||
[file-data color-id]
|
||||
(update file-data :colors dissoc color-id))
|
||||
|
||||
(defn used-colors-changed-since
|
||||
"Find all usages of any color in the library by the given shape, of colors
|
||||
that have ben modified after the date."
|
||||
[shape library since-date]
|
||||
(->> (ctc/get-all-colors shape)
|
||||
(keep #(get-ref-color (:data library) %))
|
||||
(remove #(< (:modified-at %) since-date)) ;; Note that :modified-at may be nil
|
||||
(map (fn [color] {:shape-id (:id shape)
|
||||
:asset-id (:id color)
|
||||
:asset-type :color}))))
|
|
@ -18,7 +18,6 @@
|
|||
[app.common.schema :as sm]
|
||||
[app.common.text :as ct]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.colors-list :as ctcl]
|
||||
[app.common.types.component :as ctk]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.container :as ctn]
|
||||
|
@ -59,7 +58,7 @@
|
|||
[:is-local {:optional true} :boolean]])
|
||||
|
||||
(def schema:colors
|
||||
[:map-of {:gen/max 5} ::sm/uuid ::ctc/color])
|
||||
[:map-of {:gen/max 5} ::sm/uuid ctc/schema:library-color])
|
||||
|
||||
(def schema:components
|
||||
[:map-of {:gen/max 5} ::sm/uuid ::ctn/container])
|
||||
|
@ -488,7 +487,7 @@
|
|||
[file-data library-data asset-type]
|
||||
(let [assets-seq (case asset-type
|
||||
:component (ctkl/components-seq library-data)
|
||||
:color (ctcl/colors-seq library-data)
|
||||
:color (ctc/colors-seq library-data)
|
||||
:typography (ctyl/typographies-seq library-data))
|
||||
|
||||
find-usages-in-container
|
||||
|
@ -527,7 +526,7 @@
|
|||
(letfn [(used-assets-shape [shape]
|
||||
(concat
|
||||
(ctkl/used-components-changed-since shape library since-date)
|
||||
(ctcl/used-colors-changed-since shape library since-date)
|
||||
(ctc/used-colors-changed-since shape library since-date)
|
||||
(ctyl/used-typographies-changed-since shape library since-date)))
|
||||
|
||||
(used-assets-container [container]
|
||||
|
@ -663,7 +662,7 @@
|
|||
%
|
||||
shapes)))]
|
||||
(as-> file-data $
|
||||
(ctcl/add-color $ color)
|
||||
(ctc/add-color $ color)
|
||||
(reduce remap-shapes $ usages))))]
|
||||
|
||||
(reduce absorb-color
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
(:require
|
||||
[app.common.colors :as clr]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.types.color :as ctc]))
|
||||
[app.common.types.color :refer [schema:hex-color]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; SCHEMA
|
||||
|
@ -16,7 +16,7 @@
|
|||
|
||||
(def schema:grid-color
|
||||
[:map {:title "PageGridColor"}
|
||||
[:color ::ctc/rgb-color]
|
||||
[:color schema:hex-color]
|
||||
[:opacity ::sm/safe-number]])
|
||||
|
||||
(def schema:column-params
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.geom.point :as-alias gpt]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.types.color :as-alias ctc]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.grid :as ctg]
|
||||
[app.common.types.plugins :as ctpg]
|
||||
[app.common.types.shape :as cts]
|
||||
|
@ -57,7 +57,7 @@
|
|||
[:flows {:optional true} schema:flows]
|
||||
[:guides {:optional true} schema:guides]
|
||||
[:plugin-data {:optional true} ::ctpg/plugin-data]
|
||||
[:background {:optional true} ::ctc/rgb-color]
|
||||
[:background {:optional true} ctc/schema:hex-color]
|
||||
|
||||
[:comment-thread-positions {:optional true}
|
||||
[:map-of ::sm/uuid schema:comment-thread-position]]])
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
[app.common.schema.generators :as sg]
|
||||
[app.common.text :as txt]
|
||||
[app.common.transit :as t]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.color :as types.color]
|
||||
[app.common.types.grid :as ctg]
|
||||
[app.common.types.path :as path]
|
||||
[app.common.types.path.segment :as path.segment]
|
||||
|
@ -119,22 +119,59 @@
|
|||
(def schema:points
|
||||
[:vector {:gen/max 4 :gen/min 4} ::gpt/point])
|
||||
|
||||
;; FIXME: generate from schema for make schema unique source of truth
|
||||
(def fill-attrs
|
||||
"A set of attrs that corresponds to fill data type"
|
||||
#{:fill-color :fill-opacity :fill-color-gradient :fill-color-ref-id :fill-color-ref-file})
|
||||
|
||||
(def ^:private schema:fill-attrs
|
||||
[:map {:title "FillAttrs"}
|
||||
[:fill-color-ref-file {:optional true} ::sm/uuid]
|
||||
[:fill-color-ref-id {:optional true} ::sm/uuid]
|
||||
[:fill-opacity {:optional true} [::sm/number {:min 0 :max 1}]]
|
||||
[:fill-color {:optional true} types.color/schema:hex-color]
|
||||
[:fill-color-gradient {:optional true} types.color/schema:gradient]
|
||||
[:fill-image {:optional true} types.color/schema:image]])
|
||||
|
||||
;; FIXME: the register is necessary until this is moved to a separated
|
||||
;; ns because it is used on shapes.text
|
||||
(def valid-fill-attrs
|
||||
"A set used for proper check if color should contain only one of the
|
||||
attrs listed in this set."
|
||||
#{:fill-image :fill-color :fill-color-gradient})
|
||||
|
||||
(defn has-valid-fill-attrs?
|
||||
"Check if color has correct color attrs"
|
||||
[color]
|
||||
(let [attrs (set (keys color))
|
||||
result (set/intersection attrs valid-fill-attrs)]
|
||||
(= 1 (count result))))
|
||||
|
||||
(def schema:fill
|
||||
(sm/register!
|
||||
^{::sm/type ::fill}
|
||||
[:map {:title "Fill"}
|
||||
[:fill-color {:optional true} ::ctc/rgb-color]
|
||||
[:fill-opacity {:optional true} ::sm/safe-number]
|
||||
[:fill-color-gradient {:optional true} [:maybe ::ctc/gradient]]
|
||||
[:fill-color-ref-file {:optional true} [:maybe ::sm/uuid]]
|
||||
[:fill-color-ref-id {:optional true} [:maybe ::sm/uuid]]
|
||||
[:fill-image {:optional true} ::ctc/image-color]]))
|
||||
[:and schema:fill-attrs
|
||||
[:fn has-valid-fill-attrs?]]))
|
||||
|
||||
(def schema:stroke
|
||||
(sm/register!
|
||||
^{::sm/type ::stroke}
|
||||
[:map {:title "Stroke"}
|
||||
[:stroke-color {:optional true} :string]
|
||||
(def check-fill
|
||||
(sm/check-fn schema:fill))
|
||||
|
||||
;; FIXME: the register is necessary until this is moved to a separated
|
||||
;; ns because it is used on shapes.text
|
||||
(def valid-stroke-attrs
|
||||
"A set used for proper check if color should contain only one of the
|
||||
attrs listed in this set."
|
||||
#{:stroke-image :stroke-color :stroke-color-gradient})
|
||||
|
||||
(defn has-valid-stroke-attrs?
|
||||
"Check if color has correct color attrs"
|
||||
[color]
|
||||
(let [attrs (set (keys color))
|
||||
result (set/intersection attrs valid-stroke-attrs)]
|
||||
(= 1 (count result))))
|
||||
|
||||
(def schema:stroke-attrs
|
||||
[:map {:title "StrokeAttrs"}
|
||||
[:stroke-color-ref-file {:optional true} ::sm/uuid]
|
||||
[:stroke-color-ref-id {:optional true} ::sm/uuid]
|
||||
[:stroke-opacity {:optional true} ::sm/safe-number]
|
||||
|
@ -147,8 +184,15 @@
|
|||
[::sm/one-of stroke-caps]]
|
||||
[:stroke-cap-end {:optional true}
|
||||
[::sm/one-of stroke-caps]]
|
||||
[:stroke-color-gradient {:optional true} ::ctc/gradient]
|
||||
[:stroke-image {:optional true} ::ctc/image-color]]))
|
||||
[:stroke-color {:optional true} types.color/schema:hex-color]
|
||||
[:stroke-color-gradient {:optional true} types.color/schema:gradient]
|
||||
[:stroke-image {:optional true} types.color/schema:image]])
|
||||
|
||||
(def schema:stroke
|
||||
(sm/register!
|
||||
^{::sm/type ::stroke}
|
||||
[:and schema:stroke-attrs
|
||||
[:fn has-valid-stroke-attrs?]]))
|
||||
|
||||
(def check-stroke
|
||||
(sm/check-fn schema:stroke))
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
[:blur ::sm/safe-number]
|
||||
[:spread ::sm/safe-number]
|
||||
[:hidden :boolean]
|
||||
[:color ::ctc/color]])
|
||||
[:color ctc/schema:color]])
|
||||
|
||||
(def check-shadow
|
||||
(sm/check-fn schema:shadow))
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
[app.common.test-helpers.ids-map :as thi]
|
||||
[app.common.test-helpers.shapes :as ths]
|
||||
[app.common.text :as txt]
|
||||
[app.common.types.colors-list :as ctcl]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.component :as ctk]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.file :as ctf]
|
||||
|
@ -80,7 +80,7 @@
|
|||
_ (thf/validate-file! file')
|
||||
|
||||
;; Get
|
||||
colors' (ctcl/colors-seq (ctf/file-data file'))
|
||||
colors' (ctc/colors-seq (ctf/file-data file'))
|
||||
shape1' (ths/get-shape file' :shape1)
|
||||
fill' (first (:fills shape1'))]
|
||||
|
||||
|
|
|
@ -145,4 +145,4 @@
|
|||
;; (app.common.pprint/pprint shape)
|
||||
;; (app.common.pprint/pprint shape-3)
|
||||
(= shape shape-3)))
|
||||
{:num 100})))
|
||||
{:num 200})))
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
[cljs.spec.alpha :as s]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(def accept-image-types
|
||||
(str/join "," cm/image-types))
|
||||
;; FIXME: revisit the need of this NS
|
||||
|
||||
;; --- Predicates
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.modal :as md]
|
||||
[app.main.data.workspace.layout :as layout]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
|
@ -126,11 +125,11 @@
|
|||
(contains? color :color)
|
||||
(assoc :fill-color (:color color))
|
||||
|
||||
(contains? color :id)
|
||||
(assoc :fill-color-ref-id (:id color))
|
||||
(contains? color :ref-id)
|
||||
(assoc :fill-color-ref-id (:ref-id color))
|
||||
|
||||
(contains? color :file-id)
|
||||
(assoc :fill-color-ref-file (:file-id color))
|
||||
(contains? color :ref-file)
|
||||
(assoc :fill-color-ref-file (:ref-file color))
|
||||
|
||||
(contains? color :gradient)
|
||||
(assoc :fill-color-gradient (:gradient color))
|
||||
|
@ -142,7 +141,10 @@
|
|||
(assoc :fill-image (:image color))
|
||||
|
||||
:always
|
||||
(d/without-nils))
|
||||
(d/without-nils)
|
||||
|
||||
:always
|
||||
(shp/check-fill))
|
||||
|
||||
transform-attrs #(transform % fill)]
|
||||
|
||||
|
@ -327,11 +329,11 @@
|
|||
(contains? color :color)
|
||||
(assoc :stroke-color (:color color))
|
||||
|
||||
(contains? color :id)
|
||||
(assoc :stroke-color-ref-id (:id color))
|
||||
(contains? color :ref-id)
|
||||
(assoc :stroke-color-ref-id (:ref-id color))
|
||||
|
||||
(contains? color :file-id)
|
||||
(assoc :stroke-color-ref-file (:file-id color))
|
||||
(contains? color :ref-file)
|
||||
(assoc :stroke-color-ref-file (:ref-file color))
|
||||
|
||||
(contains? color :gradient)
|
||||
(assoc :stroke-color-gradient (:gradient color))
|
||||
|
@ -533,18 +535,19 @@
|
|||
|
||||
(defn- color-att->text
|
||||
[color]
|
||||
(d/without-nils
|
||||
{:fill-color (when (:color color) (str/lower (:color color)))
|
||||
:fill-opacity (:opacity color)
|
||||
:fill-color-ref-id (:id color)
|
||||
:fill-color-ref-file (:file-id color)
|
||||
:fill-color-gradient (:gradient color)})
|
||||
:fill-color-ref-id (:ref-id color)
|
||||
:fill-color-ref-file (:ref-file color)
|
||||
:fill-color-gradient (:gradient color)}))
|
||||
|
||||
(defn change-text-color
|
||||
[old-color new-color index node]
|
||||
(let [fills (map #(dissoc % :fill-color-ref-id :fill-color-ref-file) (:fills node))
|
||||
parsed-color (-> (d/without-nils (color-att->text old-color))
|
||||
parsed-color (-> (color-att->text old-color)
|
||||
(dissoc :fill-color-ref-id :fill-color-ref-file))
|
||||
parsed-new-color (d/without-nils (color-att->text new-color))
|
||||
parsed-new-color (color-att->text new-color)
|
||||
has-color? (d/index-of fills parsed-color)]
|
||||
(cond-> node
|
||||
(some? has-color?)
|
||||
|
@ -595,11 +598,7 @@
|
|||
|
||||
(defn apply-color-from-palette
|
||||
[color stroke?]
|
||||
|
||||
(assert
|
||||
(ctc/check-color color)
|
||||
"expected valid color structure")
|
||||
|
||||
(let [color (ctc/check-color color)]
|
||||
(ptk/reify ::apply-color-from-palette
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
|
@ -625,7 +624,7 @@
|
|||
|
||||
(if stroke?
|
||||
(rx/of (change-stroke-color ids color 0))
|
||||
(rx/of (change-fill ids color 0)))))))
|
||||
(rx/of (change-fill ids color 0))))))))
|
||||
|
||||
(declare activate-colorpicker-color)
|
||||
(declare activate-colorpicker-gradient)
|
||||
|
@ -634,14 +633,10 @@
|
|||
|
||||
(defn apply-color-from-colorpicker
|
||||
[color]
|
||||
|
||||
(assert (ctc/check-color color)
|
||||
"expected valid color structure")
|
||||
|
||||
(let [color (ctc/check-color color)]
|
||||
(ptk/reify ::apply-color-from-colorpicker
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [gradient-type (dm/get-in color [:gradient :type])]
|
||||
(update state :colorpicker
|
||||
(fn [state]
|
||||
(cond
|
||||
|
@ -655,19 +650,57 @@
|
|||
(assoc :type :color)
|
||||
(dissoc :editing-stop :stops :gradient))
|
||||
|
||||
|
||||
:else
|
||||
(let [gradient-type (dm/get-in color [:gradient :type])]
|
||||
(cond
|
||||
(= :linear gradient-type)
|
||||
(-> state
|
||||
(assoc :type :linear-gradient)
|
||||
(assoc :editing-stop 0)
|
||||
(d/dissoc-in [:current-color :image]))
|
||||
(update :current-color dissoc :image))
|
||||
|
||||
(= :radial gradient-type)
|
||||
(-> state
|
||||
(assoc :type :radial-gradient)
|
||||
(assoc :editing-stop 0)
|
||||
(d/dissoc-in [:current-color :image])))))))))
|
||||
(update :current-color dissoc :image)))))))))))
|
||||
|
||||
(defn- recent-color-equal?
|
||||
[c1 c2]
|
||||
(or (= c1 c2)
|
||||
(and (some? (:color c1))
|
||||
(some? (:color c2))
|
||||
(= (:color c1) (:color c2)))))
|
||||
|
||||
(defn add-recent-color
|
||||
[color]
|
||||
(let [color (ctc/check-color color)]
|
||||
(ptk/reify ::add-recent-color
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [file-id (:current-file-id state)]
|
||||
(update-in state [:recent-colors file-id]
|
||||
(fn [colors]
|
||||
(let [colors (d/removev (partial recent-color-equal? color) colors)
|
||||
colors (conj colors color)]
|
||||
(cond-> colors
|
||||
(> (count colors) 15)
|
||||
(subvec 1)))))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [recent-colors (:recent-colors state)]
|
||||
(swap! storage/user assoc :recent-colors recent-colors))))))
|
||||
|
||||
(defn apply-color-from-assets
|
||||
[file-id color stroke?]
|
||||
(let [color (ctc/check-library-color color)]
|
||||
(ptk/reify ::apply-color-from-asserts
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(let [color (ctc/library-color->color color file-id)]
|
||||
(rx/of (apply-color-from-palette color stroke?)
|
||||
(add-recent-color color)))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; COLORPICKER STATE MANAGEMENT
|
||||
|
@ -953,8 +986,7 @@
|
|||
(update :current-color #(if (not= type :image) (dissoc % :image) %))
|
||||
;; current color can be a library one
|
||||
;; I'm changing via colorpicker
|
||||
(d/dissoc-in [:current-color :id])
|
||||
(d/dissoc-in [:current-color :file-id]))]
|
||||
(update :current-color dissoc :ref-id :ref-file))]
|
||||
(if-let [stop (:editing-stop state)]
|
||||
(update-in state [:stops stop] (fn [data] (->> changes
|
||||
(merge data)
|
||||
|
@ -966,15 +998,17 @@
|
|||
(assoc :type :color))))))))
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [selected-type (-> state
|
||||
:colorpicker
|
||||
:type)
|
||||
formated-color (get-color-from-colorpicker-state (:colorpicker state))
|
||||
(let [state (get-color-from-colorpicker-state (:colorpicker state))
|
||||
type (get state :type)
|
||||
|
||||
;; Type is set to color on closing the colorpicker, but we
|
||||
;; can can close it while still uploading an image fill
|
||||
ignore-color? (and (= selected-type :color) (nil? (:color formated-color)))]
|
||||
ignore-color?
|
||||
(and (= type :color) (nil? (:color state)))]
|
||||
|
||||
(when (and add-recent? (not ignore-color?))
|
||||
(rx/of (dwl/add-recent-color formated-color)))))))
|
||||
(let [color (select-keys state [:image :gradient :color :opacity])]
|
||||
(rx/of (add-recent-color color))))))))
|
||||
|
||||
(defn update-colorpicker-gradient
|
||||
[changes]
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
[app.main.store :as st]
|
||||
[app.util.color :as uc]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.storage :as storage]
|
||||
[app.util.time :as dt]
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
|
@ -119,11 +118,8 @@
|
|||
(assoc :name (or (get-in color [:image :name])
|
||||
(:color color)
|
||||
(uc/gradient-type->string (get-in color [:gradient :type]))))
|
||||
(d/without-nils))]
|
||||
|
||||
(dm/assert!
|
||||
"expect valid color structure"
|
||||
(ctc/check-color color))
|
||||
(d/without-nils)
|
||||
(ctc/check-library-color))]
|
||||
|
||||
(ptk/reify ::add-color
|
||||
ev/Event
|
||||
|
@ -138,22 +134,6 @@
|
|||
(fn [state] (assoc-in state [:workspace-local :color-for-rename] (:id color))))
|
||||
(dch/commit-changes changes))))))))
|
||||
|
||||
(defn add-recent-color
|
||||
[color]
|
||||
(assert (ctc/check-recent-color color)
|
||||
"expected valid recent color structure")
|
||||
|
||||
(ptk/reify ::add-recent-color
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [file-id (:current-file-id state)]
|
||||
(update state :recent-colors ctc/add-recent-color file-id color)))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ state _]
|
||||
(let [recent-colors (:recent-colors state)]
|
||||
(swap! storage/user assoc :recent-colors recent-colors)))))
|
||||
|
||||
(def clear-color-for-rename
|
||||
(ptk/reify ::clear-color-for-rename
|
||||
ptk/UpdateEvent
|
||||
|
@ -176,16 +156,10 @@
|
|||
|
||||
(defn update-color
|
||||
[color file-id]
|
||||
(let [color (d/without-nils color)]
|
||||
|
||||
(dm/assert!
|
||||
"expected valid color data structure"
|
||||
(ctc/check-color color))
|
||||
|
||||
(dm/assert!
|
||||
"expected file-id"
|
||||
(uuid? file-id))
|
||||
(assert (uuid? file-id) "expected a uuid instance for `file-id`")
|
||||
|
||||
(let [color (-> (d/without-nils color)
|
||||
(ctc/check-library-color))]
|
||||
(ptk/reify ::update-color
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
|
@ -194,15 +168,10 @@
|
|||
(defn update-color-data
|
||||
"Update color data without affecting the path location"
|
||||
[color file-id]
|
||||
(let [color (d/without-nils color)]
|
||||
(assert (uuid? file-id) "expected a uuid instance for `file-id`")
|
||||
|
||||
(dm/assert!
|
||||
"expected valid color data structure"
|
||||
(ctc/check-color color))
|
||||
|
||||
(dm/assert!
|
||||
"expected file-id"
|
||||
(uuid? file-id))
|
||||
(let [color (-> (d/without-nils color)
|
||||
(ctc/check-library-color))]
|
||||
|
||||
(ptk/reify ::update-color-data
|
||||
ptk/WatchEvent
|
||||
|
@ -213,17 +182,10 @@
|
|||
;; FIXME: revisit why file-id is passed on the event
|
||||
(defn rename-color
|
||||
[file-id id new-name]
|
||||
(dm/assert!
|
||||
"expected valid uuid for `id`"
|
||||
(uuid? id))
|
||||
|
||||
(dm/assert!
|
||||
"expected valid uuid for `file-id`"
|
||||
(uuid? file-id))
|
||||
|
||||
(dm/assert!
|
||||
"expected valid string for `new-name`"
|
||||
(string? new-name))
|
||||
(assert (uuid? id) "expected valid uuid instance for `id`")
|
||||
(assert (uuid? file-id) "expected a uuid instance for `file-id`")
|
||||
(assert (string? new-name) "expected a string instance for `new-name`")
|
||||
|
||||
(ptk/reify ::rename-color
|
||||
ptk/WatchEvent
|
||||
|
@ -232,14 +194,16 @@
|
|||
(if (str/empty? new-name)
|
||||
(rx/empty)
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
color (get-in data [:colors id])
|
||||
color (assoc color :name new-name)
|
||||
color (d/without-nils color)]
|
||||
color (-> (ctc/get-color data id)
|
||||
(assoc :name new-name)
|
||||
(d/without-nils)
|
||||
(ctc/check-library-color))]
|
||||
(update-color* it state color file-id)))))))
|
||||
|
||||
(defn delete-color
|
||||
[{:keys [id] :as params}]
|
||||
(dm/assert! (uuid? id))
|
||||
(assert (uuid? id) "expected valid uuid instance for `id`")
|
||||
|
||||
(ptk/reify ::delete-color
|
||||
ev/Event
|
||||
(-data [_] {:id id})
|
||||
|
@ -252,6 +216,7 @@
|
|||
(pcb/delete-color id))]
|
||||
(rx/of (dch/commit-changes changes))))))
|
||||
|
||||
;; FIXME: this should be deleted
|
||||
(defn add-media
|
||||
[media]
|
||||
(let [media (ctf/check-file-media media)]
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
[promesa.core :as p]
|
||||
[tubax.core :as tubax]))
|
||||
|
||||
(def accept-image-types
|
||||
(str/join "," media/image-types))
|
||||
|
||||
(defn- optimize
|
||||
[input]
|
||||
(svgo/optimize input svgo/defaultOptions))
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
[app.common.math :as mth]
|
||||
[app.common.text :as txt]
|
||||
[app.common.types.modifiers :as ctm]
|
||||
[app.common.types.shape :as types.shape]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.helpers :as dsh]
|
||||
|
@ -234,9 +235,9 @@
|
|||
|
||||
;; --- Helpers
|
||||
|
||||
(defn to-new-fills
|
||||
(defn- to-new-fills
|
||||
[data]
|
||||
[(d/without-nils (select-keys data [:fill-color :fill-opacity :fill-color-gradient :fill-color-ref-id :fill-color-ref-file]))])
|
||||
[(d/without-nils (select-keys data types.shape/fill-attrs))])
|
||||
|
||||
(defn- shape-current-values
|
||||
[shape pred attrs]
|
||||
|
@ -246,9 +247,7 @@
|
|||
(if (txt/is-text-node? node)
|
||||
(let [fills
|
||||
(cond
|
||||
(or (some? (:fill-color node))
|
||||
(some? (:fill-opacity node))
|
||||
(some? (:fill-color-gradient node)))
|
||||
(types.shape/has-valid-fill-attrs? node)
|
||||
(to-new-fills node)
|
||||
|
||||
(some? (:fills node))
|
||||
|
@ -474,13 +473,13 @@
|
|||
|
||||
(defn migrate-node
|
||||
[node]
|
||||
(let [color-attrs (select-keys node [:fill-color :fill-opacity :fill-color-ref-id :fill-color-ref-file :fill-color-gradient])]
|
||||
(let [color-attrs (not-empty (select-keys node types.shape/fill-attrs))]
|
||||
(cond-> node
|
||||
(nil? (:fills node))
|
||||
(assoc :fills [])
|
||||
|
||||
;; Migrate old colors and remove the old fromat
|
||||
(d/not-empty? color-attrs)
|
||||
color-attrs
|
||||
(-> (dissoc :fill-color :fill-opacity :fill-color-ref-id :fill-color-ref-file :fill-color-gradient)
|
||||
(update :fills conj color-attrs))
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
|
||||
(defn- color-title
|
||||
[color-item]
|
||||
(let [name (:name color-item)
|
||||
path (:path color-item)
|
||||
(let [{:keys [name path]} (meta color-item)
|
||||
path-and-name (if path (str path " / " name) name)
|
||||
gradient (:gradient color-item)
|
||||
image (:image color-item)
|
||||
|
@ -107,7 +106,8 @@
|
|||
(mf/defc color-name
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [color size on-click on-double-click origin]}]
|
||||
(let [{:keys [name color gradient]} (if (string? color) {:color color :opacity 1} color)]
|
||||
(let [{:keys [name]} (meta color)
|
||||
{:keys [color gradient]} (if (string? color) {:color color :opacity 1} color)]
|
||||
(when (or (not size) (> size 64))
|
||||
[:span {:class (stl/css-case
|
||||
:color-text (and (= origin :palette) (< size 72))
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private accept-font-types
|
||||
(str (str/join "," font-types)
|
||||
(str (str/join "," cm/font-types)
|
||||
;; A workaround to solve a problem with chrome input selector
|
||||
",.ttf,application/font-woff,woff,.otf"))
|
||||
|
||||
|
|
|
@ -21,9 +21,13 @@
|
|||
|
||||
(defn- color-title
|
||||
[color-item]
|
||||
(let [name (:name color-item)
|
||||
path (:path color-item)
|
||||
path-and-name (if (and path (not (str/empty? path))) (str path " / " name) name)
|
||||
(let [{:keys [name path]} (meta color-item)
|
||||
|
||||
path-and-name
|
||||
(if (and path (not (str/empty? path)))
|
||||
(str path " / " name)
|
||||
name)
|
||||
|
||||
gradient (:gradient color-item)
|
||||
image (:image color-item)
|
||||
color (:color color-item)]
|
||||
|
@ -75,7 +79,7 @@
|
|||
(json/->clj background)
|
||||
background)
|
||||
read-only? (nil? on-click)
|
||||
id? (some? (:id background))
|
||||
id? (some? (:ref-id background))
|
||||
element-type (if read-only? "div" "button")
|
||||
button-type (if (not read-only?) "button" nil)
|
||||
size (or size "small")
|
||||
|
@ -86,7 +90,9 @@
|
|||
:stops gradient-stops}
|
||||
image (:image background)
|
||||
format (if id? "rounded" "square")
|
||||
class (dm/str class " " (stl/css-case
|
||||
|
||||
class
|
||||
(dm/str class " " (stl/css-case
|
||||
:swatch true
|
||||
:small (= size "small")
|
||||
:medium (= size "medium")
|
||||
|
@ -95,7 +101,9 @@
|
|||
:active (= active true)
|
||||
:interactive (= element-type "button")
|
||||
:rounded (= format "rounded")))
|
||||
props (mf/spread-props props {:class class
|
||||
|
||||
props
|
||||
(mf/spread-props props {:class class
|
||||
:on-click on-click
|
||||
:type button-type
|
||||
:title (color-title background)})]
|
||||
|
|
|
@ -93,7 +93,8 @@ export const RadialGradient = {
|
|||
export const Rounded = {
|
||||
args: {
|
||||
background: {
|
||||
id: helpers.generateUuid(),
|
||||
"ref-id": helpers.generateUuid(),
|
||||
"ref-file": helpers.generateUuid(),
|
||||
color: "#2f226c",
|
||||
opacity: 0.5,
|
||||
},
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
[app.common.types.color :as ctc]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.workspace.colors :as mdc]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.color-bullet :as cb]
|
||||
|
@ -34,25 +33,29 @@
|
|||
(mf/use-fn
|
||||
(mf/deps color selected)
|
||||
(fn [event]
|
||||
(st/emit! (dwl/add-recent-color color)
|
||||
(st/emit! (mdc/add-recent-color color)
|
||||
(mdc/apply-color-from-palette color (kbd/alt? event))
|
||||
(when (not= selected :recent)
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "use-library-color"
|
||||
::ev/origin "color-palette"
|
||||
:external-library (not= selected :file)})))))]
|
||||
:external-library (not= selected :file)})))))
|
||||
title
|
||||
(uc/get-color-name color)]
|
||||
|
||||
[:button {:class (stl/css-case
|
||||
:color-cell true
|
||||
:is-not-library-color (nil? (:id color))
|
||||
:no-text (<= size 64))
|
||||
:title (uc/get-color-name color)
|
||||
:aria-label (uc/get-color-name color)
|
||||
:title title
|
||||
:aria-label title
|
||||
:type "button"
|
||||
:on-click select-color}
|
||||
[:> swatch* {:background color :size "medium"}]
|
||||
[:& cb/color-name {:color color :size size :origin :palette}]]))
|
||||
|
||||
(mf/defc palette*
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [colors size width selected]}]
|
||||
(let [state (mf/use-state #(do {:show-menu false}))
|
||||
offset-step (cond
|
||||
|
@ -121,9 +124,11 @@
|
|||
(when (not= 0 (:offset @state))
|
||||
(swap! state assoc :offset 0)))
|
||||
|
||||
[:div {:class (stl/css-case :color-palette true
|
||||
[:div {:class (stl/css-case
|
||||
:color-palette true
|
||||
:no-text (< size 64))
|
||||
:style #js {"--bullet-size" (dm/str bullet-size "px") "--color-cell-width" (dm/str color-cell-width "px")}}
|
||||
:style #js {"--bullet-size" (dm/str bullet-size "px")
|
||||
"--color-cell-width" (dm/str color-cell-width "px")}}
|
||||
|
||||
(when show-arrows?
|
||||
[:button {:class (stl/css :left-arrow)
|
||||
|
@ -154,14 +159,25 @@
|
|||
(mf/defc recent-colors-palette*
|
||||
{::mf/private true}
|
||||
[props]
|
||||
(let [colors (mf/deref refs/recent-colors)
|
||||
|
||||
colors (mf/with-memo [colors]
|
||||
(let [libraries (mf/deref refs/files)
|
||||
colors (mf/deref refs/recent-colors)
|
||||
colors (mf/with-memo [colors libraries]
|
||||
(->> (reverse colors)
|
||||
(filter ctc/valid-color?)
|
||||
(map (fn [{:keys [ref-id ref-file] :as color}]
|
||||
;; For make the UI consistent we need to ensure that a
|
||||
;; library color looks exactly as it is actually and not
|
||||
;; how it was saved first time
|
||||
(if (and ref-id ref-file)
|
||||
(let [fdata (dm/get-in libraries [ref-file :data])]
|
||||
(or (some-> (ctc/get-color fdata ref-id)
|
||||
(ctc/library-color->color ref-file))
|
||||
(dissoc color :ref-id :ref-file)))
|
||||
color)))
|
||||
(vec)))
|
||||
|
||||
props (mf/spread-props props {:colors colors})]
|
||||
|
||||
[:> palette* props]))
|
||||
|
||||
(defn- make-library-colors-ref
|
||||
|
@ -178,9 +194,9 @@
|
|||
colors (mf/deref colors-ref)
|
||||
colors (mf/with-memo [colors file-id]
|
||||
(->> (vals colors)
|
||||
(filter ctc/valid-color?)
|
||||
(map #(assoc % :file-id file-id))
|
||||
(filter ctc/valid-library-color?)
|
||||
(sort-by :name)
|
||||
(map #(ctc/library-color->color % file-id))
|
||||
(vec)))
|
||||
props (mf/spread-props props {:colors colors})]
|
||||
|
||||
|
|
|
@ -134,6 +134,7 @@
|
|||
on-fill-image-success
|
||||
(mf/use-fn
|
||||
(fn [image]
|
||||
;; FIXME: revisit
|
||||
(st/emit! (dc/update-colorpicker-color
|
||||
{:image (-> (select-keys image [:id :width :height :mtype :name])
|
||||
(assoc :keep-aspect-ratio true))}
|
||||
|
@ -200,9 +201,8 @@
|
|||
(fn [_ color]
|
||||
(if (and (some? (:color color)) (some? (:gradient data)))
|
||||
(handle-change-color {:hex (:color color) :alpha (:opacity color)})
|
||||
(do
|
||||
(st/emit!
|
||||
(dwl/add-recent-color color)
|
||||
(let [color (d/without-qualified color)]
|
||||
(st/emit! (dc/add-recent-color color)
|
||||
(dc/apply-color-from-colorpicker color))
|
||||
(on-change color)))))
|
||||
|
||||
|
|
|
@ -108,16 +108,15 @@
|
|||
(filter valid-color?)
|
||||
(map-indexed (fn [index color]
|
||||
(let [color (if (map? color) color {:color color})]
|
||||
(assoc color ::id (dm/str index)))))
|
||||
(vary-meta color assoc ::id (dm/str index)))))
|
||||
(sort c/sort-colors))
|
||||
(->> (dm/get-in libraries [file-id :data :colors])
|
||||
(vals)
|
||||
(filter valid-color?)
|
||||
(sort-by :name)
|
||||
(map #(ctc/library-color->color % file-id))
|
||||
(map-indexed (fn [index color]
|
||||
(-> color
|
||||
(assoc :file-id file-id)
|
||||
(assoc ::id (dm/str index)))))
|
||||
(sort-by :name)))]
|
||||
(vary-meta color assoc ::id (dm/str index))))))]
|
||||
|
||||
(reset! current-colors* colors)))
|
||||
|
||||
|
@ -142,6 +141,6 @@
|
|||
|
||||
(for [color current-colors]
|
||||
[:& cb/color-bullet
|
||||
{:key (dm/str "color-" (::id color))
|
||||
{:key (-> color meta ::id)
|
||||
:color color
|
||||
:on-click on-color-click}])]]))
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.types.colors-list :as ctcl]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.typographies-list :as ctyl]
|
||||
|
@ -407,7 +407,7 @@
|
|||
(sort-by #(str/lower (:name %)))
|
||||
(truncate :components))
|
||||
colors (->> color-ids
|
||||
(map #(ctcl/get-color (:data library) %))
|
||||
(map #(ctc/get-color (:data library) %))
|
||||
(sort-by #(str/lower (:name %)))
|
||||
(truncate :colors))
|
||||
typographies (->> typography-ids
|
||||
|
|
|
@ -42,8 +42,7 @@
|
|||
(let [color (mf/with-memo [color file-id]
|
||||
(cond-> color
|
||||
(:value color) (assoc :color (:value color) :opacity 1)
|
||||
(:value color) (dissoc :value)
|
||||
:always (assoc :file-id file-id)))
|
||||
(:value color) (dissoc :value)))
|
||||
|
||||
color-id (:id color)
|
||||
|
||||
|
@ -78,7 +77,6 @@
|
|||
(let [name (cfh/merge-path-item (:path color) (:name color))
|
||||
color (-> attrs
|
||||
(assoc :id (:id color))
|
||||
(assoc :file-id file-id)
|
||||
(assoc :name name))]
|
||||
(st/emit! (dwl/update-color color file-id)))))
|
||||
|
||||
|
@ -177,7 +175,7 @@
|
|||
|
||||
on-click
|
||||
(mf/use-fn
|
||||
(mf/deps color on-asset-click read-only?)
|
||||
(mf/deps color on-asset-click read-only? file-id)
|
||||
(fn [event]
|
||||
(when-not read-only?
|
||||
(st/emit! (ptk/data-event ::ev/event
|
||||
|
@ -186,8 +184,7 @@
|
|||
:external-library (not local?)}))
|
||||
|
||||
(when-not (on-asset-click event (:id color))
|
||||
(st/emit! (dwl/add-recent-color color)
|
||||
(dc/apply-color-from-palette color (kbd/alt? event)))))))]
|
||||
(st/emit! (dc/apply-color-from-assets file-id color (kbd/alt? event)))))))]
|
||||
|
||||
(mf/with-effect [editing?]
|
||||
(when editing?
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.media :as cm]
|
||||
[app.common.types.component :as ctc]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.main.data.event :as ev]
|
||||
|
|
|
@ -176,7 +176,7 @@
|
|||
(seq fills)
|
||||
[:& h/sortable-container {}
|
||||
(for [[index value] (d/enumerate fills)]
|
||||
[:> color-row* {:color (ctc/fill->shape-color value)
|
||||
[:> color-row* {:color (ctc/fill->color value)
|
||||
:key index
|
||||
:index index
|
||||
:title (tr "workspace.options.fill")
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
[app.common.colors :as clr]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.types.shape.shadow :as ctss]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.colors :as dc]
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
|
@ -91,7 +92,10 @@
|
|||
(mf/use-fn (mf/deps index) #(on-update index :blur %))
|
||||
|
||||
on-update-color
|
||||
(mf/use-fn (mf/deps index) #(on-update index :color (d/without-nils %)))
|
||||
(mf/use-fn
|
||||
(mf/deps index on-update)
|
||||
(fn [color]
|
||||
(on-update index :color color)))
|
||||
|
||||
on-detach-color
|
||||
(mf/use-fn (mf/deps index) #(on-detach-color index))
|
||||
|
@ -275,8 +279,13 @@
|
|||
(mf/use-fn
|
||||
(fn [index attr value]
|
||||
(let [ids (mf/ref-val ids-ref)]
|
||||
(st/emit! (dwsh/update-shapes ids #(assoc-in % [:shadow index attr] value))))))]
|
||||
|
||||
(st/emit! (dwsh/update-shapes ids
|
||||
(fn [shape]
|
||||
(update-in shape [:shadow index]
|
||||
(fn [shadow]
|
||||
(-> shadow
|
||||
(assoc attr value)
|
||||
(ctss/check-shadow))))))))))]
|
||||
[:div {:class (stl/css :element-set)}
|
||||
[:div {:class (stl/css :element-title)}
|
||||
[:& title-bar {:collapsable has-shadows?
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
[app.common.data.macros :as dm]
|
||||
[app.common.types.shape.attrs :refer [default-color]]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.colors :as dwc]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.color-bullet :as cb]
|
||||
|
@ -116,7 +116,7 @@
|
|||
(let [color (-> color
|
||||
(assoc :color value)
|
||||
(dissoc :gradient))]
|
||||
(st/emit! (dwl/add-recent-color color)
|
||||
(st/emit! (dwc/add-recent-color color)
|
||||
(on-change color)))))
|
||||
|
||||
handle-opacity-change
|
||||
|
@ -126,7 +126,7 @@
|
|||
(let [color (-> color
|
||||
(assoc :opacity (/ value 100))
|
||||
(dissoc :ref-id :ref-file))]
|
||||
(st/emit! (dwl/add-recent-color color)
|
||||
(st/emit! (dwc/add-recent-color color)
|
||||
(on-change color)))))
|
||||
|
||||
handle-click-color
|
||||
|
|
|
@ -149,7 +149,7 @@
|
|||
|
||||
;; Stroke Color
|
||||
;; FIXME: memorize stroke color
|
||||
[:> color-row* {:color (ctc/stroke->shape-color stroke)
|
||||
[:> color-row* {:color (ctc/stroke->color stroke)
|
||||
:index index
|
||||
:title title
|
||||
:on-change on-color-change-refactor
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.media :as cm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.workspace :as dw]
|
||||
|
|
|
@ -176,10 +176,10 @@
|
|||
(or (not (array? shapes)) (not (every? shape/shape-proxy? shapes)))
|
||||
(u/display-not-valid :replaceColor-shapes shapes)
|
||||
|
||||
(not (sm/validate ::ctc/color old-color))
|
||||
(not (sm/validate ctc/schema:color old-color))
|
||||
(u/display-not-valid :replaceColor-oldColor old-color)
|
||||
|
||||
(not (sm/validate ::ctc/color new-color))
|
||||
(not (sm/validate ctc/schema:color new-color))
|
||||
(u/display-not-valid :replaceColor-newColor new-color)
|
||||
|
||||
:else
|
||||
|
|
|
@ -139,6 +139,8 @@
|
|||
:path path
|
||||
:color color
|
||||
:opacity opacity
|
||||
:refId (format-id ref-id)
|
||||
:refFile (format-id ref-file)
|
||||
:gradient (format-gradient gradient)
|
||||
:image (format-image image)}))))
|
||||
|
||||
|
@ -188,6 +190,7 @@
|
|||
;; fillColorRefId?: string;
|
||||
;; fillImage?: ImageData;
|
||||
;;}
|
||||
|
||||
(defn format-fill
|
||||
[{:keys [fill-color fill-opacity fill-color-gradient fill-color-ref-file fill-color-ref-id fill-image] :as fill}]
|
||||
(when (some? fill)
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
(fn [self value]
|
||||
(let [value (parser/parse-gradient value)]
|
||||
(cond
|
||||
(not (sm/validate ::ctc/gradient value))
|
||||
(not (sm/validate ctc/schema:gradient value))
|
||||
(u/display-not-valid :gradient value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
|
@ -144,7 +144,7 @@
|
|||
(fn [self value]
|
||||
(let [value (parser/parse-image-data value)]
|
||||
(cond
|
||||
(not (sm/validate ::ctc/image-color value))
|
||||
(not (sm/validate ctc/schema:image value))
|
||||
(u/display-not-valid :image value)
|
||||
|
||||
(not (r/check-permission plugin-id "library:write"))
|
||||
|
|
|
@ -728,7 +728,7 @@
|
|||
(let [id (obj/get self "$id")
|
||||
value (parser/parse-strokes value)]
|
||||
(cond
|
||||
(not (sm/validate [:vector ::cts/stroke] value))
|
||||
(not (sm/validate [:vector cts/schema:stroke] value))
|
||||
(u/display-not-valid :strokes value)
|
||||
|
||||
(not (r/check-permission plugin-id "content:write"))
|
||||
|
|
|
@ -82,7 +82,7 @@
|
|||
|
||||
(defn get-color-name
|
||||
[color]
|
||||
(or (:color-library-name color)
|
||||
(or (:name (meta color))
|
||||
(:name color)
|
||||
(:color color)
|
||||
(gradient-type->string (:type (:gradient color)))))
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
(fn [key val]
|
||||
(when (some? backend)
|
||||
(if (some? val)
|
||||
(.setItem ^js backend (encode-key prefix key) (t/encode-str val))
|
||||
(.setItem ^js backend (encode-key prefix key) (t/encode-str val {:with-meta true}))
|
||||
(.removeItem ^js backend (encode-key prefix key)))))
|
||||
|
||||
on-change*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue