mirror of
https://github.com/penpot/penpot.git
synced 2025-01-24 07:29:08 -05:00
Merge pull request #2659 from penpot/alotor-flex-layout-features
Flex layout features
This commit is contained in:
commit
507800ae4e
10 changed files with 195 additions and 58 deletions
|
@ -8,7 +8,6 @@
|
|||
(:require
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes.points :as gpo]
|
||||
[app.common.math :as mth]
|
||||
[app.common.types.shape.layout :as ctl]))
|
||||
|
||||
(defn child-layout-bound-points
|
||||
|
@ -55,38 +54,32 @@
|
|||
(gpt/add (hv (/ width 2)))
|
||||
|
||||
(and col? h-end?)
|
||||
(gpt/add (hv width)))]
|
||||
(gpt/add (hv width)))
|
||||
|
||||
(cond-> [base-p]
|
||||
(and (mth/almost-zero? min-width) (mth/almost-zero? min-height))
|
||||
(conj (cond-> base-p
|
||||
row?
|
||||
(gpt/add (hv width))
|
||||
;; We need some height/width to calculate the bounds. We stablish the minimum
|
||||
min-width (max min-width 0.01)
|
||||
min-height (max min-height 0.01)]
|
||||
|
||||
col?
|
||||
(gpt/add (vv height))))
|
||||
(-> [base-p]
|
||||
(conj (cond-> base-p
|
||||
(or row? h-start?)
|
||||
(gpt/add (hv min-width))
|
||||
|
||||
(not (mth/almost-zero? min-width))
|
||||
(conj (cond-> base-p
|
||||
(or row? h-start?)
|
||||
(gpt/add (hv min-width))
|
||||
(and col? h-center?)
|
||||
(gpt/add (hv (/ min-width 2)))
|
||||
|
||||
(and col? h-center?)
|
||||
(gpt/add (hv (/ min-width 2)))
|
||||
(and col? h-center?)
|
||||
(gpt/subtract (hv min-width))))
|
||||
|
||||
(and col? h-center?)
|
||||
(gpt/subtract (hv min-width))))
|
||||
(conj (cond-> base-p
|
||||
(or col? v-start?)
|
||||
(gpt/add (vv min-height))
|
||||
|
||||
(not (mth/almost-zero? min-height))
|
||||
(conj (cond-> base-p
|
||||
(or col? v-start?)
|
||||
(gpt/add (vv min-height))
|
||||
(and row? v-center?)
|
||||
(gpt/add (vv (/ min-height 2)))
|
||||
|
||||
(and row? v-center?)
|
||||
(gpt/add (vv (/ min-height 2)))
|
||||
|
||||
(and row? v-end?)
|
||||
(gpt/subtract (vv min-height)))))))
|
||||
(and row? v-end?)
|
||||
(gpt/subtract (vv min-height)))))))
|
||||
|
||||
(defn layout-content-bounds
|
||||
[bounds {:keys [layout-padding] :as parent} children]
|
||||
|
@ -107,8 +100,11 @@
|
|||
child-bounds
|
||||
(if (or (ctl/fill-height? child) (ctl/fill-height? child))
|
||||
(child-layout-bound-points parent child parent-bounds child-bounds)
|
||||
child-bounds)]
|
||||
(gpo/parent-coords-bounds child-bounds parent-bounds)))]
|
||||
child-bounds)
|
||||
|
||||
[margin-top margin-right margin-bottom margin-left] (ctl/child-margins child)]
|
||||
(-> (gpo/parent-coords-bounds child-bounds parent-bounds)
|
||||
(gpo/pad-points (- margin-top) (- margin-right) (- margin-bottom) (- margin-left)))))]
|
||||
|
||||
(as-> children $
|
||||
(map child-bounds $)
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
ratio-width (/ target-width curr-width)
|
||||
ratio-height (/ target-height curr-height)
|
||||
scalev (gpt/point ratio-width ratio-height)]
|
||||
|
||||
(-> modifiers
|
||||
(ctm/resize scalev origin transform transform-inverse))))
|
||||
|
||||
|
@ -41,7 +42,6 @@
|
|||
corner (gpt/point bounds)
|
||||
target-corner (gpt/round corner)
|
||||
deltav (gpt/to-vec corner target-corner)]
|
||||
|
||||
(ctm/move modifiers deltav)))
|
||||
|
||||
(defn set-pixel-precision
|
||||
|
@ -56,8 +56,10 @@
|
|||
has-resize? (size-pixel-precision shape points))
|
||||
|
||||
points
|
||||
(cond-> (:points shape)
|
||||
has-resize? (gco/transform-points (ctm/modifiers->transform modifiers)))]
|
||||
(if has-resize?
|
||||
(-> (:points shape)
|
||||
(gco/transform-points (ctm/modifiers->transform modifiers)) )
|
||||
points)]
|
||||
[modifiers points])]
|
||||
(position-pixel-precision modifiers shape points)))
|
||||
|
||||
|
|
|
@ -76,7 +76,6 @@
|
|||
:layout :layout-container
|
||||
:layout-dir :layout-container
|
||||
:layout-gap :layout-container
|
||||
:layout-type :layout-container
|
||||
:layout-wrap-type :layout-container
|
||||
:layout-padding-type :layout-container
|
||||
:layout-padding :layout-container
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
|
||||
(s/def ::row-gap ::us/safe-number)
|
||||
(s/def ::column-gap ::us/safe-number)
|
||||
(s/def ::layout-type #{:flex :grid})
|
||||
|
||||
(s/def ::layout-gap
|
||||
(s/keys :opt-un [::row-gap ::column-gap]))
|
||||
|
@ -60,7 +59,6 @@
|
|||
::layout-flex-dir
|
||||
::layout-gap
|
||||
::layout-gap-type
|
||||
::layout-type
|
||||
::layout-wrap-type
|
||||
::layout-padding-type
|
||||
::layout-padding
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.snap :as snap]
|
||||
[app.main.streams :as ms]
|
||||
[app.util.dom :as dom]
|
||||
[beicon.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
[potok.core :as ptk]))
|
||||
|
@ -415,6 +416,14 @@
|
|||
(rx/take 1)
|
||||
(rx/map #(start-move from-position))))))
|
||||
|
||||
(defn set-ghost-displacement
|
||||
[move-vector]
|
||||
(ptk/reify ::set-ghost-displacement
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
(when-let [node (dom/get-element-by-class "ghost-outline")]
|
||||
(dom/set-property! node "transform" (gmt/translate-matrix move-vector))))))
|
||||
|
||||
(defn- start-move
|
||||
([from-position] (start-move from-position nil))
|
||||
([from-position ids]
|
||||
|
@ -501,6 +510,9 @@
|
|||
(dwm/build-change-frame-modifiers objects selected target-frame drop-index)
|
||||
(dwm/set-modifiers)))))
|
||||
|
||||
(->> move-stream
|
||||
(rx/map (comp set-ghost-displacement first)))
|
||||
|
||||
;; Last event will write the modifiers creating the changes
|
||||
(->> move-stream
|
||||
(rx/last)
|
||||
|
@ -508,10 +520,10 @@
|
|||
(fn [[_ target-frame drop-index]]
|
||||
(let [undo-id (uuid/next)]
|
||||
(rx/of (dwu/start-undo-transaction undo-id)
|
||||
(move-shapes-to-frame ids target-frame drop-index)
|
||||
(dwm/apply-modifiers {:undo-transation? false})
|
||||
(finish-transform)
|
||||
(dwu/commit-undo-transaction undo-id))))))))))))))
|
||||
(move-shapes-to-frame ids target-frame drop-index)
|
||||
(dwm/apply-modifiers {:undo-transation? false})
|
||||
(finish-transform)
|
||||
(dwu/commit-undo-transaction undo-id))))))))))))))
|
||||
|
||||
(s/def ::direction #{:up :down :right :left})
|
||||
|
||||
|
|
|
@ -332,16 +332,84 @@
|
|||
:penpot:preserve-scroll ((d/nilf str) (:preserve-scroll interaction))}])])))
|
||||
|
||||
|
||||
(defn- export-layout-container-data
|
||||
[{:keys [layout
|
||||
layout-flex-dir
|
||||
layout-gap
|
||||
layout-gap-type
|
||||
layout-wrap-type
|
||||
layout-padding-type
|
||||
layout-padding
|
||||
layout-justify-content
|
||||
layout-align-items
|
||||
layout-align-content]}]
|
||||
|
||||
(when layout
|
||||
(mf/html
|
||||
[:> "penpot:layout"
|
||||
#js {:penpot:layout (d/name layout)
|
||||
:penpot:layout-flex-dir (d/name layout-flex-dir)
|
||||
:penpot:layout-gap-type (d/name layout-gap-type)
|
||||
:penpot:layout-gap-row (:row-gap layout-gap)
|
||||
:penpot:layout-gap-column (:column-gap layout-gap)
|
||||
:penpot:layout-wrap-type (d/name layout-wrap-type)
|
||||
:penpot:layout-padding-type (d/name layout-padding-type)
|
||||
:penpot:layout-padding-p1 (:p1 layout-padding)
|
||||
:penpot:layout-padding-p2 (:p2 layout-padding)
|
||||
:penpot:layout-padding-p3 (:p3 layout-padding)
|
||||
:penpot:layout-padding-p4 (:p4 layout-padding)
|
||||
:penpot:layout-justify-content (d/name layout-justify-content)
|
||||
:penpot:layout-align-items (d/name layout-align-items)
|
||||
:penpot:layout-align-content (d/name layout-align-content)}])))
|
||||
|
||||
(defn- export-layout-item-data
|
||||
[{:keys [layout-item-margin
|
||||
layout-item-margin-type
|
||||
layout-item-h-sizing
|
||||
layout-item-v-sizing
|
||||
layout-item-max-h
|
||||
layout-item-min-h
|
||||
layout-item-max-w
|
||||
layout-item-min-w
|
||||
layout-item-align-self]}]
|
||||
|
||||
(when (or layout-item-margin
|
||||
layout-item-margin-type
|
||||
layout-item-h-sizing
|
||||
layout-item-v-sizing
|
||||
layout-item-max-h
|
||||
layout-item-min-h
|
||||
layout-item-max-w
|
||||
layout-item-min-w
|
||||
layout-item-align-self)
|
||||
(mf/html
|
||||
[:> "penpot:layout-item"
|
||||
#js {:penpot:layout-item-margin-m1 (:m1 layout-item-margin)
|
||||
:penpot:layout-item-margin-m2 (:m2 layout-item-margin)
|
||||
:penpot:layout-item-margin-m3 (:m3 layout-item-margin)
|
||||
:penpot:layout-item-margin-m4 (:m4 layout-item-margin)
|
||||
:penpot:layout-item-margin-type (d/name layout-item-margin-type)
|
||||
:penpot:layout-item-h-sizing (d/name layout-item-h-sizing)
|
||||
:penpot:layout-item-v-sizing (d/name layout-item-v-sizing)
|
||||
:penpot:layout-item-max-h layout-item-max-h
|
||||
:penpot:layout-item-min-h layout-item-min-h
|
||||
:penpot:layout-item-max-w layout-item-max-w
|
||||
:penpot:layout-item-min-w layout-item-min-w
|
||||
:penpot:layout-item-align-self (d/name layout-item-align-self)}])))
|
||||
|
||||
|
||||
(mf/defc export-data
|
||||
[{:keys [shape]}]
|
||||
(let [props (-> (obj/create) (add-data shape) (add-library-refs shape))]
|
||||
[:> "penpot:shape" props
|
||||
(export-shadow-data shape)
|
||||
(export-blur-data shape)
|
||||
(export-exports-data shape)
|
||||
(export-svg-data shape)
|
||||
(export-interactions-data shape)
|
||||
(export-fills-data shape)
|
||||
(export-strokes-data shape)
|
||||
(export-grid-data shape)]))
|
||||
(export-shadow-data shape)
|
||||
(export-blur-data shape)
|
||||
(export-exports-data shape)
|
||||
(export-svg-data shape)
|
||||
(export-interactions-data shape)
|
||||
(export-fills-data shape)
|
||||
(export-strokes-data shape)
|
||||
(export-grid-data shape)
|
||||
(export-layout-container-data shape)
|
||||
(export-layout-item-data shape)]))
|
||||
|
||||
|
|
|
@ -382,7 +382,6 @@
|
|||
|
||||
on-padding-change
|
||||
(fn [type prop val]
|
||||
(prn "??" type prop val)
|
||||
(cond
|
||||
(and (= type :simple) (= prop :p1))
|
||||
(st/emit! (dwsl/update-layout ids {:layout-padding {:p1 val :p3 val}}))
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.hooks :as ui-hooks]
|
||||
|
@ -293,14 +294,25 @@
|
|||
:modifiers modifiers}])
|
||||
|
||||
(when show-frame-outline?
|
||||
[:& outline/shape-outlines
|
||||
{:objects objects-modified
|
||||
:hover #{(->> @hover-ids
|
||||
(filter #(cph/frame-shape? (get base-objects %)))
|
||||
(remove selected)
|
||||
(first))}
|
||||
:zoom zoom
|
||||
:modifiers modifiers}])
|
||||
(let [outlined-frame-id
|
||||
(->> @hover-ids
|
||||
(filter #(cph/frame-shape? (get base-objects %)))
|
||||
(remove selected)
|
||||
(first))
|
||||
outlined-frame (get objects outlined-frame-id)]
|
||||
[:*
|
||||
[:& outline/shape-outlines
|
||||
{:objects objects-modified
|
||||
:hover #{outlined-frame-id}
|
||||
:zoom zoom
|
||||
:modifiers modifiers}]
|
||||
|
||||
(when (ctl/layout? outlined-frame)
|
||||
[:g.ghost-outline
|
||||
[:& outline/shape-outlines
|
||||
{:objects base-objects
|
||||
:selected selected
|
||||
:zoom zoom}]])]))
|
||||
|
||||
(when show-outlines?
|
||||
[:& outline/shape-outlines
|
||||
|
|
|
@ -75,8 +75,8 @@
|
|||
points [start-p
|
||||
(-> start-p (gpt/add (xv line-width)))
|
||||
(-> start-p (gpt/add (xv line-width)) (gpt/add (yv line-height)))
|
||||
(-> start-p (gpt/add (yv line-height)))
|
||||
]]
|
||||
(-> start-p (gpt/add (yv line-height)))]]
|
||||
|
||||
[:g.layout-line {:key (dm/str "line-" idx)}
|
||||
[:polygon {:points (->> points (map #(dm/fmt "%, %" (:x %) (:y %))) (str/join " "))
|
||||
:style {:stroke "red" :stroke-width (/ 2 zoom) :stroke-dasharray (dm/str (/ 10 zoom) " " (/ 5 zoom))}}]]))]))))
|
||||
|
|
|
@ -869,6 +869,54 @@
|
|||
:style
|
||||
parse-style))))
|
||||
|
||||
(defn add-layout-container-data [props node]
|
||||
(if-let [data (get-data node :penpot:layout)]
|
||||
(merge props
|
||||
(d/without-nils
|
||||
{:layout (get-meta data :layout keyword)
|
||||
:layout-flex-dir (get-meta data :layout-flex-dir keyword)
|
||||
:layout-wrap-type (get-meta data :layout-wrap-type keyword)
|
||||
|
||||
:layout-gap-type (get-meta data :layout-gap-type keyword)
|
||||
:layout-gap
|
||||
(d/without-nils
|
||||
{:row-gap (get-meta data :layout-gap-row d/parse-double)
|
||||
:column-gap (get-meta data :layout-gap-column d/parse-double)})
|
||||
|
||||
:layout-padding-type (get-meta data :layout-padding-type keyword)
|
||||
:layout-padding
|
||||
(d/without-nils
|
||||
{:p1 (get-meta data :layout-padding-p1 d/parse-double)
|
||||
:p2 (get-meta data :layout-padding-p2 d/parse-double)
|
||||
:p3 (get-meta data :layout-padding-p3 d/parse-double)
|
||||
:p4 (get-meta data :layout-padding-p4 d/parse-double)})
|
||||
|
||||
:layout-justify-content (get-meta data :layout-justify-content keyword)
|
||||
:layout-align-items (get-meta data :layout-align-items keyword)
|
||||
:layout-align-content (get-meta data :layout-align-content keyword)}))
|
||||
props))
|
||||
|
||||
(defn add-layout-item-data [props node]
|
||||
(if-let [data (get-data node :penpot:layout-item)]
|
||||
(merge props
|
||||
(d/without-nils
|
||||
{:layout-item-margin
|
||||
(d/without-nils
|
||||
{:m1 (get-meta data :layout-item-margin-m1 d/parse-double)
|
||||
:m2 (get-meta data :layout-item-margin-m2 d/parse-double)
|
||||
:m3 (get-meta data :layout-item-margin-m3 d/parse-double)
|
||||
:m4 (get-meta data :layout-item-margin-m4 d/parse-double)})
|
||||
|
||||
:layout-item-margin-type (get-meta data :layout-item-margin-type keyword)
|
||||
:layout-item-h-sizing (get-meta data :layout-item-h-sizing keyword)
|
||||
:layout-item-v-sizing (get-meta data :layout-item-v-sizing keyword)
|
||||
:layout-item-max-h (get-meta data :layout-item-max-h d/parse-double)
|
||||
:layout-item-min-h (get-meta data :layout-item-min-h d/parse-double)
|
||||
:layout-item-max-w (get-meta data :layout-item-max-w d/parse-double)
|
||||
:layout-item-min-w (get-meta data :layout-item-min-w d/parse-double)
|
||||
:layout-item-align-self (get-meta data :layout-item-align-self keyword)}))
|
||||
props))
|
||||
|
||||
(defn parse-data
|
||||
[type node]
|
||||
|
||||
|
@ -894,7 +942,10 @@
|
|||
(add-svg-content node))
|
||||
|
||||
(cond-> (= :frame type)
|
||||
(add-frame-data node))
|
||||
(-> (add-frame-data node)
|
||||
(add-layout-container-data node)))
|
||||
|
||||
(add-layout-item-data node)
|
||||
|
||||
(cond-> (= :group type)
|
||||
(add-group-data node))
|
||||
|
|
Loading…
Add table
Reference in a new issue