mirror of
https://github.com/penpot/penpot.git
synced 2025-08-03 01:58:29 +02:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
b3847cafa8
33 changed files with 1128 additions and 936 deletions
|
@ -44,6 +44,21 @@
|
|||
"image/svg+xml" :svg
|
||||
nil))
|
||||
|
||||
(defn mtype->extension [mtype]
|
||||
;; https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
|
||||
(case mtype
|
||||
"image/apng" ".apng"
|
||||
"image/avif" ".avif"
|
||||
"image/gif" ".gif"
|
||||
"image/jpeg" ".jpg"
|
||||
"image/png" ".png"
|
||||
"image/svg+xml" ".svg"
|
||||
"image/webp" ".webp"
|
||||
"application/zip" ".zip"
|
||||
"application/penpot" ".penpot"
|
||||
"application/pdf" ".pdf"
|
||||
nil))
|
||||
|
||||
(def max-file-size (* 5 1024 1024))
|
||||
|
||||
(s/def ::id uuid?)
|
||||
|
|
|
@ -286,37 +286,38 @@
|
|||
update-shape
|
||||
(fn [changes id]
|
||||
(let [old-obj (get objects id)
|
||||
new-obj (update-fn old-obj)
|
||||
new-obj (update-fn old-obj)]
|
||||
(if (= old-obj new-obj)
|
||||
changes
|
||||
(let [attrs (or attrs (d/concat-set (keys old-obj) (keys new-obj)))
|
||||
|
||||
attrs (or attrs (d/concat-set (keys old-obj) (keys new-obj)))
|
||||
{rops :rops uops :uops}
|
||||
(reduce #(generate-operation %1 %2 old-obj new-obj ignore-geometry?)
|
||||
{:rops [] :uops []}
|
||||
attrs)
|
||||
|
||||
{rops :rops uops :uops}
|
||||
(reduce #(generate-operation %1 %2 old-obj new-obj ignore-geometry?)
|
||||
{:rops [] :uops []}
|
||||
attrs)
|
||||
uops (cond-> uops
|
||||
(seq uops)
|
||||
(d/preconj {:type :set-touched :touched (:touched old-obj)}))
|
||||
|
||||
uops (cond-> uops
|
||||
(seq uops)
|
||||
(d/preconj {:type :set-touched :touched (:touched old-obj)}))
|
||||
change (cond-> {:type :mod-obj
|
||||
:id id}
|
||||
|
||||
change (cond-> {:type :mod-obj
|
||||
:id id}
|
||||
(some? page-id)
|
||||
(assoc :page-id page-id)
|
||||
|
||||
(some? page-id)
|
||||
(assoc :page-id page-id)
|
||||
(some? component-id)
|
||||
(assoc :component-id component-id))]
|
||||
|
||||
(some? component-id)
|
||||
(assoc :component-id component-id))]
|
||||
(cond-> changes
|
||||
(seq rops)
|
||||
(update :redo-changes conj (assoc change :operations rops))
|
||||
|
||||
(cond-> changes
|
||||
(seq rops)
|
||||
(update :redo-changes conj (assoc change :operations rops))
|
||||
(seq uops)
|
||||
(update :undo-changes d/preconj (assoc change :operations uops)))))))]
|
||||
|
||||
(seq uops)
|
||||
(update :undo-changes d/preconj (assoc change :operations uops)))))]
|
||||
|
||||
(-> (reduce update-shape changes ids)
|
||||
(apply-changes-local)))))
|
||||
(-> (reduce update-shape changes ids)
|
||||
(apply-changes-local)))))
|
||||
|
||||
(defn remove-objects
|
||||
[changes ids]
|
||||
|
|
|
@ -502,3 +502,20 @@
|
|||
(reduce process-shape (transient {}))
|
||||
(persistent!))
|
||||
persistent!)))
|
||||
|
||||
(defn selected-subtree
|
||||
"Given a set of shapes, returns an objects subtree with the parents
|
||||
of the selected items up to the root. Useful to calculate a partial z-index"
|
||||
[objects selected]
|
||||
|
||||
(let [selected+parents
|
||||
(into selected
|
||||
(mapcat #(get-parent-ids objects %))
|
||||
selected)
|
||||
|
||||
remove-children
|
||||
(fn [shape]
|
||||
(update shape :shapes #(filterv selected+parents %)))]
|
||||
|
||||
(-> (select-keys objects selected+parents)
|
||||
(d/update-vals remove-children))))
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
|
||||
(ns app.common.spec.color
|
||||
(:require
|
||||
[app.common.spec :as us]
|
||||
[clojure.spec.alpha :as s]))
|
||||
[app.common.data :as d]
|
||||
[app.common.spec :as us]
|
||||
[app.common.text :as txt]
|
||||
[clojure.spec.alpha :as s]))
|
||||
|
||||
;; TODO: waiting clojure 1.11 to rename this all :internal.stuff to a
|
||||
;; more consistent name.
|
||||
|
@ -46,7 +48,7 @@
|
|||
:internal.gradient/width
|
||||
:internal.gradient/stops]))
|
||||
|
||||
;;; --- COLORS
|
||||
;; --- COLORS
|
||||
|
||||
(s/def :internal.color/name string?)
|
||||
(s/def :internal.color/path (s/nilable string?))
|
||||
|
@ -54,6 +56,15 @@
|
|||
(s/def :internal.color/color (s/nilable string?))
|
||||
(s/def :internal.color/opacity (s/nilable ::us/safe-number))
|
||||
(s/def :internal.color/gradient (s/nilable ::gradient))
|
||||
(s/def :internal.color/ref-id uuid?)
|
||||
(s/def :internal.color/ref-file uuid?)
|
||||
|
||||
(s/def ::shape-color
|
||||
(s/keys :req-un [:us/color
|
||||
:internal.color/opacity]
|
||||
:opt-un [:internal.color/gradient
|
||||
:internal.color/ref-id
|
||||
:internal.color/ref-file]))
|
||||
|
||||
(s/def ::color
|
||||
(s/keys :opt-un [::id
|
||||
|
@ -70,6 +81,197 @@
|
|||
:internal.color/opacity
|
||||
:internal.color/gradient]))
|
||||
|
||||
;; --- Helpers for color in different parts of a shape
|
||||
|
||||
;; fill
|
||||
|
||||
(defn fill->shape-color
|
||||
[fill]
|
||||
(d/without-nils {:color (:fill-color fill)
|
||||
:opacity (:fill-opacity fill)
|
||||
:gradient (:fill-color-gradient fill)
|
||||
:ref-id (:fill-color-ref-id fill)
|
||||
:ref-file (:fill-color-ref-file fill)}))
|
||||
|
||||
(defn set-fill-color
|
||||
[shape position color opacity gradient]
|
||||
(update-in shape [:fills position]
|
||||
(fn [fill]
|
||||
(d/without-nils (assoc fill
|
||||
:fill-color color
|
||||
:fill-opacity opacity
|
||||
:fill-color-gradient gradient)))))
|
||||
|
||||
(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])))
|
||||
|
||||
;; stroke
|
||||
|
||||
(defn stroke->shape-color
|
||||
[stroke]
|
||||
(d/without-nils {:color (:stroke-color stroke)
|
||||
:opacity (:stroke-opacity stroke)
|
||||
:gradient (:stroke-color-gradient stroke)
|
||||
:ref-id (:stroke-color-ref-id stroke)
|
||||
:ref-file (:stroke-color-ref-file stroke)}))
|
||||
|
||||
(defn set-stroke-color
|
||||
[shape position color opacity gradient]
|
||||
(update-in shape [:strokes position]
|
||||
(fn [stroke]
|
||||
(d/without-nils (assoc stroke
|
||||
:stroke-color color
|
||||
:stroke-opacity opacity
|
||||
:stroke-color-gradient gradient)))))
|
||||
|
||||
(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])))
|
||||
|
||||
;; shadow
|
||||
|
||||
(defn shadow->shape-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)}))
|
||||
|
||||
(defn set-shadow-color
|
||||
[shape position color opacity gradient]
|
||||
(update-in shape [:shadow position :color]
|
||||
(fn [shadow-color]
|
||||
(d/without-nils (assoc shadow-color
|
||||
:color color
|
||||
:opacity opacity
|
||||
:gradient gradient)))))
|
||||
|
||||
(defn detach-shadow-color
|
||||
[shape position]
|
||||
(-> shape
|
||||
(d/dissoc-in [:shadow position :color :id])
|
||||
(d/dissoc-in [:shadow position :color :file-id])))
|
||||
|
||||
;; grid
|
||||
|
||||
(defn grid->shape-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)}))
|
||||
|
||||
(defn set-grid-color
|
||||
[shape position color opacity gradient]
|
||||
(update-in shape [:grids position :params :color]
|
||||
(fn [grid-color]
|
||||
(d/without-nils (assoc grid-color
|
||||
:color color
|
||||
:opacity opacity
|
||||
:gradient gradient)))))
|
||||
|
||||
(defn detach-grid-color
|
||||
[shape position]
|
||||
(-> shape
|
||||
(d/dissoc-in [:grids position :params :color :id])
|
||||
(d/dissoc-in [:grids position :params :color :file-id])))
|
||||
|
||||
;; --- 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))))
|
||||
|
||||
(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))
|
||||
(when (= (:type shape) :frame)
|
||||
(map grid->shape-color (:grids shape)))
|
||||
(when (= (:type shape) :text)
|
||||
(reduce (fn [colors node]
|
||||
(concat colors (get-text-node-colors node)))
|
||||
()
|
||||
(txt/node-seq (:content shape))))))
|
||||
|
||||
(defn uses-library-colors?
|
||||
"Check if the shape uses any color in the given library."
|
||||
[shape library-id]
|
||||
(let [all-colors (get-all-colors shape)]
|
||||
(some #(and (some? (:ref-id %))
|
||||
(= (:ref-file %) library-id))
|
||||
all-colors)))
|
||||
|
||||
(defn sync-shape-colors
|
||||
"Look for usage of any color of the given library inside the shape,
|
||||
and, in this case, copy the library color into the shape."
|
||||
[shape library-id library-colors]
|
||||
(let [sync-color (fn [shape position shape-color set-fn detach-fn]
|
||||
(if (= (:ref-file shape-color) library-id)
|
||||
(let [library-color (get library-colors (:ref-id shape-color))]
|
||||
(if (some? library-color)
|
||||
(set-fn shape
|
||||
position
|
||||
(:color library-color)
|
||||
(:opacity library-color)
|
||||
(:gradient library-color))
|
||||
(detach-fn shape position)))
|
||||
shape))
|
||||
|
||||
sync-fill (fn [shape [position fill]]
|
||||
(sync-color shape
|
||||
position
|
||||
(fill->shape-color fill)
|
||||
set-fill-color
|
||||
detach-fill-color))
|
||||
|
||||
sync-stroke (fn [shape [position stroke]]
|
||||
(sync-color shape
|
||||
position
|
||||
(stroke->shape-color stroke)
|
||||
set-stroke-color
|
||||
detach-stroke-color))
|
||||
|
||||
sync-shadow (fn [shape [position shadow]]
|
||||
(sync-color shape
|
||||
position
|
||||
(shadow->shape-color shadow)
|
||||
set-shadow-color
|
||||
detach-shadow-color))
|
||||
|
||||
sync-grid (fn [shape [position grid]]
|
||||
(sync-color shape
|
||||
position
|
||||
(grid->shape-color grid)
|
||||
set-grid-color
|
||||
detach-grid-color))
|
||||
|
||||
sync-text-node (fn [node]
|
||||
(as-> node $
|
||||
(reduce sync-fill $ (d/enumerate (:fills $)))
|
||||
(reduce sync-stroke $ (d/enumerate (:strokes $)))))
|
||||
|
||||
sync-text (fn [shape]
|
||||
(let [content (:content shape)
|
||||
new-content (txt/transform-nodes sync-text-node content)]
|
||||
(if (not= content new-content)
|
||||
(assoc shape :content new-content)
|
||||
shape)))]
|
||||
|
||||
(as-> shape $
|
||||
(reduce sync-fill $ (d/enumerate (:fills $)))
|
||||
(reduce sync-stroke $ (d/enumerate (:strokes $)))
|
||||
(reduce sync-shadow $ (d/enumerate (:shadow $)))
|
||||
(reduce sync-grid $ (d/enumerate (:grids $)))
|
||||
(sync-text $))))
|
||||
|
|
|
@ -166,11 +166,11 @@
|
|||
::blocked
|
||||
::collapsed
|
||||
::fills
|
||||
::fill-color
|
||||
::fill-opacity
|
||||
::fill-color-gradient
|
||||
::fill-color-ref-file
|
||||
::fill-color-ref-id
|
||||
::fill-color ;; TODO: remove these attributes
|
||||
::fill-opacity ;; when backward compatibility
|
||||
::fill-color-gradient ;; is no longer needed
|
||||
::fill-color-ref-file ;;
|
||||
::fill-color-ref-id ;;
|
||||
::hide-fill-on-export
|
||||
::font-family
|
||||
::font-size
|
||||
|
@ -196,10 +196,10 @@
|
|||
::exports
|
||||
::shapes
|
||||
::strokes
|
||||
::stroke-color
|
||||
::stroke-color-ref-file
|
||||
::stroke-color-ref-id
|
||||
::stroke-opacity
|
||||
::stroke-color ;; TODO: same thing
|
||||
::stroke-color-ref-file ;;
|
||||
::stroke-color-ref-i ;;
|
||||
::stroke-opacity ;;
|
||||
::stroke-style
|
||||
::stroke-width
|
||||
::stroke-alignment
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue