mirror of
https://github.com/penpot/penpot.git
synced 2025-08-03 07:38:35 +02:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
2ea81c0114
49 changed files with 788 additions and 519 deletions
|
@ -200,7 +200,7 @@
|
|||
|
||||
(assert (nil? (:current-component-id file)))
|
||||
(let [page-id (or (:id data) (uuid/next))
|
||||
page (-> (ctp/make-empty-page page-id "Page-1")
|
||||
page (-> (ctp/make-empty-page page-id "Page 1")
|
||||
(d/deep-merge data))]
|
||||
(-> file
|
||||
(commit-change
|
||||
|
|
|
@ -43,13 +43,13 @@
|
|||
(defn bounding-box
|
||||
"Returns a rect that wraps the shape after all transformations applied."
|
||||
[shape]
|
||||
; TODO: perhaps we need to store this calculation in a shape attribute
|
||||
;; TODO: perhaps we need to store this calculation in a shape attribute
|
||||
(gpr/points->rect (:points shape)))
|
||||
|
||||
(defn left-bound
|
||||
"Returns the lowest x coord of the shape BEFORE applying transformations."
|
||||
; TODO: perhaps some day we want after transformations, but for the
|
||||
; moment it's enough as is now.
|
||||
;; TODO: perhaps some day we want after transformations, but for the
|
||||
;; moment it's enough as is now.
|
||||
[shape]
|
||||
(or (:x shape) (:x (:selrect shape)))) ; Paths don't have :x attribute
|
||||
|
||||
|
@ -106,8 +106,8 @@
|
|||
|
||||
([attr val1 val2 precision]
|
||||
(let [close-val? (fn [num1 num2]
|
||||
(when (and (number? num1) (number? num2))
|
||||
(< (mth/abs (- num1 num2)) precision)))]
|
||||
(when (and (number? num1) (number? num2))
|
||||
(< (mth/abs (- num1 num2)) precision)))]
|
||||
(cond
|
||||
(and (number? val1) (number? val2))
|
||||
(close-val? val1 val2)
|
||||
|
|
|
@ -210,7 +210,7 @@
|
|||
;; after-vec will contain the side length of the grown side
|
||||
;; we scale the shape by the diference and translate it by the start
|
||||
;; displacement (so its left+top position is constant)
|
||||
scale (/ (gpt/length after-vec) (gpt/length before-vec))
|
||||
scale (/ (gpt/length after-vec) (max 0.01 (gpt/length before-vec)))
|
||||
|
||||
resize-origin (gpo/origin child-points-after)
|
||||
|
||||
|
@ -268,11 +268,11 @@
|
|||
|
||||
scale-x (if (= :scale constraints-h)
|
||||
1
|
||||
(/ (gpo/width-points child-bb-before) (gpo/width-points child-bb-after)))
|
||||
(/ (gpo/width-points child-bb-before) (max 0.01 (gpo/width-points child-bb-after))))
|
||||
|
||||
scale-y (if (= :scale constraints-v)
|
||||
1
|
||||
(/ (gpo/height-points child-bb-before) (gpo/height-points child-bb-after)))
|
||||
(/ (gpo/height-points child-bb-before) (max 0.01 (gpo/height-points child-bb-after))))
|
||||
|
||||
resize-vector (gpt/point scale-x scale-y)
|
||||
resize-origin (gpo/origin transformed-child-bounds)
|
||||
|
|
|
@ -238,6 +238,30 @@
|
|||
(and col? (< total-min-width rest-layout-width total-max-width) (not (ctl/auto-width? parent)))
|
||||
(distribute-space :line-width :line-min-width :line-max-width total-min-width rest-layout-width))
|
||||
|
||||
;; Add information to limit the growth of width: 100% shapes to the bounds of the layout
|
||||
layout-lines
|
||||
(cond
|
||||
row?
|
||||
(->> layout-lines
|
||||
(reduce
|
||||
(fn [[result rest-layout-height] {:keys [line-height] :as line}]
|
||||
[(conj result (assoc line :to-bound-height rest-layout-height))
|
||||
(- rest-layout-height line-height layout-gap-row)])
|
||||
[[] layout-height])
|
||||
(first))
|
||||
|
||||
col?
|
||||
(->> layout-lines
|
||||
(reduce
|
||||
(fn [[result rest-layout-width] {:keys [line-width] :as line}]
|
||||
[(conj result (assoc line :to-bound-width rest-layout-width))
|
||||
(- rest-layout-width line-width layout-gap-col)])
|
||||
[[] layout-width])
|
||||
(first))
|
||||
|
||||
:else
|
||||
layout-lines)
|
||||
|
||||
[total-width total-height] (->> layout-lines (reduce add-lines [0 0]))
|
||||
|
||||
base-p (flp/get-base-line parent layout-bounds total-width total-height num-lines)]
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
transform-inverse
|
||||
child
|
||||
child-origin child-width
|
||||
{:keys [children-data line-width] :as layout-data}]
|
||||
{:keys [children-data line-width to-bound-width] :as layout-data}]
|
||||
|
||||
(cond
|
||||
(ctl/row? parent)
|
||||
|
@ -30,8 +30,9 @@
|
|||
:modifiers (ctm/resize-modifiers (gpt/point fill-scale 1) child-origin transform transform-inverse)})
|
||||
|
||||
(ctl/col? parent)
|
||||
(let [target-width (max (- line-width (ctl/child-width-margin child)) 0.01)
|
||||
max-width (ctl/child-max-width child)
|
||||
(let [line-width (min line-width (or to-bound-width line-width))
|
||||
target-width (max (- line-width (ctl/child-width-margin child)) 0.01)
|
||||
max-width (max (ctl/child-max-width child) 0.01)
|
||||
target-width (min max-width target-width)
|
||||
fill-scale (/ target-width child-width)]
|
||||
{:width target-width
|
||||
|
@ -43,7 +44,7 @@
|
|||
transform transform-inverse
|
||||
child
|
||||
child-origin child-height
|
||||
{:keys [children-data line-height] :as layout-data}]
|
||||
{:keys [children-data line-height to-bound-height] :as layout-data}]
|
||||
|
||||
(cond
|
||||
(ctl/col? parent)
|
||||
|
@ -53,8 +54,9 @@
|
|||
:modifiers (ctm/resize-modifiers (gpt/point 1 fill-scale) child-origin transform transform-inverse)})
|
||||
|
||||
(ctl/row? parent)
|
||||
(let [target-height (max (- line-height (ctl/child-height-margin child)) 0.01)
|
||||
max-height (ctl/child-max-height child)
|
||||
(let [line-height (min line-height (or to-bound-height line-height))
|
||||
target-height (max (- line-height (ctl/child-height-margin child)) 0.01)
|
||||
max-height (max (ctl/child-max-height child) 0.01)
|
||||
target-height (min max-height target-height)
|
||||
fill-scale (/ target-height child-height)]
|
||||
{:height target-height
|
||||
|
@ -71,8 +73,13 @@
|
|||
(when (or (ctl/fill-width? child) (ctl/fill-height? child))
|
||||
(gtr/calculate-geometry @parent-bounds))
|
||||
|
||||
fill-width (when (ctl/fill-width? child) (calc-fill-width-data parent transform transform-inverse child child-origin child-width layout-line))
|
||||
fill-height (when (ctl/fill-height? child) (calc-fill-height-data parent transform transform-inverse child child-origin child-height layout-line))
|
||||
fill-width
|
||||
(when (ctl/fill-width? child)
|
||||
(calc-fill-width-data parent transform transform-inverse child child-origin child-width layout-line))
|
||||
|
||||
fill-height
|
||||
(when (ctl/fill-height? child)
|
||||
(calc-fill-height-data parent transform transform-inverse child child-origin child-height layout-line))
|
||||
|
||||
child-width (or (:width fill-width) child-width)
|
||||
child-height (or (:height fill-height) child-height)
|
||||
|
|
|
@ -20,9 +20,13 @@
|
|||
hv (partial gpo/start-hv layout-bounds)
|
||||
vv (partial gpo/start-vv layout-bounds)
|
||||
|
||||
end? (ctl/content-end? parent)
|
||||
center? (ctl/content-center? parent)
|
||||
around? (ctl/content-around? parent)
|
||||
wrap? (ctl/wrap? parent)
|
||||
|
||||
end? (or (and wrap? (ctl/content-end? parent))
|
||||
(and (not wrap?) (ctl/align-items-end? parent)))
|
||||
center? (or (and wrap? (ctl/content-center? parent))
|
||||
(and (not wrap?) (ctl/align-items-center? parent)))
|
||||
around? (and wrap? (ctl/content-around? parent))
|
||||
|
||||
;; Adjust the totals so it takes into account the gaps
|
||||
[layout-gap-row layout-gap-col] (ctl/gaps parent)
|
||||
|
|
|
@ -54,11 +54,11 @@
|
|||
|
||||
(defn width-points
|
||||
[[p0 p1 _ _]]
|
||||
(gpt/length (gpt/to-vec p0 p1)))
|
||||
(max 0.01 (gpt/length (gpt/to-vec p0 p1))))
|
||||
|
||||
(defn height-points
|
||||
[[p0 _ _ p3]]
|
||||
(gpt/length (gpt/to-vec p0 p3)))
|
||||
(max 0.01 (gpt/length (gpt/to-vec p0 p3))))
|
||||
|
||||
(defn pad-points
|
||||
[[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left]
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
(defn abs
|
||||
[v]
|
||||
#?(:cljs (js/Math.abs v)
|
||||
:clj (Math/abs v)))
|
||||
:clj (Math/abs (double v))))
|
||||
|
||||
(defn sin
|
||||
"Returns the sine of a number"
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
(dm/export common/file-version)
|
||||
(dm/export common/default-color)
|
||||
(dm/export common/component-sync-attrs)
|
||||
(dm/export common/retrieve-used-names)
|
||||
(dm/export common/generate-unique-name)
|
||||
|
||||
;; Focus
|
||||
(dm/export focus/focus-objects)
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
(ns app.common.pages.common
|
||||
(:require
|
||||
[app.common.colors :as clr]
|
||||
[app.common.uuid :as uuid]))
|
||||
[app.common.data :as d]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.spec.alpha :as s]))
|
||||
|
||||
(def file-version 20)
|
||||
(def default-color clr/gray-20)
|
||||
|
@ -580,3 +583,31 @@
|
|||
:layout-item-min-w
|
||||
:layout-item-align-self}})
|
||||
|
||||
(defn retrieve-used-names
|
||||
"Return a set with the all unique names used in the
|
||||
elements (any entity thas has a :name)"
|
||||
[elements]
|
||||
(into #{} (comp (map :name) (remove nil?)) (vals elements)))
|
||||
|
||||
(defn- extract-numeric-suffix
|
||||
[basename]
|
||||
(if-let [[_ p1 p2] (re-find #"(.*) ([0-9]+)$" basename)]
|
||||
[p1 (+ 1 (d/parse-integer p2))]
|
||||
[basename 1]))
|
||||
|
||||
(s/def ::set-of-strings
|
||||
(s/every ::us/string :kind set?))
|
||||
|
||||
(defn generate-unique-name
|
||||
"A unique name generator"
|
||||
[used basename]
|
||||
(us/assert! ::set-of-strings used)
|
||||
(us/assert! ::us/string basename)
|
||||
(if-not (contains? used basename)
|
||||
basename
|
||||
(let [[prefix initial] (extract-numeric-suffix basename)]
|
||||
(loop [counter initial]
|
||||
(let [candidate (str prefix " " counter)]
|
||||
(if (contains? used candidate)
|
||||
(recur (inc counter))
|
||||
candidate))))))
|
||||
|
|
|
@ -109,6 +109,20 @@
|
|||
(recur (conj result parent-id) parent-id)
|
||||
result))))
|
||||
|
||||
(defn get-parent-ids-with-index
|
||||
"Returns a tuple with the list of parents and a map with the position within each parent"
|
||||
[objects shape-id]
|
||||
(loop [parent-list []
|
||||
parent-indices {}
|
||||
current shape-id]
|
||||
(let [parent-id (dm/get-in objects [current :parent-id])
|
||||
parent (get objects parent-id)]
|
||||
(if (and (some? parent) (not= parent-id current))
|
||||
(let [parent-list (conj parent-list parent-id)
|
||||
parent-indices (assoc parent-indices parent-id (d/index-of (:shapes parent) current))]
|
||||
(recur parent-list parent-indices parent-id))
|
||||
[parent-list parent-indices]))))
|
||||
|
||||
(defn get-siblings-ids
|
||||
[objects id]
|
||||
(let [parent (get-parent objects id)]
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages.common :as common]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[clojure.spec.alpha :as s]))
|
||||
|
@ -130,7 +131,7 @@
|
|||
delta (gpt/subtract position orig-pos)
|
||||
|
||||
objects (:objects container)
|
||||
unames (volatile! (ctst/retrieve-used-names objects))
|
||||
unames (volatile! (common/retrieve-used-names objects))
|
||||
|
||||
frame-id (ctst/frame-id-by-position objects (gpt/add orig-pos delta))
|
||||
frame-ids-map (volatile! {})
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
|
||||
([file-id page-id]
|
||||
(let [page (when (some? page-id)
|
||||
(ctp/make-empty-page page-id "Page-1"))]
|
||||
(ctp/make-empty-page page-id "Page 1"))]
|
||||
(cond-> (-> empty-file-data
|
||||
(assoc :id file-id))
|
||||
|
||||
|
|
|
@ -275,6 +275,21 @@
|
|||
(or (= :stretch layout-align-content)
|
||||
(nil? layout-align-content)))
|
||||
|
||||
(defn align-items-center?
|
||||
[{:keys [layout-align-items]}]
|
||||
(= layout-align-items :center))
|
||||
|
||||
(defn align-items-start?
|
||||
[{:keys [layout-align-items]}]
|
||||
(= layout-align-items :start))
|
||||
|
||||
(defn align-items-end?
|
||||
[{:keys [layout-align-items]}]
|
||||
(= layout-align-items :end))
|
||||
|
||||
(defn align-items-stretch?
|
||||
[{:keys [layout-align-items]}]
|
||||
(= layout-align-items :stretch))
|
||||
|
||||
(defn reverse?
|
||||
[{:keys [layout-flex-dir]}]
|
||||
|
|
|
@ -132,43 +132,34 @@
|
|||
(defn get-base
|
||||
[objects id-a id-b]
|
||||
|
||||
(let [parents-a (reverse (cons id-a (cph/get-parent-ids objects id-a)))
|
||||
parents-b (reverse (cons id-b (cph/get-parent-ids objects id-b)))
|
||||
(let [[parents-a parents-a-index] (cph/get-parent-ids-with-index objects id-a)
|
||||
[parents-b parents-b-index] (cph/get-parent-ids-with-index objects id-b)
|
||||
|
||||
[base base-child-a base-child-b]
|
||||
(loop [parents-a (rest parents-a)
|
||||
parents-b (rest parents-b)
|
||||
base uuid/zero]
|
||||
(cond
|
||||
(not= (first parents-a) (first parents-b))
|
||||
[base (first parents-a) (first parents-b)]
|
||||
parents-a (cons id-a parents-a)
|
||||
parents-b (into #{id-b} parents-b)
|
||||
|
||||
(or (empty? parents-a) (empty? parents-b))
|
||||
[uuid/zero (first parents-a) (first parents-b)]
|
||||
;; Search for the common frame in order
|
||||
base (or (d/seek parents-b parents-a) uuid/zero)
|
||||
|
||||
:else
|
||||
(recur (rest parents-a) (rest parents-b) (first parents-a))))
|
||||
idx-a (get parents-a-index base)
|
||||
idx-b (get parents-b-index base)]
|
||||
|
||||
index-base-a (when base-child-a (cph/get-position-on-parent objects base-child-a))
|
||||
index-base-b (when base-child-b (cph/get-position-on-parent objects base-child-b))]
|
||||
|
||||
[base index-base-a index-base-b]))
|
||||
[base idx-a idx-b]))
|
||||
|
||||
(defn is-shape-over-shape?
|
||||
[objects base-shape-id over-shape-id]
|
||||
|
||||
(let [[base index-a index-b] (get-base objects base-shape-id over-shape-id)]
|
||||
(cond
|
||||
;; The base the base shape, so the other item is bellow
|
||||
(= base base-shape-id)
|
||||
(let [object (get objects base-shape-id)]
|
||||
(or (cph/frame-shape? object)
|
||||
(cph/root-frame? object)))
|
||||
false
|
||||
|
||||
;; The base is the testing over, so it's over
|
||||
(= base over-shape-id)
|
||||
(let [object (get objects over-shape-id)]
|
||||
(or (not (cph/frame-shape? object))
|
||||
(not (cph/root-frame? object))))
|
||||
true
|
||||
|
||||
;; Check which index is lower
|
||||
:else
|
||||
(< index-a index-b))))
|
||||
|
||||
|
@ -284,35 +275,6 @@
|
|||
[frame]
|
||||
(not (mth/almost-zero? (:rotation frame 0))))
|
||||
|
||||
(defn retrieve-used-names
|
||||
[objects]
|
||||
(into #{} (comp (map :name) (remove nil?)) (vals objects)))
|
||||
|
||||
(defn- extract-numeric-suffix
|
||||
[basename]
|
||||
(if-let [[_ p1 p2] (re-find #"(.*)-([0-9]+)$" basename)]
|
||||
[p1 (+ 1 (d/parse-integer p2))]
|
||||
[basename 1]))
|
||||
|
||||
(s/def ::set-of-strings
|
||||
(s/every ::us/string :kind set?))
|
||||
|
||||
(defn generate-unique-name
|
||||
"A unique name generator"
|
||||
[used basename]
|
||||
(us/assert! ::set-of-strings used)
|
||||
(us/assert! ::us/string basename)
|
||||
;; We have add a condition because UX doesn't want numbers on
|
||||
;; layer names.
|
||||
(if-not (contains? used basename)
|
||||
basename
|
||||
(let [[prefix initial] (extract-numeric-suffix basename)]
|
||||
(loop [counter initial]
|
||||
(let [candidate (str prefix "-" counter)]
|
||||
(if (contains? used candidate)
|
||||
(recur (inc counter))
|
||||
candidate))))))
|
||||
|
||||
(defn clone-object
|
||||
"Gets a copy of the object and all its children, with new ids
|
||||
and with the parent-children links correctly set. Admits functions
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
(fn [file-data]
|
||||
(let [id (uuid/next)
|
||||
props (merge {:id id
|
||||
:name "Color-1"
|
||||
:name "Color 1"
|
||||
:color "#000000"
|
||||
:opacity 1}
|
||||
props)]
|
||||
|
@ -140,7 +140,7 @@
|
|||
(fn [file-data]
|
||||
(let [id (uuid/next)
|
||||
props (merge {:id id
|
||||
:name "Typography-1"
|
||||
:name "Typography 1"
|
||||
:font-id "sourcesanspro"
|
||||
:font-family "sourcesanspro"
|
||||
:font-size "14"
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
;; false)
|
||||
|
||||
(t/is (= (count pages) 2))
|
||||
(t/is (= (:name (first pages)) "Page-1"))
|
||||
(t/is (= (:name (first pages)) "Page 1"))
|
||||
(t/is (= (:name (second pages)) "Library backup"))
|
||||
|
||||
(t/is (= (count components) 1))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue