0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-24 23:49:45 -05:00

Edit cell panel

This commit is contained in:
alonso.torres 2023-02-20 15:43:54 +01:00
parent 4b7e93ab84
commit eb425dc4f2
7 changed files with 299 additions and 142 deletions

View file

@ -0,0 +1,44 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.data.workspace.grid-layout.editor
(:require
[potok.core :as ptk]))
(defn hover-grid-cell
[grid-id row column add-to-set]
(ptk/reify ::hover-grid-cell
ptk/UpdateEvent
(update [_ state]
(update-in
state
[:workspace-grid-edition grid-id :hover]
(fn [hover-set]
(let [hover-set (or hover-set #{})]
(if add-to-set
(conj hover-set [row column])
(disj hover-set [row column]))))))))
(defn select-grid-cell
[grid-id row column]
(ptk/reify ::hover-grid-cell
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-grid-edition grid-id :selected] [row column]))))
(defn remove-selection
[grid-id]
(ptk/reify ::hover-grid-cell
ptk/UpdateEvent
(update [_ state]
(update-in state [:workspace-grid-edition grid-id] dissoc :selected))))
(defn stop-grid-layout-editing
[grid-id]
(ptk/reify ::stop-grid-layout-editing
ptk/UpdateEvent
(update [_ state]
(update state :workspace-grid-edition dissoc grid-id))))

View file

@ -68,7 +68,6 @@
(defn get-layout-initializer
[type from-frame?]
(prn "??type" type)
(let [initial-layout-data
(case type
:flex initial-flex-layout
@ -157,7 +156,6 @@
(defn create-layout-from-id
[ids type from-frame?]
(.trace js/console "create-layout-from-id" type)
(ptk/reify ::create-layout-from-id
ptk/WatchEvent
(watch [_ state _]

View file

@ -522,3 +522,12 @@
(def colorpicker
(l/derived :colorpicker st/state))
(def workspace-grid-edition
(l/derived :workspace-grid-edition st/state))
(defn workspace-grid-edition-id
[id]
(l/derived #(get % id) workspace-grid-edition))

View file

@ -6,6 +6,7 @@
(ns app.main.ui.workspace.sidebar.options
(:require
[app.main.ui.workspace.sidebar.options.shapes.grid-cell :as grid-cell]
[app.common.data :as d]
[app.common.geom.shapes :as gsh]
[app.common.pages.helpers :as cph]
@ -67,9 +68,18 @@
(let [drawing (mf/deref refs/workspace-drawing)
objects (mf/deref refs/workspace-page-objects)
shared-libs (mf/deref refs/workspace-libraries)
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 {[row-selected col-selected] :selected}]
(d/seek (fn [[grid-id {:keys [selected]}]]
(some? selected))
grid-edition)
grid-cell-selected? (and (some? grid-id) (some? row-selected) (some? col-selected))
on-change-tab
(fn [options-mode]
(st/emit! (udw/set-options-mode options-mode)
@ -87,6 +97,10 @@
[:& align-options]
[:& bool-options]
(cond
grid-cell-selected? [:& grid-cell/options {:shape (get objects grid-id)
:row row-selected
:column col-selected}]
(d/not-empty? drawing) [:& shape-options {:shape (:object drawing)
:page-id page-id
:file-id file-id
@ -138,4 +152,3 @@
:file-id file-id
:page-id page-id
:section section}]))

View file

@ -0,0 +1,22 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.workspace.sidebar.options.shapes.grid-cell
(:require
[rumext.v2 :as mf]))
(mf/defc options
{::mf/wrap [mf/memo]}
[{:keys [shape row column] :as props}]
[:div.element-set
[:div.element-set-title
[:span "Grid Cell"]]
[:div.element-set-content.layout-item-menu
[:div.layout-row
[:div.row-title.sizing "Position"]
[:div (str row "," column)]]]])

View file

@ -477,11 +477,6 @@
:disabled-guides? disabled-guides?
:modifiers modifiers}])
[:& grid-layout/editor
{:zoom zoom
:objects base-objects
:shape (first selected-shapes)}]
;; DEBUG LAYOUT DROP-ZONES
(when (debug? :layout-drop-zones)
[:& wvd/debug-drop-zones {:selected-shapes selected-shapes
@ -543,4 +538,12 @@
(when show-gradient-handlers?
[:& gradients/gradient-handlers
{:id (first selected)
:zoom zoom}])]]]))
:zoom zoom}])
(when-let [selected (first selected-shapes)]
(when (ctl/grid-layout? selected)
[:& grid-layout/editor
{:zoom zoom
:objects base-objects
:shape selected}]))
]]]))

View file

@ -6,21 +6,23 @@
(ns app.main.ui.workspace.viewport.grid-layout-editor
(:require
[app.main.ui.icons :as i]
[app.common.geom.shapes.grid-layout.layout-data :refer [set-sample-data] ]
[cuerdas.core :as str]
[app.common.geom.point :as gpt]
[app.main.data.workspace.grid-layout.editor :as dwge]
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.point :as gpt]
[app.common.geom.shapes.grid-layout :as gsg]
[app.common.geom.shapes.grid-layout.layout-data :refer [set-sample-data] ]
[app.common.geom.shapes.points :as gpo]
[app.common.pages.helpers :as cph]
[app.common.types.shape.layout :as ctl]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.icons :as i]
[cuerdas.core :as str]
[rumext.v2 :as mf]))
(defn apply-to-point [result next-fn]
(conj result (next-fn (last result))))
(mf/defc track-marker
{::mf/wrap-props false}
@ -30,32 +32,25 @@
value (unchecked-get props "value")
zoom (unchecked-get props "zoom")
p1 (-> center
(update :x - (/ 13 zoom))
(update :y - (/ 16 zoom)))
p2 (-> p1
(update :x + (/ 26 zoom)))
p3 (-> p2
(update :y + (/ 24 zoom)))
p4 (-> p3
(update :x - (/ 13 zoom))
(update :y + (/ 8 zoom)))
p5 (-> p4
(update :x - (/ 13 zoom))
(update :y - (/ 8 zoom)))
marker-points
(reduce
apply-to-point
[(gpt/subtract center
(gpt/point (/ 13 zoom) (/ 16 zoom)))]
[#(gpt/add % (gpt/point (/ 26 zoom) 0))
#(gpt/add % (gpt/point 0 (/ 24 zoom)))
#(gpt/add % (gpt/point (- (/ 13 zoom)) (/ 8 zoom)))
#(gpt/subtract % (gpt/point (/ 13 zoom) (/ 8 zoom)))])
text-x (:x center)
text-y (:y center)]
[:g.grid-track-marker
[:polygon {:points (->> [p1 p2 p3 p4 p5]
[:polygon {:points (->> marker-points
(map #(dm/fmt "%,%" (:x %) (:y %)))
(str/join " "))
:style {:fill "#DB00FF"
:style {:fill "var(--color-distance)"
:fill-opacity 0.3}}]
[:text {:x text-x
:y text-y
@ -64,9 +59,122 @@
:font-size (/ 16 zoom)
:text-anchor "middle"
:dominant-baseline "middle"
:style {:fill "#DB00FF"}}
:style {:fill "var(--color-distance)"}}
(dm/str value)]]))
(mf/defc grid-editor-frame
{::mf/wrap-props false}
[props]
(let [bounds (unchecked-get props "bounds")
zoom (unchecked-get props "zoom")
hv #(gpo/start-hv bounds %)
vv #(gpo/start-vv bounds %)
width (gpo/width-points bounds)
height (gpo/height-points bounds)
origin (gpo/origin bounds)
frame-points
(reduce
apply-to-point
[origin]
[#(gpt/add % (hv width))
#(gpt/subtract % (vv (/ 40 zoom)))
#(gpt/subtract % (hv (+ width (/ 40 zoom))))
#(gpt/add % (vv (+ height (/ 40 zoom))))
#(gpt/add % (hv (/ 40 zoom)))])]
[:polygon {:points (->> frame-points
(map #(dm/fmt "%,%" (:x %) (:y %)))
(str/join " "))
:style {:stroke "var(--color-distance)"
:stroke-width (/ 1 zoom)}}]))
(mf/defc plus-btn
{::mf/wrap-props false}
[props]
(let [start-p (unchecked-get props "start-p")
zoom (unchecked-get props "zoom")
type (unchecked-get props "type")
[rect-x rect-y icon-x icon-y]
(if (= type :column)
[(:x start-p)
(- (:y start-p) (/ 40 zoom))
(+ (:x start-p) (/ 12 zoom))
(- (:y start-p) (/ 28 zoom))]
[(- (:x start-p) (/ 40 zoom))
(:y start-p)
(- (:x start-p) (/ 28 zoom))
(+ (:y start-p) (/ 12 zoom))])]
[:g.plus-button
[:rect {:x rect-x
:y rect-y
:width (/ 40 zoom)
:height (/ 40 zoom)
:style {:fill "var(--color-distance)"
:stroke "var(--color-distance)"
:stroke-width (/ 1 zoom)}}]
[:use {:x icon-x
:y icon-y
:width (/ 16 zoom)
:height (/ 16 zoom)
:href (dm/str "#icon-plus")
:fill "white"}]]))
(mf/defc grid-cell
{::mf/wrap-props false}
[props]
(let [shape (unchecked-get props "shape")
{:keys [row-tracks column-tracks]} (unchecked-get props "layout-data")
bounds (unchecked-get props "bounds")
zoom (unchecked-get props "zoom")
hover? (unchecked-get props "hover?")
selected? (unchecked-get props "selected?")
row (unchecked-get props "row")
column (unchecked-get props "column")
column-track (nth column-tracks (dec column) nil)
row-track (nth row-tracks (dec row) nil)
origin (gpo/origin bounds)
hv #(gpo/start-hv bounds %)
vv #(gpo/start-vv bounds %)
start-p (-> origin
(gpt/add (hv (:distance column-track)))
(gpt/add (vv (:distance row-track))))
end-p (-> start-p
(gpt/add (hv (:value column-track)))
(gpt/add (vv (:value row-track))))]
[:rect.cell-editor
{:x (:x start-p)
:y (:y start-p)
:width (- (:x end-p) (:x start-p))
:height (- (:y end-p) (:y start-p))
:on-pointer-enter #(st/emit! (dwge/hover-grid-cell (:id shape) row column true))
:on-pointer-leave #(st/emit! (dwge/hover-grid-cell (:id shape) row column false))
:on-click #(st/emit! (dwge/select-grid-cell (:id shape) row column))
:style {:fill "transparent"
:stroke "var(--color-distance)"
:stroke-dasharray (when-not (or hover? selected?)
(str/join " " (map #(/ % zoom) [0 8]) ))
:stroke-linecap "round"
:stroke-width (/ 2 zoom)}}])
)
(mf/defc editor
{::mf/wrap-props false}
[props]
@ -74,124 +182,84 @@
(let [shape (unchecked-get props "shape")
objects (unchecked-get props "objects")
zoom (unchecked-get props "zoom")
bounds (:points shape)]
bounds (:points shape)
(when (ctl/grid-layout? shape)
(let [children (->> (cph/get-immediate-children objects (:id shape))
(remove :hidden)
(map #(vector (gpo/parent-coords-bounds (:points %) (:points shape)) %)))
grid-edition-id-ref (mf/use-memo #(refs/workspace-grid-edition-id (:id shape)))
grid-edition (mf/deref grid-edition-id-ref)
hv #(gpo/start-hv bounds %)
vv #(gpo/start-vv bounds %)
hover-cells (:hover grid-edition)
selected-cells (:selected grid-edition)
width (gpo/width-points bounds)
height (gpo/height-points bounds)
origin (gpo/origin bounds)
children (->> (cph/get-immediate-children objects (:id shape))
(remove :hidden)
(map #(vector (gpo/parent-coords-bounds (:points %) (:points shape)) %)))
{:keys [row-tracks column-tracks shape-cells]}
(gsg/calc-layout-data shape children bounds)
hv #(gpo/start-hv bounds %)
vv #(gpo/start-vv bounds %)
width (gpo/width-points bounds)
height (gpo/height-points bounds)
origin (gpo/origin bounds)
[shape children] (set-sample-data shape children)]
{:keys [row-tracks column-tracks shape-cells] :as layout-data}
(gsg/calc-layout-data shape children bounds)
[:g.grid-editor
[:polygon {:points (->> [origin
(-> origin
(gpt/add (hv width)))
(-> origin
(gpt/add (hv width))
(gpt/subtract (vv (/ 40 zoom))))
[shape children] (set-sample-data shape children)]
(-> origin
(gpt/add (hv width))
(gpt/subtract (vv (/ 40 zoom)))
(gpt/subtract (hv (+ width (/ 40 zoom)))))
(mf/use-effect
(fn []
#(st/emit! (dwge/stop-grid-layout-editing (:id shape)))))
(-> origin
(gpt/add (hv width))
(gpt/subtract (vv (/ 40 zoom)))
(gpt/subtract (hv (+ width (/ 40 zoom))))
(gpt/add (vv (+ height (/ 40 zoom)))))
(-> origin
(gpt/add (hv width))
(gpt/subtract (vv (/ 40 zoom)))
(gpt/subtract (hv (+ width (/ 40 zoom))))
(gpt/add (vv (+ height (/ 40 zoom))))
(gpt/add (hv (/ 40 zoom))))]
(map #(dm/fmt "%,%" (:x %) (:y %)))
(str/join " "))
:style {:stroke "#DB00FF"
:stroke-width (/ 1 zoom)}}]
[:g.grid-editor
[:& grid-editor-frame {:zoom zoom
:bounds bounds}]
(let [start-p (-> origin (gpt/add (hv width)))]
[:& plus-btn {:start-p start-p
:zoom zoom
:type :column}])
(let [start-p (-> origin (gpt/add (hv width)))]
[:*
[:rect {:x (:x start-p)
:y (- (:y start-p) (/ 40 zoom))
:width (/ 40 zoom)
:height (/ 40 zoom)
:style {:fill "#DB00FF"
:stroke "#DB00FF"
:stroke-width (/ 1 zoom)}}]
(let [start-p (-> origin (gpt/add (vv height)))]
[:& plus-btn {:start-p start-p
:zoom zoom
:type :row}])
[:use {:x (+ (:x start-p) (/ 12 zoom))
:y (- (:y start-p) (/ 28 zoom))
:width (/ 16 zoom)
:height (/ 16 zoom)
:href (dm/str "#icon-plus")
:fill "white"}]])
(for [[_ {:keys [column row]}] (:layout-grid-cells shape)]
(let []
[:& grid-cell {:shape shape
:layout-data layout-data
:row row
:column column
:bounds bounds
:zoom zoom
:hover? (contains? hover-cells [row column])
:selected? (= selected-cells [row column])
}]))
(let [start-p (-> origin (gpt/add (vv height)))]
[:rect {:x (- (:x start-p) (/ 40 zoom))
:y (:y start-p)
:width (/ 40 zoom)
:height (/ 40 zoom)
:style {:fill "#DB00FF"
:stroke "#DB00FF"
:stroke-width (/ 1 zoom)}}])
(for [[idx column-data] (d/enumerate column-tracks)]
(let [start-p (-> origin (gpt/add (hv (:distance column-data))))
marker-p (-> start-p (gpt/subtract (vv (/ 20 zoom))))]
[:*
[:& track-marker {:center marker-p
:value (dm/str (inc idx))
:zoom zoom}]
[:rect.resize-handler
{:x (- (:x start-p) (/ 8 zoom))
:y (:y start-p)
:height height
:width (/ 16 zoom)
:style {:fill "transparent"}}]]))
(for [[idx column-data] (d/enumerate column-tracks)]
(let [start-p (-> origin
(gpt/add (hv (:distance column-data)))
(gpt/subtract (vv (/ 20 zoom))))]
[:& track-marker {:center start-p
:value (dm/str (inc idx))
:zoom zoom}]))
(for [[idx row-data] (d/enumerate row-tracks)]
(let [start-p (-> origin (gpt/add (vv (:distance row-data))))
marker-p (-> start-p (gpt/subtract (hv (/ 20 zoom))))]
[:*
[:g {:transform (dm/fmt "rotate(-90 % %)" (:x marker-p) (:y marker-p))}
[:& track-marker {:center marker-p
:value (dm/str (inc idx))
:zoom zoom}]]
(for [[idx row-data] (d/enumerate row-tracks)]
(let [start-p (-> origin
(gpt/add (vv (:distance row-data)))
(gpt/subtract (hv (/ 20 zoom))))]
[:g {:transform (dm/fmt "rotate(-90 % %)" (:x start-p) (:y start-p))}
[:& track-marker {:center start-p
:value (dm/str (inc idx))
:zoom zoom}]]))
(for [[_ grid-cell] (:layout-grid-cells shape)]
(let [column (nth column-tracks (dec (:column grid-cell)) nil)
row (nth row-tracks (dec (:row grid-cell)) nil)
start-p (-> origin
(gpt/add (hv (:distance column)))
(gpt/add (vv (:distance row))))
end-p (-> start-p
(gpt/add (hv (:value column)))
(gpt/add (vv (:value row))))]
[:*
#_[:rect {:x (:x start-p)
:y (- (:y start-p) (/ 32 zoom) (/ 8 zoom))
:width (/ 26.26 zoom)
:height (/ 32 zoom)
:style {:fill "#DB00FF"
:fill-opacity 0.3}
}]
[:rect.cell-editor {:x (:x start-p)
:y (:y start-p)
:width (- (:x end-p) (:x start-p))
:height (- (:y end-p) (:y start-p))
:style {:stroke "#DB00FF"
:stroke-dasharray (str/join " " (map #(/ % zoom) [0 8]) )
:stroke-linecap "round"
:stroke-width (/ 2 zoom)}
}]]))]))))
[:rect.resize-handler
{:x (:x start-p)
:y (- (:y start-p) (/ 8 zoom))
:height (/ 16 zoom)
:width width
:style {:fill "transparent"}}]]))]))