Context menu for cells

This commit is contained in:
alonso.torres 2024-01-02 15:31:33 +01:00 committed by Andrey Antukh
parent 9ed3ad2f3c
commit 40d4a917e1
9 changed files with 305 additions and 60 deletions

View File

@ -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]))

View File

@ -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 %)

View File

@ -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

View File

@ -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))))))

View File

@ -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)

View File

@ -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

View File

@ -110,3 +110,10 @@
}
}
}
.icon-menu-item[disabled],
.context-menu-item[disabled]
{
pointer-events: none;
opacity: 0.6;
}

View File

@ -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"

View File

@ -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"