mirror of
https://github.com/penpot/penpot.git
synced 2025-03-12 07:41:43 -05:00
✨ Grid layout polishing
This commit is contained in:
parent
03c64303f5
commit
b13db69cf9
14 changed files with 179 additions and 116 deletions
|
@ -8,9 +8,7 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes.common :as gco]
|
||||
[app.common.geom.shapes.grid-layout.layout-data :as ld]
|
||||
[app.common.geom.shapes.points :as gpo]
|
||||
[app.common.geom.shapes.transforms :as gtr]
|
||||
|
|
|
@ -6,8 +6,11 @@
|
|||
|
||||
(ns app.main.data.workspace.common
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.logging :as log]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.util.router :as rt]
|
||||
[beicon.core :as rx]
|
||||
|
@ -53,10 +56,13 @@
|
|||
(ptk/reify ::undo
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [edition (get-in state [:workspace-local :edition])
|
||||
(let [objects (wsh/lookup-page-objects state)
|
||||
edition (get-in state [:workspace-local :edition])
|
||||
drawing (get state :workspace-drawing)]
|
||||
|
||||
;; Editors handle their own undo's
|
||||
(when (and (nil? edition) (nil? (:object drawing)))
|
||||
(when (or (and (nil? edition) (nil? (:object drawing)))
|
||||
(ctl/grid-layout? objects edition))
|
||||
(let [undo (:workspace-undo state)
|
||||
items (:items undo)
|
||||
index (or (:index undo) (dec (count items)))]
|
||||
|
@ -64,14 +70,17 @@
|
|||
(let [item (get items index)
|
||||
changes (:undo-changes item)
|
||||
undo-group (:undo-group item)
|
||||
find-first-group-idx (fn ffgidx[index]
|
||||
(let [item (get items index)]
|
||||
(if (= (:undo-group item) undo-group)
|
||||
(ffgidx (dec index))
|
||||
(inc index))))
|
||||
|
||||
undo-group-index (when undo-group
|
||||
(find-first-group-idx index))]
|
||||
find-first-group-idx
|
||||
(fn [index]
|
||||
(if (= (dm/get-in items [index :undo-group]) undo-group)
|
||||
(recur (dec index))
|
||||
(inc index)))
|
||||
|
||||
undo-group-index
|
||||
(when undo-group
|
||||
(find-first-group-idx index))]
|
||||
|
||||
(if undo-group
|
||||
(rx/of (undo-to-index (dec undo-group-index)))
|
||||
(rx/of (dwu/materialize-undo changes (dec index))
|
||||
|
@ -117,9 +126,11 @@
|
|||
(ptk/reify ::undo-to-index
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [edition (get-in state [:workspace-local :edition])
|
||||
(let [objects (wsh/lookup-page-objects state)
|
||||
edition (get-in state [:workspace-local :edition])
|
||||
drawing (get state :workspace-drawing)]
|
||||
(when-not (or (some? edition) (not-empty drawing))
|
||||
(when-not (and (or (some? edition) (not-empty drawing))
|
||||
(not (ctl/grid-layout? objects edition)))
|
||||
(let [undo (:workspace-undo state)
|
||||
items (:items undo)
|
||||
index (or (:index undo) (dec (count items)))]
|
||||
|
|
|
@ -45,4 +45,5 @@
|
|||
(let [id (get-in state [:workspace-local :edition])]
|
||||
(-> state
|
||||
(update :workspace-local dissoc :edition)
|
||||
(dissoc :workspace-grid-edition)
|
||||
(cond-> (some? id) (update-in [:workspace-local :edit-path] dissoc id)))))))
|
||||
|
|
|
@ -343,22 +343,21 @@
|
|||
(create-layout-from-selection type))
|
||||
(dwu/commit-undo-transaction undo-id))))))
|
||||
|
||||
(defn toggle-layout-flex
|
||||
[]
|
||||
(defn toggle-layout
|
||||
[type]
|
||||
(ptk/reify ::toggle-layout-flex
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
(let [objects (wsh/lookup-page-objects state)
|
||||
selected (wsh/lookup-selected state)
|
||||
selected-shapes (map (d/getf objects) selected)
|
||||
single? (= (count selected-shapes) 1)
|
||||
has-flex-layout? (and single? (ctl/flex-layout? objects (:id (first selected-shapes))))]
|
||||
has-layout? (and single? (ctl/any-layout? objects (:id (first selected-shapes))))]
|
||||
|
||||
(when (not= 0 (count selected))
|
||||
(if has-flex-layout?
|
||||
(if has-layout?
|
||||
(rx/of (remove-layout selected))
|
||||
(rx/of (create-layout :flex))))))))
|
||||
(rx/of (create-layout type))))))))
|
||||
|
||||
(defn update-layout
|
||||
[ids changes]
|
||||
|
|
|
@ -219,7 +219,12 @@
|
|||
:toggle-layout-flex {:tooltip (ds/shift "A")
|
||||
:command "shift+a"
|
||||
:subsections [:modify-layers]
|
||||
:fn #(emit-when-no-readonly (dwsl/toggle-layout-flex))}
|
||||
:fn #(emit-when-no-readonly (dwsl/toggle-layout :flex))}
|
||||
|
||||
:toggle-layout-grid {:tooltip (ds/meta-shift "A")
|
||||
:command (ds/c-mod "shift+a")
|
||||
:subsections [:modify-layers]
|
||||
:fn #(emit-when-no-readonly (dwsl/toggle-layout :grid))}
|
||||
|
||||
;; TOOLS
|
||||
|
||||
|
|
|
@ -413,9 +413,10 @@
|
|||
is-frame? (and single? has-frame?)
|
||||
is-flex-container? (and is-frame? (= :flex (:layout (first shapes))))
|
||||
ids (->> shapes (map :id))
|
||||
add-flex #(st/emit! (if is-frame?
|
||||
(dwsl/create-layout-from-id ids :flex true)
|
||||
(dwsl/create-layout-from-selection :flex)))
|
||||
add-layout (fn [type]
|
||||
(st/emit! (if is-frame?
|
||||
(dwsl/create-layout-from-id ids type true)
|
||||
(dwsl/create-layout-from-selection type))))
|
||||
remove-flex #(st/emit! (dwsl/remove-layout ids))]
|
||||
|
||||
[:*
|
||||
|
@ -424,7 +425,10 @@
|
|||
[:& menu-separator]
|
||||
[:& menu-entry {:title (tr "workspace.shape.menu.add-flex")
|
||||
:shortcut (sc/get-tooltip :toggle-layout-flex)
|
||||
:on-click add-flex}]])
|
||||
:on-click #(add-layout :flex)}]
|
||||
[:& menu-entry {:title (tr "workspace.shape.menu.add-grid")
|
||||
:shortcut (sc/get-tooltip :toggle-layout-grid)
|
||||
:on-click #(add-layout :grid)}]])
|
||||
(when is-flex-container?
|
||||
[:div
|
||||
[:& menu-separator]
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
(ns app.main.ui.workspace.sidebar.options
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[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.data.workspace :as udw]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
|
@ -20,6 +22,7 @@
|
|||
[app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell]
|
||||
[app.main.ui.workspace.sidebar.options.menus.interactions :refer [interactions-menu]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.layout-container :as layout-container]
|
||||
[app.main.ui.workspace.sidebar.options.page :as page]
|
||||
[app.main.ui.workspace.sidebar.options.shapes.bool :as bool]
|
||||
[app.main.ui.workspace.sidebar.options.shapes.circle :as circle]
|
||||
|
@ -68,15 +71,15 @@
|
|||
(let [drawing (mf/deref refs/workspace-drawing)
|
||||
objects (mf/deref refs/workspace-page-objects)
|
||||
shared-libs (mf/deref refs/workspace-libraries)
|
||||
edition (mf/deref refs/selected-edition)
|
||||
grid-edition (mf/deref refs/workspace-grid-edition)
|
||||
|
||||
selected-shapes (into [] (keep (d/getf objects)) selected)
|
||||
first-selected-shape (first selected-shapes)
|
||||
shape-parent-frame (cph/get-frame objects (:frame-id first-selected-shape))
|
||||
|
||||
[grid-id {cell-id :selected}]
|
||||
(d/seek (fn [[_ {:keys [selected]}]] (some? selected)) grid-edition)
|
||||
|
||||
grid-cell-selected? (and (some? grid-id) (some? cell-id))
|
||||
edit-grid? (ctl/grid-layout? objects edition)
|
||||
selected-cell (dm/get-in grid-edition [edition :selected])
|
||||
|
||||
on-change-tab
|
||||
(fn [options-mode]
|
||||
|
@ -96,10 +99,15 @@
|
|||
[:& align-options]
|
||||
[:& bool-options]
|
||||
(cond
|
||||
grid-cell-selected?
|
||||
(some? selected-cell)
|
||||
[:& grid-cell/options
|
||||
{:shape (get objects grid-id)
|
||||
:cell (get-in objects [grid-id :layout-grid-cells cell-id])}]
|
||||
{:shape (get objects edition)
|
||||
:cell (dm/get-in objects [edition :layout-grid-cells selected-cell])}]
|
||||
|
||||
edit-grid?
|
||||
[:& layout-container/grid-layout-edition
|
||||
{:ids [edition]
|
||||
:values (get objects edition)}]
|
||||
|
||||
(d/not-empty? drawing)
|
||||
[:& shape-options
|
||||
|
|
|
@ -238,7 +238,8 @@
|
|||
[:button.btn-options {:disabled is-default
|
||||
:on-click handle-set-as-default} (tr "workspace.options.grid.params.set-default")]]]]))
|
||||
|
||||
(mf/defc frame-grid [{:keys [shape]}]
|
||||
(mf/defc frame-grid
|
||||
[{:keys [shape]}]
|
||||
(let [id (:id shape)
|
||||
saved-grids (mf/deref workspace-saved-grids)
|
||||
default-grid-params (mf/use-memo (mf/deps saved-grids) #(merge dw/default-grid-params saved-grids))
|
||||
|
|
|
@ -477,7 +477,7 @@
|
|||
|
||||
(mf/defc layout-container-menu
|
||||
{::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "multiple"]))]}
|
||||
[{:keys [ids values multiple] :as props}]
|
||||
[{:keys [ids values multiple] :as props}]
|
||||
(let [open? (mf/use-state false)
|
||||
|
||||
;; Display
|
||||
|
@ -594,53 +594,7 @@
|
|||
(fn [value type]
|
||||
(if (= type :row)
|
||||
(st/emit! (dwsl/update-layout ids {:layout-align-content value}))
|
||||
(st/emit! (dwsl/update-layout ids {:layout-justify-content value})))))
|
||||
|
||||
|
||||
;;Grid columns
|
||||
column-grid-values (:layout-grid-columns values)
|
||||
grid-columns-open? (mf/use-state false)
|
||||
toggle-columns-info (mf/use-callback
|
||||
(fn [_]
|
||||
(swap! grid-columns-open? not)))
|
||||
|
||||
; Grid rows / columns
|
||||
rows-grid-values (:layout-grid-rows values)
|
||||
grid-rows-open? (mf/use-state false)
|
||||
toggle-rows-info
|
||||
(mf/use-callback
|
||||
(fn [_]
|
||||
(swap! grid-rows-open? not)))
|
||||
|
||||
add-new-element
|
||||
(mf/use-callback
|
||||
(mf/deps ids)
|
||||
(fn [type value]
|
||||
(st/emit! (dwsl/add-layout-track ids type value))))
|
||||
|
||||
remove-element
|
||||
(mf/use-callback
|
||||
(mf/deps ids)
|
||||
(fn [type index]
|
||||
(st/emit! (dwsl/remove-layout-track ids type index))))
|
||||
|
||||
set-column-value
|
||||
(mf/use-callback
|
||||
(mf/deps ids)
|
||||
(fn [type index value]
|
||||
(st/emit! (dwsl/change-layout-track ids type index {:value value}))))
|
||||
|
||||
set-column-type
|
||||
(mf/use-callback
|
||||
(mf/deps ids)
|
||||
(fn [type index track-type]
|
||||
(let [value (case track-type
|
||||
:auto nil
|
||||
:flex 1
|
||||
:percent 20
|
||||
:fixed 100)]
|
||||
(st/emit! (dwsl/change-layout-track ids type index {:value value
|
||||
:type track-type})))))]
|
||||
(st/emit! (dwsl/update-layout ids {:layout-justify-content value})))))]
|
||||
|
||||
[:div.element-set
|
||||
[:div.element-set-title
|
||||
|
@ -751,36 +705,112 @@
|
|||
:set-justify set-justify-grid}]
|
||||
[:& justify-grid-row {:is-col? false
|
||||
:justify-items grid-justify-content-row
|
||||
:set-justify set-justify-grid}]]]
|
||||
|
||||
[:& grid-columns-row {:is-col? true
|
||||
:expanded? @grid-columns-open?
|
||||
:toggle toggle-columns-info
|
||||
:column-values column-grid-values
|
||||
:add-new-element add-new-element
|
||||
:set-column-value set-column-value
|
||||
:set-column-type set-column-type
|
||||
:remove-element remove-element}]
|
||||
|
||||
[:& grid-columns-row {:is-col? false
|
||||
:expanded? @grid-rows-open?
|
||||
:toggle toggle-rows-info
|
||||
:column-values rows-grid-values
|
||||
:add-new-element add-new-element
|
||||
:set-column-value set-column-value
|
||||
:set-column-type set-column-type
|
||||
:remove-element remove-element}]
|
||||
|
||||
[:& gap-section {:is-col? is-col?
|
||||
:wrap-type wrap-type
|
||||
:gap-selected? gap-selected?
|
||||
:set-gap set-gap
|
||||
:gap-value (:layout-gap values)}]
|
||||
|
||||
[:& padding-section {:values values
|
||||
:on-change-style change-padding-type
|
||||
:on-change on-padding-change}]]
|
||||
|
||||
:set-justify set-justify-grid}]]]]
|
||||
|
||||
;; Default if not grid or flex
|
||||
nil)))]))
|
||||
|
||||
(mf/defc grid-layout-edition
|
||||
{::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values"]))]}
|
||||
[{:keys [ids values] :as props}]
|
||||
(let [;; Gap
|
||||
gap-selected? (mf/use-state :none)
|
||||
|
||||
set-gap
|
||||
(fn [gap-multiple? type val]
|
||||
(if gap-multiple?
|
||||
(st/emit! (dwsl/update-layout ids {:layout-gap {:row-gap val :column-gap val}}))
|
||||
(st/emit! (dwsl/update-layout ids {:layout-gap {type val}}))))
|
||||
|
||||
;; Padding
|
||||
change-padding-type
|
||||
(fn [type]
|
||||
(st/emit! (dwsl/update-layout ids {:layout-padding-type type})))
|
||||
|
||||
on-padding-change
|
||||
(fn [type prop val]
|
||||
(cond
|
||||
(and (= type :simple) (= prop :p1))
|
||||
(st/emit! (dwsl/update-layout ids {:layout-padding {:p1 val :p3 val}}))
|
||||
|
||||
(and (= type :simple) (= prop :p2))
|
||||
(st/emit! (dwsl/update-layout ids {:layout-padding {:p2 val :p4 val}}))
|
||||
|
||||
:else
|
||||
(st/emit! (dwsl/update-layout ids {:layout-padding {prop val}}))))
|
||||
|
||||
;;Grid columns
|
||||
column-grid-values (:layout-grid-columns values)
|
||||
grid-columns-open? (mf/use-state false)
|
||||
toggle-columns-info (mf/use-callback
|
||||
(fn [_]
|
||||
(swap! grid-columns-open? not)))
|
||||
|
||||
; Grid rows / columns
|
||||
rows-grid-values (:layout-grid-rows values)
|
||||
grid-rows-open? (mf/use-state false)
|
||||
toggle-rows-info
|
||||
(mf/use-callback
|
||||
(fn [_]
|
||||
(swap! grid-rows-open? not)))
|
||||
|
||||
add-new-element
|
||||
(mf/use-callback
|
||||
(mf/deps ids)
|
||||
(fn [type value]
|
||||
(st/emit! (dwsl/add-layout-track ids type value))))
|
||||
|
||||
remove-element
|
||||
(mf/use-callback
|
||||
(mf/deps ids)
|
||||
(fn [type index]
|
||||
(st/emit! (dwsl/remove-layout-track ids type index))))
|
||||
|
||||
set-column-value
|
||||
(mf/use-callback
|
||||
(mf/deps ids)
|
||||
(fn [type index value]
|
||||
(st/emit! (dwsl/change-layout-track ids type index {:value value}))))
|
||||
|
||||
set-column-type
|
||||
(mf/use-callback
|
||||
(mf/deps ids)
|
||||
(fn [type index track-type]
|
||||
(let [value (case track-type
|
||||
:auto nil
|
||||
:flex 1
|
||||
:percent 20
|
||||
:fixed 100)]
|
||||
(st/emit! (dwsl/change-layout-track ids type index {:value value
|
||||
:type track-type})))))]
|
||||
|
||||
[:div.element-set
|
||||
[:div.element-set-title
|
||||
[:span "Grid Layout"]]
|
||||
|
||||
[:div.element-set-content.layout-menu
|
||||
[:& grid-columns-row {:is-col? true
|
||||
:expanded? @grid-columns-open?
|
||||
:toggle toggle-columns-info
|
||||
:column-values column-grid-values
|
||||
:add-new-element add-new-element
|
||||
:set-column-value set-column-value
|
||||
:set-column-type set-column-type
|
||||
:remove-element remove-element}]
|
||||
|
||||
[:& grid-columns-row {:is-col? false
|
||||
:expanded? @grid-rows-open?
|
||||
:toggle toggle-rows-info
|
||||
:column-values rows-grid-values
|
||||
:add-new-element add-new-element
|
||||
:set-column-value set-column-value
|
||||
:set-column-type set-column-type
|
||||
:remove-element remove-element}]
|
||||
|
||||
[:& gap-section {:gap-selected? gap-selected?
|
||||
:set-gap set-gap
|
||||
:gap-value (:layout-gap values)}]
|
||||
|
||||
[:& padding-section {:values values
|
||||
:on-change-style change-padding-type
|
||||
:on-change on-padding-change}]]]))
|
||||
|
|
|
@ -159,7 +159,7 @@
|
|||
create-comment? (= :comments drawing-tool)
|
||||
drawing-path? (or (and edition (= :draw (get-in edit-path [edition :edit-mode])))
|
||||
(and (some? drawing-obj) (= :path (:type drawing-obj))))
|
||||
node-editing? (and edition (not= :text (get-in base-objects [edition :type])))
|
||||
node-editing? (and edition (= :path (get-in base-objects [edition :type])))
|
||||
text-editing? (and edition (= :text (get-in base-objects [edition :type])))
|
||||
grid-editing? (and edition (ctl/grid-layout? base-objects edition))
|
||||
|
||||
|
|
|
@ -231,8 +231,8 @@
|
|||
(mf/use-fn
|
||||
(mf/deps @hover @hover-ids workspace-read-only?)
|
||||
(fn [event]
|
||||
(if workspace-read-only?
|
||||
(dom/prevent-default event)
|
||||
(dom/prevent-default event)
|
||||
(when-not workspace-read-only?
|
||||
(when (or (dom/class? (dom/get-target event) "viewport-controls")
|
||||
(dom/child? (dom/get-target event) (dom/query ".viewport-controls"))
|
||||
(dom/class? (dom/get-target event) "viewport-selrect")
|
||||
|
|
|
@ -354,5 +354,5 @@
|
|||
(do (st/emit! (dsc/push-shortcuts ::path psc/shortcuts))
|
||||
#(st/emit! (dsc/pop-shortcuts ::path)))
|
||||
text-editing?
|
||||
(do (st/emit! (dsc/push-shortcuts ::text tsc/shortcuts))
|
||||
#(st/emit! (dsc/pop-shortcuts ::text)))))))
|
||||
(do (st/emit! (dsc/push-shortcuts ::text tsc/shortcuts))
|
||||
#(st/emit! (dsc/pop-shortcuts ::text)))))))
|
||||
|
|
|
@ -4379,6 +4379,9 @@ msgstr "Updating %s..."
|
|||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Add flex layout"
|
||||
|
||||
msgid "workspace.shape.menu.add-grid"
|
||||
msgstr "Add grid layout"
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.back"
|
||||
msgstr "Send to back"
|
||||
|
|
|
@ -4481,6 +4481,9 @@ msgstr "Actualizando %s..."
|
|||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Añadir flex layout"
|
||||
|
||||
msgid "workspace.shape.menu.add-grid"
|
||||
msgstr "Añadir grid layout"
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs
|
||||
msgid "workspace.shape.menu.back"
|
||||
msgstr "Enviar al fondo"
|
||||
|
|
Loading…
Add table
Reference in a new issue