mirror of
https://github.com/penpot/penpot.git
synced 2025-08-07 14:38:33 +02:00
✨ Reorder grid tracks
This commit is contained in:
parent
de4ef1b19d
commit
495ba6e4a4
7 changed files with 220 additions and 41 deletions
|
@ -695,6 +695,25 @@
|
||||||
(update :layout-grid-cells update-cells)
|
(update :layout-grid-cells update-cells)
|
||||||
(assign-cells))))
|
(assign-cells))))
|
||||||
|
|
||||||
|
(defn- reorder-grid-track
|
||||||
|
[prop parent from-index to-index]
|
||||||
|
(-> parent
|
||||||
|
(update prop
|
||||||
|
(fn [tracks]
|
||||||
|
(let [tr (nth tracks from-index)]
|
||||||
|
(-> tracks
|
||||||
|
(assoc from-index nil)
|
||||||
|
(d/insert-at-index (inc to-index) [tr])
|
||||||
|
(d/vec-without-nils)))))))
|
||||||
|
|
||||||
|
(defn reorder-grid-column
|
||||||
|
[parent from-index to-index]
|
||||||
|
(reorder-grid-track :layout-grid-columns parent from-index to-index))
|
||||||
|
|
||||||
|
(defn reorder-grid-row
|
||||||
|
[parent from-index to-index]
|
||||||
|
(reorder-grid-track :layout-grid-rows parent from-index to-index))
|
||||||
|
|
||||||
(defn get-cells
|
(defn get-cells
|
||||||
([parent]
|
([parent]
|
||||||
(get-cells parent nil))
|
(get-cells parent nil))
|
||||||
|
|
|
@ -1880,6 +1880,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.single-button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: end;
|
||||||
|
height: 1.5rem;
|
||||||
|
|
||||||
|
.btn-wrapper {
|
||||||
|
width: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.no-wrap {
|
.no-wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -2262,6 +2272,13 @@
|
||||||
grid-template-columns: 35px 1fr 1fr auto;
|
grid-template-columns: 35px 1fr 1fr auto;
|
||||||
background-color: $color-gray-60;
|
background-color: $color-gray-60;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border: 1px solid $color-primary;
|
||||||
|
}
|
||||||
|
|
||||||
&:not(:first-child) {
|
&:not(:first-child) {
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,13 @@
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(update-in state [:workspace-grid-edition grid-id] dissoc :selected))))
|
(update-in state [:workspace-grid-edition grid-id] dissoc :selected))))
|
||||||
|
|
||||||
|
(defn clear-selection
|
||||||
|
[grid-id]
|
||||||
|
(ptk/reify ::clear-selection
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(update-in state [:workspace-grid-edition grid-id] dissoc :selected))))
|
||||||
|
|
||||||
(defn stop-grid-layout-editing
|
(defn stop-grid-layout-editing
|
||||||
[grid-id]
|
[grid-id]
|
||||||
(ptk/reify ::stop-grid-layout-editing
|
(ptk/reify ::stop-grid-layout-editing
|
||||||
|
|
|
@ -407,6 +407,38 @@
|
||||||
(ptk/data-event :layout/update ids)
|
(ptk/data-event :layout/update ids)
|
||||||
(dwu/commit-undo-transaction undo-id))))))
|
(dwu/commit-undo-transaction undo-id))))))
|
||||||
|
|
||||||
|
(defn reorder-layout-track
|
||||||
|
[ids type from-index to-index]
|
||||||
|
(assert (#{:row :column} type))
|
||||||
|
|
||||||
|
(ptk/reify ::reorder-layout-track
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ _]
|
||||||
|
(let [undo-id (js/Symbol)]
|
||||||
|
(rx/of (dwu/start-undo-transaction undo-id)
|
||||||
|
(dwc/update-shapes
|
||||||
|
ids
|
||||||
|
(fn [shape]
|
||||||
|
(case type
|
||||||
|
:row (ctl/reorder-grid-row shape from-index to-index)
|
||||||
|
:column (ctl/reorder-grid-column shape from-index to-index))))
|
||||||
|
(ptk/data-event :layout/update ids)
|
||||||
|
(dwu/commit-undo-transaction undo-id))))))
|
||||||
|
|
||||||
|
(defn hover-layout-track
|
||||||
|
[ids type index hover?]
|
||||||
|
(assert (#{:row :column} type))
|
||||||
|
|
||||||
|
(ptk/reify ::hover-layout-track
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(cond-> state
|
||||||
|
hover?
|
||||||
|
(update-in [:workspace-grid-edition (first ids) :hover-track] (fnil conj #{}) [type index])
|
||||||
|
|
||||||
|
(not hover?)
|
||||||
|
(update-in [:workspace-grid-edition (first ids) :hover-track] (fnil disj #{}) [type index])))))
|
||||||
|
|
||||||
(defn change-layout-track
|
(defn change-layout-track
|
||||||
[ids type index props]
|
[ids type index props]
|
||||||
(assert (#{:row :column} type))
|
(assert (#{:row :column} type))
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
[app.main.data.workspace.grid-layout.editor :as dwge]
|
||||||
[app.main.data.workspace.shape-layout :as dwsl]
|
[app.main.data.workspace.shape-layout :as dwsl]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.numeric-input :refer [numeric-input*]]
|
[app.main.ui.components.numeric-input :refer [numeric-input*]]
|
||||||
|
@ -99,7 +100,13 @@
|
||||||
(let [props (cond-> {:mode mode}
|
(let [props (cond-> {:mode mode}
|
||||||
(not= mode :area)
|
(not= mode :area)
|
||||||
(assoc :area-name nil))]
|
(assoc :area-name nil))]
|
||||||
(st/emit! (dwsl/update-grid-cell (:id shape) (:id cell) props)))))]
|
(st/emit! (dwsl/update-grid-cell (:id shape) (:id cell) props)))))
|
||||||
|
|
||||||
|
toggle-edit-mode
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps (:id shape))
|
||||||
|
(fn []
|
||||||
|
(st/emit! (dwge/remove-selection (:id shape)))))]
|
||||||
|
|
||||||
[:div.element-set
|
[:div.element-set
|
||||||
[:div.element-set-title
|
[:div.element-set-title
|
||||||
|
@ -191,4 +198,14 @@
|
||||||
[:div.btn-wrapper
|
[:div.btn-wrapper
|
||||||
[:& set-self-alignment {:is-col? true
|
[:& set-self-alignment {:is-col? true
|
||||||
:alignment justify-self
|
:alignment justify-self
|
||||||
:set-alignment set-justify-self}]]]]]))
|
:set-alignment set-justify-self}]]]
|
||||||
|
|
||||||
|
[:div.layout-row.single-button
|
||||||
|
[:div.btn-wrapper
|
||||||
|
[:div.edit-mode
|
||||||
|
[:button.tooltip.tooltip-bottom-left
|
||||||
|
{:alt "Grid edit mode"
|
||||||
|
:on-click toggle-edit-mode
|
||||||
|
:style {:padding 0}}
|
||||||
|
"Edit grid"
|
||||||
|
i/grid-layout-mode]]]]]]))
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
[app.main.ui.components.select :refer [select]]
|
[app.main.ui.components.select :refer [select]]
|
||||||
[app.main.ui.components.title-bar :refer [title-bar]]
|
[app.main.ui.components.title-bar :refer [title-bar]]
|
||||||
[app.main.ui.context :as ctx]
|
[app.main.ui.context :as ctx]
|
||||||
|
[app.main.ui.hooks :as h]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
|
@ -871,8 +872,68 @@
|
||||||
:fixed (dm/str value "px")
|
:fixed (dm/str value "px")
|
||||||
value))
|
value))
|
||||||
|
|
||||||
|
(mf/defc grid-track-info
|
||||||
|
[{:keys [is-col? type index column set-column-value set-column-type remove-element reorder-track hover-track]}]
|
||||||
|
(let [drop-track
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps type reorder-track index)
|
||||||
|
(fn [drop-position data]
|
||||||
|
(reorder-track type (:index data) (if (= :top drop-position) (dec index) index))))
|
||||||
|
|
||||||
|
pointer-enter
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps type hover-track index)
|
||||||
|
(fn []
|
||||||
|
(hover-track type index true)))
|
||||||
|
|
||||||
|
pointer-leave
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps type hover-track index)
|
||||||
|
(fn []
|
||||||
|
(hover-track type index false)))
|
||||||
|
|
||||||
|
[dprops dref]
|
||||||
|
(h/use-sortable
|
||||||
|
:data-type "penpot/layer"
|
||||||
|
:on-drop drop-track
|
||||||
|
:data {:is-col? is-col?
|
||||||
|
:index index
|
||||||
|
:column column}
|
||||||
|
:draggable? true)]
|
||||||
|
[:div.column-info
|
||||||
|
{:ref dref
|
||||||
|
:class (dom/classnames
|
||||||
|
:dnd-over-top (or (= (:over dprops) :top)
|
||||||
|
(= (:over dprops) :center))
|
||||||
|
:dnd-over-bot (= (:over dprops) :bot))
|
||||||
|
:on-pointer-enter pointer-enter
|
||||||
|
:on-pointer-leave pointer-leave}
|
||||||
|
[:div.direction-grid-icon
|
||||||
|
(if is-col?
|
||||||
|
i/layout-rows
|
||||||
|
i/layout-columns)]
|
||||||
|
|
||||||
|
[:div.grid-column-value
|
||||||
|
[:> numeric-input* {:no-validate true
|
||||||
|
:value (:value column)
|
||||||
|
:on-change #(set-column-value type index %)
|
||||||
|
:placeholder "--"
|
||||||
|
:disabled (= :auto (:type column))}]]
|
||||||
|
[:div.grid-column-unit
|
||||||
|
[:& select
|
||||||
|
{:class "grid-column-unit-selector"
|
||||||
|
:default-value (:type column)
|
||||||
|
:options [{:value :flex :label "FR"}
|
||||||
|
{:value :auto :label "AUTO"}
|
||||||
|
{:value :fixed :label "PX"}
|
||||||
|
{:value :percent :label "%"}]
|
||||||
|
:on-change #(set-column-type type index %)}]]
|
||||||
|
[:button.remove-grid-column
|
||||||
|
{:on-click #(remove-element type index)}
|
||||||
|
i/minus]]))
|
||||||
|
|
||||||
(mf/defc grid-columns-row
|
(mf/defc grid-columns-row
|
||||||
[{:keys [is-col? expanded? column-values toggle add-new-element set-column-value set-column-type remove-element] :as props}]
|
[{:keys [is-col? expanded? column-values toggle add-new-element set-column-value set-column-type remove-element reorder-track hover-track] :as props}]
|
||||||
(let [column-num (count column-values)
|
(let [column-num (count column-values)
|
||||||
direction (if (> column-num 1)
|
direction (if (> column-num 1)
|
||||||
(if is-col? "Columns " "Rows ")
|
(if is-col? "Columns " "Rows ")
|
||||||
|
@ -894,32 +955,19 @@
|
||||||
(add-new-element type ctl/default-track-value))} i/plus]]
|
(add-new-element type ctl/default-track-value))} i/plus]]
|
||||||
|
|
||||||
(when expanded?
|
(when expanded?
|
||||||
[:div.columns-info-wrapper
|
[:& h/sortable-container {}
|
||||||
(for [[index column] (d/enumerate column-values)]
|
[:div.columns-info-wrapper
|
||||||
[:div.column-info {:key (dm/str index "-" (name type) "-" column)}
|
(for [[index column] (d/enumerate column-values)]
|
||||||
[:div.direction-grid-icon
|
[:& grid-track-info {:key (dm/str index "-" (name type) "-" column)
|
||||||
(if is-col?
|
:type type
|
||||||
i/layout-rows
|
:is-col? is-col?
|
||||||
i/layout-columns)]
|
:index index
|
||||||
|
:column column
|
||||||
[:div.grid-column-value
|
:set-column-value set-column-value
|
||||||
[:> numeric-input* {:no-validate true
|
:set-column-type set-column-type
|
||||||
:value (:value column)
|
:remove-element remove-element
|
||||||
:on-change #(set-column-value type index %)
|
:reorder-track reorder-track
|
||||||
:placeholder "--"
|
:hover-track hover-track}])]])]))
|
||||||
:disabled (= :auto (:type column))}]]
|
|
||||||
[:div.grid-column-unit
|
|
||||||
[:& select
|
|
||||||
{:class "grid-column-unit-selector"
|
|
||||||
:default-value (:type column)
|
|
||||||
:options [{:value :flex :label "FR"}
|
|
||||||
{:value :auto :label "AUTO"}
|
|
||||||
{:value :fixed :label "PX"}
|
|
||||||
{:value :percent :label "%"}]
|
|
||||||
:on-change #(set-column-type type index %)}]]
|
|
||||||
[:button.remove-grid-column
|
|
||||||
{:on-click #(remove-element type index)}
|
|
||||||
i/minus]])])]))
|
|
||||||
|
|
||||||
;; LAYOUT COMPONENT
|
;; LAYOUT COMPONENT
|
||||||
|
|
||||||
|
@ -1352,7 +1400,7 @@
|
||||||
{::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values"]))]}
|
{::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values"]))]}
|
||||||
[{:keys [ids values] :as props}]
|
[{:keys [ids values] :as props}]
|
||||||
(let [;; Gap
|
(let [;; Gap
|
||||||
gap-selected? (mf/use-state :none)
|
gap-selected? (mf/use-state :none)
|
||||||
saved-grid-dir (:layout-grid-dir values)
|
saved-grid-dir (:layout-grid-dir values)
|
||||||
|
|
||||||
set-direction
|
set-direction
|
||||||
|
@ -1431,6 +1479,18 @@
|
||||||
(fn [type index]
|
(fn [type index]
|
||||||
(st/emit! (dwsl/remove-layout-track ids type index))))
|
(st/emit! (dwsl/remove-layout-track ids type index))))
|
||||||
|
|
||||||
|
reorder-track
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps ids)
|
||||||
|
(fn [type from-index to-index]
|
||||||
|
(st/emit! (dwsl/reorder-layout-track ids type from-index to-index))))
|
||||||
|
|
||||||
|
hover-track
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps ids)
|
||||||
|
(fn [type index hover?]
|
||||||
|
(st/emit! (dwsl/hover-layout-track ids type index hover?))))
|
||||||
|
|
||||||
set-column-value
|
set-column-value
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
|
@ -1496,7 +1556,9 @@
|
||||||
:add-new-element add-new-element
|
:add-new-element add-new-element
|
||||||
:set-column-value set-column-value
|
:set-column-value set-column-value
|
||||||
:set-column-type set-column-type
|
:set-column-type set-column-type
|
||||||
:remove-element remove-element}]
|
:remove-element remove-element
|
||||||
|
:reorder-track reorder-track
|
||||||
|
:hover-track hover-track}]
|
||||||
|
|
||||||
[:& grid-columns-row {:is-col? false
|
[:& grid-columns-row {:is-col? false
|
||||||
:expanded? @grid-rows-open?
|
:expanded? @grid-rows-open?
|
||||||
|
@ -1505,7 +1567,9 @@
|
||||||
:add-new-element add-new-element
|
:add-new-element add-new-element
|
||||||
:set-column-value set-column-value
|
:set-column-value set-column-value
|
||||||
:set-column-type set-column-type
|
:set-column-type set-column-type
|
||||||
:remove-element remove-element}]
|
:remove-element remove-element
|
||||||
|
:reorder-track reorder-track
|
||||||
|
:hover-track hover-track}]
|
||||||
|
|
||||||
[:& gap-section {:gap-selected? gap-selected?
|
[:& gap-section {:gap-selected? gap-selected?
|
||||||
:on-change set-gap
|
:on-change set-gap
|
||||||
|
|
|
@ -531,16 +531,17 @@
|
||||||
(dm/str value)]]))
|
(dm/str value)]]))
|
||||||
|
|
||||||
(mf/defc track
|
(mf/defc track
|
||||||
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape" "zoom" "index" "type" "track-data" "layout-data"]))]
|
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape" "zoom" "index" "type" "track-data" "layout-data" "hovering?"]))]
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
(let [shape (unchecked-get props "shape")
|
(let [shape (unchecked-get props "shape")
|
||||||
zoom (unchecked-get props "zoom")
|
zoom (unchecked-get props "zoom")
|
||||||
type (unchecked-get props "type")
|
type (unchecked-get props "type")
|
||||||
index (unchecked-get props "index")
|
index (unchecked-get props "index")
|
||||||
snap-pixel? (unchecked-get props "snap-pixel?")
|
snap-pixel? (unchecked-get props "snap-pixel?")
|
||||||
track-data (unchecked-get props "track-data")
|
track-data (unchecked-get props "track-data")
|
||||||
layout-data (unchecked-get props "layout-data")
|
layout-data (unchecked-get props "layout-data")
|
||||||
|
hovering? (unchecked-get props "hovering?")
|
||||||
|
|
||||||
track-input-ref (mf/use-ref)
|
track-input-ref (mf/use-ref)
|
||||||
[layout-gap-row layout-gap-col] (ctl/gaps shape)
|
[layout-gap-row layout-gap-col] (ctl/gaps shape)
|
||||||
|
@ -621,6 +622,15 @@
|
||||||
[:g {:transform (if (= type :column)
|
[:g {:transform (if (= type :column)
|
||||||
(dm/str (gmt/transform-in text-p (:transform shape)))
|
(dm/str (gmt/transform-in text-p (:transform shape)))
|
||||||
(dm/str (gmt/transform-in text-p (gmt/rotate (:transform shape) -90))))}
|
(dm/str (gmt/transform-in text-p (gmt/rotate (:transform shape) -90))))}
|
||||||
|
|
||||||
|
(when hovering?
|
||||||
|
[:rect {:x (+ text-x (/ 5 zoom))
|
||||||
|
:y text-y
|
||||||
|
:width (- text-width (/ 10 zoom))
|
||||||
|
:height (- text-height (/ 5 zoom))
|
||||||
|
:rx (/ 3 zoom)
|
||||||
|
:fill "#DB00FF"
|
||||||
|
:opacity 0.2}])
|
||||||
[:foreignObject {:x text-x :y text-y :width text-width :height text-height}
|
[:foreignObject {:x text-x :y text-y :width text-width :height text-height}
|
||||||
[:input
|
[:input
|
||||||
{:ref track-input-ref
|
{:ref track-input-ref
|
||||||
|
@ -684,6 +694,18 @@
|
||||||
hover-cells (:hover grid-edition)
|
hover-cells (:hover grid-edition)
|
||||||
selected-cells (:selected grid-edition)
|
selected-cells (:selected grid-edition)
|
||||||
|
|
||||||
|
hover-columns
|
||||||
|
(->> (:hover-track grid-edition)
|
||||||
|
(filter (fn [[t _]] (= t :column)))
|
||||||
|
(map (fn [[_ idx]] idx))
|
||||||
|
(into #{}))
|
||||||
|
|
||||||
|
hover-rows
|
||||||
|
(->> (:hover-track grid-edition)
|
||||||
|
(filter (fn [[t _]] (= t :row)))
|
||||||
|
(map (fn [[_ idx]] idx))
|
||||||
|
(into #{}))
|
||||||
|
|
||||||
children
|
children
|
||||||
(mf/use-memo
|
(mf/use-memo
|
||||||
(mf/deps shape modifiers)
|
(mf/deps shape modifiers)
|
||||||
|
@ -759,7 +781,8 @@
|
||||||
:index idx
|
:index idx
|
||||||
:layout-data layout-data
|
:layout-data layout-data
|
||||||
:snap-pixel? snap-pixel?
|
:snap-pixel? snap-pixel?
|
||||||
:track-data column-data}])
|
:track-data column-data
|
||||||
|
:hovering? (contains? hover-columns idx)}])
|
||||||
|
|
||||||
;; Last track resize handler
|
;; Last track resize handler
|
||||||
(when-not (empty? column-tracks)
|
(when-not (empty? column-tracks)
|
||||||
|
@ -796,8 +819,8 @@
|
||||||
:snap-pixel? snap-pixel?
|
:snap-pixel? snap-pixel?
|
||||||
:track-data row-data
|
:track-data row-data
|
||||||
:type :row
|
:type :row
|
||||||
:zoom zoom}])
|
:zoom zoom
|
||||||
|
:hovering? (contains? hover-rows idx)}])
|
||||||
(when-not (empty? row-tracks)
|
(when-not (empty? row-tracks)
|
||||||
(let [last-track (last row-tracks)
|
(let [last-track (last row-tracks)
|
||||||
start-p (:start-p last-track)
|
start-p (:start-p last-track)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue