From 2030f987db3264b347d7a6782b2ef1b58dca1d5b Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 13 Feb 2023 17:33:41 +0100 Subject: [PATCH 01/10] :zap: Performance improvements --- .../src/app/common/geom/shapes/modifiers.cljc | 79 ++++++++++--------- common/src/app/common/pages/helpers.cljc | 19 ++++- .../src/app/main/ui/workspace/viewport.cljs | 31 +++++--- 3 files changed, 77 insertions(+), 52 deletions(-) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index df17fefd9..3e69afb2f 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -46,46 +46,51 @@ :expr (or (nil? ids) (set? ids)) :hint (dm/str "tree sequence from not set: " ids)) - (letfn [(get-tree-root ;; Finds the tree root for the current id - [id] + (let [get-tree-root + (fn ;; Finds the tree root for the current id + [id] - (loop [current id - result id] - (let [shape (get objects current) - parent (get objects (:parent-id shape))] - (cond - (or (not shape) (= uuid/zero current)) + (loop [current id + result id] + (let [shape (get objects current) + parent (get objects (:parent-id shape))] + (cond + (or (not shape) (= uuid/zero current)) + result + + ;; Frame found, but not layout we return the last layout found (or the id) + (and (= :frame (:type parent)) + (not (ctl/any-layout? parent))) + result + + ;; Layout found. We continue upward but we mark this layout + (ctl/any-layout? parent) + (recur (:id parent) (:id parent)) + + ;; If group or boolean or other type of group we continue with the last result + :else + (recur (:id parent) result))))) + + is-child? #(cph/is-child? objects %1 %2) + + calculate-common-roots + (fn ;; Given some roots retrieves the minimum number of tree roots + [result id] + (if (= id uuid/zero) + result + (let [root (get-tree-root id) + + ;; Remove the children from the current root result + (if (cph/has-children? objects root) + (into #{} (remove #(is-child? root %)) result) + result) - ;; Frame found, but not layout we return the last layout found (or the id) - (and (= :frame (:type parent)) - (not (ctl/layout? parent))) - result - - ;; Layout found. We continue upward but we mark this layout - (ctl/layout? parent) - (recur (:id parent) (:id parent)) - - ;; If group or boolean or other type of group we continue with the last result - :else - (recur (:id parent) result))))) - - (calculate-common-roots ;; Given some roots retrieves the minimum number of tree roots - [result id] - (if (= id uuid/zero) - result - (let [root (get-tree-root id) - - ;; Remove the children from the current root - result - (into #{} (remove #(cph/is-child? objects root %)) result) - - contains-parent? - (some #(cph/is-child? objects % root) result)] - - (cond-> result - (not contains-parent?) - (conj root)))))] + root-parents (cph/get-parent-ids objects root) + contains-parent? (some #(contains? result %) root-parents)] + (cond-> result + (not contains-parent?) + (conj root)))))] (let [roots (->> ids (reduce calculate-common-roots #{}))] (concat diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index 3c4649c5e..eedc9beff 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -76,6 +76,12 @@ (and (not (frame-shape? shape)) (= (:frame-id shape) uuid/zero))) +(defn has-children? + ([objects id] + (has-children? (get objects id))) + ([shape] + (d/not-empty? (:shapes shape)))) + (defn get-children-ids [objects id] (letfn [(get-children-ids-rec @@ -487,8 +493,17 @@ (defn is-child? [objects parent-id candidate-child-id] - (let [parents (get-parent-ids objects candidate-child-id)] - (some? (d/seek #(= % parent-id) parents)))) + (loop [cur-id candidate-child-id] + (let [cur-parent-id (dm/get-in objects [cur-id :parent-id])] + (cond + (= parent-id cur-parent-id) + true + + (or (= cur-parent-id uuid/zero) (nil? cur-parent-id)) + false + + :else + (recur cur-parent-id))))) (defn reduce-objects ([objects reducer-fn init-val] diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index f48c82a0b..20a5abe6f 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -51,17 +51,20 @@ (defn apply-modifiers-to-selected [selected objects text-modifiers modifiers] - (into [] - (comp - (keep (d/getf objects)) - (map (fn [{:keys [id] :as shape}] - (cond-> shape - (and (cph/text-shape? shape) (contains? text-modifiers id)) - (dwm/apply-text-modifier (get text-modifiers id)) + (reduce + (fn [objects id] + (update + objects id + (fn [shape] + (cond-> shape + (and (cph/text-shape? shape) (contains? text-modifiers id)) + (dwm/apply-text-modifier (get text-modifiers id)) - (contains? modifiers id) - (gsh/transform-shape (dm/get-in modifiers [id :modifiers])))))) - selected)) + (contains? modifiers id) + (gsh/transform-shape (dm/get-in modifiers [id :modifiers])))))) + + objects + selected)) (mf/defc viewport [{:keys [wlocal wglobal selected layout file] :as props}] @@ -97,8 +100,11 @@ modifiers (mf/deref refs/workspace-modifiers) text-modifiers (mf/deref refs/workspace-text-modifier) - objects-modified (mf/with-memo [base-objects modifiers] - (gsh/apply-objects-modifiers base-objects modifiers selected)) + objects-modified (mf/with-memo + [base-objects text-modifiers modifiers] + (apply-modifiers-to-selected selected base-objects text-modifiers modifiers)) + + selected-shapes (->> selected (keep (d/getf objects-modified))) background (get options :background clr/canvas) @@ -138,7 +144,6 @@ drawing-tool (:tool drawing) drawing-obj (:object drawing) - selected-shapes (apply-modifiers-to-selected selected base-objects text-modifiers modifiers) selected-frames (into #{} (map :frame-id) selected-shapes) From a0cd94cfaed3cf89dbf2b13e7c7af30fe91069c5 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 14 Feb 2023 11:56:00 +0100 Subject: [PATCH 02/10] :sparkles: Grid layout infrastructure --- .../app/common/geom/shapes/constraints.cljc | 4 +- .../app/common/geom/shapes/grid_layout.cljc | 16 ++++ .../geom/shapes/grid_layout/layout_data.cljc | 71 ++++++++++++++++ .../geom/shapes/grid_layout/positions.cljc | 16 ++++ .../src/app/common/geom/shapes/modifiers.cljc | 65 +++++++++++---- common/src/app/common/types/shape/layout.cljc | 80 ++++++++++++++++--- frontend/src/app/main/data/workspace.cljs | 2 +- .../app/main/data/workspace/drawing/box.cljs | 5 +- .../main/data/workspace/drawing/curve.cljs | 12 +-- .../app/main/data/workspace/modifiers.cljs | 8 +- .../app/main/data/workspace/path/drawing.cljs | 12 +-- .../app/main/data/workspace/shape_layout.cljs | 28 +++++-- .../src/app/main/data/workspace/shapes.cljs | 6 -- .../app/main/data/workspace/transforms.cljs | 25 +++--- frontend/src/app/main/refs.cljs | 12 +-- .../app/main/ui/components/shape_icon.cljs | 6 +- .../options/menus/layout_container.cljs | 20 ++--- .../sidebar/options/menus/measures.cljs | 4 +- .../sidebar/options/shapes/bool.cljs | 8 +- .../sidebar/options/shapes/circle.cljs | 6 +- .../sidebar/options/shapes/frame.cljs | 14 ++-- .../sidebar/options/shapes/group.cljs | 22 ++--- .../sidebar/options/shapes/image.cljs | 8 +- .../sidebar/options/shapes/multiple.cljs | 20 ++--- .../sidebar/options/shapes/path.cljs | 8 +- .../sidebar/options/shapes/rect.cljs | 6 +- .../sidebar/options/shapes/svg_raw.cljs | 8 +- .../sidebar/options/shapes/text.cljs | 8 +- .../src/app/main/ui/workspace/viewport.cljs | 2 +- .../app/main/ui/workspace/viewport/debug.cljs | 2 +- .../ui/workspace/viewport/snap_distances.cljs | 2 +- .../ui/workspace/viewport/snap_points.cljs | 2 +- frontend/src/app/util/snap_data.cljs | 4 +- 33 files changed, 362 insertions(+), 150 deletions(-) create mode 100644 common/src/app/common/geom/shapes/grid_layout.cljc create mode 100644 common/src/app/common/geom/shapes/grid_layout/layout_data.cljc create mode 100644 common/src/app/common/geom/shapes/grid_layout/positions.cljc diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 3f40a9d0a..82ed2097b 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -288,7 +288,7 @@ constraints-h (cond - (and (ctl/layout? parent) (not (ctl/layout-absolute? child))) + (and (ctl/any-layout? parent) (not (ctl/layout-absolute? child))) :left (not ignore-constraints) @@ -299,7 +299,7 @@ constraints-v (cond - (and (ctl/layout? parent) (not (ctl/layout-absolute? child))) + (and (ctl/any-layout? parent) (not (ctl/layout-absolute? child))) :top (not ignore-constraints) diff --git a/common/src/app/common/geom/shapes/grid_layout.cljc b/common/src/app/common/geom/shapes/grid_layout.cljc new file mode 100644 index 000000000..2588b0e53 --- /dev/null +++ b/common/src/app/common/geom/shapes/grid_layout.cljc @@ -0,0 +1,16 @@ +;; 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.common.geom.shapes.grid-layout + (:require + [app.common.data.macros :as dm] + [app.common.geom.shapes.grid-layout.layout-data :as glld] + [app.common.geom.shapes.grid-layout.positions :as glp])) + +(dm/export glld/calc-layout-data) +(dm/export glld/get-cell-data) +(dm/export glld/get-child-coordinates) +(dm/export glp/child-modifiers) diff --git a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc new file mode 100644 index 000000000..ae6ee4bfb --- /dev/null +++ b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc @@ -0,0 +1,71 @@ +;; 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.common.geom.shapes.grid-layout.layout-data + (:require + [app.common.data.macros :as dm] + [app.common.geom.point :as gpt] + [app.common.geom.shapes.points :as gpo])) + +(defn calc-layout-data + [_parent _children transformed-parent-bounds] + (let [num-columns 3 + num-rows 2 + + height (gpo/height-points transformed-parent-bounds) + width (gpo/width-points transformed-parent-bounds) + + row-lines + (->> (range 0 num-rows) + (reduce (fn [[result start-dist] _] + (let [height (/ height num-rows)] + [(conj result {:distance start-dist + :height height}) + (+ start-dist height)])) + + [[] 0]) + first) + + column-lines + (->> (range 0 num-columns) + (reduce (fn [[result start-dist] _] + (let [width (/ width num-columns)] + [(conj result {:distance start-dist + :width width}) + (+ start-dist width)])) + [[] 0]) + first)] + {:columns 3 + :rows 3 + :row-lines row-lines + :column-lines column-lines})) + +(defn get-child-coordinates + [{:keys [columns]} _child child-idx] + [;; Row + (quot child-idx columns) + ;; column + (mod child-idx columns)]) + +(defn get-cell-data + [grid-data transformed-parent-bounds row col] + + (let [origin (gpo/origin transformed-parent-bounds) + hv #(gpo/start-hv transformed-parent-bounds %) + vv #(gpo/start-vv transformed-parent-bounds %) + + {col-dist :distance width :width} (dm/get-in grid-data [:column-lines col]) + {row-dist :distance height :height} (dm/get-in grid-data [:row-lines row]) + + start-p + (-> origin + (gpt/add (hv col-dist)) + (gpt/add (vv row-dist)))] + {:start-p start-p + :width width + :height height + :row row + :col col})) diff --git a/common/src/app/common/geom/shapes/grid_layout/positions.cljc b/common/src/app/common/geom/shapes/grid_layout/positions.cljc new file mode 100644 index 000000000..3f81928b4 --- /dev/null +++ b/common/src/app/common/geom/shapes/grid_layout/positions.cljc @@ -0,0 +1,16 @@ +;; 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.common.geom.shapes.grid-layout.positions + (:require + [app.common.geom.point :as gpt] + [app.common.geom.shapes.points :as gpo] + [app.common.types.modifiers :as ctm])) + +(defn child-modifiers + [_parent _transformed-parent-bounds _child child-bounds cell-data] + (ctm/move-modifiers + (gpt/subtract (:start-p cell-data) (gpo/origin child-bounds)))) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 3e69afb2f..f0c247229 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -10,7 +10,8 @@ [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes.constraints :as gct] - [app.common.geom.shapes.flex-layout :as gcl] + [app.common.geom.shapes.flex-layout :as gcfl] + [app.common.geom.shapes.grid-layout :as gcgl] [app.common.geom.shapes.pixel-precision :as gpp] [app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.transforms :as gtr] @@ -90,12 +91,12 @@ contains-parent? (some #(contains? result %) root-parents)] (cond-> result (not contains-parent?) - (conj root)))))] + (conj root))))) - (let [roots (->> ids (reduce calculate-common-roots #{}))] - (concat - (when (contains? ids uuid/zero) [(get objects uuid/zero)]) - (mapcat #(children-sequence % objects) roots))))) + roots (->> ids (reduce calculate-common-roots #{}))] + (concat + (when (contains? ids uuid/zero) [(get objects uuid/zero)]) + (mapcat #(children-sequence % objects) roots)))) (defn- set-children-modifiers "Propagates the modifiers from a parent too its children applying constraints if necesary" @@ -157,7 +158,7 @@ (not (ctm/empty? modifiers)) (gtr/transform-bounds modifiers))))) -(defn- set-layout-modifiers +(defn- set-flex-layout-modifiers [modif-tree children objects bounds parent transformed-parent-bounds] (letfn [(apply-modifiers [child] @@ -167,7 +168,7 @@ (set-child-modifiers [[layout-line modif-tree] [child-bounds child]] (let [[modifiers layout-line] - (gcl/layout-child-modifiers parent transformed-parent-bounds child child-bounds layout-line) + (gcfl/layout-child-modifiers parent transformed-parent-bounds child child-bounds layout-line) modif-tree (cond-> modif-tree @@ -180,7 +181,7 @@ (map (d/getf objects)) (remove :hidden) (map apply-modifiers)) - layout-data (gcl/calc-layout-data parent children @transformed-parent-bounds) + layout-data (gcfl/calc-layout-data parent children @transformed-parent-bounds) children (into [] (cond-> children (not (:reverse? layout-data)) reverse)) max-idx (dec (count children)) layout-lines (:layout-lines layout-data)] @@ -198,6 +199,35 @@ modif-tree))))) +(defn- set-grid-layout-modifiers + [modif-tree objects bounds parent transformed-parent-bounds] + + (letfn [(apply-modifiers [child] + [(-> (get-group-bounds objects bounds modif-tree child) + (gpo/parent-coords-bounds @transformed-parent-bounds)) + child]) + (set-child-modifiers [modif-tree cell-data [child-bounds child]] + (let [modifiers (gcgl/child-modifiers parent transformed-parent-bounds child child-bounds cell-data) + modif-tree + (cond-> modif-tree + (d/not-empty? modifiers) + (update-in [(:id child) :modifiers] ctm/add-modifiers modifiers))] + modif-tree))] + (let [children (->> (cph/get-immediate-children objects (:id parent)) + (remove :hidden) + (map apply-modifiers)) + grid-data (gcgl/calc-layout-data parent children @transformed-parent-bounds)] + (loop [modif-tree modif-tree + child-idx 0 + child (first children) + pending (rest children)] + (if (some? child) + (let [[row col] (gcgl/get-child-coordinates grid-data child child-idx) + cell-data (gcgl/get-cell-data grid-data @transformed-parent-bounds row col) + modif-tree (set-child-modifiers modif-tree cell-data child)] + (recur modif-tree (inc child-idx) (first pending) (rest pending))) + modif-tree))))) + (defn- calc-auto-modifiers "Calculates the modifiers to adjust the bounds for auto-width/auto-height shapes" [objects bounds parent] @@ -223,7 +253,7 @@ content-bounds (when (and (d/not-empty? children) (or (ctl/auto-height? parent) (ctl/auto-width? parent))) - (gcl/layout-content-bounds bounds parent children)) + (gcfl/layout-content-bounds bounds parent children)) auto-width (when content-bounds (gpo/width-points content-bounds)) auto-height (when content-bounds (gpo/height-points content-bounds))] @@ -259,14 +289,15 @@ modifiers (-> (dm/get-in modif-tree [parent-id :modifiers]) (ctm/select-geometry)) has-modifiers? (ctm/child-modifiers? modifiers) - layout? (ctl/layout? parent) + flex-layout? (ctl/flex-layout? parent) + grid-layout? (ctl/grid-layout? parent) auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent)) parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent)) transformed-parent-bounds (delay (gtr/transform-bounds @(get bounds parent-id) modifiers)) children-modifiers - (if layout? + (if flex-layout? (->> (:shapes parent) (filter #(ctl/layout-absolute? objects %))) (:shapes parent)) @@ -280,8 +311,11 @@ (and has-modifiers? parent? (not root?)) (set-children-modifiers children-modifiers objects bounds parent transformed-parent-bounds ignore-constraints) - layout? - (set-layout-modifiers children-layout objects bounds parent transformed-parent-bounds)) + flex-layout? + (set-flex-layout-modifiers children-layout objects bounds parent transformed-parent-bounds)) + + grid-layout? + (set-grid-layout-modifiers objects bounds parent transformed-parent-bounds)) ;; Auto-width/height can change the positions in the parent so we need to recalculate (cond-> autolayouts auto? (conj (:id parent)))])) @@ -377,7 +411,7 @@ to-reflow (cond-> to-reflow - (and (ctl/layout-descent? objects parent-base) + (and (ctl/flex-layout-descent? objects parent-base) (not= uuid/zero (:frame-id parent-base))) (conj (:frame-id parent-base)))] (recur modif-tree @@ -409,6 +443,7 @@ ([old-modif-tree modif-tree objects {:keys [ignore-constraints snap-pixel? snap-precision snap-ignore-axis] :or {ignore-constraints false snap-pixel? false snap-precision 1 snap-ignore-axis nil}}] + (let [objects (-> objects (cond-> (some? old-modif-tree) (apply-structure-modifiers old-modif-tree)) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 1f7b6950a..776271f6a 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -14,6 +14,7 @@ ;; :layout-flex-dir ;; :row, :row-reverse, :column, :column-reverse ;; :layout-gap-type ;; :simple, :multiple ;; :layout-gap ;; {:row-gap number , :column-gap number} + ;; :layout-align-items ;; :start :end :center :stretch ;; :layout-justify-content ;; :start :center :end :space-between :space-around :space-evenly ;; :layout-align-content ;; :start :center :end :space-between :space-around :space-evenly :stretch (by default) @@ -21,6 +22,10 @@ ;; :layout-padding-type ;; :simple, :multiple ;; :layout-padding ;; {:p1 num :p2 num :p3 num :p4 num} number could be negative +;; layout-grid-rows +;; layout-grid-columns +;; layout-justify-items + ;; ITEMS ;; :layout-item-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0} ;; :layout-item-margin-type ;; :simple :multiple @@ -34,15 +39,25 @@ ;; :layout-item-z-index (s/def ::layout #{:flex :grid}) + (s/def ::layout-flex-dir #{:row :reverse-row :row-reverse :column :reverse-column :column-reverse}) ;;TODO remove reverse-column and reverse-row after script (s/def ::layout-gap-type #{:simple :multiple}) (s/def ::layout-gap ::us/safe-number) + (s/def ::layout-align-items #{:start :end :center :stretch}) +(s/def ::layout-justify-items #{:start :end :center :stretch}) (s/def ::layout-align-content #{:start :end :center :space-between :space-around :space-evenly :stretch}) (s/def ::layout-justify-content #{:start :center :end :space-between :space-around :space-evenly}) (s/def ::layout-wrap-type #{:wrap :nowrap :no-wrap}) ;;TODO remove no-wrap after script (s/def ::layout-padding-type #{:simple :multiple}) +(s/def :grid/type #{:fr :auto :fixed}) +(s/def :grid/value (s/nilable ::us/string)) +(s/def ::grid-definition (s/keys :opt-un [:grid/type + :grid/value])) +(s/def ::layout-grid-rows (s/coll-of ::grid-definition :kind vector?)) +(s/def ::layout-grid-columns (s/coll-of ::grid-definition :kind vector?)) + (s/def ::p1 ::us/safe-number) (s/def ::p2 ::us/safe-number) (s/def ::p3 ::us/safe-number) @@ -67,7 +82,13 @@ ::layout-padding ::layout-justify-content ::layout-align-items - ::layout-align-content])) + ::layout-align-content + + ;; grid + ::layout-justify-items + ::layout-grid-rows + ::layout-grid-columns + ])) (s/def ::m1 ::us/safe-number) (s/def ::m2 ::us/safe-number) @@ -100,26 +121,61 @@ ::layout-item-absolute ::layout-item-z-index])) -(defn layout? +(defn flex-layout? ([objects id] - (layout? (get objects id))) + (flex-layout? (get objects id))) ([shape] - (and (= :frame (:type shape)) (= :flex (:layout shape))))) + (and (= :frame (:type shape)) + (= :flex (:layout shape))))) -(defn layout-immediate-child? [objects shape] +(defn grid-layout? + ([objects id] + (grid-layout? (get objects id))) + ([shape] + (and (= :frame (:type shape)) + (= :grid (:layout shape))))) + +(defn any-layout? + ([objects id] + (any-layout? (get objects id))) + + ([shape] + (or (flex-layout? shape) (grid-layout? shape)))) + +(defn flex-layout-immediate-child? [objects shape] (let [parent-id (:parent-id shape) parent (get objects parent-id)] - (layout? parent))) + (flex-layout? parent))) -(defn layout-immediate-child-id? [objects id] +(defn any-layout-immediate-child? [objects shape] + (let [parent-id (:parent-id shape) + parent (get objects parent-id)] + (any-layout? parent))) + +(defn flex-layout-immediate-child-id? [objects id] (let [parent-id (dm/get-in objects [id :parent-id]) parent (get objects parent-id)] - (layout? parent))) + (flex-layout? parent))) -(defn layout-descent? [objects shape] +(defn any-layout-immediate-child-id? [objects id] + (let [parent-id (dm/get-in objects [id :parent-id]) + parent (get objects parent-id)] + (any-layout? parent))) + +(defn flex-layout-descent? [objects shape] (let [frame-id (:frame-id shape) frame (get objects frame-id)] - (layout? frame))) + (flex-layout? frame))) + +(defn grid-layout-descent? [objects shape] + (let [frame-id (:frame-id shape) + frame (get objects frame-id)] + (grid-layout? frame))) + +(defn any-layout-descent? [objects shape] + (let [frame-id (:frame-id shape) + frame (get objects frame-id)] + (any-layout? frame))) (defn inside-layout? "Check if the shape is inside a layout" @@ -360,7 +416,7 @@ (defn change-h-sizing? [frame-id objects children-ids] - (and (layout? objects frame-id) + (and (flex-layout? objects frame-id) (auto-width? objects frame-id) (or (and (col? objects frame-id) (->> children-ids @@ -373,7 +429,7 @@ (defn change-v-sizing? [frame-id objects children-ids] - (and (layout? objects frame-id) + (and (flex-layout? objects frame-id) (auto-height? objects frame-id) (or (and (col? objects frame-id) (some (partial fill-height? objects) children-ids)) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 04ee77b0a..04dcb5a96 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -714,7 +714,7 @@ ;; Fix the sizing when moving a shape (pcb/update-shapes parents (fn [parent] - (if (ctl/layout? parent) + (if (ctl/flex-layout? parent) (cond-> parent (ctl/change-h-sizing? (:id parent) objects (:shapes parent)) (assoc :layout-item-h-sizing :fix) diff --git a/frontend/src/app/main/data/workspace/drawing/box.cljs b/frontend/src/app/main/data/workspace/drawing/box.cljs index 140d58bbd..9517047d7 100644 --- a/frontend/src/app/main/data/workspace/drawing/box.cljs +++ b/frontend/src/app/main/data/workspace/drawing/box.cljs @@ -82,8 +82,9 @@ focus (:workspace-focus-selected state) fid (ctst/top-nested-frame objects initial) - layout? (ctl/layout? objects fid) - drop-index (when layout? (gsl/get-drop-index fid objects initial)) + + flex-layout? (ctl/flex-layout? objects fid) + drop-index (when flex-layout? (gsl/get-drop-index fid objects initial)) shape (get-in state [:workspace-drawing :object]) shape (-> shape diff --git a/frontend/src/app/main/data/workspace/drawing/curve.cljs b/frontend/src/app/main/data/workspace/drawing/curve.cljs index 1f3000eb9..5f8a8e34f 100644 --- a/frontend/src/app/main/data/workspace/drawing/curve.cljs +++ b/frontend/src/app/main/data/workspace/drawing/curve.cljs @@ -47,12 +47,12 @@ ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) - content (get-in state [:workspace-drawing :object :content] []) - position (gpt/point (get-in content [0 :params] nil)) - frame-id (ctst/top-nested-frame objects position) - layout? (ctl/layout? objects frame-id) - drop-index (when layout? (gsl/get-drop-index frame-id objects position))] + (let [objects (wsh/lookup-page-objects state) + content (get-in state [:workspace-drawing :object :content] []) + position (gpt/point (get-in content [0 :params] nil)) + frame-id (ctst/top-nested-frame objects position) + flex-layout? (ctl/flex-layout? objects frame-id) + drop-index (when flex-layout? (gsl/get-drop-index frame-id objects position))] (-> state (assoc-in [:workspace-drawing :object :frame-id] frame-id) (cond-> (some? drop-index) diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index 110439add..e73441f6c 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -179,8 +179,8 @@ (let [origin-frame-ids (->> selected (group-by #(get-in objects [% :frame-id]))) child-set (set (get-in objects [target-frame-id :shapes])) - target-frame (get objects target-frame-id) - target-layout? (ctl/layout? target-frame) + target-frame (get objects target-frame-id) + target-flex-layout? (ctl/flex-layout? target-frame) children-ids (concat (:shapes target-frame) selected) @@ -201,7 +201,7 @@ (fn [modif-tree [original-frame shapes]] (let [shapes (->> shapes (d/removev #(= target-frame-id %))) shapes (cond->> shapes - (and target-layout? (= original-frame target-frame-id)) + (and target-flex-layout? (= original-frame target-frame-id)) ;; When movining inside a layout frame remove the shapes that are not immediate children (filterv #(contains? child-set %))) children-ids (->> (dm/get-in objects [original-frame :shapes]) @@ -219,7 +219,7 @@ (cond-> v-sizing? (update-in [original-frame :modifiers] ctm/change-property :layout-item-v-sizing :fix))) - (and target-layout? (= original-frame target-frame-id)) + (and target-flex-layout? (= original-frame target-frame-id)) (update-in [target-frame-id :modifiers] ctm/add-children shapes drop-index))))] (as-> modif-tree $ diff --git a/frontend/src/app/main/data/workspace/path/drawing.cljs b/frontend/src/app/main/data/workspace/path/drawing.cljs index 307c6e290..873d9d95d 100644 --- a/frontend/src/app/main/data/workspace/path/drawing.cljs +++ b/frontend/src/app/main/data/workspace/path/drawing.cljs @@ -240,12 +240,12 @@ (ptk/reify ::setup-frame-path ptk/UpdateEvent (update [_ state] - (let [objects (wsh/lookup-page-objects state) - content (get-in state [:workspace-drawing :object :content] []) - position (gpt/point (get-in content [0 :params] nil)) - frame-id (ctst/top-nested-frame objects position) - layout? (ctl/layout? objects frame-id) - drop-index (when layout? (gsl/get-drop-index frame-id objects position))] + (let [objects (wsh/lookup-page-objects state) + content (get-in state [:workspace-drawing :object :content] []) + position (gpt/point (get-in content [0 :params] nil)) + frame-id (ctst/top-nested-frame objects position) + flex-layout? (ctl/flex-layout? objects frame-id) + drop-index (when flex-layout? (gsl/get-drop-index frame-id objects position))] (-> state (assoc-in [:workspace-drawing :object :frame-id] frame-id) (cond-> (some? drop-index) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 2a61391b9..f3317e214 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -53,11 +53,25 @@ :layout-padding {:p1 0 :p2 0 :p3 0 :p4 0}}) (def initial-grid-layout ;; TODO - {:layout :grid}) + {:layout :grid + :layout-gap-type :multiple + :layout-gap {:row-gap 0 :column-gap 0} + :layout-align-items :start + :layout-align-content :stretch + :layout-justify-items :start + :layout-justify-content :start + :layout-padding-type :simple + :layout-padding {:p1 0 :p2 0 :p3 0 :p4 0} + + :layout-grid-rows [] + :layout-grid-columns []}) (defn get-layout-initializer [type from-frame?] - (let [initial-layout-data (if (= type :flex) initial-flex-layout initial-grid-layout)] + (let [initial-layout-data + (case type + :flex initial-flex-layout + :grid initial-grid-layout)] (fn [shape] (-> shape (merge initial-layout-data) @@ -288,7 +302,7 @@ (dwu/commit-undo-transaction undo-id)))))) (defn create-layout - [] + [type] (ptk/reify ::create-layout ptk/WatchEvent (watch [_ state _] @@ -303,11 +317,11 @@ (if (and single? is-frame?) (rx/of (dwu/start-undo-transaction undo-id) - (create-layout-from-id [(first selected)] :flex true) + (create-layout-from-id [(first selected)] type true) (dwu/commit-undo-transaction undo-id)) (rx/of (dwu/start-undo-transaction undo-id) - (create-layout-from-selection :flex) + (create-layout-from-selection type) (dwu/commit-undo-transaction undo-id))))))) (defn toggle-layout-flex @@ -320,12 +334,12 @@ selected (wsh/lookup-selected state) selected-shapes (map (d/getf objects) selected) single? (= (count selected-shapes) 1) - has-flex-layout? (and single? (ctl/layout? objects (:id (first selected-shapes))))] + has-flex-layout? (and single? (ctl/flex-layout? objects (:id (first selected-shapes))))] (when (not= 0 (count selected)) (if has-flex-layout? (rx/of (remove-layout selected)) - (rx/of (create-layout)))))))) + (rx/of (create-layout :flex)))))))) (defn update-layout [ids changes] diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index 326849ed0..353ee2f6b 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -18,7 +18,6 @@ [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] [app.common.types.shape.interactions :as ctsi] - [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.main.data.comments :as dc] [app.main.data.workspace.changes :as dch] @@ -194,10 +193,6 @@ [file page objects ids it components-v2] (let [lookup (d/getf objects) - layout-ids (->> ids - (mapcat (partial cph/get-parent-ids objects)) - (filter (partial ctl/layout? objects))) - groups-to-unmask (reduce (fn [group-ids id] ;; When the shape to delete is the mask of a masked group, @@ -319,7 +314,6 @@ (dc/detach-comment-thread ids) (ptk/data-event :layout/update all-parents) (dch/commit-changes changes) - (ptk/data-event :layout/update layout-ids) (dwu/commit-undo-transaction undo-id)))) (defn create-and-add-shape diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index daaf0f0ad..77357fe7b 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -438,9 +438,10 @@ (cph/selected-with-children objects selected)) exclude-frames-siblings - (into exclude-frames + exclude-frames + #_(into exclude-frames (comp (mapcat (partial cph/get-siblings-ids objects)) - (filter (partial ctl/layout-immediate-child-id? objects))) + (filter (partial ctl/any-layout-immediate-child-id? objects))) selected) position (->> ms/mouse-position @@ -469,11 +470,11 @@ (rx/map (fn [[move-vector mod?]] - (let [position (gpt/add from-position move-vector) + (let [position (gpt/add from-position move-vector) exclude-frames (if mod? exclude-frames exclude-frames-siblings) - target-frame (ctst/top-nested-frame objects position exclude-frames) - layout? (ctl/layout? objects target-frame) - drop-index (when layout? (gsl/get-drop-index target-frame objects position))] + target-frame (ctst/top-nested-frame objects position exclude-frames) + flex-layout? (ctl/flex-layout? objects target-frame) + drop-index (when flex-layout? (gsl/get-drop-index target-frame objects position))] [move-vector target-frame drop-index]))) (rx/take-until stopper))] @@ -529,7 +530,8 @@ get-new-position (fn [parent-id position] (let [parent (get objects parent-id)] - (when (ctl/layout? parent) + (cond + (ctl/flex-layout? parent) (if (or (and (ctl/reverse? parent) (or (= direction :left) @@ -538,7 +540,12 @@ (or (= direction :right) (= direction :down)))) (dec position) - (+ position 2))))) + (+ position 2)) + + ;; TODO: GRID + (ctl/grid-layout? parent) + nil + ))) add-children-position (fn [[parent-id children]] @@ -643,7 +650,7 @@ (let [objects (wsh/lookup-page-objects state) selected (wsh/lookup-selected state {:omit-blocked? true}) selected-shapes (->> selected (map (d/getf objects)))] - (if (every? #(and (ctl/layout-immediate-child? objects %) + (if (every? #(and (ctl/any-layout-immediate-child? objects %) (not (ctl/layout-absolute? %))) selected-shapes) (rx/of (reorder-selected-layout-child direction)) diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index df5637cf2..7e7bc193a 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -405,7 +405,7 @@ (let [objects (wsh/lookup-page-objects state)] (into [] (comp (map (d/getf objects)) - (filter (partial ctl/layout-immediate-child? objects))) + (filter (partial ctl/flex-layout-immediate-child? objects))) ids))) st/state =)) @@ -478,22 +478,22 @@ (defn workspace-text-modifier-by-id [id] (l/derived #(get % id) workspace-text-modifier =)) -(defn is-layout-child? +(defn is-flex-layout-child? [ids] (l/derived (fn [objects] (->> ids (map (d/getf objects)) - (some (partial ctl/layout-immediate-child? objects)))) + (some (partial ctl/flex-layout-immediate-child? objects)))) workspace-page-objects)) -(defn all-layout-child? +(defn all-flex-layout-child? [ids] (l/derived (fn [objects] (->> ids (map (d/getf objects)) - (every? (partial ctl/layout-immediate-child? objects)))) + (every? (partial ctl/flex-layout-immediate-child? objects)))) workspace-page-objects)) (defn get-flex-child-viewer @@ -503,7 +503,7 @@ (let [objects (wsh/lookup-viewer-objects state page-id)] (into [] (comp (map (d/getf objects)) - (filter (partial ctl/layout-immediate-child? objects))) + (filter (partial ctl/flex-layout-immediate-child? objects))) ids))) st/state =)) diff --git a/frontend/src/app/main/ui/components/shape_icon.cljs b/frontend/src/app/main/ui/components/shape_icon.cljs index 9eca7fa5b..fa6d7606b 100644 --- a/frontend/src/app/main/ui/components/shape_icon.cljs +++ b/frontend/src/app/main/ui/components/shape_icon.cljs @@ -20,12 +20,14 @@ i/component-copy) (case (:type shape) :frame (cond - (and (ctl/layout? shape) (ctl/col? shape)) + (and (ctl/flex-layout? shape) (ctl/col? shape)) i/layout-columns - (and (ctl/layout? shape) (ctl/row? shape)) + (and (ctl/flex-layout? shape) (ctl/row? shape)) i/layout-rows + ;; TODO: GRID ICON + :else i/artboard) :image i/image diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index 5b51a8456..9d941d190 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -308,8 +308,8 @@ layout-type (:layout values) on-add-layout - (fn [_] - (st/emit! (dwsl/create-layout)) + (fn [type] + (st/emit! (dwsl/create-layout type)) (reset! open? true)) @@ -319,13 +319,13 @@ (reset! open? false)) ;; Uncomment when activating the grid options - ;; set-flex (fn [] - ;; (st/emit! (dwsl/remove-layout ids)) - ;; (on-add-layout :flex)) - ;; - ;; set-grid (fn [] - ;; (st/emit! (dwsl/remove-layout ids)) - ;; (on-add-layout :grid)) + set-flex (fn [] + (st/emit! (dwsl/remove-layout ids)) + (on-add-layout :flex)) + + set-grid (fn [] + (st/emit! (dwsl/remove-layout ids)) + (on-add-layout :grid)) ;; Flex-direction @@ -394,7 +394,7 @@ [:span "Layout"] (if (and (not multiple) (:layout values)) [:div.title-actions - #_[:div.layout-btns + [:div.layout-btns [:button {:on-click set-flex :class (dom/classnames :active (= :flex layout-type))} "Flex"] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index f79bfedba..e24b088d6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -83,9 +83,9 @@ selection-parents-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) selection-parents (mf/deref selection-parents-ref) - flex-child? (->> selection-parents (some ctl/layout?)) + flex-child? (->> selection-parents (some ctl/flex-layout?)) absolute? (ctl/layout-absolute? shape) - flex-container? (ctl/layout? shape) + flex-container? (ctl/flex-layout? shape) flex-auto-width? (ctl/auto-width? shape) flex-fill-width? (ctl/fill-width? shape) flex-auto-height? (ctl/auto-height? shape) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs index 9803d57c6..458acf5d9 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs @@ -30,8 +30,8 @@ layout-item-values (select-keys shape layout-item-attrs) layout-container-values (select-keys shape layout-container-flex-attrs) - is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) - is-layout-child? (mf/deref is-layout-child-ref) + is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) + is-flex-layout-child? (mf/deref is-flex-layout-child-ref) is-layout-child-absolute? (ctl/layout-absolute? shape)] [:* @@ -41,7 +41,7 @@ :shape shape}] [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] - (when is-layout-child? + (when is-flex-layout-child? [:& layout-item-menu {:ids ids :type type @@ -49,7 +49,7 @@ :is-layout-child? true :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) + (when (or (not is-flex-layout-child?) is-layout-child-absolute?) [:& constraints-menu {:ids ids :values constraint-values}]) [:& layer-menu {:ids ids diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs index 44146155f..576d21be2 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs @@ -32,7 +32,7 @@ layout-item-values (select-keys shape layout-item-attrs) layout-container-values (select-keys shape layout-container-flex-attrs) - is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) + is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) is-layout-child? (mf/deref is-layout-child-ref) is-layout-child-absolute? (ctl/layout-absolute? shape)] @@ -43,14 +43,14 @@ :shape shape}] [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] - (when is-layout-child? + (when is-flex-layout-child? [:& layout-item-menu {:ids ids :type type :values layout-item-values :is-layout-child? true :is-layout-container? false :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) + (when (or (not is-flex-layout-child?) is-layout-child-absolute?) [:& constraints-menu {:ids ids :values constraint-values}]) [:& layer-menu {:ids ids diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs index ebbb5b618..832e8bb1f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs @@ -36,9 +36,9 @@ layout-item-values (select-keys shape layout-item-attrs) [comp-ids comp-values] [[(:id shape)] (select-keys shape component-attrs)] - is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) - is-layout-child? (mf/deref is-layout-child-ref) - is-layout-container? (ctl/layout? shape) + is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) + is-flex-layout-child? (mf/deref is-flex-layout-child-ref) + is-flex-layout-container? (ctl/flex-layout? shape)] is-layout-child-absolute? (ctl/layout-absolute? shape)] [:* [:& measures-menu {:ids [(:id shape)] @@ -48,18 +48,18 @@ [:& component-menu {:ids comp-ids :values comp-values :shape-name (:name shape)}] - (when (or (not is-layout-child?) is-layout-child-absolute?) + (when (or (not is-flex-layout-child?) is-layout-child-absolute?) [:& constraints-menu {:ids ids :values constraint-values}]) [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] - (when (or is-layout-child? is-layout-container?) + (when (or is-flex-layout-child? is-flex-layout-container?) [:& layout-item-menu {:ids ids :type type :values layout-item-values - :is-layout-child? is-layout-child? - :is-layout-container? is-layout-container? + :is-layout-child? is-flex-layout-child? + :is-layout-container? is-flex-layout-container? :shape shape}]) [:& layer-menu {:ids ids diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs index 7b336181a..4d4520350 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs @@ -29,15 +29,15 @@ {::mf/wrap [mf/memo] ::mf/wrap-props false} [props] - (let [shape (unchecked-get props "shape") - shape-with-children (unchecked-get props "shape-with-children") - shared-libs (unchecked-get props "shared-libs") - objects (->> shape-with-children (group-by :id) (d/mapm (fn [_ v] (first v)))) - file-id (unchecked-get props "file-id") - layout-container-values (select-keys shape layout-container-flex-attrs) - ids [(:id shape)] - is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) - is-layout-child? (mf/deref is-layout-child-ref) + (let [shape (unchecked-get props "shape") + shape-with-children (unchecked-get props "shape-with-children") + shared-libs (unchecked-get props "shared-libs") + objects (->> shape-with-children (group-by :id) (d/mapm (fn [_ v] (first v)))) + file-id (unchecked-get props "file-id") + layout-container-values (select-keys shape layout-container-flex-attrs) + ids [(:id shape)] + is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) + is-flex-layout-child? (mf/deref is-flex-layout-child-ref) is-layout-child-absolute? (ctl/layout-absolute? shape) type :group @@ -58,7 +58,7 @@ [:& component-menu {:ids comp-ids :values comp-values :shape-name (:name shape)}] [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] - (when is-layout-child? + (when is-flex-layout-child? [:& layout-item-menu {:type type :ids layout-item-ids @@ -66,7 +66,7 @@ :is-layout-container? false :values layout-item-values}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) + (when (or (not is-flex-layout-child?) is-layout-child-absolute?) [:& constraints-menu {:ids constraint-ids :values constraint-values}]) [:& layer-menu {:type type :ids layer-ids :values layer-values}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs index 0f3bf75fb..d911e489e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs @@ -32,8 +32,8 @@ layout-item-values (select-keys shape layout-item-attrs) layout-container-values (select-keys shape layout-container-flex-attrs) - is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) - is-layout-child? (mf/deref is-layout-child-ref) + is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) + is-flex-layout-child? (mf/deref is-flex-layout-child-ref)] is-layout-child-absolute? (ctl/layout-absolute? shape)] [:* [:& measures-menu {:ids ids @@ -42,7 +42,7 @@ :shape shape}] [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] - (when is-layout-child? + (when is-flex-layout-child? [:& layout-item-menu {:ids ids :type type @@ -50,7 +50,7 @@ :is-layout-child? true :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) + (when (or (not is-flex-layout-child?) is-layout-child-absolute?) [:& constraints-menu {:ids ids :values constraint-values}]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs index 7245fe2ad..ad19265dd 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs @@ -294,17 +294,17 @@ all-types (into #{} (map :type shapes)) ids (->> shapes (map :id)) - is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) - is-layout-child? (mf/deref is-layout-child-ref) + is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) + is-flex-layout-child? (mf/deref is-flex-layout-child-ref) has-text? (contains? all-types :text) - has-layout-container? (->> shapes (some ctl/layout?)) + has-flex-layout-container? (->> shapes (some ctl/flex-layout?)) - all-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/all-layout-child? ids)) - all-layout-child? (mf/deref all-layout-child-ref) + all-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/all-flex-layout-child? ids)) + all-flex-layout-child? (mf/deref all-flex-layout-child-ref) - all-layout-container? (->> shapes (every? ctl/layout?)) + all-flex-layout-container? (->> shapes (every? ctl/flex-layout?)) [measure-ids measure-values] (get-attrs shapes objects :measure) @@ -342,15 +342,15 @@ [:& layout-container-menu {:type type :ids layout-container-ids :values layout-container-values :multiple true}] - (when (or is-layout-child? has-layout-container?) + (when (or is-flex-layout-child? has-flex-layout-container?) [:& layout-item-menu {:type type :ids layout-item-ids - :is-layout-child? all-layout-child? - :is-layout-container? all-layout-container? + :is-layout-child? all-flex-layout-child? + :is-layout-container? all-flex-layout-container? :values layout-item-values}]) - (when-not (or (empty? constraint-ids) is-layout-child?) + (when-not (or (empty? constraint-ids) is-flex-layout-child?) [:& constraints-menu {:ids constraint-ids :values constraint-values}]) (when-not (empty? layer-ids) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs index 28494c225..b60ce4872 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs @@ -32,8 +32,8 @@ layout-item-values (select-keys shape layout-item-attrs) layout-container-values (select-keys shape layout-container-flex-attrs) - is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) - is-layout-child? (mf/deref is-layout-child-ref) + is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) + is-flex-layout-child? (mf/deref is-flex-layout-child-ref)] is-layout-child-absolute? (ctl/layout-absolute? shape)] [:* [:& measures-menu {:ids ids @@ -42,14 +42,14 @@ :shape shape}] [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] - (when is-layout-child? + (when is-flex-layout-child? [:& layout-item-menu {:ids ids :type type :values layout-item-values :is-layout-child? true :is-layout-container? false :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) + (when (or (not is-flex-layout-child?) is-layout-child-absolute?) [:& constraints-menu {:ids ids :values constraint-values}]) [:& layer-menu {:ids ids diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs index 5ee633fcf..6eb3fcd67 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs @@ -32,8 +32,8 @@ stroke-values (select-keys shape stroke-attrs) layout-item-values (select-keys shape layout-item-attrs) layout-container-values (select-keys shape layout-container-flex-attrs) - is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) - is-layout-child? (mf/deref is-layout-child-ref) + is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) + is-flex-layout-child? (mf/deref is-flex-layout-child-ref)] is-layout-child-absolute? (ctl/layout-absolute? shape)] [:* [:& measures-menu {:ids ids @@ -41,7 +41,7 @@ :values measure-values :shape shape}] [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] - (when is-layout-child? + (when is-flex-layout-child? [:& layout-item-menu {:ids ids :type type diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs index a8ec66fb9..570e13e24 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs @@ -106,8 +106,8 @@ layout-item-values (select-keys shape layout-item-attrs) layout-container-values (select-keys shape layout-container-flex-attrs) - is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) - is-layout-child? (mf/deref is-layout-child-ref) + is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) + is-flex-layout-child? (mf/deref is-flex-layout-child-ref)] is-layout-child-absolute? (ctl/layout-absolute? shape)] (when (contains? svg-elements tag) @@ -118,7 +118,7 @@ :shape shape}] [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] - (when is-layout-child? + (when is-flex-layout-child? [:& layout-item-menu {:ids ids :type type @@ -126,7 +126,7 @@ :is-layout-child? true :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) + (when (or (not is-flex-layout-child?) is-layout-child-absolute?) [:& constraints-menu {:ids ids :values constraint-values}]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs index 6bfcb5dda..8c93c8f9e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs @@ -28,8 +28,8 @@ (let [ids [(:id shape)] type (:type shape) - is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) - is-layout-child? (mf/deref is-layout-child-ref) + is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) + is-flex-layout-child? (mf/deref is-flex-layout-child-ref) layout-container-values (select-keys shape layout-container-flex-attrs) is-layout-child-absolute? (ctl/layout-absolute? shape) state-map (mf/deref refs/workspace-editor-state) @@ -76,7 +76,7 @@ :shape shape}] [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] - (when is-layout-child? + (when is-flex-layout-child? [:& layout-item-menu {:ids ids :type type @@ -84,7 +84,7 @@ :is-layout-child? true :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) + (when (or (not is-flex-layout-child?) is-layout-child-absolute?) [:& constraints-menu {:ids ids :values (select-keys shape constraint-attrs)}]) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 20a5abe6f..30e2e8ec2 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -338,7 +338,7 @@ :zoom zoom :modifiers modifiers}] - (when (ctl/layout? outlined-frame) + (when (ctl/any-layout? outlined-frame) [:g.ghost-outline [:& outline/shape-outlines {:objects base-objects diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index 1fb9b6d02..3842e7290 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -68,7 +68,7 @@ shape (or selected-frame (get objects hover-top-frame-id))] - (when (and shape (ctl/layout? shape)) + (when (and shape (ctl/flex-layout? shape)) (let [row? (ctl/row? shape) col? (ctl/col? shape) diff --git a/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs b/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs index 9ae906cc5..185d50e74 100644 --- a/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs @@ -268,7 +268,7 @@ frame (mf/deref (refs/object-by-id frame-id)) selrect (gsh/selection-rect selected-shapes)] - (when-not (ctl/layout? frame) + (when-not (ctl/any-layout? frame) [:g.distance [:& shape-distance {:selrect selrect diff --git a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs index 88fe7bc81..a57260864 100644 --- a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs @@ -175,7 +175,7 @@ shapes (if drawing [drawing] shapes) frame-id (snap/snap-frame-id shapes)] - (when-not (ctl/layout? objects frame-id) + (when-not (ctl/any-layout? objects frame-id) [:& snap-feedback {:shapes shapes :page-id page-id :remove-snap? remove-snap? diff --git a/frontend/src/app/util/snap_data.cljs b/frontend/src/app/util/snap_data.cljs index deb4239fe..c7b00e954 100644 --- a/frontend/src/app/util/snap_data.cljs +++ b/frontend/src/app/util/snap_data.cljs @@ -82,7 +82,7 @@ grid-y-data (get-grids-snap-points frame :y)] (cond-> page-data - (not (ctl/layout-descent? objects frame)) + (not (ctl/any-layout-descent? objects frame)) (-> ;; Update root frame information (assoc-in [uuid/zero :objects-data frame-id] frame-data) @@ -106,7 +106,7 @@ :id (:id shape) :pt %)))] (cond-> page-data - (not (ctl/layout-descent? objects shape)) + (not (ctl/any-layout-descent? objects shape)) (-> (assoc-in [frame-id :objects-data (:id shape)] shape-data) (update-in [frame-id :x] (make-insert-tree-data shape-data :x)) (update-in [frame-id :y] (make-insert-tree-data shape-data :y)))))) From 6f99209a62924c0d44786da6b64dce04b972cb02 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 15 Feb 2023 13:00:54 +0100 Subject: [PATCH 03/10] :sparkles: Grid layout editor interface --- .../src/app/main/ui/workspace/viewport.cljs | 6 +++ .../app/main/ui/workspace/viewport/debug.cljs | 49 +++++++++++++++++++ frontend/src/debug.cljs | 3 ++ 3 files changed, 58 insertions(+) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 30e2e8ec2..d4f4ce663 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -501,6 +501,12 @@ :hover-top-frame-id @hover-top-frame-id :zoom zoom}]) + (when (debug? :grid-layout) + [:& wvd/debug-grid-layout {:selected-shapes selected-shapes + :objects base-objects + :hover-top-frame-id @hover-top-frame-id + :zoom zoom}]) + (when show-selection-handlers? [:g.selection-handlers {:clipPath "url(#clip-handlers)"} [:defs diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index 3842e7290..ada80994d 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -11,6 +11,7 @@ [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.geom.shapes.flex-layout :as gsl] + [app.common.geom.shapes.grid-layout :as gsg] [app.common.geom.shapes.points :as gpo] [app.common.pages.helpers :as cph] [app.common.types.shape.layout :as ctl] @@ -195,3 +196,51 @@ :cy (:y point) :r (/ 2 zoom) :style {:fill "red"}}]))])])))) + +(mf/defc debug-grid-layout + {::mf/wrap-props false} + [props] + + (let [objects (unchecked-get props "objects") + zoom (unchecked-get props "zoom") + selected-shapes (unchecked-get props "selected-shapes") + hover-top-frame-id (unchecked-get props "hover-top-frame-id") + + selected-frame + (when (and (= (count selected-shapes) 1) (= :frame (-> selected-shapes first :type))) + (first selected-shapes)) + + parent (or selected-frame (get objects hover-top-frame-id)) + parent-bounds (:points parent)] + + (when (and (some? parent) (not= uuid/zero (:id parent))) + (let [children (->> (cph/get-immediate-children objects (:id parent)) + (remove :hidden)) + + hv #(gpo/start-hv parent-bounds %) + vv #(gpo/start-vv parent-bounds %) + + width (gpo/width-points parent-bounds) + height (gpo/height-points parent-bounds) + origin (gpo/origin parent-bounds) + + grid-layout (gsg/calc-layout-data parent children parent-bounds)] + + [:* + (for [row-data (:row-lines grid-layout)] + (let [start-p (gpt/add origin (vv (:distance row-data))) + end-p (gpt/add start-p (hv width))] + [:line {:x1 (:x start-p) + :y1 (:y start-p) + :x2 (:x end-p) + :y2 (:y end-p) + :style {:stroke "red"}}])) + + (for [column-data (:column-lines grid-layout)] + (let [start-p (gpt/add origin (hv (:distance column-data))) + end-p (gpt/add start-p (vv height))] + [:line {:x1 (:x start-p) + :y1 (:y start-p) + :x2 (:x end-p) + :y2 (:y end-p) + :style {:stroke "red"}}]))])))) diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index b663cdc49..c306f5820 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -95,6 +95,9 @@ ;; Show shape name and id :shape-titles + + ;; + :grid-layout }) ;; These events are excluded when we activate the :events flag From 4b7e93ab84fafd72f3c00a0d424a29d4e28051ef Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 16 Feb 2023 17:15:27 +0100 Subject: [PATCH 04/10] :sparkles: First draft of cell display --- .../app/common/geom/shapes/grid_layout.cljc | 1 - .../geom/shapes/grid_layout/layout_data.cljc | 166 +++++++++++---- .../src/app/common/geom/shapes/modifiers.cljc | 10 +- .../app/main/data/workspace/shape_layout.cljs | 2 + .../options/menus/layout_container.cljs | 2 +- .../src/app/main/ui/workspace/viewport.cljs | 6 + .../app/main/ui/workspace/viewport/debug.cljs | 10 +- .../viewport/grid_layout_editor.cljs | 197 ++++++++++++++++++ 8 files changed, 339 insertions(+), 55 deletions(-) create mode 100644 frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs diff --git a/common/src/app/common/geom/shapes/grid_layout.cljc b/common/src/app/common/geom/shapes/grid_layout.cljc index 2588b0e53..36f927081 100644 --- a/common/src/app/common/geom/shapes/grid_layout.cljc +++ b/common/src/app/common/geom/shapes/grid_layout.cljc @@ -12,5 +12,4 @@ (dm/export glld/calc-layout-data) (dm/export glld/get-cell-data) -(dm/export glld/get-child-coordinates) (dm/export glp/child-modifiers) diff --git a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc index ae6ee4bfb..aba5d9f87 100644 --- a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc @@ -6,66 +6,144 @@ (ns app.common.geom.shapes.grid-layout.layout-data (:require + [app.common.data :as d] + [app.common.uuid :as uuid] [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes.points :as gpo])) +(defn set-sample-data + [parent children] + + (let [parent (assoc parent + :layout-grid-columns + [{:type :percent :value 25} + {:type :percent :value 25} + {:type :fixed :value 100} + ;;{:type :auto} + ;;{:type :fr :value 1} + ] + + :layout-grid-rows + [{:type :percent :value 50} + {:type :percent :value 50} + ;;{:type :fixed :value 100} + ;;{:type :auto} + ;;{:type :fr :value 1} + ]) + + num-rows (count (:layout-grid-rows parent)) + num-columns (count (:layout-grid-columns parent)) + + layout-grid-cells + (into + {} + (for [[row-idx row] (d/enumerate (:layout-grid-rows parent)) + [col-idx col] (d/enumerate (:layout-grid-columns parent))] + (let [[_bounds shape] (nth children (+ (* row-idx num-columns) col-idx) nil) + cell-data {:id (uuid/next) + :row (inc row-idx) + :column (inc col-idx) + :row-span 1 + :col-span 1 + :shapes (when shape [(:id shape)])}] + [(:id cell-data) cell-data]))) + + parent (assoc parent :layout-grid-cells layout-grid-cells)] + + [parent children])) + +(defn calculate-initial-track-values + [{:keys [type value]} total-value] + + (case type + :percent + (let [value (/ (* total-value value) 100) ] + value) + + :fixed + value + + :auto + 0 + )) + (defn calc-layout-data - [_parent _children transformed-parent-bounds] - (let [num-columns 3 - num-rows 2 + [parent children transformed-parent-bounds] + + (let [ + + ;; TODO: Delete when there is UI + [parent children] (set-sample-data parent children) height (gpo/height-points transformed-parent-bounds) width (gpo/width-points transformed-parent-bounds) - row-lines - (->> (range 0 num-rows) - (reduce (fn [[result start-dist] _] - (let [height (/ height num-rows)] - [(conj result {:distance start-dist - :height height}) - (+ start-dist height)])) + ;; Initialize tracks + column-tracks + (->> (:layout-grid-columns parent) + (map (fn [track] + (let [initial (calculate-initial-track-values track width)] + (assoc track :value initial))))) - [[] 0]) + row-tracks + (->> (:layout-grid-rows parent) + (map (fn [track] + (let [initial (calculate-initial-track-values track height)] + (assoc track :value initial))))) + + ;; Go through cells to adjust auto sizes + + + ;; Once auto sizes have been calculated we get calculate the `fr` with the remainining size and adjust the size + + + ;; Adjust final distances + + acc-track-distance + (fn [[result next-distance] data] + (let [result (conj result (assoc data :distance next-distance)) + next-distance (+ next-distance (:value data))] + [result next-distance])) + + column-tracks + (->> column-tracks + (reduce acc-track-distance [[] 0]) first) - column-lines - (->> (range 0 num-columns) - (reduce (fn [[result start-dist] _] - (let [width (/ width num-columns)] - [(conj result {:distance start-dist - :width width}) - (+ start-dist width)])) - [[] 0]) - first)] - {:columns 3 - :rows 3 - :row-lines row-lines - :column-lines column-lines})) + row-tracks + (->> row-tracks + (reduce acc-track-distance [[] 0]) + first) -(defn get-child-coordinates - [{:keys [columns]} _child child-idx] - [;; Row - (quot child-idx columns) - ;; column - (mod child-idx columns)]) + shape-cells + (into {} + (mapcat (fn [[_ cell]] + (->> (:shapes cell) + (map #(vector % cell))))) + (:layout-grid-cells parent)) + ] + + {:row-tracks row-tracks + :column-tracks column-tracks + :shape-cells shape-cells})) (defn get-cell-data - [grid-data transformed-parent-bounds row col] + [{:keys [row-tracks column-tracks shape-cells]} transformed-parent-bounds [child-bounds child]] (let [origin (gpo/origin transformed-parent-bounds) - hv #(gpo/start-hv transformed-parent-bounds %) - vv #(gpo/start-vv transformed-parent-bounds %) + hv #(gpo/start-hv transformed-parent-bounds %) + vv #(gpo/start-vv transformed-parent-bounds %) - {col-dist :distance width :width} (dm/get-in grid-data [:column-lines col]) - {row-dist :distance height :height} (dm/get-in grid-data [:row-lines row]) + grid-cell (get shape-cells (:id child))] - start-p - (-> origin - (gpt/add (hv col-dist)) - (gpt/add (vv row-dist)))] - {:start-p start-p - :width width - :height height - :row row - :col col})) + (when (some? grid-cell) + (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)))) + ] + + (assoc grid-cell :start-p start-p))))) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index f0c247229..29fe313ed 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -218,14 +218,14 @@ (map apply-modifiers)) grid-data (gcgl/calc-layout-data parent children @transformed-parent-bounds)] (loop [modif-tree modif-tree - child-idx 0 child (first children) pending (rest children)] (if (some? child) - (let [[row col] (gcgl/get-child-coordinates grid-data child child-idx) - cell-data (gcgl/get-cell-data grid-data @transformed-parent-bounds row col) - modif-tree (set-child-modifiers modif-tree cell-data child)] - (recur modif-tree (inc child-idx) (first pending) (rest pending))) + (let [cell-data (gcgl/get-cell-data grid-data @transformed-parent-bounds child) + modif-tree (cond-> modif-tree + (some? cell-data) + (set-child-modifiers cell-data child))] + (recur modif-tree (first pending) (rest pending))) modif-tree))))) (defn- calc-auto-modifiers diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index f3317e214..e201ad54c 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -68,6 +68,7 @@ (defn get-layout-initializer [type from-frame?] + (prn "??type" type) (let [initial-layout-data (case type :flex initial-flex-layout @@ -156,6 +157,7 @@ (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 _] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index 9d941d190..925d0a84c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -403,7 +403,7 @@ :active (= :grid layout-type))} "Grid"]] [:button.remove-layout {:on-click on-remove-layout} i/minus]] - [:button.add-page {:on-click on-add-layout} i/close])]] + [:button.add-page {:on-click #(on-add-layout :flex)} i/close])]] (when (:layout values) (when (not= :multiple layout-type) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index d4f4ce663..d9102d9f9 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -6,6 +6,7 @@ (ns app.main.ui.workspace.viewport (:require + [app.main.ui.workspace.viewport.grid-layout-editor :as grid-layout] [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] @@ -476,6 +477,11 @@ :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 diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index ada80994d..8cd73894c 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -215,7 +215,8 @@ (when (and (some? parent) (not= uuid/zero (:id parent))) (let [children (->> (cph/get-immediate-children objects (:id parent)) - (remove :hidden)) + (remove :hidden) + (map #(vector (gpo/parent-coords-bounds (:points %) (:points parent)) %))) hv #(gpo/start-hv parent-bounds %) vv #(gpo/start-vv parent-bounds %) @@ -224,10 +225,11 @@ height (gpo/height-points parent-bounds) origin (gpo/origin parent-bounds) - grid-layout (gsg/calc-layout-data parent children parent-bounds)] + {:keys [row-tracks column-tracks shape-cells]} + (gsg/calc-layout-data parent children parent-bounds)] [:* - (for [row-data (:row-lines grid-layout)] + (for [row-data row-tracks] (let [start-p (gpt/add origin (vv (:distance row-data))) end-p (gpt/add start-p (hv width))] [:line {:x1 (:x start-p) @@ -236,7 +238,7 @@ :y2 (:y end-p) :style {:stroke "red"}}])) - (for [column-data (:column-lines grid-layout)] + (for [column-data column-tracks] (let [start-p (gpt/add origin (hv (:distance column-data))) end-p (gpt/add start-p (vv height))] [:line {:x1 (:x start-p) diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs new file mode 100644 index 000000000..77732e1a6 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -0,0 +1,197 @@ +;; 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.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.common.data :as d] + [app.common.data.macros :as dm] + [app.common.geom.shapes.grid-layout :as gsg] + [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] + [rumext.v2 :as mf])) + + +(mf/defc track-marker + {::mf/wrap-props false} + [props] + + (let [center (unchecked-get props "center") + 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))) + + text-x (:x center) + text-y (:y center)] + [:g.grid-track-marker + [:polygon {:points (->> [p1 p2 p3 p4 p5] + (map #(dm/fmt "%,%" (:x %) (:y %))) + (str/join " ")) + + :style {:fill "#DB00FF" + :fill-opacity 0.3}}] + [:text {:x text-x + :y text-y + :width (/ 26.26 zoom) + :height (/ 32 zoom) + :font-size (/ 16 zoom) + :text-anchor "middle" + :dominant-baseline "middle" + :style {:fill "#DB00FF"}} + (dm/str value)]])) + +(mf/defc editor + {::mf/wrap-props false} + [props] + + (let [shape (unchecked-get props "shape") + objects (unchecked-get props "objects") + zoom (unchecked-get props "zoom") + 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)) %))) + + hv #(gpo/start-hv bounds %) + vv #(gpo/start-vv bounds %) + + width (gpo/width-points bounds) + height (gpo/height-points bounds) + origin (gpo/origin bounds) + + {:keys [row-tracks column-tracks shape-cells]} + (gsg/calc-layout-data shape children bounds) + + [shape children] (set-sample-data shape children)] + + [:g.grid-editor + [:polygon {:points (->> [origin + (-> origin + (gpt/add (hv width))) + (-> origin + (gpt/add (hv width)) + (gpt/subtract (vv (/ 40 zoom)))) + + (-> origin + (gpt/add (hv width)) + (gpt/subtract (vv (/ 40 zoom))) + (gpt/subtract (hv (+ width (/ 40 zoom))))) + + (-> 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)}}] + + (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)}}] + + [: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"}]]) + + (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))) + (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))) + (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)} + }]]))])))) From eb425dc4f275d73d2864cd0b9a1e1f611e3aa13c Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 20 Feb 2023 15:43:54 +0100 Subject: [PATCH 05/10] :sparkles: Edit cell panel --- .../data/workspace/grid_layout/editor.cljs | 44 +++ .../app/main/data/workspace/shape_layout.cljs | 2 - frontend/src/app/main/refs.cljs | 9 + .../main/ui/workspace/sidebar/options.cljs | 15 +- .../sidebar/options/shapes/grid_cell.cljs | 22 ++ .../src/app/main/ui/workspace/viewport.cljs | 15 +- .../viewport/grid_layout_editor.cljs | 334 +++++++++++------- 7 files changed, 299 insertions(+), 142 deletions(-) create mode 100644 frontend/src/app/main/data/workspace/grid_layout/editor.cljs create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs diff --git a/frontend/src/app/main/data/workspace/grid_layout/editor.cljs b/frontend/src/app/main/data/workspace/grid_layout/editor.cljs new file mode 100644 index 000000000..7cd464a05 --- /dev/null +++ b/frontend/src/app/main/data/workspace/grid_layout/editor.cljs @@ -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)))) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index e201ad54c..f3317e214 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -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 _] diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index 7e7bc193a..49f1b4d13 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -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)) + diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs index 80d4fa796..1847962c0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs @@ -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}])) - diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs new file mode 100644 index 000000000..7f46e045b --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs @@ -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)]]]]) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index d9102d9f9..007754eb7 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -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}])) + ]]])) diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index 77732e1a6..48ba04343 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -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"}}]]))])) From cc8347a871ef400389074be3722e5f10e93c33ce Mon Sep 17 00:00:00 2001 From: Eva Date: Tue, 21 Feb 2023 09:12:30 +0100 Subject: [PATCH 06/10] :sparkles: Add options to sidebar --- .../grid-justify-content-column-around.svg | 38 +++ .../grid-justify-content-column-between.svg | 38 +++ .../grid-justify-content-column-center.svg | 38 +++ .../icons/grid-justify-content-column-end.svg | 38 +++ .../grid-justify-content-column-start.svg | 38 +++ .../icons/grid-justify-content-row-around.svg | 38 +++ .../grid-justify-content-row-between.svg | 38 +++ .../icons/grid-justify-content-row-center.svg | 38 +++ .../icons/grid-justify-content-row-end.svg | 38 +++ .../icons/grid-justify-content-row-start.svg | 38 +++ .../partials/sidebar-element-options.scss | 144 +++++++++ frontend/src/app/main/ui/icons.cljs | 10 + .../options/menus/layout_container.cljs | 275 +++++++++++++++++- 13 files changed, 794 insertions(+), 15 deletions(-) create mode 100644 frontend/resources/images/icons/grid-justify-content-column-around.svg create mode 100644 frontend/resources/images/icons/grid-justify-content-column-between.svg create mode 100644 frontend/resources/images/icons/grid-justify-content-column-center.svg create mode 100644 frontend/resources/images/icons/grid-justify-content-column-end.svg create mode 100644 frontend/resources/images/icons/grid-justify-content-column-start.svg create mode 100644 frontend/resources/images/icons/grid-justify-content-row-around.svg create mode 100644 frontend/resources/images/icons/grid-justify-content-row-between.svg create mode 100644 frontend/resources/images/icons/grid-justify-content-row-center.svg create mode 100644 frontend/resources/images/icons/grid-justify-content-row-end.svg create mode 100644 frontend/resources/images/icons/grid-justify-content-row-start.svg diff --git a/frontend/resources/images/icons/grid-justify-content-column-around.svg b/frontend/resources/images/icons/grid-justify-content-column-around.svg new file mode 100644 index 000000000..65cd17d58 --- /dev/null +++ b/frontend/resources/images/icons/grid-justify-content-column-around.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/frontend/resources/images/icons/grid-justify-content-column-between.svg b/frontend/resources/images/icons/grid-justify-content-column-between.svg new file mode 100644 index 000000000..783d91a21 --- /dev/null +++ b/frontend/resources/images/icons/grid-justify-content-column-between.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/frontend/resources/images/icons/grid-justify-content-column-center.svg b/frontend/resources/images/icons/grid-justify-content-column-center.svg new file mode 100644 index 000000000..fc52ce5ed --- /dev/null +++ b/frontend/resources/images/icons/grid-justify-content-column-center.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/frontend/resources/images/icons/grid-justify-content-column-end.svg b/frontend/resources/images/icons/grid-justify-content-column-end.svg new file mode 100644 index 000000000..18825a412 --- /dev/null +++ b/frontend/resources/images/icons/grid-justify-content-column-end.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/frontend/resources/images/icons/grid-justify-content-column-start.svg b/frontend/resources/images/icons/grid-justify-content-column-start.svg new file mode 100644 index 000000000..823ef4ebf --- /dev/null +++ b/frontend/resources/images/icons/grid-justify-content-column-start.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/frontend/resources/images/icons/grid-justify-content-row-around.svg b/frontend/resources/images/icons/grid-justify-content-row-around.svg new file mode 100644 index 000000000..41a980b7f --- /dev/null +++ b/frontend/resources/images/icons/grid-justify-content-row-around.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/frontend/resources/images/icons/grid-justify-content-row-between.svg b/frontend/resources/images/icons/grid-justify-content-row-between.svg new file mode 100644 index 000000000..bfc38460a --- /dev/null +++ b/frontend/resources/images/icons/grid-justify-content-row-between.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/frontend/resources/images/icons/grid-justify-content-row-center.svg b/frontend/resources/images/icons/grid-justify-content-row-center.svg new file mode 100644 index 000000000..402b8dba2 --- /dev/null +++ b/frontend/resources/images/icons/grid-justify-content-row-center.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/frontend/resources/images/icons/grid-justify-content-row-end.svg b/frontend/resources/images/icons/grid-justify-content-row-end.svg new file mode 100644 index 000000000..3515d5a95 --- /dev/null +++ b/frontend/resources/images/icons/grid-justify-content-row-end.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/frontend/resources/images/icons/grid-justify-content-row-start.svg b/frontend/resources/images/icons/grid-justify-content-row-start.svg new file mode 100644 index 000000000..6539a9314 --- /dev/null +++ b/frontend/resources/images/icons/grid-justify-content-row-start.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss index 914a88b61..f5265b7bd 100644 --- a/frontend/resources/styles/main/partials/sidebar-element-options.scss +++ b/frontend/resources/styles/main/partials/sidebar-element-options.scss @@ -1649,6 +1649,12 @@ align-items: start; margin-top: 4px; } + + &.align-items-grid, + &.jusfiy-content-grid { + align-items: start; + margin-top: 11px; + } } .btn-wrapper { display: flex; @@ -1748,6 +1754,34 @@ width: 30px; } } + + .edit-mode { + display: flex; + justify-content: center; + align-items: center; + margin-left: 5px; + + button { + display: flex; + justify-content: center; + align-items: center; + background: transparent; + border: none; + cursor: pointer; + &.active, + &:hover { + svg { + fill: $color-primary; + } + } + } + } + + &.align-grid { + flex-direction: column; + gap: 7px; + margin: 7px 0; + } } } .no-wrap { @@ -2076,6 +2110,116 @@ } } } + + .grid-columns { + border: 1px solid $color-gray-60; + padding: 5px; + min-height: 38px; + display: flex; + flex-direction: column; + align-items: center; + &:not(:first-child) { + margin-top: 5px; + } + .grid-columns-header { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + flex-grow: 1; + min-height: 36px; + .columns-info { + flex-grow: 1; + font-size: 12px; + } + .expand-icon, + .add-column { + cursor: pointer; + background-color: transparent; + border: none; + display: flex; + justify-content: center; + align-items: center; + + &.active, + &:hover { + svg { + fill: $color-primary; + } + } + } + + .add-column svg { + height: 12px; + width: 12px; + fill: $color-gray-20; + } + } + .columns-info-wrapper { + .column-info { + display: grid; + grid-template-columns: 35px 1fr 1fr auto; + background-color: $color-gray-60; + padding: 3px; + &:not(:first-child) { + margin-top: 3px; + } + .direction-grid-icon { + display: flex; + justify-content: center; + align-items: center; + padding: 5px; + } + input { + background-color: $color-gray-60; + } + .grid-column-value, + .grid-column-unit { + display: flex; + justify-content: center; + align-items: center; + height: 30px; + &.active, + &:focus, + &:focus-within { + border-bottom: 1px solid $color-primary; + } + } + .grid-column-unit-selector { + border: none; + border-bottom: 1px solid $color-gray-30; + margin: 0.25rem 0; + height: 23px; + width: 100%; + &:hover { + border-bottom: 1px solid $color-gray-20; + } + } + + .remove-grid-column { + cursor: pointer; + background-color: transparent; + border: none; + display: flex; + justify-content: center; + align-items: center; + margin-left: 40px; + svg { + height: 12px; + width: 12px; + fill: $color-gray-20; + } + &.active, + &:hover { + svg { + fill: $color-primary; + } + } + } + } + } + } } .advanced-ops { diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index e7427a13e..6d511b0d8 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -114,6 +114,16 @@ (def full-screen-off (icon-xref :full-screen-off)) (def grid (icon-xref :grid)) (def grid-snap (icon-xref :grid-snap)) +(def grid-justify-content-column-around (icon-xref :grid-justify-content-column-around)) +(def grid-justify-content-column-between (icon-xref :grid-justify-content-column-between)) +(def grid-justify-content-column-center (icon-xref :grid-justify-content-column-center)) +(def grid-justify-content-column-end (icon-xref :grid-justify-content-column-end)) +(def grid-justify-content-column-start (icon-xref :grid-justify-content-column-start)) +(def grid-justify-content-row-around (icon-xref :grid-justify-content-row-around)) +(def grid-justify-content-row-between (icon-xref :grid-justify-content-row-between)) +(def grid-justify-content-row-center (icon-xref :grid-justify-content-row-center)) +(def grid-justify-content-row-end (icon-xref :grid-justify-content-row-end)) +(def grid-justify-content-row-start (icon-xref :grid-justify-content-row-start)) (def go-next (icon-xref :go-next)) (def go-prev (icon-xref :go-prev)) (def help (icon-xref :help)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index 925d0a84c..fd4f032e1 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -11,6 +11,7 @@ [app.main.data.workspace.shape-layout :as dwsl] [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input]] + [app.main.ui.components.select :refer [select]] [app.main.ui.icons :as i] [app.util.dom :as dom] [cuerdas.core :as str] @@ -94,8 +95,25 @@ :stretch i/align-self-column-strech :baseline i/align-self-column-baseline)))) +(defn get-layout-grid-icon + [type val is-col?] + (case type + :justify-content (if is-col? + (case val + :start i/grid-justify-content-column-start + :end i/grid-justify-content-column-end + :center i/grid-justify-content-column-center + :space-around i/grid-justify-content-column-around + :space-between i/grid-justify-content-column-between) + (case val + :start i/grid-justify-content-row-start + :end i/grid-justify-content-row-end + :center i/grid-justify-content-row-center + :space-around i/grid-justify-content-row-around + :space-between i/grid-justify-content-row-between)))) + (mf/defc direction-btn - [{:keys [dir saved-dir set-direction] :as props}] + [{:keys [dir saved-dir set-direction icon?] :as props}] (let [handle-on-click (mf/use-callback (mf/deps set-direction dir) @@ -112,7 +130,9 @@ :key (dm/str "direction-" dir) :alt (str/replace (str/capital (d/name dir)) "-" " ") :on-click handle-on-click} - i/auto-direction])) + (if icon? + i/auto-direction + (str/replace (str/capital (d/name dir)) "-" " "))])) (mf/defc wrap-row [{:keys [wrap-type set-wrap] :as props}] @@ -299,6 +319,108 @@ :value (:row-gap gap-value) :disabled (and (= :nowrap wrap-type) (not is-col?))}]]]]) +(mf/defc grid-edit-mode + [{:keys [active toggle-edit-mode] :as props}] + [:* + [:button.tooltip.tooltip-bottom-left + {:class (dom/classnames :active (= active true)) + :alt "Grid edit mode" + :on-click #(toggle-edit-mode) + :style {:padding 0}} + i/set-thumbnail]]) + +(mf/defc align-grid-row + [{:keys [is-col? align-items set-align] :as props}] + (let [type (if is-col? + :column + :row)] + [:div.align-items-style + (for [align [:start :center :end :stretch :baseline]] + [:button.align-start.tooltip + {:class (dom/classnames :active (= align-items align) + :tooltip-bottom-left (not= align :start) + :tooltip-bottom (= align :start)) + :alt (dm/str "Align items " (d/name align)) + :on-click #(set-align align % type) + :key (dm/str "align-items" (d/name align))} + (get-layout-flex-icon :align-items align is-col?)])])) + +(mf/defc justify-grid-row + [{:keys [is-col? justify-items set-justify] :as props}] + (let [type (if is-col? + :column + :row)] + [:div.justify-content-style + (for [align [:start :center :end :space-around :space-between]] + [:button.align-start.tooltip + {:class (dom/classnames :active (= justify-items align) + :tooltip-bottom-left (not= align :start) + :tooltip-bottom (= align :start)) + :alt (dm/str "Justify content " (d/name align)) + :on-click #(set-justify align % type) + :key (dm/str "justify-content" (d/name align))} + (get-layout-grid-icon :justify-content align is-col?)])])) + +(defn manage-values [value] + (let [quantity (:value value) + unit (:unit value)] + (case unit + :auto (d/name unit) + :perc (str/join [quantity "%"]) + (str/join [quantity (d/name unit)])))) + +(mf/defc grid-columns-row + [{:keys [is-col? expanded? column-values toggle add-new-element set-column-value handle-focus handle-blur on-unit-change remove-column] :as props}] + (let [column-num (count column-values) + direction (if (< 1 column-num) + (if is-col? + "Columns " + "Rows ") + (if is-col? + "Column " + "Row ")) + column-vals (str/join ", " (map manage-values column-values)) + generated-name (str direction column-num " (" column-vals ")")] + [:div.grid-columns + [:div.grid-columns-header + [:button.expand-icon + {:on-click toggle} + i/actions] + + [:div.columns-info + generated-name] + [:button.add-column + {:on-click add-new-element} + i/plus]] + (when expanded? + [:div.columns-info-wrapper + (for [column column-values] + [:div.column-info + [: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 + :on-focus handle-focus + :on-blur handle-blur + :placeholder "--"}]] + [:div.grid-column-unit + [:& select + {:class "grid-column-unit-selector" + :default-value (:unit column) + :options [{:value :fr :label "fr"} + {:value :auto :label "auto"} + {:value :px :label "px"} + {:value :perc :label "%"}] + :on-change on-unit-change}]] + [:button.remove-grid-column + {:on-change remove-column} + i/minus]])])])) + (mf/defc layout-container-menu {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "type" "multiple"]))]} [{:keys [ids _type values multiple] :as props}] @@ -322,7 +444,7 @@ set-flex (fn [] (st/emit! (dwsl/remove-layout ids)) (on-add-layout :flex)) - + set-grid (fn [] (st/emit! (dwsl/remove-layout ids)) (on-add-layout :grid)) @@ -331,9 +453,6 @@ saved-dir (:layout-flex-dir values) is-col? (or (= :column saved-dir) (= :column-reverse saved-dir)) - set-direction - (fn [dir] - (st/emit! (dwsl/update-layout ids {:layout-flex-dir dir}))) ;; Wrap type @@ -386,7 +505,63 @@ (st/emit! (dwsl/update-layout ids {:layout-padding {:p2 val :p4 val}})) :else - (st/emit! (dwsl/update-layout ids {:layout-padding {prop val}}))))] + (st/emit! (dwsl/update-layout ids {:layout-padding {prop val}})))) + + ;; Grid-direction + + saved-grid-dir (:layout-grid-dir values) + + set-direction + (fn [dir type] + (if (= :flex type) + (st/emit! (dwsl/update-layout ids {:layout-flex-dir dir})) + (st/emit! (dwsl/update-layout ids {:layout-grid-dir dir})))) + + ;; Align grid + align-items-row (:layout-grid-align-row values) + align-items-column (:layout-grid-align-column values) + set-align-grid (fn [value type] + (if (= type :row) + (st/emit! (dwsl/update-layout ids {:layout-grid-align-row value})) + (st/emit! (dwsl/update-layout ids {:layout-grid-align-column value})))) + + ;; Justify grid + grid-justify-content-row (:layout-grid-justify-row values) + grid-justify-content-column (:layout-grid-justify-column values) + set-justify-grid (fn [value type] + (if (= type :row) + (st/emit! (dwsl/update-layout ids {:layout-grid-justify-row value})) + (st/emit! (dwsl/update-layout ids {:layout-grid-justify-column value})))) + + + ;;Grid columns + + column-grid-values (:layout-grid-column-values 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-row-values values) + grid-rows-open? (mf/use-state false) + toggle-rows-info (mf/use-callback + (fn [_] + (swap! grid-rows-open? not))) + + ;; TODO -> fix this, is doing nothing + add-new-element (fn [value type] + (if (= type :row) + (st/emit! (dwsl/update-layout ids {:layout-grid-row-values value})) + (st/emit! (dwsl/update-layout ids {:layout-grid-column-values value})))) + + set-column-value (fn[] ) + handle-focus (fn []) + handle-blur (fn []) + set-colum-unit (fn []) + remove-column (fn [])] [:div.element-set [:div.element-set-title @@ -395,12 +570,12 @@ (if (and (not multiple) (:layout values)) [:div.title-actions [:div.layout-btns - [:button {:on-click set-flex - :class (dom/classnames - :active (= :flex layout-type))} "Flex"] - [:button {:on-click set-grid - :class (dom/classnames - :active (= :grid layout-type))} "Grid"]] + [:button {:on-click set-flex + :class (dom/classnames + :active (= :flex layout-type))} "Flex"] + [:button {:on-click set-grid + :class (dom/classnames + :active (= :grid layout-type))} "Grid"]] [:button.remove-layout {:on-click on-remove-layout} i/minus]] [:button.add-page {:on-click #(on-add-layout :flex)} i/close])]] @@ -418,7 +593,8 @@ [:& direction-btn {:key (d/name dir) :dir dir :saved-dir saved-dir - :set-direction set-direction}])]] + :set-direction #(set-direction dir :flex) + :icon? true}])]] [:div.wrap-type [:& wrap-row {:wrap-type wrap-type @@ -456,4 +632,73 @@ :on-change-style change-padding-type :on-change on-padding-change}]] - [:div "GRID TO COME"])))])) + [:div.element-set-content.layout-menu + [:div.layout-row + [:div.direction-wrap.row-title "Direction"] + [:div.btn-wrapper + [:div.direction + [:* + (for [dir [:row :column]] + [:& direction-btn {:key (d/name dir) + :dir dir + :saved-dir saved-grid-dir + :set-direction #(set-direction dir :grid) + :icon? false}])]] + + [:div.edit-mode + [:& grid-edit-mode + {:active false + :toggle-edit-mode ()}]]]] + + [:div.layout-row + [:div.align-items-grid.row-title "Align"] + [:div.btn-wrapper.align-grid + [:& align-grid-row {:is-col? false + :align-items align-items-row + :set-align set-align-grid}] + + [:& align-grid-row {:is-col? true + :align-items align-items-column + :set-align set-align-grid}]]] + + [:div.layout-row + [:div.jusfiy-content-grid.row-title "Justify"] + [:div.btn-wrapper.align-grid + [:& justify-grid-row {:is-col? true + :align-items grid-justify-content-column + :set-justify set-justify-grid}] + [:& justify-grid-row {:is-col? false + :align-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 [{:value 1 :unit :fr} {:value 1 :unit :fr}];; column-grid-values + :add-new-column add-new-element + :set-column-value set-column-value + :handle-focus handle-focus + :handle-blur handle-blur + :set-colum-unit set-colum-unit + :remove-column remove-column}] + + [:& grid-columns-row {:is-col? false + :expanded? @grid-rows-open? + :toggle toggle-rows-info + :column-values [{:value "--" :unit :auto} {:value "--" :unit :auto}] ;; column-grid-values + :add-new-column add-new-element + :set-column-value set-column-value + :handle-focus handle-focus + :handle-blur handle-blur + :set-colum-unit set-colum-unit + :remove-column remove-column}] + + [:& 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}]])))])) From 284fc2acbcfcb47f790e7a15018933e3bc56d2d0 Mon Sep 17 00:00:00 2001 From: Eva Date: Tue, 21 Feb 2023 14:33:15 +0100 Subject: [PATCH 07/10] :sparkles: Add grid cell options --- .../images/icons/grid-layout-mode.svg | 3 + .../resources/images/icons/set-thumbnail.svg | 4 +- .../partials/sidebar-element-options.scss | 58 ++++++- frontend/src/app/main/ui/icons.cljs | 3 +- .../options/menus/layout_container.cljs | 16 +- .../sidebar/options/shapes/grid_cell.cljs | 159 +++++++++++++++++- 6 files changed, 225 insertions(+), 18 deletions(-) create mode 100644 frontend/resources/images/icons/grid-layout-mode.svg diff --git a/frontend/resources/images/icons/grid-layout-mode.svg b/frontend/resources/images/icons/grid-layout-mode.svg new file mode 100644 index 000000000..c90cf5c85 --- /dev/null +++ b/frontend/resources/images/icons/grid-layout-mode.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/images/icons/set-thumbnail.svg b/frontend/resources/images/icons/set-thumbnail.svg index c90cf5c85..e82fa55b1 100644 --- a/frontend/resources/images/icons/set-thumbnail.svg +++ b/frontend/resources/images/icons/set-thumbnail.svg @@ -1,3 +1,3 @@ - - + + diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss index f5265b7bd..2f7991f9b 100644 --- a/frontend/resources/styles/main/partials/sidebar-element-options.scss +++ b/frontend/resources/styles/main/partials/sidebar-element-options.scss @@ -1624,7 +1624,8 @@ } .layout-menu, -.layout-item-menu { +.layout-item-menu, +.layout-grid-item-menu { font-family: "worksans", sans-serif; svg { height: 16px; @@ -1660,6 +1661,7 @@ display: flex; width: 100%; max-width: 185px; + &.wrap { flex-direction: column; gap: 5px; @@ -1783,6 +1785,32 @@ margin: 7px 0; } } + .position-wrapper { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + width: 100%; + max-width: 185px; + height: 26px; + border-radius: 4px; + border: 1px solid $color-gray-60; + .position-btn { + display: flex; + justify-content: center; + align-items: center; + background: transparent; + border: none; + cursor: pointer; + color: $color-gray-20; + border-right: 1px solid $color-gray-60; + &:last-child { + border-right: none; + } + &.active, + &:hover { + color: $color-primary; + } + } + } } .no-wrap { display: flex; @@ -2220,6 +2248,34 @@ } } } + .manage-grid-columns { + margin-left: 60px; + margin-bottom: 10px; + .grid-auto, + .grid-manual { + display: grid; + grid-template-columns: 1fr 1fr; + .grid-columns-auto, + .grid-rows-auto { + display: grid; + grid-template-columns: 20px 1fr; + .icon { + display: flex; + justify-content: center; + align-items: center; + } + input { + width: 80%; + } + } + } + .grid-manual { + .input-wrapper { + display: grid; + grid-template-columns: 1fr 1fr; + } + } + } } .advanced-ops { diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index 6d511b0d8..edc033bfc 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -113,7 +113,6 @@ (def full-screen (icon-xref :full-screen)) (def full-screen-off (icon-xref :full-screen-off)) (def grid (icon-xref :grid)) -(def grid-snap (icon-xref :grid-snap)) (def grid-justify-content-column-around (icon-xref :grid-justify-content-column-around)) (def grid-justify-content-column-between (icon-xref :grid-justify-content-column-between)) (def grid-justify-content-column-center (icon-xref :grid-justify-content-column-center)) @@ -124,6 +123,8 @@ (def grid-justify-content-row-center (icon-xref :grid-justify-content-row-center)) (def grid-justify-content-row-end (icon-xref :grid-justify-content-row-end)) (def grid-justify-content-row-start (icon-xref :grid-justify-content-row-start)) +(def grid-layout-mode (icon-xref :grid-layout-mode)) +(def grid-snap (icon-xref :grid-snap)) (def go-next (icon-xref :go-next)) (def go-prev (icon-xref :go-prev)) (def help (icon-xref :help)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index fd4f032e1..1643228d9 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -83,16 +83,18 @@ :align-self (if is-col? (case val - :start i/align-self-row-left - :end i/align-self-row-right + :auto i/minus + :start i/align-self-row-left + :end i/align-self-row-right :center i/align-self-row-center - :stretch i/align-self-row-strech + :stretch i/align-self-row-strech :baseline i/align-self-row-baseline) (case val - :start i/align-self-column-top - :end i/align-self-column-bottom + :auto i/minus + :start i/align-self-column-top + :end i/align-self-column-bottom :center i/align-self-column-center - :stretch i/align-self-column-strech + :stretch i/align-self-column-strech :baseline i/align-self-column-baseline)))) (defn get-layout-grid-icon @@ -327,7 +329,7 @@ :alt "Grid edit mode" :on-click #(toggle-edit-mode) :style {:padding 0}} - i/set-thumbnail]]) + i/grid-layout-mode]]) (mf/defc align-grid-row [{:keys [is-col? align-items set-align] :as props}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs index 7f46e045b..838e10794 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs @@ -6,17 +6,162 @@ (ns app.main.ui.workspace.sidebar.options.shapes.grid-cell (:require + [app.common.data :as d] + [app.common.data.macros :as dm] + [app.main.ui.components.numeric-input :refer [numeric-input]] + [app.main.ui.icons :as i] + [app.main.ui.workspace.sidebar.options.menus.layout-container :as lyc] + [app.util.dom :as dom] [rumext.v2 :as mf])) +(mf/defc set-self-alignment + [{:keys [is-col? alignment set-alignment] :as props}] + (let [dir-v [:auto :start :center :end :stretch #_:baseline]] + [:div.align-self-style + (for [align dir-v] + [:button.align-self.tooltip.tooltip-bottom + {:class (dom/classnames :active (= alignment align) + :tooltip-bottom-left (not= align :start) + :tooltip-bottom (= align :start)) + :alt (dm/str "Align self " (d/name align)) ;; TODO fix this tooltip + :on-click #(set-alignment align) + :key (str "align-self" align)} + (lyc/get-layout-flex-icon :align-self align is-col?)])])) + + (mf/defc options {::mf/wrap [mf/memo]} [{:keys [shape row column] :as props}] - [:div.element-set - [:div.element-set-title - [:span "Grid Cell"]] + (let [position-mode (mf/use-state :auto) ;; TODO this should come from shape - [:div.element-set-content.layout-item-menu - [:div.layout-row - [:div.row-title.sizing "Position"] - [:div (str row "," column)]]]]) + set-position-mode (fn [mode] + (reset! position-mode mode)) + + + align-self (mf/use-state :auto) ;; TODO this should come from shape + justify-alignment (mf/use-state :auto) ;; TODO this should come from shape + set-alignment (fn [value] + (reset! align-self value) + #_(if (= align-self value) + (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self nil})) + (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self value})))) + set-justify-self (fn [value] + (reset! justify-alignment value) + #_(if (= align-self value) + (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self nil})) + (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self value})))) + column-start (mf/use-state 1) + column-end (mf/use-state 1) + row-start (mf/use-state 1) + row-end (mf/use-state 1) + on-change (fn [side orientation value] + (if (= orientation :column) + (case side + :all ((reset! column-start value) + (reset! column-end value)) + :start (reset! column-start value) + :end (reset! column-end value)) + (case side + :all ((reset! row-start value) + (reset! row-end value)) + :start (reset! row-start value) + :end (reset! row-end value)))) + + area-name (mf/use-state "header") ;; TODO this should come from shape + + on-area-name-change (fn [value] + (reset! area-name value)) + on-key-press (fn [event])] + [:div.element-set + [:div.element-set-title + [:span "Grid Cell"]] + + [:div.element-set-content.layout-grid-item-menu + [:div.layout-row + [:div.row-title.sizing "Position"] + [:div.position-wrapper + [:button.position-btn + {:on-click #(set-position-mode :auto) + :class (dom/classnames :active (= :auto @position-mode))} "Auto"] + [:button.position-btn + {:on-click #(set-position-mode :manual) + :class (dom/classnames :active (= :manual @position-mode))} "Manual"] + [:button.position-btn + {:on-click #(set-position-mode :area) + :class (dom/classnames :active (= :area @position-mode))} "Area"]]] + [:div.manage-grid-columns + (when (= :auto @position-mode) + [:div.grid-auto + [:div.grid-columns-auto + [:spam.icon i/layout-rows] + [:div.input-wrapper + [:> numeric-input + {:placeholder "--" + :on-click #(dom/select-target %) + :on-change (partial on-change :all :column) ;; TODO cambiar este on-change y el value + :value @column-start}]]] + [:div.grid-rows-auto + [:spam.icon i/layout-columns] + [:div.input-wrapper + [:> numeric-input + {:placeholder "--" + :on-click #(dom/select-target %) + :on-change (partial on-change :all :row) ;; TODO cambiar este on-change y el value + :value @row-start}]]]]) + (when (= :area @position-mode) + [:div.input-wrapper + [:input.input-text + {:key "grid-area-name" + :id "grid-area-name" + :type "text" + :aria-label "grid-area-name" + :placeholder "--" + :default-value @area-name + :auto-complete "off" + :on-change on-area-name-change + :on-key-press on-key-press}]]) + + (when (or (= :manual @position-mode) (= :area @position-mode)) + [:div.grid-manual + [:div.grid-columns-auto + [:spam.icon i/layout-rows] + [:div.input-wrapper + [:> numeric-input + {:placeholder "--" + :on-click #(dom/select-target %) + :on-change (partial on-change :start :column) ;; TODO cambiar este on-change y el value + :value @column-start}] + [:> numeric-input + {:placeholder "--" + :on-click #(dom/select-target %) + :on-change (partial on-change :end :column) ;; TODO cambiar este on-change y el value + :value @column-end}]]] + [:div.grid-rows-auto + [:spam.icon i/layout-columns] + [:div.input-wrapper + [:> numeric-input + {:placeholder "--" + :on-click #(dom/select-target %) + :on-change (partial on-change :start :row) ;; TODO cambiar este on-change y el value + :value @row-start}] + [:> numeric-input + {:placeholder "--" + :on-click #(dom/select-target %) + :on-change (partial on-change :end :row) ;; TODO cambiar este on-change y el value + :value @row-end}]]]])] + + [:div.layout-row + [:div.row-title "Align"] + [:div.btn-wrapper + [:& set-self-alignment {:is-col? false + :alignment @align-self + :set-alignment set-alignment}]]] + + + [:div.layout-row + [:div.row-title "Justify"] + [:div.btn-wrapper + [:& set-self-alignment {:is-col? true + :alignment @justify-alignment + :set-alignment set-justify-self}]]]]])) From b497de0daeea157471b24248287f1dbfa982c412 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 22 Feb 2023 12:21:44 +0100 Subject: [PATCH 08/10] :sparkles: UI Integration --- .../geom/shapes/grid_layout/layout_data.cljc | 11 +- .../src/app/common/geom/shapes/modifiers.cljc | 4 +- common/src/app/common/types/shape/layout.cljc | 4 +- common/src/app/common/types/shape_tree.cljc | 2 +- .../partials/sidebar-element-options.scss | 7 +- frontend/src/app/main/data/workspace.cljs | 2 +- .../src/app/main/data/workspace/groups.cljs | 2 +- .../app/main/data/workspace/shape_layout.cljs | 102 ++++- .../src/app/main/data/workspace/shapes.cljs | 3 +- .../app/main/data/workspace/transforms.cljs | 2 +- frontend/src/app/main/ui/shapes/frame.cljs | 2 +- .../options/menus/layout_container.cljs | 378 ++++++++++-------- .../sidebar/options/shapes/circle.cljs | 3 +- .../sidebar/options/shapes/frame.cljs | 2 +- .../sidebar/options/shapes/grid_cell.cljs | 55 +-- .../sidebar/options/shapes/image.cljs | 2 +- .../sidebar/options/shapes/path.cljs | 2 +- .../sidebar/options/shapes/rect.cljs | 4 +- .../sidebar/options/shapes/svg_raw.cljs | 2 +- .../viewport/grid_layout_editor.cljs | 99 ++++- 20 files changed, 442 insertions(+), 246 deletions(-) diff --git a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc index aba5d9f87..08caa33eb 100644 --- a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc @@ -21,7 +21,7 @@ {:type :percent :value 25} {:type :fixed :value 100} ;;{:type :auto} - ;;{:type :fr :value 1} + ;;{:type :flex :value 1} ] :layout-grid-rows @@ -29,7 +29,7 @@ {:type :percent :value 50} ;;{:type :fixed :value 100} ;;{:type :auto} - ;;{:type :fr :value 1} + ;;{:type :flex :value 1} ]) num-rows (count (:layout-grid-rows parent)) @@ -71,12 +71,7 @@ (defn calc-layout-data [parent children transformed-parent-bounds] - (let [ - - ;; TODO: Delete when there is UI - [parent children] (set-sample-data parent children) - - height (gpo/height-points transformed-parent-bounds) + (let [height (gpo/height-points transformed-parent-bounds) width (gpo/width-points transformed-parent-bounds) ;; Initialize tracks diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 29fe313ed..62a7e784d 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -303,7 +303,7 @@ (:shapes parent)) children-layout - (when layout? + (when flex-layout? (->> (:shapes parent) (remove #(ctl/layout-absolute? objects %))))] @@ -312,7 +312,7 @@ (set-children-modifiers children-modifiers objects bounds parent transformed-parent-bounds ignore-constraints) flex-layout? - (set-flex-layout-modifiers children-layout objects bounds parent transformed-parent-bounds)) + (set-flex-layout-modifiers children-layout objects bounds parent transformed-parent-bounds) grid-layout? (set-grid-layout-modifiers objects bounds parent transformed-parent-bounds)) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 776271f6a..17639f9a1 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -51,8 +51,8 @@ (s/def ::layout-wrap-type #{:wrap :nowrap :no-wrap}) ;;TODO remove no-wrap after script (s/def ::layout-padding-type #{:simple :multiple}) -(s/def :grid/type #{:fr :auto :fixed}) -(s/def :grid/value (s/nilable ::us/string)) +(s/def :grid/type #{:percent :flex :auto :fixed}) +(s/def :grid/value (s/nilable ::us/safe-number)) (s/def ::grid-definition (s/keys :opt-un [:grid/type :grid/value])) (s/def ::layout-grid-rows (s/coll-of ::grid-definition :kind vector?)) diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc index 356b99f5d..3997cd3b3 100644 --- a/common/src/app/common/types/shape_tree.cljc +++ b/common/src/app/common/types/shape_tree.cljc @@ -164,7 +164,7 @@ :else ;; If the base is a layout we should check if the z-index property is set (let [[z-index-a z-index-b] - (if (ctl/layout? objects base) + (if (ctl/any-layout? objects base) [(ctl/layout-z-index objects (dm/get-in objects [base :shapes index-a])) (ctl/layout-z-index objects (dm/get-in objects [base :shapes index-b]))] [0 0])] diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss index 2f7991f9b..41b636aa8 100644 --- a/frontend/resources/styles/main/partials/sidebar-element-options.scss +++ b/frontend/resources/styles/main/partials/sidebar-element-options.scss @@ -1705,7 +1705,9 @@ color: $color-gray-20; &.active, &:hover { - color: $color-primary; + &.dir { + color: $color-primary; + } svg { fill: $color-primary; } @@ -2160,6 +2162,9 @@ .columns-info { flex-grow: 1; font-size: 12px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .expand-icon, .add-column { diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 04dcb5a96..2278c0c9d 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -660,7 +660,7 @@ (pcb/with-objects objects) ;; Remove layout-item properties when moving a shape outside a layout - (cond-> (not (ctl/layout? objects parent-id)) + (cond-> (not (ctl/any-layout? objects parent-id)) (pcb/update-shapes ordered-indexes ctl/remove-layout-item-data)) ;; Move the shapes diff --git a/frontend/src/app/main/data/workspace/groups.cljs b/frontend/src/app/main/data/workspace/groups.cljs index bbdaf1045..de927b33f 100644 --- a/frontend/src/app/main/data/workspace/groups.cljs +++ b/frontend/src/app/main/data/workspace/groups.cljs @@ -144,7 +144,7 @@ (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) - (cond-> (ctl/layout? frame) + (cond-> (ctl/any-layout? frame) (pcb/update-shapes (:shapes frame) ctl/remove-layout-item-data)) (pcb/change-parent parent-id children idx-in-parent) (pcb/remove-objects [(:id frame)])))) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index f3317e214..612cd1646 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -183,6 +183,7 @@ ;; Never call this directly but through the data-event `:layout/update` ;; Otherwise a lot of cycle dependencies could be generated +(declare check-grid-cells-update) (defn- update-layout-positions [ids] (ptk/reify ::update-layout-positions @@ -190,10 +191,16 @@ (watch [_ state _] (let [objects (wsh/lookup-page-objects state) ids (->> ids (filter #(contains? objects %)))] - (if (d/not-empty? ids) - (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))] - (rx/of (dwm/apply-modifiers {:modifiers modif-tree}))) - (rx/empty)))))) + + (rx/concat + ;; Update grids if necesary + (rx/of (check-grid-cells-update + (->> (concat ids (map #(cph/get-parent-id objects %) ids)) + (filter #(ctl/grid-layout? objects %))))) + (if (d/not-empty? ids) + (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))] + (rx/of (dwm/apply-modifiers {:modifiers modif-tree}))) + (rx/empty))))))) (defn initialize [] @@ -352,6 +359,93 @@ (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) +(defn update-grid-cells + [parent objects] + + (let [children (cph/get-immediate-children objects (:id parent)) + layout-grid-rows (:layout-grid-rows parent) + layout-grid-columns (:layout-grid-columns parent) + num-rows (count layout-grid-columns) + num-columns (count layout-grid-columns) + + layout-grid-cells + (for [[row-idx row] (d/enumerate layout-grid-rows) + [col-idx col] (d/enumerate layout-grid-columns)] + + (let [shape (nth children (+ (* row-idx num-columns) col-idx) nil) + cell-data {:id (uuid/next) + :row (inc row-idx) + :column (inc col-idx) + :row-span 1 + :col-span 1 + :shapes (when shape [(:id shape)])}] + [(:id cell-data) cell-data]))] + (assoc parent :layout-grid-cells layout-grid-cells))) + +(defn check-grid-cells-update + [ids] + (ptk/reify ::check-grid-cells-update + ptk/WatchEvent + (watch [_ state _] + (let [objects (wsh/lookup-page-objects state) + undo-id (js/Symbol)] + (rx/of (dwc/update-shapes + ids + (fn [shape] + (-> shape + (update-grid-cells objects))))))))) + +(defn add-layout-column + [ids property value] + (ptk/reify ::add-layout-column + ptk/WatchEvent + (watch [_ state _] + (let [objects (wsh/lookup-page-objects state) + undo-id (js/Symbol)] + (rx/of (dwu/start-undo-transaction undo-id) + (dwc/update-shapes + ids + (fn [shape] + (-> shape + (update property (fnil conj []) value) + (update-grid-cells objects)))) + (ptk/data-event :layout/update ids) + (dwu/commit-undo-transaction undo-id)))))) + +(defn remove-layout-column + [ids property index] + (ptk/reify ::remove-layout-column + ptk/WatchEvent + (watch [_ state _] + (let [objects (wsh/lookup-page-objects state) + undo-id (js/Symbol)] + (rx/of (dwu/start-undo-transaction undo-id) + (dwc/update-shapes + ids + (fn [shape] + (-> shape + (update property d/remove-at-index index) + (update-grid-cells objects)))) + (ptk/data-event :layout/update ids) + (dwu/commit-undo-transaction undo-id)))))) + +(defn change-layout-column + [ids property index props] + (ptk/reify ::change-layout-column + ptk/WatchEvent + (watch [_ state _] + (let [objects (wsh/lookup-page-objects state) + undo-id (js/Symbol)] + (rx/of (dwu/start-undo-transaction undo-id) + (dwc/update-shapes + ids + (fn [shape] + (-> shape + (update-in [property index] merge props) + (update-grid-cells objects)))) + (ptk/data-event :layout/update ids) + (dwu/commit-undo-transaction undo-id)))))) + (defn fix-child-sizing [objects parent-changes shape] diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index 353ee2f6b..f123efb69 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -18,6 +18,7 @@ [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] [app.common.types.shape.interactions :as ctsi] + [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.main.data.comments :as dc] [app.main.data.workspace.changes :as dch] @@ -130,7 +131,7 @@ (when (d/not-empty? to-move-shapes) (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) - (cond-> (not (ctl/layout? objects frame-id)) + (cond-> (not (ctl/any-layout? objects frame-id)) (pcb/update-shapes ordered-indexes ctl/remove-layout-item-data)) (pcb/change-parent frame-id to-move-shapes 0)))] diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 77357fe7b..656d2e9fb 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -739,7 +739,7 @@ (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) ;; Remove layout-item properties when moving a shape outside a layout - (cond-> (not (ctl/layout? objects frame-id)) + (cond-> (not (ctl/any-layout? objects frame-id)) (pcb/update-shapes (map :id moving-shapes) ctl/remove-layout-item-data)) (pcb/change-parent frame-id moving-shapes drop-index) (pcb/remove-objects empty-parents))] diff --git a/frontend/src/app/main/ui/shapes/frame.cljs b/frontend/src/app/main/ui/shapes/frame.cljs index f667cd2f4..11be6ba00 100644 --- a/frontend/src/app/main/ui/shapes/frame.cljs +++ b/frontend/src/app/main/ui/shapes/frame.cljs @@ -129,7 +129,7 @@ (let [shape (unchecked-get props "shape") childs (unchecked-get props "childs") childs (cond-> childs - (ctl/layout? shape) + (ctl/any-layout? shape) (cph/sort-layout-children-z-index))] [:> frame-container props [:g.frame-children {:opacity (:opacity shape)} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index 1643228d9..a25b8e75c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -5,114 +5,135 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.layout-container - (:require [app.common.data :as d] - [app.common.data.macros :as dm] - [app.main.data.workspace :as udw] - [app.main.data.workspace.shape-layout :as dwsl] - [app.main.store :as st] - [app.main.ui.components.numeric-input :refer [numeric-input]] - [app.main.ui.components.select :refer [select]] - [app.main.ui.icons :as i] - [app.util.dom :as dom] - [cuerdas.core :as str] - [rumext.v2 :as mf])) + (:require + [app.common.data :as d] + [app.common.data.macros :as dm] + [app.main.data.workspace :as udw] + [app.main.data.workspace.shape-layout :as dwsl] + [app.main.store :as st] + [app.main.ui.components.numeric-input :refer [numeric-input]] + [app.main.ui.components.select :refer [select]] + [app.main.ui.icons :as i] + [app.util.dom :as dom] + [cuerdas.core :as str] + [rumext.v2 :as mf])) (def layout-container-flex-attrs [:layout ;; :flex, :grid in the future :layout-flex-dir ;; :row, :row-reverse, :column, :column-reverse :layout-gap-type ;; :simple, :multiple :layout-gap ;; {:row-gap number , :column-gap number} + :layout-align-items ;; :start :end :center :stretch :layout-justify-content ;; :start :center :end :space-between :space-around :space-evenly :layout-align-content ;; :start :center :end :space-between :space-around :space-evenly :stretch (by default) :layout-wrap-type ;; :wrap, :nowrap :layout-padding-type ;; :simple, :multiple :layout-padding ;; {:p1 num :p2 num :p3 num :p4 num} number could be negative + + :layout-grid-dir ;; :row :column + :layout-justify-items + :layout-grid-columns + :layout-grid-rows ]) (defn get-layout-flex-icon [type val is-col?] (case type - :align-items (if is-col? - (case val - :start i/align-items-column-start - :end i/align-items-column-end - :center i/align-items-column-center - :stretch i/align-items-column-strech - :baseline i/align-items-column-baseline) - (case val - :start i/align-items-row-start - :end i/align-items-row-end - :center i/align-items-row-center - :stretch i/align-items-row-strech - :baseline i/align-items-row-baseline)) - :justify-content (if is-col? - (case val - :start i/justify-content-column-start - :end i/justify-content-column-end - :center i/justify-content-column-center - :space-around i/justify-content-column-around - :space-evenly i/justify-content-column-evenly - :space-between i/justify-content-column-between) - (case val - :start i/justify-content-row-start - :end i/justify-content-row-end - :center i/justify-content-row-center - :space-around i/justify-content-row-around - :space-evenly i/justify-content-row-evenly - :space-between i/justify-content-row-between)) + :align-items + (if is-col? + (case val + :start i/align-items-column-start + :end i/align-items-column-end + :center i/align-items-column-center + :stretch i/align-items-column-strech + :baseline i/align-items-column-baseline) + (case val + :start i/align-items-row-start + :end i/align-items-row-end + :center i/align-items-row-center + :stretch i/align-items-row-strech + :baseline i/align-items-row-baseline)) + + :justify-content + (if is-col? + (case val + :start i/justify-content-column-start + :end i/justify-content-column-end + :center i/justify-content-column-center + :space-around i/justify-content-column-around + :space-evenly i/justify-content-column-evenly + :space-between i/justify-content-column-between) + (case val + :start i/justify-content-row-start + :end i/justify-content-row-end + :center i/justify-content-row-center + :space-around i/justify-content-row-around + :space-evenly i/justify-content-row-evenly + :space-between i/justify-content-row-between)) - :align-content (if is-col? - (case val - :start i/align-content-column-start - :end i/align-content-column-end - :center i/align-content-column-center - :space-around i/align-content-column-around - :space-evenly i/align-content-column-evenly - :space-between i/align-content-column-between - :stretch nil) + :align-content + (if is-col? + (case val + :start i/align-content-column-start + :end i/align-content-column-end + :center i/align-content-column-center + :space-around i/align-content-column-around + :space-evenly i/align-content-column-evenly + :space-between i/align-content-column-between + :stretch nil) - (case val - :start i/align-content-row-start - :end i/align-content-row-end - :center i/align-content-row-center - :space-around i/align-content-row-around - :space-evenly i/align-content-row-evenly - :space-between i/align-content-row-between - :stretch nil)) + (case val + :start i/align-content-row-start + :end i/align-content-row-end + :center i/align-content-row-center + :space-around i/align-content-row-around + :space-evenly i/align-content-row-evenly + :space-between i/align-content-row-between + :stretch nil)) - :align-self (if is-col? - (case val - :auto i/minus - :start i/align-self-row-left - :end i/align-self-row-right - :center i/align-self-row-center - :stretch i/align-self-row-strech - :baseline i/align-self-row-baseline) - (case val - :auto i/minus - :start i/align-self-column-top - :end i/align-self-column-bottom - :center i/align-self-column-center - :stretch i/align-self-column-strech - :baseline i/align-self-column-baseline)))) + (case val + :start i/align-content-row-start + :end i/align-content-row-end + :center i/align-content-row-center + :space-around i/align-content-row-around + :space-between i/align-content-row-between + :stretch nil) + + :align-self + (if is-col? + (case val + :auto i/minus + :start i/align-self-row-left + :end i/align-self-row-right + :center i/align-self-row-center + :stretch i/align-self-row-strech + :baseline i/align-self-row-baseline) + (case val + :auto i/minus + :start i/align-self-column-top + :end i/align-self-column-bottom + :center i/align-self-column-center + :stretch i/align-self-column-strech + :baseline i/align-self-column-baseline)))) (defn get-layout-grid-icon [type val is-col?] (case type - :justify-content (if is-col? - (case val - :start i/grid-justify-content-column-start - :end i/grid-justify-content-column-end - :center i/grid-justify-content-column-center - :space-around i/grid-justify-content-column-around - :space-between i/grid-justify-content-column-between) - (case val - :start i/grid-justify-content-row-start - :end i/grid-justify-content-row-end - :center i/grid-justify-content-row-center - :space-around i/grid-justify-content-row-around - :space-between i/grid-justify-content-row-between)))) + :justify-items + (if is-col? + (case val + :start i/grid-justify-content-column-start + :end i/grid-justify-content-column-end + :center i/grid-justify-content-column-center + :space-around i/grid-justify-content-column-around + :space-between i/grid-justify-content-column-between) + (case val + :start i/grid-justify-content-row-start + :end i/grid-justify-content-row-end + :center i/grid-justify-content-row-center + :space-around i/grid-justify-content-row-around + :space-between i/grid-justify-content-row-between)))) (mf/defc direction-btn [{:keys [dir saved-dir set-direction icon?] :as props}] @@ -333,9 +354,7 @@ (mf/defc align-grid-row [{:keys [is-col? align-items set-align] :as props}] - (let [type (if is-col? - :column - :row)] + (let [type (if is-col? :column :row)] [:div.align-items-style (for [align [:start :center :end :stretch :baseline]] [:button.align-start.tooltip @@ -343,15 +362,13 @@ :tooltip-bottom-left (not= align :start) :tooltip-bottom (= align :start)) :alt (dm/str "Align items " (d/name align)) - :on-click #(set-align align % type) + :on-click #(set-align align type) :key (dm/str "align-items" (d/name align))} (get-layout-flex-icon :align-items align is-col?)])])) (mf/defc justify-grid-row [{:keys [is-col? justify-items set-justify] :as props}] - (let [type (if is-col? - :column - :row)] + (let [type (if is-col? :column :row)] [:div.justify-content-style (for [align [:start :center :end :space-around :space-between]] [:button.align-start.tooltip @@ -359,44 +376,43 @@ :tooltip-bottom-left (not= align :start) :tooltip-bottom (= align :start)) :alt (dm/str "Justify content " (d/name align)) - :on-click #(set-justify align % type) + :on-click #(set-justify align type) :key (dm/str "justify-content" (d/name align))} - (get-layout-grid-icon :justify-content align is-col?)])])) + (get-layout-grid-icon :justify-items align is-col?)])])) -(defn manage-values [value] - (let [quantity (:value value) - unit (:unit value)] - (case unit - :auto (d/name unit) - :perc (str/join [quantity "%"]) - (str/join [quantity (d/name unit)])))) +(defn manage-values [{:keys [value type]}] + (case type + :auto "auto" + :percent (dm/str value "%") + :flex (dm/str value "fr") + :fixed (dm/str value "px") + value)) (mf/defc grid-columns-row - [{:keys [is-col? expanded? column-values toggle add-new-element set-column-value handle-focus handle-blur on-unit-change remove-column] :as props}] + [{:keys [is-col? expanded? column-values toggle add-new-element set-column-value set-column-type remove-element] :as props}] (let [column-num (count column-values) - direction (if (< 1 column-num) - (if is-col? - "Columns " - "Rows ") - (if is-col? - "Column " - "Row ")) + direction (if (> column-num 1) + (if is-col? "Columns " "Rows ") + (if is-col? "Column " "Row ")) + column-vals (str/join ", " (map manage-values column-values)) - generated-name (str direction column-num " (" column-vals ")")] + generated-name (dm/str direction (if (= column-num 0) " - empty" (dm/str column-num " (" column-vals ")"))) + type (if is-col? :column :row)] + [:div.grid-columns [:div.grid-columns-header [:button.expand-icon - {:on-click toggle} - i/actions] + {:on-click toggle} i/actions] + + [:div.columns-info {:title generated-name + :on-click toggle} generated-name] + [:button.add-column {:on-click #(do + (when-not expanded? (toggle)) + (add-new-element type {:type :fixed :value 100}))} i/plus]] - [:div.columns-info - generated-name] - [:button.add-column - {:on-click add-new-element} - i/plus]] (when expanded? [:div.columns-info-wrapper - (for [column column-values] + (for [[index column] (d/enumerate column-values)] [:div.column-info [:div.direction-grid-icon (if is-col? @@ -406,21 +422,19 @@ [:div.grid-column-value [:> numeric-input {:no-validate true :value (:value column) - :on-change set-column-value - :on-focus handle-focus - :on-blur handle-blur + :on-change #(set-column-value type index %) :placeholder "--"}]] [:div.grid-column-unit [:& select {:class "grid-column-unit-selector" - :default-value (:unit column) - :options [{:value :fr :label "fr"} + :default-value (:type column) + :options [{:value :flex :label "fr"} {:value :auto :label "auto"} - {:value :px :label "px"} - {:value :perc :label "%"}] - :on-change on-unit-change}]] + {:value :fixed :label "px"} + {:value :percent :label "%"}] + :on-change #(set-column-type type index %)}]] [:button.remove-grid-column - {:on-change remove-column} + {:on-click #(remove-element type index)} i/minus]])])])) (mf/defc layout-container-menu @@ -520,50 +534,74 @@ (st/emit! (dwsl/update-layout ids {:layout-grid-dir dir})))) ;; Align grid - align-items-row (:layout-grid-align-row values) - align-items-column (:layout-grid-align-column values) - set-align-grid (fn [value type] - (if (= type :row) - (st/emit! (dwsl/update-layout ids {:layout-grid-align-row value})) - (st/emit! (dwsl/update-layout ids {:layout-grid-align-column value})))) + align-items-row (:layout-align-items values) + align-items-column (:layout-justify-items values) + + set-align-grid + (fn [value type] + (if (= type :row) + (st/emit! (dwsl/update-layout ids {:layout-align-items value})) + (st/emit! (dwsl/update-layout ids {:layout-justify-items value})))) ;; Justify grid - grid-justify-content-row (:layout-grid-justify-row values) - grid-justify-content-column (:layout-grid-justify-column values) - set-justify-grid (fn [value type] - (if (= type :row) - (st/emit! (dwsl/update-layout ids {:layout-grid-justify-row value})) - (st/emit! (dwsl/update-layout ids {:layout-grid-justify-column value})))) + grid-justify-content-row (:layout-align-content values) + grid-justify-content-column (:layout-justify-content values) + + set-justify-grid + (mf/use-callback + (mf/deps ids) + (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-column-values values) + 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-row-values values) + 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))) + toggle-rows-info + (mf/use-callback + (fn [_] + (swap! grid-rows-open? not))) - ;; TODO -> fix this, is doing nothing - add-new-element (fn [value type] - (if (= type :row) - (st/emit! (dwsl/update-layout ids {:layout-grid-row-values value})) - (st/emit! (dwsl/update-layout ids {:layout-grid-column-values value})))) + add-new-element + (mf/use-callback + (mf/deps ids) + (fn [type value] + (if (= type :row) + (st/emit! (dwsl/add-layout-column ids :layout-grid-rows value)) + (st/emit! (dwsl/add-layout-column ids :layout-grid-columns value))))) - set-column-value (fn[] ) - handle-focus (fn []) - handle-blur (fn []) - set-colum-unit (fn []) - remove-column (fn [])] + remove-element + (mf/use-callback + (mf/deps ids) + (fn [type index] + (if (= type :row) + (st/emit! (dwsl/remove-layout-column ids :layout-grid-rows index)) + (st/emit! (dwsl/remove-layout-column ids :layout-grid-columns index))))) + + set-column-value + (mf/use-callback + (mf/deps ids) + (fn [type index value] + (if (= type :row) + (st/emit! (dwsl/change-layout-column ids :layout-grid-rows index {:value value})) + (st/emit! (dwsl/change-layout-column ids :layout-grid-columns index {:value value}))))) + + set-column-type + (mf/use-callback + (mf/deps ids) + (fn [type index col-type] + (if (= type :row) + (st/emit! (dwsl/change-layout-column ids :layout-grid-rows index {:type col-type})) + (st/emit! (dwsl/change-layout-column ids :layout-grid-columns index {:type col-type})))))] [:div.element-set [:div.element-set-title @@ -585,6 +623,7 @@ (when (:layout values) (when (not= :multiple layout-type) (if (= :flex layout-type) + ;; FLEX [:div.element-set-content.layout-menu [:div.layout-row [:div.direction-wrap.row-title "Direction"] @@ -634,6 +673,7 @@ :on-change-style change-padding-type :on-change on-padding-change}]] + ;; GRID [:div.element-set-content.layout-menu [:div.layout-row [:div.direction-wrap.row-title "Direction"] @@ -667,34 +707,30 @@ [:div.jusfiy-content-grid.row-title "Justify"] [:div.btn-wrapper.align-grid [:& justify-grid-row {:is-col? true - :align-items grid-justify-content-column + :justify-items grid-justify-content-column :set-justify set-justify-grid}] [:& justify-grid-row {:is-col? false - :align-items grid-justify-content-row + :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 [{:value 1 :unit :fr} {:value 1 :unit :fr}];; column-grid-values - :add-new-column add-new-element + :column-values column-grid-values + :add-new-element add-new-element :set-column-value set-column-value - :handle-focus handle-focus - :handle-blur handle-blur - :set-colum-unit set-colum-unit - :remove-column remove-column}] + :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 [{:value "--" :unit :auto} {:value "--" :unit :auto}] ;; column-grid-values - :add-new-column add-new-element + :column-values rows-grid-values + :add-new-element add-new-element :set-column-value set-column-value - :handle-focus handle-focus - :handle-blur handle-blur - :set-colum-unit set-colum-unit - :remove-column remove-column}] - + :set-column-type set-column-type + :remove-element remove-element}] + [:& gap-section {:is-col? is-col? :wrap-type wrap-type :gap-selected? gap-selected? diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs index 576d21be2..78b938ca7 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs @@ -33,8 +33,7 @@ layout-container-values (select-keys shape layout-container-flex-attrs) is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) - is-layout-child? (mf/deref is-layout-child-ref) - + is-flex-layout-child? (mf/deref is-flex-layout-child-ref) is-layout-child-absolute? (ctl/layout-absolute? shape)] [:* [:& measures-menu {:ids ids diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs index 832e8bb1f..2f33bd52a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs @@ -38,7 +38,7 @@ is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) is-flex-layout-child? (mf/deref is-flex-layout-child-ref) - is-flex-layout-container? (ctl/flex-layout? shape)] + is-flex-layout-container? (ctl/flex-layout? shape) is-layout-child-absolute? (ctl/layout-absolute? shape)] [:* [:& measures-menu {:ids [(:id shape)] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs index 838e10794..f7afd6277 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs @@ -51,28 +51,31 @@ #_(if (= align-self value) (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self nil})) (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self value})))) - column-start (mf/use-state 1) - column-end (mf/use-state 1) - row-start (mf/use-state 1) - row-end (mf/use-state 1) - on-change (fn [side orientation value] - (if (= orientation :column) - (case side - :all ((reset! column-start value) - (reset! column-end value)) - :start (reset! column-start value) - :end (reset! column-end value)) - (case side - :all ((reset! row-start value) - (reset! row-end value)) - :start (reset! row-start value) - :end (reset! row-end value)))) + column-start column + column-end (inc column) + row-start row + row-end (inc row) + + on-change + (fn [side orientation value] + (if (= orientation :column) + (case side + :all ((reset! column-start value) + (reset! column-end value)) + :start (reset! column-start value) + :end (reset! column-end value)) + (case side + :all ((reset! row-start value) + (reset! row-end value)) + :start (reset! row-start value) + :end (reset! row-end value)))) area-name (mf/use-state "header") ;; TODO this should come from shape on-area-name-change (fn [value] (reset! area-name value)) on-key-press (fn [event])] + [:div.element-set [:div.element-set-title [:span "Grid Cell"]] @@ -100,7 +103,7 @@ {:placeholder "--" :on-click #(dom/select-target %) :on-change (partial on-change :all :column) ;; TODO cambiar este on-change y el value - :value @column-start}]]] + :value column-start}]]] [:div.grid-rows-auto [:spam.icon i/layout-columns] [:div.input-wrapper @@ -108,7 +111,7 @@ {:placeholder "--" :on-click #(dom/select-target %) :on-change (partial on-change :all :row) ;; TODO cambiar este on-change y el value - :value @row-start}]]]]) + :value row-start}]]]]) (when (= :area @position-mode) [:div.input-wrapper [:input.input-text @@ -130,26 +133,26 @@ [:> numeric-input {:placeholder "--" :on-click #(dom/select-target %) - :on-change (partial on-change :start :column) ;; TODO cambiar este on-change y el value - :value @column-start}] + :on-change (partial on-change :start :column) + :value column-start}] [:> numeric-input {:placeholder "--" :on-click #(dom/select-target %) - :on-change (partial on-change :end :column) ;; TODO cambiar este on-change y el value - :value @column-end}]]] + :on-change (partial on-change :end :column) + :value column-end}]]] [:div.grid-rows-auto [:spam.icon i/layout-columns] [:div.input-wrapper [:> numeric-input {:placeholder "--" :on-click #(dom/select-target %) - :on-change (partial on-change :start :row) ;; TODO cambiar este on-change y el value - :value @row-start}] + :on-change (partial on-change :start :row) + :value row-start}] [:> numeric-input {:placeholder "--" :on-click #(dom/select-target %) - :on-change (partial on-change :end :row) ;; TODO cambiar este on-change y el value - :value @row-end}]]]])] + :on-change (partial on-change :end :row) + :value row-end}]]]])] [:div.layout-row [:div.row-title "Align"] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs index d911e489e..7d9327304 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs @@ -33,7 +33,7 @@ layout-container-values (select-keys shape layout-container-flex-attrs) is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) - is-flex-layout-child? (mf/deref is-flex-layout-child-ref)] + is-flex-layout-child? (mf/deref is-flex-layout-child-ref) is-layout-child-absolute? (ctl/layout-absolute? shape)] [:* [:& measures-menu {:ids ids diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs index b60ce4872..5a7b1bd95 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs @@ -33,7 +33,7 @@ layout-container-values (select-keys shape layout-container-flex-attrs) is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) - is-flex-layout-child? (mf/deref is-flex-layout-child-ref)] + is-flex-layout-child? (mf/deref is-flex-layout-child-ref) is-layout-child-absolute? (ctl/layout-absolute? shape)] [:* [:& measures-menu {:ids ids diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs index 6eb3fcd67..401ef70ef 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs @@ -33,7 +33,7 @@ layout-item-values (select-keys shape layout-item-attrs) layout-container-values (select-keys shape layout-container-flex-attrs) is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) - is-flex-layout-child? (mf/deref is-flex-layout-child-ref)] + is-flex-layout-child? (mf/deref is-flex-layout-child-ref) is-layout-child-absolute? (ctl/layout-absolute? shape)] [:* [:& measures-menu {:ids ids @@ -49,7 +49,7 @@ :is-layout-child? true :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) + (when (or (not is-flex-layout-child?) is-layout-child-absolute?) [:& constraints-menu {:ids ids :values constraint-values}]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs index 570e13e24..0560de549 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs @@ -107,7 +107,7 @@ layout-container-values (select-keys shape layout-container-flex-attrs) is-flex-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-flex-layout-child? ids)) - is-flex-layout-child? (mf/deref is-flex-layout-child-ref)] + is-flex-layout-child? (mf/deref is-flex-layout-child-ref) is-layout-child-absolute? (ctl/layout-absolute? shape)] (when (contains? svg-elements tag) diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index 48ba04343..9910f6300 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -6,7 +6,6 @@ (ns app.main.ui.workspace.viewport.grid-layout-editor (:require - [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] @@ -15,9 +14,12 @@ [app.common.geom.shapes.points :as gpo] [app.common.pages.helpers :as cph] [app.common.types.shape.layout :as ctl] + [app.main.data.workspace.grid-layout.editor :as dwge] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.cursors :as cur] [app.main.ui.icons :as i] + [app.util.dom :as dom] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -172,8 +174,74 @@ :stroke-dasharray (when-not (or hover? selected?) (str/join " " (map #(/ % zoom) [0 8]) )) :stroke-linecap "round" - :stroke-width (/ 2 zoom)}}]) - ) + :stroke-width (/ 2 zoom)}}])) + +(mf/defc resize-handler + {::mf/wrap-props false} + [props] + + (let [start-p (unchecked-get props "start-p") + type (unchecked-get props "type") + bounds (unchecked-get props "bounds") + zoom (unchecked-get props "zoom") + + width (gpo/width-points bounds) + height (gpo/height-points bounds) + + dragging-ref (mf/use-ref false) + start-ref (mf/use-ref nil) + + on-pointer-down + (mf/use-callback + (fn [event] + (dom/capture-pointer event) + (mf/set-ref-val! dragging-ref true) + (mf/set-ref-val! start-ref (dom/get-client-position event)))) + + on-lost-pointer-capture + (mf/use-callback + (fn [event] + (dom/release-pointer event) + (mf/set-ref-val! dragging-ref false) + (mf/set-ref-val! start-ref nil))) + + on-mouse-move + (mf/use-callback + (fn [event] + (when (mf/ref-val dragging-ref) + (let [start (mf/ref-val start-ref) + pos (dom/get-client-position event) + delta (-> (gpt/to-vec start pos) + (get (if (= type :column) :x :y)))] + + ;; TODO Implement resize + #_(prn ">Delta" delta))))) + + + [x y width height] + (if (= type :column) + [(- (:x start-p) (/ 8 zoom)) + (- (:y start-p) (/ 40 zoom)) + (/ 16 zoom) + (+ height (/ 40 zoom))] + + [(- (:x start-p) (/ 40 zoom)) + (- (:y start-p) (/ 8 zoom)) + (+ width (/ 40 zoom)) + (/ 16 zoom)])] + + [:rect.resize-handler + {:x x + :y y + :height height + :width width + :on-pointer-down on-pointer-down + :on-lost-pointer-capture on-lost-pointer-capture + :on-mouse-move on-mouse-move + :style {:fill "transparent" + :cursor (if (= type :column) + (cur/resize-ew 0) + (cur/resize-ns 0))}}])) (mf/defc editor {::mf/wrap-props false} @@ -201,9 +269,7 @@ origin (gpo/origin bounds) {:keys [row-tracks column-tracks shape-cells] :as layout-data} - (gsg/calc-layout-data shape children bounds) - - [shape children] (set-sample-data shape children)] + (gsg/calc-layout-data shape children bounds)] (mf/use-effect (fn [] @@ -241,12 +307,11 @@ [:& 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"}}]])) + + [:& resize-handler {:type :column + :start-p start-p + :zoom zoom + :bounds bounds}]])) (for [[idx row-data] (d/enumerate row-tracks)] (let [start-p (-> origin (gpt/add (vv (:distance row-data)))) @@ -257,9 +322,7 @@ :value (dm/str (inc idx)) :zoom zoom}]] - [:rect.resize-handler - {:x (:x start-p) - :y (- (:y start-p) (/ 8 zoom)) - :height (/ 16 zoom) - :width width - :style {:fill "transparent"}}]]))])) + [:& resize-handler {:type :row + :start-p start-p + :zoom zoom + :bounds bounds}]]))])) From 23104b28b6df4b81885b286d40813710af2d5272 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 24 Feb 2023 12:42:16 +0100 Subject: [PATCH 09/10] :sparkles: Edition mode for grid --- .../app/common/geom/shapes/grid_layout.cljc | 4 + .../geom/shapes/grid_layout/layout_data.cljc | 16 +-- .../common/geom/shapes/pixel_precision.cljc | 2 +- common/src/app/common/types/shape/layout.cljc | 127 +++++++++++++++++- .../app/main/data/workspace/shape_layout.cljs | 110 ++++++++------- .../src/app/main/data/workspace/shapes.cljs | 11 +- .../app/main/data/workspace/transforms.cljs | 8 +- .../main/ui/workspace/sidebar/options.cljs | 6 +- .../options/menus/layout_container.cljs | 88 ++++++------ .../sidebar/options/shapes/grid_cell.cljs | 9 +- .../src/app/main/ui/workspace/viewport.cljs | 17 +-- .../main/ui/workspace/viewport/actions.cljs | 6 +- .../app/main/ui/workspace/viewport/debug.cljs | 8 +- .../viewport/grid_layout_editor.cljs | 26 ++-- .../main/ui/workspace/viewport/widgets.cljs | 8 +- 15 files changed, 298 insertions(+), 148 deletions(-) diff --git a/common/src/app/common/geom/shapes/grid_layout.cljc b/common/src/app/common/geom/shapes/grid_layout.cljc index 36f927081..eb45960f8 100644 --- a/common/src/app/common/geom/shapes/grid_layout.cljc +++ b/common/src/app/common/geom/shapes/grid_layout.cljc @@ -13,3 +13,7 @@ (dm/export glld/calc-layout-data) (dm/export glld/get-cell-data) (dm/export glp/child-modifiers) + +(defn get-drop-index + [frame objects _position] + (dec (count (get-in objects [frame :shapes])))) diff --git a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc index 08caa33eb..e797b1c64 100644 --- a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc @@ -6,13 +6,10 @@ (ns app.common.geom.shapes.grid-layout.layout-data (:require - [app.common.data :as d] - [app.common.uuid :as uuid] - [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes.points :as gpo])) -(defn set-sample-data +#_(defn set-sample-data [parent children] (let [parent (assoc parent @@ -38,8 +35,8 @@ layout-grid-cells (into {} - (for [[row-idx row] (d/enumerate (:layout-grid-rows parent)) - [col-idx col] (d/enumerate (:layout-grid-columns parent))] + (for [[row-idx _row] (d/enumerate (:layout-grid-rows parent)) + [col-idx _col] (d/enumerate (:layout-grid-columns parent))] (let [[_bounds shape] (nth children (+ (* row-idx num-columns) col-idx) nil) cell-data {:id (uuid/next) :row (inc row-idx) @@ -69,7 +66,7 @@ )) (defn calc-layout-data - [parent children transformed-parent-bounds] + [parent _children transformed-parent-bounds] (let [height (gpo/height-points transformed-parent-bounds) width (gpo/width-points transformed-parent-bounds) @@ -124,7 +121,7 @@ :shape-cells shape-cells})) (defn get-cell-data - [{:keys [row-tracks column-tracks shape-cells]} transformed-parent-bounds [child-bounds child]] + [{:keys [row-tracks column-tracks shape-cells]} transformed-parent-bounds [_child-bounds child]] (let [origin (gpo/origin transformed-parent-bounds) hv #(gpo/start-hv transformed-parent-bounds %) @@ -138,7 +135,6 @@ start-p (-> origin (gpt/add (hv (:distance column))) - (gpt/add (vv (:distance row)))) - ] + (gpt/add (vv (:distance row))))] (assoc grid-cell :start-p start-p))))) diff --git a/common/src/app/common/geom/shapes/pixel_precision.cljc b/common/src/app/common/geom/shapes/pixel_precision.cljc index e85c70893..9994b0978 100644 --- a/common/src/app/common/geom/shapes/pixel_precision.cljc +++ b/common/src/app/common/geom/shapes/pixel_precision.cljc @@ -80,7 +80,7 @@ (fn [modif-tree shape] (let [modifiers (dm/get-in modif-tree [(:id shape) :modifiers])] (cond-> modif-tree - (ctm/has-geometry? modifiers) + (and (some? modifiers) (ctm/has-geometry? modifiers)) (update-in [(:id shape) :modifiers] set-pixel-precision shape precision ignore-axis))))] (->> (keys modif-tree) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 17639f9a1..e7d8867b9 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -6,8 +6,10 @@ (ns app.common.types.shape.layout (:require + [app.common.data :as d] [app.common.data.macros :as dm] [app.common.spec :as us] + [app.common.uuid :as uuid] [clojure.spec.alpha :as s])) ;; :layout ;; :flex, :grid in the future @@ -41,6 +43,7 @@ (s/def ::layout #{:flex :grid}) (s/def ::layout-flex-dir #{:row :reverse-row :row-reverse :column :reverse-column :column-reverse}) ;;TODO remove reverse-column and reverse-row after script +(s/def ::layout-grid-dir #{:row :column}) (s/def ::layout-gap-type #{:simple :multiple}) (s/def ::layout-gap ::us/safe-number) @@ -53,11 +56,34 @@ (s/def :grid/type #{:percent :flex :auto :fixed}) (s/def :grid/value (s/nilable ::us/safe-number)) -(s/def ::grid-definition (s/keys :opt-un [:grid/type - :grid/value])) +(s/def ::grid-definition (s/keys :req-un [:grid/type] + :opt-un [:grid/value])) (s/def ::layout-grid-rows (s/coll-of ::grid-definition :kind vector?)) (s/def ::layout-grid-columns (s/coll-of ::grid-definition :kind vector?)) +(s/def :grid-cell/id uuid?) +(s/def :grid-cell/area-name ::us/string) +(s/def :grid-cell/row-start ::us/safe-integer) +(s/def :grid-cell/row-span ::us/safe-integer) +(s/def :grid-cell/column-start ::us/safe-integer) +(s/def :grid-cell/column-span ::us/safe-integer) +(s/def :grid-cell/position #{:auto :manual :area}) +(s/def :grid-cell/align-self #{:auto :start :end :center :stretch}) +(s/def :grid-cell/justify-self #{:auto :start :end :center :stretch}) +(s/def :grid-cell/shapes (s/coll-of uuid?)) + +(s/def ::grid-cell (s/keys :opt-un [:grid-cell/id + :grid-cell/area-name + :grid-cell/row-start + :grid-cell/row-span + :grid-cell/column-start + :grid-cell/column-span + :grid-cell/position ;; auto, manual, area + :grid-cell/align-self + :grid-cell/justify-self + :grid-cell/shapes])) +(s/def ::layout-grid-cells (s/map-of uuid? ::grid-cell)) + (s/def ::p1 ::us/safe-number) (s/def ::p2 ::us/safe-number) (s/def ::p3 ::us/safe-number) @@ -85,9 +111,11 @@ ::layout-align-content ;; grid + ::layout-grid-dir ::layout-justify-items ::layout-grid-rows ::layout-grid-columns + ::layout-grid-cells ])) (s/def ::m1 ::us/safe-number) @@ -448,7 +476,12 @@ :layout-padding :layout-justify-content :layout-align-items - :layout-align-content)) + :layout-align-content + :layout-grid-dir + :layout-justify-items + :layout-grid-columns + :layout-grid-rows + )) (defn remove-layout-item-data [shape] @@ -464,3 +497,91 @@ :layout-item-align-self :layout-item-absolute :layout-item-z-index)) +(declare assign-cells) + +(def grid-cell-defaults + {:row-span 1 + :column-span 1 + :position :auto + :align-self :auto + :justify-self :auto + :shapes []}) + +;; TODO: GRID ASSIGNMENTS + +;; Adding a track creates the cells. We should check the shapes that are not tracked (with default values) and assign to the correct tracked values +(defn add-grid-column + [parent value] + (us/assert ::grid-definition value) + (let [rows (:layout-grid-rows parent) + new-col-num (count (:layout-grid-columns parent)) + + layout-grid-cells + (->> (d/enumerate rows) + (reduce (fn [result [row-idx _row]] + (let [id (uuid/next)] + (assoc result id + (merge {:id id + :row (inc row-idx) + :column new-col-num + :track? true} + grid-cell-defaults)))) + (:layout-grid-cells parent)))] + (-> parent + (update :layout-grid-columns (fnil conj []) value) + (assoc :layout-grid-cells layout-grid-cells)))) + +(defn add-grid-row + [parent value] + (us/assert ::grid-definition value) + (let [cols (:layout-grid-columns parent) + new-row-num (inc (count (:layout-grid-rows parent))) + + layout-grid-cells + (->> (d/enumerate cols) + (reduce (fn [result [col-idx _col]] + (let [id (uuid/next)] + (assoc result id + (merge {:id id + :column (inc col-idx) + :row new-row-num + :track? true} + grid-cell-defaults)))) + (:layout-grid-cells parent)))] + (-> parent + (update :layout-grid-rows (fnil conj []) value) + (assoc :layout-grid-cells layout-grid-cells)))) + +;; TODO: Remove a track and its corresponding cells. We need to reassign the orphaned shapes into not-tracked cells +(defn remove-grid-column + [parent _index] + parent) + +(defn remove-grid-row + [parent _index] + parent) + +;; TODO: Mix the cells given as arguments leaving only one. It should move all the shapes in those cells in the direction for the grid +;; and lastly use assign-cells to reassing the orphaned shapes +(defn merge-cells + [parent _cells] + parent) + + +;; TODO +;; Assign cells takes the children and move them into the aloted cells. If there are not enough cells it creates +;; not-tracked rows/columns and put the shapes there +;; Should be caled each time a child can be added like: +;; - On shape creation +;; - When moving a child from layers +;; - Moving from the transform into a cell and there are shapes without cell +;; - Shape duplication +;; - (maybe) create group/frames. This case will assigna a cell that had one of its children +(defn assign-cells + [parent] + #_(let [allocated-shapes + (into #{} (mapcat :shapes) (:layout-grid-cells parent)) + + no-cell-shapes + (->> (:shapes parent) (remove allocated-shapes))]) + parent) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 612cd1646..026b72144 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -1,4 +1,4 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public +; 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/. ;; @@ -54,6 +54,7 @@ (def initial-grid-layout ;; TODO {:layout :grid + :layout-grid-dir :row :layout-gap-type :multiple :layout-gap {:row-gap 0 :column-gap 0} :layout-align-items :start @@ -62,7 +63,6 @@ :layout-justify-content :start :layout-padding-type :simple :layout-padding {:p1 0 :p2 0 :p3 0 :p4 0} - :layout-grid-rows [] :layout-grid-columns []}) @@ -75,6 +75,7 @@ (fn [shape] (-> shape (merge initial-layout-data) + (cond-> (= type :grid) ctl/assign-cells) ;; If the original shape is not a frame we set clip content and show-viewer to false (cond-> (not from-frame?) (assoc :show-content true :hide-in-viewer true)))))) @@ -154,6 +155,13 @@ :layout-align-items :center :layout-gap layout-gap))))) +(defn shapes->grid-params + "Given the shapes calculate its flex parameters (horizontal vs vertical, gaps, etc)" + ([objects shapes] + (shapes->flex-params objects shapes nil)) + ([_objects _shapes _parent] + {})) + (defn create-layout-from-id [ids type from-frame?] (ptk/reify ::create-layout-from-id @@ -163,8 +171,10 @@ children-ids (into [] (mapcat #(get-in objects [% :shapes])) ids) children-shapes (map (d/getf objects) children-ids) parent (get objects (first ids)) - flex-params (when (d/not-empty? children-shapes) - (shapes->flex-params objects children-shapes parent)) + layout-params (when (d/not-empty? children-shapes) + (case type + :flex (shapes->flex-params objects children-shapes parent) + :grid (shapes->grid-params objects children-shapes parent))) undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) (dwc/update-shapes ids (get-layout-initializer type from-frame?)) @@ -175,7 +185,7 @@ (not from-frame?) (-> (assoc :layout-item-h-sizing :auto :layout-item-v-sizing :auto) - (merge flex-params))))) + (merge layout-params))))) (ptk/data-event :layout/update ids) (dwc/update-shapes children-ids #(dissoc % :constraints-h :constraints-v)) (dwu/commit-undo-transaction undo-id)))))) @@ -183,7 +193,6 @@ ;; Never call this directly but through the data-event `:layout/update` ;; Otherwise a lot of cycle dependencies could be generated -(declare check-grid-cells-update) (defn- update-layout-positions [ids] (ptk/reify ::update-layout-positions @@ -191,16 +200,10 @@ (watch [_ state _] (let [objects (wsh/lookup-page-objects state) ids (->> ids (filter #(contains? objects %)))] - - (rx/concat - ;; Update grids if necesary - (rx/of (check-grid-cells-update - (->> (concat ids (map #(cph/get-parent-id objects %) ids)) - (filter #(ctl/grid-layout? objects %))))) - (if (d/not-empty? ids) - (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))] - (rx/of (dwm/apply-modifiers {:modifiers modif-tree}))) - (rx/empty))))))) + (if (d/not-empty? ids) + (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))] + (rx/of (dwm/apply-modifiers {:modifiers modif-tree}))) + (rx/empty)))))) (defn initialize [] @@ -321,15 +324,12 @@ is-frame? (= :frame (:type (first selected-shapes))) undo-id (js/Symbol)] - (if (and single? is-frame?) - (rx/of - (dwu/start-undo-transaction undo-id) + (rx/of + (dwu/start-undo-transaction undo-id) + (if (and single? is-frame?) (create-layout-from-id [(first selected)] type true) - (dwu/commit-undo-transaction undo-id)) - (rx/of - (dwu/start-undo-transaction undo-id) - (create-layout-from-selection type) - (dwu/commit-undo-transaction undo-id))))))) + (create-layout-from-selection type)) + (dwu/commit-undo-transaction undo-id)))))) (defn toggle-layout-flex [] @@ -359,14 +359,20 @@ (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) -(defn update-grid-cells +#_(defn update-grid-cells [parent objects] - (let [children (cph/get-immediate-children objects (:id parent)) layout-grid-rows (:layout-grid-rows parent) layout-grid-columns (:layout-grid-columns parent) num-rows (count layout-grid-columns) num-columns (count layout-grid-columns) + layout-grid-cells (:layout-grid-cells parent) + + allocated-shapes + (into #{} (mapcat :shapes) (:layout-grid-cells parent)) + + no-cell-shapes + (->> children (:shapes parent) (remove allocated-shapes)) layout-grid-cells (for [[row-idx row] (d/enumerate layout-grid-rows) @@ -380,9 +386,9 @@ :col-span 1 :shapes (when shape [(:id shape)])}] [(:id cell-data) cell-data]))] - (assoc parent :layout-grid-cells layout-grid-cells))) + (assoc parent :layout-grid-cells (into {} layout-grid-cells)))) -(defn check-grid-cells-update +#_(defn check-grid-cells-update [ids] (ptk/reify ::check-grid-cells-update ptk/WatchEvent @@ -395,54 +401,56 @@ (-> shape (update-grid-cells objects))))))))) -(defn add-layout-column - [ids property value] +(defn add-layout-track + [ids type value] + (assert (#{:row :column} type)) (ptk/reify ::add-layout-column ptk/WatchEvent - (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - undo-id (js/Symbol)] + (watch [_ _ _] + (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) (dwc/update-shapes ids (fn [shape] - (-> shape - (update property (fnil conj []) value) - (update-grid-cells objects)))) + (case type + :row (ctl/add-grid-row shape value) + :column (ctl/add-grid-column shape value)))) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) -(defn remove-layout-column - [ids property index] +(defn remove-layout-track + [ids type index] + (assert (#{:row :column} type)) + (ptk/reify ::remove-layout-column ptk/WatchEvent - (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - undo-id (js/Symbol)] + (watch [_ _ _] + (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) (dwc/update-shapes ids (fn [shape] - (-> shape - (update property d/remove-at-index index) - (update-grid-cells objects)))) + (case type + :row (ctl/remove-grid-row shape index) + :column (ctl/remove-grid-column shape index)))) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) -(defn change-layout-column - [ids property index props] +(defn change-layout-track + [ids type index props] + (assert (#{:row :column} type)) (ptk/reify ::change-layout-column ptk/WatchEvent - (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - undo-id (js/Symbol)] + (watch [_ _ _] + (let [undo-id (js/Symbol) + property (case :row :layout-grid-rows + :column :layout-grid-columns)] (rx/of (dwu/start-undo-transaction undo-id) (dwc/update-shapes ids (fn [shape] (-> shape - (update-in [property index] merge props) - (update-grid-cells objects)))) + (update-in [property index] merge props)))) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index f123efb69..b79c545fc 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -82,6 +82,7 @@ (ptk/reify ::add-shape ptk/WatchEvent (watch [it state _] + (.log js/console (clj->js attrs)) (let [page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) selected (wsh/lookup-selected state) @@ -95,6 +96,7 @@ selected) index (:index (meta attrs)) + changes (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) (cond-> (some? index) @@ -102,7 +104,10 @@ (cond-> (nil? index) (pcb/add-object shape)) (cond-> (some? (:parent-id attrs)) - (pcb/change-parent (:parent-id attrs) [shape]))) + (pcb/change-parent (:parent-id attrs) [shape])) + (cond-> (ctl/grid-layout? objects (:parent-id shape)) + (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells)) + ) undo-id (js/Symbol)] (rx/concat @@ -133,7 +138,9 @@ (pcb/with-objects objects) (cond-> (not (ctl/any-layout? objects frame-id)) (pcb/update-shapes ordered-indexes ctl/remove-layout-item-data)) - (pcb/change-parent frame-id to-move-shapes 0)))] + (pcb/change-parent frame-id to-move-shapes 0) + (cond-> (ctl/grid-layout? objects frame-id) + (pcb/update-shapes [frame-id] ctl/assign-cells))))] (if (some? changes) (rx/of (dch/commit-changes changes)) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 656d2e9fb..08c23c20f 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -12,7 +12,8 @@ [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] - [app.common.geom.shapes.flex-layout :as gsl] + [app.common.geom.shapes.flex-layout :as gslf] + [app.common.geom.shapes.grid-layout :as gslg] [app.common.math :as mth] [app.common.pages.changes-builder :as pcb] [app.common.pages.helpers :as cph] @@ -474,7 +475,10 @@ exclude-frames (if mod? exclude-frames exclude-frames-siblings) target-frame (ctst/top-nested-frame objects position exclude-frames) flex-layout? (ctl/flex-layout? objects target-frame) - drop-index (when flex-layout? (gsl/get-drop-index target-frame objects position))] + grid-layout? (ctl/grid-layout? objects target-frame) + drop-index (cond + flex-layout? (gslf/get-drop-index target-frame objects position) + grid-layout? (gslg/get-drop-index target-frame objects position))] [move-vector target-frame drop-index]))) (rx/take-until stopper))] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs index 1847962c0..9c98a763f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs @@ -6,7 +6,6 @@ (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] @@ -24,6 +23,7 @@ [app.main.ui.workspace.sidebar.options.shapes.bool :as bool] [app.main.ui.workspace.sidebar.options.shapes.circle :as circle] [app.main.ui.workspace.sidebar.options.shapes.frame :as frame] + [app.main.ui.workspace.sidebar.options.shapes.grid-cell :as grid-cell] [app.main.ui.workspace.sidebar.options.shapes.group :as group] [app.main.ui.workspace.sidebar.options.shapes.image :as image] [app.main.ui.workspace.sidebar.options.shapes.multiple :as multiple] @@ -74,9 +74,7 @@ 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) + (d/seek (fn [[_ {:keys [selected]}]] (some? selected)) grid-edition) grid-cell-selected? (and (some? grid-id) (some? row-selected) (some? col-selected)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index a25b8e75c..1cc0397c6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -10,6 +10,7 @@ [app.common.data.macros :as dm] [app.main.data.workspace :as udw] [app.main.data.workspace.shape-layout :as dwsl] + [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input]] [app.main.ui.components.select :refer [select]] @@ -34,8 +35,7 @@ :layout-grid-dir ;; :row :column :layout-justify-items :layout-grid-columns - :layout-grid-rows - ]) + :layout-grid-rows]) (defn get-layout-flex-icon [type val is-col?] @@ -54,7 +54,7 @@ :center i/align-items-row-center :stretch i/align-items-row-strech :baseline i/align-items-row-baseline)) - + :justify-content (if is-col? (case val @@ -343,14 +343,24 @@ :disabled (and (= :nowrap wrap-type) (not is-col?))}]]]]) (mf/defc grid-edit-mode - [{:keys [active toggle-edit-mode] :as props}] - [:* - [:button.tooltip.tooltip-bottom-left - {:class (dom/classnames :active (= active true)) - :alt "Grid edit mode" - :on-click #(toggle-edit-mode) - :style {:padding 0}} - i/grid-layout-mode]]) + [{:keys [id] :as props}] + (let [edition (mf/deref refs/selected-edition) + active? (= id edition) + + toggle-edit-mode + (mf/use-callback + (mf/deps id edition) + (fn [] + (if-not active? + (st/emit! (udw/start-edition-mode id)) + (st/emit! :interrupt))))] + + [:button.tooltip.tooltip-bottom-left + {:class (dom/classnames :active active?) + :alt "Grid edit mode" + :on-click #(toggle-edit-mode) + :style {:padding 0}} + i/grid-layout-mode])) (mf/defc align-grid-row [{:keys [is-col? align-items set-align] :as props}] @@ -456,14 +466,15 @@ (st/emit! (dwsl/remove-layout ids)) (reset! open? false)) - ;; Uncomment when activating the grid options - set-flex (fn [] - (st/emit! (dwsl/remove-layout ids)) - (on-add-layout :flex)) + _set-flex + (fn [] + (st/emit! (dwsl/remove-layout ids)) + (on-add-layout :flex)) - set-grid (fn [] - (st/emit! (dwsl/remove-layout ids)) - (on-add-layout :grid)) + _set-grid + (fn [] + (st/emit! (dwsl/remove-layout ids)) + (on-add-layout :grid)) ;; Flex-direction @@ -575,33 +586,25 @@ (mf/use-callback (mf/deps ids) (fn [type value] - (if (= type :row) - (st/emit! (dwsl/add-layout-column ids :layout-grid-rows value)) - (st/emit! (dwsl/add-layout-column ids :layout-grid-columns value))))) + (st/emit! (dwsl/add-layout-track ids type value)))) remove-element (mf/use-callback (mf/deps ids) (fn [type index] - (if (= type :row) - (st/emit! (dwsl/remove-layout-column ids :layout-grid-rows index)) - (st/emit! (dwsl/remove-layout-column ids :layout-grid-columns index))))) + (st/emit! (dwsl/remove-layout-track ids type index)))) set-column-value (mf/use-callback (mf/deps ids) (fn [type index value] - (if (= type :row) - (st/emit! (dwsl/change-layout-column ids :layout-grid-rows index {:value value})) - (st/emit! (dwsl/change-layout-column ids :layout-grid-columns index {:value value}))))) + (st/emit! (dwsl/change-layout-track ids type index {:value value})))) set-column-type (mf/use-callback (mf/deps ids) - (fn [type index col-type] - (if (= type :row) - (st/emit! (dwsl/change-layout-column ids :layout-grid-rows index {:type col-type})) - (st/emit! (dwsl/change-layout-column ids :layout-grid-columns index {:type col-type})))))] + (fn [type index track-type] + (st/emit! (dwsl/change-layout-track ids type index {:type track-type}))))] [:div.element-set [:div.element-set-title @@ -609,7 +612,7 @@ [:span "Layout"] (if (and (not multiple) (:layout values)) [:div.title-actions - [:div.layout-btns + #_[:div.layout-btns [:button {:on-click set-flex :class (dom/classnames :active (= :flex layout-type))} "Flex"] @@ -622,8 +625,9 @@ (when (:layout values) (when (not= :multiple layout-type) - (if (= :flex layout-type) - ;; FLEX + (case layout-type + :flex + [:div.element-set-content.layout-menu [:div.layout-row [:div.direction-wrap.row-title "Direction"] @@ -673,7 +677,8 @@ :on-change-style change-padding-type :on-change on-padding-change}]] - ;; GRID + :grid + [:div.element-set-content.layout-menu [:div.layout-row [:div.direction-wrap.row-title "Direction"] @@ -687,10 +692,9 @@ :set-direction #(set-direction dir :grid) :icon? false}])]] - [:div.edit-mode - [:& grid-edit-mode - {:active false - :toggle-edit-mode ()}]]]] + (when (= 1 (count ids)) + [:div.edit-mode + [:& grid-edit-mode {:id (first ids)}]])]] [:div.layout-row [:div.align-items-grid.row-title "Align"] @@ -739,4 +743,8 @@ [:& padding-section {:values values :on-change-style change-padding-type - :on-change on-padding-change}]])))])) + :on-change on-padding-change}]] + + + ;; Default if not grid or flex + nil)))])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs index f7afd6277..5b4f96dd8 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs @@ -31,7 +31,7 @@ (mf/defc options {::mf/wrap [mf/memo]} - [{:keys [shape row column] :as props}] + [{:keys [_shape row column] :as props}] (let [position-mode (mf/use-state :auto) ;; TODO this should come from shape @@ -57,8 +57,9 @@ row-end (inc row) on-change - (fn [side orientation value] - (if (= orientation :column) + (fn [_side _orientation _value] + ;; TODO + #_(if (= orientation :column) (case side :all ((reset! column-start value) (reset! column-end value)) @@ -74,7 +75,7 @@ on-area-name-change (fn [value] (reset! area-name value)) - on-key-press (fn [event])] + on-key-press (fn [_event])] [:div.element-set [:div.element-set-title diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 007754eb7..18a1e6f77 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -6,7 +6,6 @@ (ns app.main.ui.workspace.viewport (:require - [app.main.ui.workspace.viewport.grid-layout-editor :as grid-layout] [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] @@ -30,6 +29,7 @@ [app.main.ui.workspace.viewport.drawarea :as drawarea] [app.main.ui.workspace.viewport.frame-grid :as frame-grid] [app.main.ui.workspace.viewport.gradients :as gradients] + [app.main.ui.workspace.viewport.grid-layout-editor :as grid-layout] [app.main.ui.workspace.viewport.guides :as guides] [app.main.ui.workspace.viewport.hooks :as hooks] [app.main.ui.workspace.viewport.interactions :as interactions] @@ -158,6 +158,7 @@ (and (some? drawing-obj) (= :path (:type drawing-obj)))) node-editing? (and edition (not= :text (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)) workspace-read-only? (mf/use-ctx ctx/workspace-read-only?) mode-inspect? (= options-mode :inspect) @@ -168,7 +169,7 @@ on-drag-enter (actions/on-drag-enter) on-drag-over (actions/on-drag-over) on-drop (actions/on-drop file) - on-mouse-down (actions/on-mouse-down @hover selected edition drawing-tool text-editing? node-editing? + on-mouse-down (actions/on-mouse-down @hover selected edition drawing-tool text-editing? node-editing? grid-editing? drawing-path? create-comment? space? panning z? workspace-read-only?) on-mouse-up (actions/on-mouse-up disable-paste) on-pointer-down (actions/on-pointer-down) @@ -199,6 +200,7 @@ show-pixel-grid? (and (contains? layout :show-pixel-grid) (>= zoom 8)) show-text-editor? (and editing-shape (= :text (:type editing-shape))) + show-grid-editor? (and editing-shape (ctl/grid-layout? editing-shape)) show-presence? page-id show-prototypes? (= options-mode :prototype) show-selection-handlers? (and (seq selected) (not show-text-editor?)) @@ -540,10 +542,9 @@ {:id (first selected) :zoom zoom}]) - (when-let [selected (first selected-shapes)] - (when (ctl/grid-layout? selected) - [:& grid-layout/editor - {:zoom zoom - :objects base-objects - :shape selected}])) + (when show-grid-editor? + [:& grid-layout/editor + {:zoom zoom + :objects base-objects + :shape (get base-objects edition)}]) ]]])) diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index 8cf782224..237f2ef30 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -34,10 +34,10 @@ (defn on-mouse-down [{:keys [id blocked hidden type]} selected edition drawing-tool text-editing? - node-editing? drawing-path? create-comment? space? panning z? workspace-read-only?] + node-editing? grid-editing? drawing-path? create-comment? space? panning z? workspace-read-only?] (mf/use-callback (mf/deps id blocked hidden type selected edition drawing-tool text-editing? - node-editing? drawing-path? create-comment? @z? @space? + node-editing? grid-editing? drawing-path? create-comment? @z? @space? panning workspace-read-only?) (fn [bevent] (when (or (dom/class? (dom/get-target bevent) "viewport-controls") @@ -70,7 +70,7 @@ (do (st/emit! (ms/->MouseEvent :down ctrl? shift? alt? meta?)) - (when (and (not= edition id) text-editing?) + (when (and (not= edition id) (or text-editing? grid-editing?)) (st/emit! dw/clear-edition-mode)) (when (and (not text-editing?) diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index 8cd73894c..1719fd2aa 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -225,7 +225,7 @@ height (gpo/height-points parent-bounds) origin (gpo/origin parent-bounds) - {:keys [row-tracks column-tracks shape-cells]} + {:keys [row-tracks column-tracks]} (gsg/calc-layout-data parent children parent-bounds)] [:* @@ -236,7 +236,8 @@ :y1 (:y start-p) :x2 (:x end-p) :y2 (:y end-p) - :style {:stroke "red"}}])) + :style {:stroke "red" + :stroke-width (/ 1 zoom)}}])) (for [column-data column-tracks] (let [start-p (gpt/add origin (hv (:distance column-data))) @@ -245,4 +246,5 @@ :y1 (:y start-p) :x2 (:x end-p) :y2 (:y end-p) - :style {:stroke "red"}}]))])))) + :style {:stroke "red" + :stroke-width (/ 1 zoom)}}]))])))) diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index 9910f6300..4bbfb68b8 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -10,15 +10,12 @@ [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.data.workspace.grid-layout.editor :as dwge] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.cursors :as cur] - [app.main.ui.icons :as i] [app.util.dom :as dom] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -211,7 +208,7 @@ (when (mf/ref-val dragging-ref) (let [start (mf/ref-val start-ref) pos (dom/get-client-position event) - delta (-> (gpt/to-vec start pos) + _delta (-> (gpt/to-vec start pos) (get (if (= type :column) :x :y)))] ;; TODO Implement resize @@ -268,7 +265,7 @@ height (gpo/height-points bounds) origin (gpo/origin bounds) - {:keys [row-tracks column-tracks shape-cells] :as layout-data} + {:keys [row-tracks column-tracks] :as layout-data} (gsg/calc-layout-data shape children bounds)] (mf/use-effect @@ -289,16 +286,15 @@ :type :row}]) (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]) - }])) + [:& 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]) + }]) (for [[idx column-data] (d/enumerate column-tracks)] (let [start-p (-> origin (gpt/add (hv (:distance column-data)))) diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs index be1d5372e..261361df6 100644 --- a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.point :as gpt] + [app.common.pages.helpers :as cph] [app.common.types.shape-tree :as ctt] [app.common.uuid :as uuid] [app.main.data.workspace :as dw] @@ -55,8 +56,11 @@ drawing (mf/deref refs/workspace-drawing) drawing-obj (:object drawing) shape (or drawing-obj (-> selected first))] - (when (or (and (= (count selected) 1) (= (:id shape) edition) (not= :text (:type shape))) - (and (some? drawing-obj) (= :path (:type drawing-obj)) + (when (or (and (= (count selected) 1) + (= (:id shape) edition) + (cph/path-shape? shape)) + (and (some? drawing-obj) + (cph/path-shape? drawing-obj) (not= :curve (:tool drawing)))) [:div.viewport-actions [:& path-actions {:shape shape}]]))) From a12baf684c158a373351906f9849993655c7c894 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 3 Mar 2023 10:53:46 +0100 Subject: [PATCH 10/10] :sparkles: Review fixes --- common/src/app/common/types/shape/layout.cljc | 2 +- frontend/src/app/main/data/workspace/shapes.cljs | 1 - frontend/src/app/main/data/workspace/transforms.cljs | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index e7d8867b9..c669aae62 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -569,7 +569,7 @@ ;; TODO -;; Assign cells takes the children and move them into the aloted cells. If there are not enough cells it creates +;; Assign cells takes the children and move them into the allotted cells. If there are not enough cells it creates ;; not-tracked rows/columns and put the shapes there ;; Should be caled each time a child can be added like: ;; - On shape creation diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index b79c545fc..525fc5397 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -82,7 +82,6 @@ (ptk/reify ::add-shape ptk/WatchEvent (watch [it state _] - (.log js/console (clj->js attrs)) (let [page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) selected (wsh/lookup-selected state) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 08c23c20f..5b22c724f 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -439,8 +439,7 @@ (cph/selected-with-children objects selected)) exclude-frames-siblings - exclude-frames - #_(into exclude-frames + (into exclude-frames (comp (mapcat (partial cph/get-siblings-ids objects)) (filter (partial ctl/any-layout-immediate-child-id? objects))) selected)