mirror of
https://github.com/penpot/penpot.git
synced 2026-07-22 22:17:58 +00:00
✨ Context menu for cells
This commit is contained in:
parent
9ed3ad2f3c
commit
40d4a917e1
@ -16,7 +16,7 @@
|
||||
[app.common.uuid :as uuid]))
|
||||
|
||||
(defn prepare-add-shape
|
||||
[changes shape objects _selected]
|
||||
[changes shape objects]
|
||||
(let [index (:index (meta shape))
|
||||
id (:id shape)
|
||||
|
||||
@ -55,53 +55,115 @@
|
||||
changes)))
|
||||
|
||||
(defn prepare-create-artboard-from-selection
|
||||
[changes id parent-id objects selected index frame-name without-fill?]
|
||||
(let [selected-objs (map #(get objects %) selected)
|
||||
new-index (or index
|
||||
(cfh/get-index-replacement selected objects))]
|
||||
(when (d/not-empty? selected)
|
||||
(let [srect (gsh/shapes->rect selected-objs)
|
||||
selected-id (first selected)
|
||||
([changes id parent-id objects selected index frame-name without-fill?]
|
||||
(prepare-create-artboard-from-selection
|
||||
changes id parent-id objects selected index frame-name without-fill? nil))
|
||||
|
||||
frame-id (dm/get-in objects [selected-id :frame-id])
|
||||
parent-id (or parent-id (dm/get-in objects [selected-id :parent-id]))
|
||||
([changes id parent-id objects selected index frame-name without-fill? target-cell-id]
|
||||
(let [selected-objs (map #(get objects %) selected)
|
||||
new-index (or index
|
||||
(cfh/get-index-replacement selected objects))]
|
||||
(when (d/not-empty? selected)
|
||||
(let [srect (gsh/shapes->rect selected-objs)
|
||||
selected-id (first selected)
|
||||
|
||||
attrs {:type :frame
|
||||
:x (:x srect)
|
||||
:y (:y srect)
|
||||
:width (:width srect)
|
||||
:height (:height srect)}
|
||||
frame-id (dm/get-in objects [selected-id :frame-id])
|
||||
parent-id (or parent-id (dm/get-in objects [selected-id :parent-id]))
|
||||
base-parent (get objects parent-id)
|
||||
|
||||
shape (cts/setup-shape
|
||||
(cond-> attrs
|
||||
(some? id)
|
||||
(assoc :id id)
|
||||
attrs {:type :frame
|
||||
:x (:x srect)
|
||||
:y (:y srect)
|
||||
:width (:width srect)
|
||||
:height (:height srect)}
|
||||
|
||||
(some? frame-name)
|
||||
(assoc :name frame-name)
|
||||
shape (cts/setup-shape
|
||||
(cond-> attrs
|
||||
(some? id)
|
||||
(assoc :id id)
|
||||
|
||||
:always
|
||||
(assoc :frame-id frame-id
|
||||
:parent-id parent-id
|
||||
:shapes (into [] selected))
|
||||
(some? frame-name)
|
||||
(assoc :name frame-name)
|
||||
|
||||
:always
|
||||
(with-meta {:index new-index})
|
||||
:always
|
||||
(assoc :frame-id frame-id
|
||||
:parent-id parent-id
|
||||
:shapes (into [] selected))
|
||||
|
||||
(or (not= frame-id uuid/zero) without-fill?)
|
||||
(assoc :fills [] :hide-in-viewer true)))
|
||||
:always
|
||||
(with-meta {:index new-index})
|
||||
|
||||
[shape changes]
|
||||
(prepare-add-shape changes shape objects selected)
|
||||
(or (not= frame-id uuid/zero) without-fill?)
|
||||
(assoc :fills [] :hide-in-viewer true)))
|
||||
|
||||
changes
|
||||
(prepare-move-shapes-into-frame changes (:id shape) selected objects)
|
||||
[shape changes]
|
||||
(prepare-add-shape changes shape objects)
|
||||
|
||||
changes
|
||||
(cond-> changes
|
||||
(ctl/grid-layout? objects (:parent-id shape))
|
||||
(-> (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells)
|
||||
(pcb/reorder-grid-children [(:parent-id shape)])))]
|
||||
changes
|
||||
(prepare-move-shapes-into-frame changes (:id shape) selected objects)
|
||||
|
||||
[shape changes]))))
|
||||
changes
|
||||
(cond-> changes
|
||||
(ctl/grid-layout? objects (:parent-id shape))
|
||||
(-> (cond-> (some? target-cell-id)
|
||||
(pcb/update-shapes
|
||||
[(:parent-id shape)]
|
||||
(fn [parent]
|
||||
(-> parent
|
||||
(assoc :layout-grid-cells (:layout-grid-cells base-parent))
|
||||
(assoc-in [:layout-grid-cells target-cell-id :shapes] [id])
|
||||
(assoc :position :auto)))))
|
||||
(pcb/update-shapes [(:parent-id shape)] ctl/assign-cells)
|
||||
(pcb/reorder-grid-children [(:parent-id shape)])))]
|
||||
|
||||
[shape changes])))))
|
||||
|
||||
|
||||
(defn prepare-create-empty-artboard
|
||||
[changes frame-id parent-id objects index frame-name without-fill? target-cell-id]
|
||||
|
||||
(let [base-parent (get objects parent-id)
|
||||
|
||||
attrs {:type :frame
|
||||
:x 0
|
||||
:y 0
|
||||
:width 0.01
|
||||
:height 0.01}
|
||||
|
||||
shape (cts/setup-shape
|
||||
(cond-> attrs
|
||||
(some? frame-id)
|
||||
(assoc :id frame-id)
|
||||
|
||||
(some? frame-name)
|
||||
(assoc :name frame-name)
|
||||
|
||||
:always
|
||||
(assoc :frame-id frame-id
|
||||
:parent-id parent-id
|
||||
:shapes [])
|
||||
|
||||
:always
|
||||
(with-meta {:index index})
|
||||
|
||||
(or (not= frame-id uuid/zero) without-fill?)
|
||||
(assoc :fills [] :hide-in-viewer true)))
|
||||
|
||||
[shape changes]
|
||||
(prepare-add-shape changes shape objects)
|
||||
|
||||
changes
|
||||
(cond-> changes
|
||||
(ctl/grid-layout? objects (:parent-id shape))
|
||||
(-> (cond-> (some? target-cell-id)
|
||||
(pcb/update-shapes
|
||||
[(:parent-id shape)]
|
||||
(fn [parent]
|
||||
(-> parent
|
||||
(assoc :layout-grid-cells (:layout-grid-cells base-parent))
|
||||
(assoc-in [:layout-grid-cells target-cell-id :shapes] [frame-id])
|
||||
(assoc :position :auto)))))
|
||||
(pcb/update-shapes [(:parent-id shape)] ctl/assign-cells)
|
||||
(pcb/reorder-grid-children [(:parent-id shape)])))]
|
||||
|
||||
[shape changes]))
|
||||
|
||||
@ -1227,6 +1227,7 @@
|
||||
target-cell
|
||||
(-> prev-cell
|
||||
(assoc
|
||||
:position :manual
|
||||
:row new-row
|
||||
:column new-column
|
||||
:row-span new-row-span
|
||||
@ -1459,7 +1460,6 @@
|
||||
|
||||
(defn valid-area-cells?
|
||||
[cells]
|
||||
|
||||
(let [{:keys [first-row last-row first-column last-column cell-coords]} (cells-coordinates cells)]
|
||||
(every?
|
||||
#(contains? cell-coords %)
|
||||
|
||||
@ -1506,10 +1506,13 @@
|
||||
(ptk/reify ::show-grid-cell-context-menu
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [cells (get-in state [:workspace-grid-edition grid-id :selected])]
|
||||
(let [objects (wsh/lookup-page-objects state)
|
||||
grid (get objects grid-id)
|
||||
cells (->> (get-in state [:workspace-grid-edition grid-id :selected])
|
||||
(map #(get-in grid [:layout-grid-cells %])))]
|
||||
(rx/of (show-context-menu
|
||||
(-> params (assoc :kind :grid-cells
|
||||
:grid-id grid-id
|
||||
:grid grid
|
||||
:cells cells))))))))
|
||||
(def hide-context-menu
|
||||
(ptk/reify ::hide-context-menu
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.changes-builder :as pcb]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.files.shapes-helpers :as cfsh]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes.flex-layout :as flex]
|
||||
[app.common.geom.shapes.grid-layout :as grid]
|
||||
@ -583,6 +584,37 @@
|
||||
(ptk/data-event :layout/update [layout-id])
|
||||
(dwu/commit-undo-transaction undo-id))))))
|
||||
|
||||
(defn merge-cells
|
||||
[layout-id ids]
|
||||
|
||||
(ptk/reify ::merge-cells
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(let [undo-id (js/Symbol)]
|
||||
(rx/of
|
||||
(dwu/start-undo-transaction undo-id)
|
||||
(dwc/update-shapes
|
||||
[layout-id]
|
||||
(fn [shape objects]
|
||||
(let [cells (->> ids (map #(get-in shape [:layout-grid-cells %])))
|
||||
|
||||
{:keys [first-row first-column last-row last-column]}
|
||||
(ctl/cells-coordinates cells)
|
||||
|
||||
target-cell
|
||||
(ctl/get-cell-by-position shape first-row first-column)]
|
||||
(-> shape
|
||||
(ctl/resize-cell-area
|
||||
(:row target-cell) (:column target-cell)
|
||||
first-row
|
||||
first-column
|
||||
(inc (- last-row first-row))
|
||||
(inc (- last-column first-column)))
|
||||
(ctl/assign-cells objects)))))
|
||||
(dwge/clean-selection layout-id)
|
||||
(ptk/data-event :layout/update [layout-id])
|
||||
(dwu/commit-undo-transaction undo-id))))))
|
||||
|
||||
(defn update-grid-cell-position
|
||||
[layout-id cell-id props]
|
||||
|
||||
@ -607,3 +639,58 @@
|
||||
(ctl/assign-cells objects)))))
|
||||
(ptk/data-event :layout/update [layout-id])
|
||||
(dwu/commit-undo-transaction undo-id))))))
|
||||
|
||||
|
||||
(defn create-cell-board
|
||||
[layout-id cell-ids]
|
||||
(ptk/reify ::create-cell-board
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state)
|
||||
frame-id (uuid/next)
|
||||
|
||||
undo-id (js/Symbol)
|
||||
|
||||
shape (get objects layout-id)
|
||||
cells (->> cell-ids (map #(get-in shape [:layout-grid-cells %])))
|
||||
selected (into #{} (mapcat :shapes) cells)
|
||||
|
||||
{:keys [first-row first-column last-row last-column]} (ctl/cells-coordinates cells)
|
||||
|
||||
target-cell (ctl/get-cell-by-position shape first-row first-column)
|
||||
|
||||
[_ changes]
|
||||
(-> (pcb/empty-changes it page-id)
|
||||
(pcb/with-objects objects)
|
||||
(cond-> (d/not-empty? selected)
|
||||
(cfsh/prepare-create-artboard-from-selection
|
||||
frame-id layout-id objects selected 0 nil true (:id target-cell)))
|
||||
|
||||
(cond-> (empty? (seq selected))
|
||||
(cfsh/prepare-create-empty-artboard
|
||||
frame-id layout-id objects 0 nil true (:id target-cell))))
|
||||
|
||||
changes
|
||||
(-> changes
|
||||
(pcb/update-shapes
|
||||
[frame-id]
|
||||
(fn [shape]
|
||||
(-> shape
|
||||
(assoc :layout-item-h-sizing :fill)
|
||||
(assoc :layout-item-v-sizing :fill))))
|
||||
(pcb/update-shapes
|
||||
[layout-id]
|
||||
(fn [shape]
|
||||
(let [new-row-span (inc (- last-row first-row))
|
||||
new-col-span (inc (- last-column first-column))]
|
||||
(-> shape
|
||||
(ctl/resize-cell-area
|
||||
(:row target-cell) (:column target-cell)
|
||||
first-row first-column new-row-span new-col-span))))))]
|
||||
|
||||
(rx/of
|
||||
(dwu/start-undo-transaction undo-id)
|
||||
(dwc/commit-changes changes)
|
||||
(ptk/data-event :layout/update [layout-id])
|
||||
(dwu/commit-undo-transaction undo-id))))))
|
||||
|
||||
@ -41,12 +41,11 @@
|
||||
(watch [it state _]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
selected (wsh/lookup-selected state)
|
||||
|
||||
[shape changes]
|
||||
(-> (pcb/empty-changes it page-id)
|
||||
(pcb/with-objects objects)
|
||||
(cfsh/prepare-add-shape shape objects selected))
|
||||
(cfsh/prepare-add-shape shape objects))
|
||||
|
||||
changes (cond-> changes
|
||||
(cfh/text-shape? shape)
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
(dom/stop-propagation event))
|
||||
|
||||
(mf/defc menu-entry
|
||||
[{:keys [title shortcut on-click on-pointer-enter on-pointer-leave on-unmount children selected? icon] :as props}]
|
||||
[{:keys [title shortcut on-click on-pointer-enter on-pointer-leave on-unmount children selected? icon disabled] :as props}]
|
||||
(let [submenu-ref (mf/use-ref nil)
|
||||
hovering? (mf/use-ref false)
|
||||
new-css-system (mf/use-ctx ctx/new-css-system)
|
||||
@ -89,6 +89,7 @@
|
||||
[:li {:class (if new-css-system
|
||||
(dom/classnames (css :icon-menu-item) true)
|
||||
(dom/classnames :icon-menu-item true))
|
||||
:disabled disabled
|
||||
:ref set-dom-node
|
||||
:on-click on-click
|
||||
:on-pointer-enter on-pointer-enter
|
||||
@ -113,6 +114,7 @@
|
||||
(dom/classnames (css :title) true)
|
||||
(dom/classnames :title true))} title]]
|
||||
[:li {:class (dom/classnames (css :context-menu-item) new-css-system)
|
||||
:disabled disabled
|
||||
:ref set-dom-node
|
||||
:on-click on-click
|
||||
:on-pointer-enter on-pointer-enter
|
||||
@ -579,33 +581,50 @@
|
||||
|
||||
(if (= type :column)
|
||||
[:*
|
||||
[:& menu-entry {:title "Duplicate column" :on-click do-duplicate-track}]
|
||||
[:& menu-entry {:title "Add 1 column to the left" :on-click do-add-track-before}]
|
||||
[:& menu-entry {:title "Add 1 column to the right" :on-click do-add-track-after}]
|
||||
[:& menu-entry {:title "Delete column" :on-click do-delete-track}]]
|
||||
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.duplicate") :on-click do-duplicate-track}]
|
||||
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.add-before") :on-click do-add-track-before}]
|
||||
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.add-after") :on-click do-add-track-after}]
|
||||
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.column.delete") :on-click do-delete-track}]]
|
||||
|
||||
[:*
|
||||
[:& menu-entry {:title "Duplicate row" :on-click do-duplicate-track}]
|
||||
[:& menu-entry {:title "Add 1 row above" :on-click do-add-track-before}]
|
||||
[:& menu-entry {:title "Add 1 row bellow" :on-click do-add-track-after}]
|
||||
[:& menu-entry {:title "Delete row" :on-click do-delete-track}]])))
|
||||
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.duplicate") :on-click do-duplicate-track}]
|
||||
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.add-before") :on-click do-add-track-before}]
|
||||
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.add-after") :on-click do-add-track-after}]
|
||||
[:& menu-entry {:title (tr "workspace.context-menu.grid-track.row.delete") :on-click do-delete-track}]])))
|
||||
|
||||
(mf/defc grid-cells-context-menu
|
||||
[{:keys [mdata] :as props}]
|
||||
(let [{:keys [grid-id cells]} mdata
|
||||
(let [{:keys [grid cells]} mdata
|
||||
|
||||
single? (= (count cells) 1)
|
||||
can-merge?
|
||||
(mf/use-memo
|
||||
(mf/deps cells)
|
||||
#(ctl/valid-area-cells? cells))
|
||||
|
||||
do-merge-cells
|
||||
(mf/use-callback
|
||||
(mf/deps grid-id cells)
|
||||
(fn []))
|
||||
(mf/deps grid cells)
|
||||
(fn []
|
||||
(st/emit! (dwsl/merge-cells (:id grid) (map :id cells)))))
|
||||
|
||||
do-create-board
|
||||
(mf/use-callback
|
||||
(mf/deps grid-id cells)
|
||||
(fn []))]
|
||||
(mf/deps grid cells)
|
||||
(fn []
|
||||
(st/emit! (dwsl/create-cell-board (:id grid) (map :id cells)))))]
|
||||
[:*
|
||||
[:& menu-entry {:title "Merge cells" :on-click do-merge-cells}]
|
||||
[:& menu-entry {:title "Create board" :on-click do-create-board}]]))
|
||||
(when (not single?)
|
||||
[:& menu-entry {:title (tr "workspace.context-menu.grid-cells.merge")
|
||||
:on-click do-merge-cells
|
||||
:disabled (not can-merge?)}])
|
||||
|
||||
(when single?
|
||||
[:& menu-entry {:title (tr "workspace.context-menu.grid-cells.area")
|
||||
:on-click do-merge-cells}])
|
||||
|
||||
[:& menu-entry {:title (tr "workspace.context-menu.grid-cells.create-board")
|
||||
:on-click do-create-board}]]))
|
||||
|
||||
|
||||
(mf/defc context-menu
|
||||
|
||||
@ -110,3 +110,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon-menu-item[disabled],
|
||||
.context-menu-item[disabled]
|
||||
{
|
||||
pointer-events: none;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
@ -5057,3 +5057,37 @@ msgstr "Choose image"
|
||||
|
||||
msgid "workspace.options.guides.title"
|
||||
msgstr "Guides"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.column.duplicate"
|
||||
msgstr "Duplicate column"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.column.add-before"
|
||||
msgstr "Add 1 column to the left"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.column.add-after"
|
||||
msgstr "Add 1 column to the right"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.column.delete"
|
||||
msgstr "Delete column"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.row.duplicate"
|
||||
msgstr "Duplicate row"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.row.add-before"
|
||||
msgstr "Add 1 row above"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.row.add-after"
|
||||
msgstr "Add 1 row bellow"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.row.delete"
|
||||
msgstr "Delete row"
|
||||
|
||||
msgid "workspace.context-menu.grid-cells.merge"
|
||||
msgstr "Merge cells"
|
||||
|
||||
msgid "workspace.context-menu.grid-cells.area"
|
||||
msgstr "Create area"
|
||||
|
||||
msgid "workspace.context-menu.grid-cells.create-board"
|
||||
msgstr "Create board"
|
||||
|
||||
|
||||
@ -5146,3 +5146,37 @@ msgstr "Elegir imagen"
|
||||
|
||||
msgid "workspace.options.guides.title"
|
||||
msgstr "Guías"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.column.duplicate"
|
||||
msgstr "Duplicar columna"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.column.add-before"
|
||||
msgstr "Añadir 1 columna a la izquierda"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.column.add-after"
|
||||
msgstr "Añadir 1 columna a la derecha"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.column.delete"
|
||||
msgstr "Borrar columna"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.row.duplicate"
|
||||
msgstr "Duplicar fila"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.row.add-before"
|
||||
msgstr "Añadir 1 fila encima"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.row.add-after"
|
||||
msgstr "Añadir 1 fila debajo"
|
||||
|
||||
msgid "workspace.context-menu.grid-track.row.delete"
|
||||
msgstr "Borrar fila"
|
||||
|
||||
msgid "workspace.context-menu.grid-cells.merge"
|
||||
msgstr "Fusionar celdas"
|
||||
|
||||
msgid "workspace.context-menu.grid-cells.area"
|
||||
msgstr "Crear area"
|
||||
|
||||
msgid "workspace.context-menu.grid-cells.create-board"
|
||||
msgstr "Crear tablero"
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user