diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 9abd71970a..cccafdb200 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -735,6 +735,19 @@ (maybe-remove?) (map (fn [[id cell]] (assoc cell :id id))))))) +(defn cells-seq + [{:keys [layout-grid-cells layout-grid-dir]} & {:keys [sort?] :or {sort? false}}] + + (let [comp-fn (if (= layout-grid-dir :row) + (juxt :row :column) + (juxt :column :row)) + maybe-sort? + (if sort? (partial sort-by (comp comp-fn second)) identity)] + + (->> layout-grid-cells + (maybe-sort?) + (map second)))) + (defn get-free-cells ([parent] (get-free-cells parent nil)) @@ -782,7 +795,7 @@ (reduce find-overlaps #{} cells))) ;; FIXME: This is only for development -#_(defn fix-overlaps +(defn fix-overlaps [parent overlaps] (reduce (fn [parent ids] (let [id (if (empty? (get-in parent [:layout-grid-cells (first ids)])) @@ -792,6 +805,32 @@ parent overlaps)) +(defn position-auto-shapes + [parent] + ;; Iterate through the cells. While auto and contains shape no changes. + ;; If auto without shape start moving auto + ;; Move shapes in auto-cells to the first free auto. + (let [auto-cells (->> (cells-seq parent :sort? true) + (filter #(and (= (:position %) :auto) + (= (:row-span %) 1) + (= (:column-span %) 1)))) + + shapes (->> auto-cells (mapcat :shapes)) + + parent + (loop [parent parent + cells (seq auto-cells) + shapes (seq shapes)] + (if (empty? cells) + parent + (let [shape (first shapes) + cell (first cells) + parent (assoc-in parent [:layout-grid-cells (:id cell) :shapes] (if (some? shape) [shape] []))] + (recur parent + (rest cells) + (rest shapes)))))] + parent)) + ;; 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 ;; Non-tracked tracks need to be deleted when they are empty and there are no more shapes unallocated @@ -803,13 +842,21 @@ ;; - (maybe) create group/frames. This case will assigna a cell that had one of its children (defn assign-cells [parent] - (let [parent (-> parent check-deassigned-cells) + (let [;; TODO: Remove this, shouldn't be happening + ;;overlaps (overlapping-cells parent) + ;;_ (when (not (empty? overlaps)) + ;; (.warn js/console "OVERLAPS" overlaps)) + parent (cond-> (check-deassigned-cells parent) + #_(d/not-empty? overlaps) + #_(fix-overlaps overlaps)) shape-has-cell? (into #{} (mapcat (comp :shapes second)) (:layout-grid-cells parent)) no-cell-shapes - (->> (:shapes parent) (remove shape-has-cell?))] + (->> (:shapes parent) (remove shape-has-cell?)) + + parent (position-auto-shapes parent)] (if (empty? no-cell-shapes) ;; All shapes are within a cell. No need to assign @@ -840,9 +887,10 @@ (reduce (fn [parent _] (add-track parent default-track-value)) parent)) cells - (loop [cells (:layout-grid-cells parent) + (loop [cells (:layout-grid-cells parent) free-cells (get-free-cells parent {:sort? true}) - pending no-cell-shapes] + pending no-cell-shapes] + (if (or (empty? free-cells) (empty? pending)) cells (let [next-free (first free-cells) @@ -924,7 +972,8 @@ (reduce (fn [[parent cells] [shape-id idx]] (let [[parent cells] (free-cell-push parent cells idx)] [(update-in parent [:layout-grid-cells (get-in cells [idx :id])] - assoc :position :manual :shapes [shape-id]) + assoc :position :manual + :shapes [shape-id]) cells])) [parent cells]) (first))) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index bc645e92d2..45dd0d30c9 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -598,8 +598,34 @@ (dwc/update-shapes [layout-id] (fn [shape] - (cond - (= mode :area) + (case mode + :auto + ;; change the manual cells and move to auto + (->> ids + (reduce + (fn [shape cell-id] + (let [cell (get-in shape [:layout-grid-cells cell-id])] + (cond-> shape + (or (contains? #{:area :manual} (:position cell)) + (> (:row-span cell) 1) + (> (:column-span cell) 1)) + (-> (d/update-in-when [:layout-grid-cells cell-id] assoc :shapes [] :position :auto) + (ctl/resize-cell-area (:row cell) (:column cell) (:row cell) (:column cell) 1 1) + (ctl/assign-cells))))) + shape)) + + :manual + (->> ids + (reduce + (fn [shape cell-id] + (let [cell (get-in shape [:layout-grid-cells cell-id])] + (cond-> shape + (contains? #{:area :auto} (:position cell)) + (-> (d/assoc-in-when [:layout-grid-cells cell-id :position] :manual) + (ctl/assign-cells))))) + shape)) + + :area ;; Create area with the selected cells (let [{:keys [first-row first-column last-row last-column]} (ctl/cells-coordinates (->> ids (map #(get-in shape [:layout-grid-cells %])))) @@ -618,18 +644,7 @@ (ctl/assign-cells))] (-> shape - (d/update-in-when [:layout-grid-cells (:id target-cell)] assoc :position :area))) - - (= mode :auto) - ;; change the manual cells and move to auto - (->> ids - (reduce - (fn [shape cell-id] - (cond-> shape - (contains? #{:area :manual} (get-in shape [:layout-grid-cells cell-id :position])) - (-> (d/update-in-when [:layout-grid-cells cell-id] assoc :shapes [] :position :auto) - (ctl/assign-cells)))) - shape))))) + (d/update-in-when [:layout-grid-cells (:id target-cell)] assoc :position :area)))))) (dwge/clean-selection layout-id) (ptk/data-event :layout/update [layout-id]) (dwu/commit-undo-transaction undo-id)))))) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 593dcb6949..ce1cd5a1dd 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -611,7 +611,9 @@ (ctl/swap-shapes id (:id next-cell))))) parent))] (-> changes - (pcb/update-shapes [(:id parent)] (fn [shape] (assoc shape :layout-grid-cells layout-grid-cells))) + (pcb/update-shapes [(:id parent)] (fn [shape] (-> shape + (assoc :layout-grid-cells layout-grid-cells) + (ctl/assign-cells)))) (pcb/reorder-grid-children [(:id parent)])))) changes diff --git a/frontend/src/app/util/code_gen/style_css.cljs b/frontend/src/app/util/code_gen/style_css.cljs index a17e454df5..5ab4655c12 100644 --- a/frontend/src/app/util/code_gen/style_css.cljs +++ b/frontend/src/app/util/code_gen/style_css.cljs @@ -100,6 +100,7 @@ body { ;; Grid related properties :grid-template-rows :grid-template-columns + :grid-template-areas ;; Flex/grid self properties :flex-shrink @@ -114,6 +115,7 @@ body { ;; Grid cell properties :grid-column :grid-row + :grid-area ]) (def text-node-css-properties diff --git a/frontend/src/app/util/code_gen/style_css_values.cljs b/frontend/src/app/util/code_gen/style_css_values.cljs index 5c11a80056..e2e184de41 100644 --- a/frontend/src/app/util/code_gen/style_css_values.cljs +++ b/frontend/src/app/util/code_gen/style_css_values.cljs @@ -14,7 +14,8 @@ [app.common.pages.helpers :as cph] [app.common.types.shape.layout :as ctl] [app.main.ui.formats :as fmt] - [app.util.code-gen.common :as cgc])) + [app.util.code-gen.common :as cgc] + [cuerdas.core :as str])) (defn fill->color [{:keys [fill-color fill-opacity fill-color-gradient]}] @@ -279,15 +280,38 @@ [_ shape _] (:layout-grid-columns shape)) +(defmethod get-value :grid-template-areas + [_ shape _] + (when (ctl/grid-layout? shape) + (let [result + (->> (d/enumerate (:layout-grid-rows shape)) + (map + (fn [[row _]] + (dm/str + "\"" + (->> (d/enumerate (:layout-grid-columns shape)) + (map (fn [[column _]] + (let [cell (ctl/get-cell-by-position shape (inc row) (inc column))] + (str/replace (:area-name cell ".") " " "-")))) + (str/join " ")) + "\""))) + (str/join "\n"))] + result))) + (defn get-grid-coord [shape objects prop span-prop] (when (and (ctl/grid-layout-immediate-child? objects shape) (not (ctl/layout-absolute? shape))) (let [parent (get objects (:parent-id shape)) cell (ctl/get-cell-by-shape-id parent (:id shape))] - (if (> (get cell span-prop) 1) - (dm/str (get cell prop) " / " (+ (get cell prop) (get cell span-prop))) - (get cell prop))))) + (when (and + (not (and (= (:position cell) :area) (d/not-empty? (:area-name cell)))) + (or (= (:position cell) :manual) + (> (:row-span cell) 1) + (> (:column-span cell) 1))) + (if (> (get cell span-prop) 1) + (dm/str (get cell prop) " / " (+ (get cell prop) (get cell span-prop))) + (get cell prop)))))) (defmethod get-value :grid-column [_ shape objects] @@ -297,6 +321,15 @@ [_ shape objects] (get-grid-coord shape objects :row :row-span)) +(defmethod get-value :grid-area + [_ shape objects] + (when (and (ctl/grid-layout-immediate-child? objects shape) + (not (ctl/layout-absolute? shape))) + (let [parent (get objects (:parent-id shape)) + cell (ctl/get-cell-by-shape-id parent (:id shape))] + (when (and (= (:position cell) :area) (d/not-empty? (:area-name cell))) + (str/replace (:area-name cell) " " "-"))))) + (defmethod get-value :flex-shrink [_ shape objects] (when (and (ctl/flex-layout-immediate-child? objects shape)