From 88d259a12399363899d904ecfcb0d741f69f223f Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 5 Dec 2023 10:51:53 +0100 Subject: [PATCH 01/12] :sparkles: Highlight elements on hover in grid editor panel --- .../src/app/main/data/workspace/shape_layout.cljs | 12 +++++++----- .../app/main/ui/workspace/sidebar/layer_item.cljs | 3 +++ .../app/main/ui/workspace/sidebar/layer_item.scss | 15 ++++++++++++--- .../sidebar/options/menus/layout_container.scss | 2 +- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 01f2fecb0..0bdc1e582 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -311,11 +311,13 @@ (update [_ state] (let [objects (wsh/lookup-page-objects state) shape (get objects (first ids)) - highlighted (when hover? - (->> (if (= type :row) - (ctl/shapes-by-row shape index) - (ctl/shapes-by-column shape index)) - (set)))] + + highlighted + (when hover? + (->> (if (= type :row) + (ctl/shapes-by-row shape index) + (ctl/shapes-by-column shape index)) + (set)))] (cond-> state hover? (update-in [:workspace-grid-edition (first ids) :hover-track] (fnil conj #{}) [type index]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs index b76d8efe2..c0bd4e527 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs @@ -53,6 +53,7 @@ selected? (contains? selected id) highlighted? (contains? highlighted id) + container? (or (cfh/frame-shape? item) (cfh/group-shape? item)) absolute? (ctl/layout-absolute? item) @@ -229,6 +230,7 @@ :id id :class (stl/css-case :layer-row true + :highlight highlighted? :component (some? (:component-id item)) :masked (:masked-group item) :selected selected? @@ -329,6 +331,7 @@ (when-let [item (get objects id)] [:& layer-item {:item item + :highlighted highlighted :selected selected :index index :objects objects diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss b/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss index 6a42cc6a5..a7fd62bac 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss @@ -139,6 +139,7 @@ } } } + &.highlight, &:hover { --context-hover-color: var(--layer-row-foreground-color-hover); --context-hover-opacity: $op-10; @@ -238,12 +239,14 @@ .element-children { background-color: transparent; color: var(--layer-row-foreground-color-selected); - &:hover { - background-color: var(--layer-row-background-color-selected); - } } + &.highlight, &:hover { background-color: var(--layer-row-background-color-selected); + + .element-children { + background-color: var(--layer-row-background-color-selected); + } } } &.type-comp { @@ -295,6 +298,7 @@ } } } + &.highlight, &:hover { .element-list-body { .button-content { @@ -376,6 +380,7 @@ } } } + &.highlight, &:hover { .element-list-body { .button-content { @@ -404,6 +409,7 @@ } } } + &.highlight, &:hover { .element-list-body { .button-content { @@ -437,6 +443,8 @@ } .parent-selected .layer-row { background-color: var(--layer-child-row-background-color); + + &.highlight, &:hover { background-color: var(--layer-row-background-color-hover); &.hidden { @@ -478,6 +486,7 @@ .element-children :global(.layer-row) { background-color: transparent; color: var(--layer-row-foreground-color-hover); + &.highlight, &:hover { background-color: var(--layer-row-background-color-hover); } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss index 04a5f04d9..94a8f9790 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss @@ -224,7 +224,7 @@ .track-info-dir-icon { border-radius: $br-8 0 0 $br-8; background-color: var(--input-background-color); - padding-left: $s-12; + padding: 0 $s-8; svg { @extend .button-icon; From c609d2dec6174c8704d59be39b577959663fcad5 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 5 Dec 2023 16:42:48 +0100 Subject: [PATCH 02/12] :sparkles: Select on track row/column selects cells --- common/src/app/common/types/shape/layout.cljc | 18 +++++++--- .../data/workspace/grid_layout/editor.cljs | 16 +++++++++ .../options/menus/layout_container.cljs | 35 ++++++++++++++----- .../options/menus/layout_container.scss | 5 ++- 4 files changed, 60 insertions(+), 14 deletions(-) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 2259a12e6..5427519bc 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -1146,22 +1146,30 @@ (assoc parent :shapes (into [] (reverse new-shapes))))) -(defn shapes-by-row +(defn cells-by-row [parent index] (->> (:layout-grid-cells parent) (filter (fn [[_ {:keys [row row-span]}]] (and (>= (inc index) row) (< (inc index) (+ row row-span))))) - (map second) - (mapcat :shapes))) + (map second))) -(defn shapes-by-column +(defn cells-by-column [parent index] (->> (:layout-grid-cells parent) (filter (fn [[_ {:keys [column column-span]}]] (and (>= (inc index) column) (< (inc index) (+ column column-span))))) - (map second) + (map second))) + +(defn shapes-by-row + [parent index] + (->> (cells-by-row parent index) + (mapcat :shapes))) + +(defn shapes-by-column + [parent index] + (->> (cells-by-column parent index) (mapcat :shapes))) (defn cells-coordinates diff --git a/frontend/src/app/main/data/workspace/grid_layout/editor.cljs b/frontend/src/app/main/data/workspace/grid_layout/editor.cljs index 82621a7c4..5512447b5 100644 --- a/frontend/src/app/main/data/workspace/grid_layout/editor.cljs +++ b/frontend/src/app/main/data/workspace/grid_layout/editor.cljs @@ -7,6 +7,7 @@ (ns app.main.data.workspace.grid-layout.editor (:require [app.common.geom.rect :as grc] + [app.common.types.shape.layout :as ctl] [app.main.data.workspace.state-helpers :as wsh] [potok.core :as ptk])) @@ -84,3 +85,18 @@ (-> local (update :vbox merge (select-keys srect [:x :y :x1 :x2 :y1 :y2]))))))))))) +(defn select-track-cells + [grid-id type index] + (ptk/reify ::select-track-cells + ptk/UpdateEvent + (update [_ state] + (let [objects (wsh/lookup-page-objects state) + parent (get objects grid-id) + + cells + (if (= type :column) + (ctl/cells-by-column parent index) + (ctl/cells-by-row parent index)) + + selected (into #{} (map :id) cells)] + (assoc-in state [:workspace-grid-edition grid-id :selected] 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 c0adcfe32..4c080c873 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 @@ -957,7 +957,7 @@ value)) (mf/defc grid-track-info - [{:keys [is-col? type index column set-column-value set-column-type remove-element reorder-track hover-track]}] + [{:keys [is-col? type index column set-column-value set-column-type remove-element reorder-track hover-track on-select-track]}] (let [new-css-system (mf/use-ctx ctx/new-css-system) drop-track @@ -978,6 +978,13 @@ (fn [] (hover-track type index false))) + handle-select-track + (mf/use-fn + (mf/deps on-select-track type index) + (fn [] + (when on-select-track + (on-select-track type index)))) + [dprops dref] (h/use-sortable :data-type "penpot/grid-track" @@ -998,7 +1005,8 @@ :on-pointer-leave pointer-leave} [:div {:class (stl/css :track-info-container)} - [:div {:class (stl/css :track-info-dir-icon)} + [:div {:class (stl/css :track-info-dir-icon) + :on-click handle-select-track} (if is-col? i/flex-vertical-refactor i/flex-horizontal-refactor)] [:div {:class (stl/css :track-info-value)} @@ -1057,7 +1065,8 @@ i/minus]]))) (mf/defc grid-columns-row - [{:keys [is-col? expanded? column-values toggle add-new-element set-column-value set-column-type remove-element reorder-track hover-track] :as props}] + [{:keys [is-col? expanded? column-values toggle add-new-element set-column-value set-column-type + remove-element reorder-track hover-track on-select-track] :as props}] (let [new-css-system (mf/use-ctx ctx/new-css-system) column-num (count column-values) @@ -1098,7 +1107,8 @@ :set-column-type set-column-type :remove-element remove-element :reorder-track reorder-track - :hover-track hover-track}])]])] + :hover-track hover-track + :on-select-track on-select-track}])]])] [:div.grid-columns [:div.grid-columns-header @@ -1119,7 +1129,8 @@ :set-column-type set-column-type :remove-element remove-element :reorder-track reorder-track - :hover-track hover-track}])]])]))) + :hover-track hover-track + :on-select-track on-select-track}])]])]))) ;; LAYOUT COMPONENT @@ -1695,6 +1706,12 @@ (fn [type index hover?] (st/emit! (dwsl/hover-layout-track ids type index hover?)))) + handle-select-track + (mf/use-fn + (mf/deps ids) + (fn [type index] + (st/emit! (dwge/select-track-cells (first ids) type index)))) + set-column-value (mf/use-fn (mf/deps ids) @@ -1720,7 +1737,7 @@ handle-locate-grid (mf/use-callback (fn [] - (st/emit! (dwge/locate-board (first ids))))) ] + (st/emit! (dwge/locate-board (first ids)))))] (if new-css-system [:div {:class (stl/css :grid-layout-menu)} @@ -1767,7 +1784,8 @@ :set-column-type set-column-type :remove-element remove-element :reorder-track reorder-track - :hover-track hover-track}] + :hover-track hover-track + :on-select-track handle-select-track}] [:& grid-columns-row {:is-col? false :expanded? @grid-rows-open? @@ -1778,7 +1796,8 @@ :set-column-type set-column-type :remove-element remove-element :reorder-track reorder-track - :hover-track hover-track}]] + :hover-track hover-track + :on-select-track handle-select-track}]] [:div {:class (stl/css :row)} [:& gap-section {:gap-selected? gap-selected? :on-change set-gap diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss index 94a8f9790..97fe318b2 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss @@ -222,15 +222,18 @@ } .track-info-dir-icon { + cursor: pointer; border-radius: $br-8 0 0 $br-8; background-color: var(--input-background-color); padding: 0 $s-8; - svg { @extend .button-icon; stroke: var(--icon-foreground); height: 100%; } + &:hover svg { + stroke: var(--icon-foreground-hover); + } } .track-info-value { From aab53b40bd38e8f43de544b3fe62a312933229d7 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 5 Dec 2023 16:44:42 +0100 Subject: [PATCH 03/12] :bug: Fix problem with highlight and fonts --- frontend/src/app/main/ui/components/code_block.cljs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/main/ui/components/code_block.cljs b/frontend/src/app/main/ui/components/code_block.cljs index 69a54a656..8079cc006 100644 --- a/frontend/src/app/main/ui/components/code_block.cljs +++ b/frontend/src/app/main/ui/components/code_block.cljs @@ -10,6 +10,7 @@ ["highlight.js" :as hljs] [app.common.data.macros :as dm] [app.main.ui.context :as ctx] + [app.util.dom :as dom] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -19,8 +20,10 @@ (let [new-css-system (mf/use-ctx ctx/new-css-system) block-ref (mf/use-ref) code (str/trim code)] - (mf/with-effect [code type] + (mf/with-effect + [code type] (when-let [node (mf/ref-val block-ref)] + (dom/set-data! node "highlighted" nil) (hljs/highlightElement node))) (if new-css-system From 96f2b13d7473714862230b96394de04421d7531c Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 5 Dec 2023 16:47:21 +0100 Subject: [PATCH 04/12] :recycle: Refactor the layers css --- .../main/ui/workspace/sidebar/layer_item.scss | 655 ++++++------------ 1 file changed, 200 insertions(+), 455 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss b/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss index a7fd62bac..876205aec 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss @@ -13,486 +13,231 @@ width: 100%; background-color: var(--layer-row-background-color); - .element-list-body { - display: flex; - align-items: center; - height: $s-32; - width: calc(100% - (var(--depth) * var(--layer-indentation-size))); - padding-right: $s-12; - cursor: pointer; - - &.filtered { - width: calc(100% - $s-12); - } - .button-content { - display: flex; - height: 100%; - .toggle-content { - @include buttonStyle; - display: grid; - grid-template-columns: 1fr 1fr; - align-items: center; - height: 100%; - width: $s-24; - padding: 0 4px 0 8px; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - &.inverse { - svg { - transform: rotate(90deg); - } - .icon-shape { - transform: rotate(-90deg); - } - } - } - .icon-shape { - @include flexCenter; - @include buttonStyle; - position: relative; - justify-self: flex-end; - width: $s-16; - height: 100%; - width: $s-24; - padding: 0 $s-8 0 $s-4; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - - .absolute { - position: absolute; - background-color: var(--layer-row-foreground-color); - opacity: $op-4; - width: $s-12; - height: $s-12; - border-radius: $br-2; - } - } - } - .element-actions { - display: none; - height: 100%; - .toggle-element, - .block-element { - @include buttonStyle; - @include flexCenter; - height: 100%; - width: $s-24; - margin: 0; - display: none; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } - &.selected { - display: flex; - .toggle-element, - .block-element { - display: flex; - opacity: $op-0; - &.selected { - opacity: $op-10; - } - } - } - } - } - .element-children { - width: 100%; - ul { - margin-bottom: 0; - } - &.parent-selected { - .layer-row { - background-color: var(--layer-child-row-background-color); - } - } - } - &.hidden { - .element-list-body { - .button-content { - .toggle-content { - svg { - opacity: $op-7; - } - } - .icon-shape { - svg { - opacity: $op-7; - } - .absolute { - opacity: $op-1; - } - } - } - .element-actions { - .toggle-element, - .block-element { - svg { - opacity: $op-7; - } - } - } - } - } &.highlight, &:hover { --context-hover-color: var(--layer-row-foreground-color-hover); --context-hover-opacity: $op-10; background-color: var(--layer-row-background-color-hover); + color: var(--layer-row-foreground-color-hover); box-shadow: $s-16 0px 0px 0px var(--layer-row-background-color-hover); &.hidden { opacity: $op-10; } - .element-list-body { - .button-content { - .toggle-content { - background-color: var(--layer-row-background-color-hover); - svg { - opacity: $op-10; - stroke: var(--layer-row-foreground-color-hover); - } - } - .icon-shape { - opacity: $op-10; - svg { - stroke: var(--layer-row-foreground-color-hover); - } - & .absolute { - opacity: $op-4; - background-color: var(--layer-row-foreground-color-hover); - } - } - } - .element-actions { - display: flex; - .toggle-element, - .block-element { - display: flex; - svg { - opacity: $op-10; - stroke: var(--layer-row-foreground-color-hover); - } - } - &.selected { - .toggle-element, - .block-element { - opacity: $op-10; - } - } - } - } - .element-children { - .layer-row { - background-color: transparent; - color: var(--layer-row-foreground-color-hover); - &:hover { - background-color: var(--layer-row-background-color-hover); - } - } - } } + &.selected { background-color: var(--layer-row-background-color-selected); box-shadow: $s-16 0px 0px 0px var(--layer-row-background-color-selected); - .element-list-body { - .button-content { - .toggle-content { - background-color: var(--layer-row-background-color-selected); - svg { - stroke: var(--layer-row-foreground-color-selected); - } - } - .icon-shape { - svg { - stroke: var(--layer-row-foreground-color-selected); - } - .absolute { - background-color: var(--layer-row-foreground-color-selected); - } - } - } - .element-actions { - .toggle-element, - .block-element { - display: flex; - svg { - stroke: var(--layer-row-foreground-color-selected); - } - } - &.selected { - .toggle-element, - .block-element { - display: flex; - opacity: $op-10; - &.selected { - opacity: $op-10; - } - } - } - } - } - .element-children { - background-color: transparent; - color: var(--layer-row-foreground-color-selected); - } - &.highlight, - &:hover { - background-color: var(--layer-row-background-color-selected); + } - .element-children { - background-color: var(--layer-row-background-color-selected); - } - } + &.selected.highlight, + &.selected:hover { + background-color: var(--layer-row-background-color-selected); } - &.type-comp { - .button-content { - .toggle-content { - svg { - stroke: var(--layer-row-component-foreground-color); - } - } - .icon-shape { - svg { - stroke: var(--layer-row-component-foreground-color); - } - .absolute { - background-color: var(--layer-row-component-foreground-color); - } - } - } - .element-actions { - .toggle-element, - .block-element { - svg { - stroke: var(--layer-row-component-foreground-color); - } - } - } - .element-children { - color: var(--layer-row-component-foreground-color); - } - &.hidden { - .element-list-body { - .button-content { - .toggle-content { - opacity: $op-7; - } - .icon-shape { - opacity: $op-7; - .absolute { - opacity: $op-1; - } - } - } - .element-actions { - .toggle-element, - .block-element { - svg { - opacity: $op-7; - } - } - } - } - &.highlight, - &:hover { - .element-list-body { - .button-content { - .toggle-content { - opacity: $op-10; - svg { - stroke: var(--layer-row-foreground-color-hover); - } - } - .icon-shape { - opacity: $op-10; - svg { - stroke: var(--layer-row-foreground-color-hover); - } - & .absolute { - opacity: $op-4; - } - } - } - .element-actions { - .toggle-element, - .block-element { - svg { - opacity: $op-10; - stroke: var(--layer-row-foreground-color-hover); - } - } - } - } - } - } + + .parent-selected & { + background-color: var(--layer-child-row-background-color); } - &.type-comp.selected { - .button-content { - .toggle-content { - svg { - stroke: var(--layer-row-component-foreground-color); - } - } - .icon-shape { - svg { - stroke: var(--layer-row-component-foreground-color); - } - .absolute { - background-color: var(--layer-row-component-foreground-color); - } - } - } - .element-actions { - .toggle-element, - .block-element { - svg { - stroke: var(--layer-row-component-foreground-color); - } - } - } - .element-children { - color: var(--layer-row-component-foreground-color); - } - &.hidden { - .element-list-body { - .button-content { - .toggle-content { - opacity: $op-7; - } - .icon-shape { - opacity: $op-7; - .absolute { - opacity: $op-1; - } - } - } - .element-actions { - .toggle-element, - .block-element { - svg { - opacity: $op-7; - } - } - } - } - &.highlight, - &:hover { - .element-list-body { - .button-content { - .toggle-content { - opacity: $op-10; - svg { - stroke: var(--layer-row-foreground-color-hover); - } - } - .icon-shape { - opacity: $op-10; - & .absolute { - opacity: $op-4; - } - } - } - .element-actions { - .toggle-element, - .block-element { - svg { - opacity: $op-10; - stroke: var(--layer-row-foreground-color-hover); - } - } - } - } - } - } - &.highlight, - &:hover { - .element-list-body { - .button-content { - .toggle-content { - svg { - stroke: var(--layer-row-foreground-color-hover); - } - } - .icon-shape { - svg { - stroke: var(--layer-row-foreground-color-hover); - } - } - } - .element-actions { - .toggle-element, - .block-element { - svg { - stroke: var(--layer-row-foreground-color-hover); - } - } - } - } - } - } - &:global(.sticky) { - position: sticky; - top: 0px; - z-index: 3; + + .parent-selected &.highlight, + .parent-selected &:hover { + background-color: var(--layer-row-background-color-hover); } } -.parent-selected .layer-row { - background-color: var(--layer-child-row-background-color); - &.highlight, - &:hover { - background-color: var(--layer-row-background-color-hover); - &.hidden { +.element-children { + .layer-row.highlight &, + .layer-row:hover & { + background-color: var(--layer-row-background-color-selected); + } + .layer-row.type-comp & { + color: var(--layer-row-component-foreground-color); + } + .layer-row.selected & { + background-color: transparent; + color: var(--layer-row-foreground-color-selected); + } +} + +.element-list-body { + display: flex; + align-items: center; + height: $s-32; + width: calc(100% - (var(--depth) * var(--layer-indentation-size))); + padding-right: $s-12; + cursor: pointer; + + &.filtered { + width: calc(100% - $s-12); + } +} + +.element-actions { + display: none; + height: 100%; + &.selected { + display: flex; + } + .layer-row.highlight &, + .layer-row:hover & { + display: flex; + } +} + +.button-content { + display: flex; + height: 100%; +} + +.icon-shape { + @include flexCenter; + @include buttonStyle; + position: relative; + justify-self: flex-end; + width: $s-16; + height: 100%; + width: $s-24; + padding: 0 $s-8 0 $s-4; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + + .layer-row.selected & { + stroke: var(--layer-row-foreground-color-selected); + } + .layer-row.type-comp & { + stroke: var(--layer-row-component-foreground-color); + } + } + .inverse & { + transform: rotate(-90deg); + } + .layer-row.hidden & { + opacity: $op-7; + } + .layer-row.highlight &, + .layer-row:hover & { + opacity: $op-10; + svg { + stroke: var(--layer-row-foreground-color-hover); + } + } +} + +.absolute { + position: absolute; + background-color: var(--layer-row-foreground-color); + opacity: $op-4; + width: $s-12; + height: $s-12; + border-radius: $br-2; + + .layer-row.hidden & { + opacity: $op-1; + } + .layer-row.type-comp & { + background-color: var(--layer-row-component-foreground-color); + } + .layer-row.highlight &, + .layer-row:hover & { + opacity: $op-4; + background-color: var(--layer-row-foreground-color-hover); + } + .layer-row.selected & { + background-color: var(--layer-row-foreground-color-selected); + } +} + +.toggle-content { + @include buttonStyle; + display: grid; + grid-template-columns: 1fr 1fr; + align-items: center; + height: 100%; + width: $s-24; + padding: 0 4px 0 8px; + + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + + .layer-row.hidden & { + opacity: $op-7; + } + .layer-row.type-comp & { + stroke: var(--layer-row-component-foreground-color); + } + .layer-row.highlight &, + .layer-row:hover & { + opacity: $op-10; + stroke: var(--layer-row-foreground-color-hover); + } + + .layer-row.selected & { + stroke: var(--layer-row-foreground-color-selected); + } + } + + .layer-row.selected & { + background-color: var(--layer-row-background-color-selected); + } + &.inverse svg { + transform: rotate(90deg); + } +} + +.toggle-element, +.block-element { + @include buttonStyle; + @include flexCenter; + height: 100%; + width: $s-24; + margin: 0; + display: none; + + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + + .layer-row.hidden & { + opacity: $op-7; + } + .type-comp & { + stroke: var(--layer-row-component-foreground-color); + } + } + + .element-actions.selected & { + display: flex; + opacity: $op-0; + + &.selected { opacity: $op-10; } - .element-list-body { - .button-content { - .toggle-content { - background-color: var(--layer-row-background-color-hover); - svg { - stroke: var(--layer-row-foreground-color-hover); - } - } - .icon-shape { - svg { - stroke: var(--layer-row-foreground-color-hover); - } - .absolute { - background-color: var(--layer-row-foreground-color-hover); - } - } - } - .element-actions { - .toggle-element, - .block-element { - display: flex; - svg { - stroke: var(--layer-row-foreground-color-hover); - } - } - &.selected { - .toggle-element, - .block-element { - opacity: $op-10; - } - } - } + } + + .layer-row.highlight &, + .layer-row:hover & { + display: flex; + svg { + opacity: $op-10; + stroke: var(--layer-row-foreground-color-hover); } - .element-children :global(.layer-row) { - background-color: transparent; - color: var(--layer-row-foreground-color-hover); - &.highlight, - &:hover { - background-color: var(--layer-row-background-color-hover); - } + } + .layer-row.selected & { + display: flex; + svg { + stroke: var(--layer-row-foreground-color-selected); } } } + +:global(.sticky) { + position: sticky; + top: 0px; + z-index: 3; +} + .tab-indentation { display: block; height: $s-16; From 8b2ae380b09cf6f34a307b3a9475545b9dbbb752 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 5 Dec 2023 17:02:08 +0100 Subject: [PATCH 05/12] :bug: Removed locate grid from normal grid menu --- .../sidebar/options/menus/layout_container.cljs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) 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 4c080c873..315c62401 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 @@ -1375,12 +1375,7 @@ handle-open-grid-help (mf/use-callback (fn [] - (st/emit! (dom/open-new-window cf/grid-help-uri)))) - - handle-locate-grid - (mf/use-callback - (fn [] - (st/emit! (dwge/locate-board (first ids)))))] + (st/emit! (dom/open-new-window cf/grid-help-uri))))] (if new-css-system [:div {:class (stl/css :element-set)} @@ -1480,11 +1475,7 @@ :set-justify set-justify-grid}] [:& justify-grid-row {:is-col? false :justify-items grid-justify-content-row - :set-justify set-justify-grid}] - - [:button {:on-click handle-locate-grid - :class (stl/css :locate-button)} - i/locate-refactor]]] + :set-justify set-justify-grid}]]] nil)))] [:div.element-set From e75fb67eec645458ad82c4274e334eb87484f753 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 5 Dec 2023 17:05:46 +0100 Subject: [PATCH 06/12] :bug: Remove negative values from the input in teh grid editor --- .../src/app/main/ui/workspace/viewport/grid_layout_editor.cljs | 1 + 1 file changed, 1 insertion(+) 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 34a674261..2a2c0aa9c 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 @@ -664,6 +664,7 @@ (let [target (-> event dom/get-target) value (-> target dom/get-input-value str/upper) value-int (d/parse-integer value) + value-int (when value-int (max 0 value-int)) [track-type value] (cond From 39b41d7037a4d4dcf6cb20f8305329a895daacb5 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 7 Dec 2023 11:53:02 +0100 Subject: [PATCH 07/12] :sparkles: Reorder grid tracks moving content --- common/src/app/common/types/shape/layout.cljc | 75 ++++++++++++++++--- .../app/main/data/workspace/shape_layout.cljs | 6 +- frontend/src/app/main/ui/formats.cljs | 9 +++ frontend/src/app/main/ui/hooks.cljs | 2 +- .../options/menus/layout_container.cljs | 16 ++-- 5 files changed, 88 insertions(+), 20 deletions(-) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 5427519bc..358f94669 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -705,8 +705,9 @@ (update :layout-grid-cells update-cells) (assign-cells)))) -(defn- reorder-grid-track - [prop parent from-index to-index] +(defn- reorder-grid-tracks + "Swap the positions of the tracks info" + [parent prop from-index to-index] (-> parent (update prop @@ -720,13 +721,70 @@ (d/insert-at-index (inc to-index) [[nil tr]]) (d/vec-without-nils)))))))) +(defn- swap-track-content + "Swap the shapes contained in the given tracks moves as necessary the others." + [parent prop from-track to-track] + (let [remap-tracks + (cond + (> from-track to-track) + (into {from-track to-track} + (map #(vector % (inc %))) + (range to-track from-track)) + (< from-track to-track) + (into {from-track to-track} + (map #(vector % (dec %))) + (range (inc from-track) (inc to-track))))] + (-> parent + (update + :layout-grid-cells + update-vals + (fn [cell] (update cell prop #(get remap-tracks % %))))))) + +(declare resize-cell-area) +(declare cells-by-column) +(declare cells-by-row) + +(defn- reorder-grid-track + [parent from-index to-index move-content? cells-by tracks-props prop prop-span] + (let [from-track (inc from-index) + to-track (if (< to-index from-index) + (+ to-index 2) + (inc to-index)) + move-content? + (and move-content? (not= from-track to-track)) + + parent + (if move-content? + (->> (concat (cells-by parent (dec from-track)) + (cells-by parent (dec to-track))) + (reduce (fn [parent cell] + (cond-> parent + (and (> (get cell prop-span) 1) + (or (> to-track from-track) (not (= to-track (get cell prop)))) + (or (< to-track from-track) (not (= to-track (+ (get cell prop) (dec (get cell prop-span))))))) + (resize-cell-area + (:row cell) + (:column cell) + (:row cell) + (:column cell) + (if (= prop :row) 1 (:row-span cell)) + (if (= prop :column) 1 (:column-span cell))))) + parent)) + parent) + + parent + (reorder-grid-tracks parent tracks-props from-index to-index)] + (cond-> parent + move-content? + (swap-track-content prop from-track to-track)))) + (defn reorder-grid-column - [parent from-index to-index] - (reorder-grid-track :layout-grid-columns parent from-index to-index)) + [parent from-index to-index move-content?] + (reorder-grid-track parent from-index to-index move-content? cells-by-column :layout-grid-columns :column :column-span)) (defn reorder-grid-row - [parent from-index to-index] - (reorder-grid-track :layout-grid-rows parent from-index to-index)) + [parent from-index to-index move-content?] + (reorder-grid-track parent from-index to-index move-content? cells-by-row :layout-grid-rows :row :row-span)) (defn cells-seq [{:keys [layout-grid-cells layout-grid-dir]} & {:keys [sort?] :or {sort? false}}] @@ -992,9 +1050,8 @@ (defn resize-cell-area "Increases/decreases the cell size" [parent row column new-row new-column new-row-span new-column-span] - - (if (and (>= new-row 0) - (>= new-column 0) + (if (and (>= new-row 1) + (>= new-column 1) (>= new-row-span 1) (>= new-column-span 1)) (let [prev-cell (cell-by-row-column parent row column) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 0bdc1e582..c0295a181 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -285,7 +285,7 @@ (dwu/commit-undo-transaction undo-id)))))) (defn reorder-layout-track - [ids type from-index to-index] + [ids type from-index to-index move-content?] (assert (#{:row :column} type)) (ptk/reify ::reorder-layout-track @@ -297,8 +297,8 @@ ids (fn [shape] (case type - :row (ctl/reorder-grid-row shape from-index to-index) - :column (ctl/reorder-grid-column shape from-index to-index)))) + :row (ctl/reorder-grid-row shape from-index to-index move-content?) + :column (ctl/reorder-grid-column shape from-index to-index move-content?)))) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) diff --git a/frontend/src/app/main/ui/formats.cljs b/frontend/src/app/main/ui/formats.cljs index a11c12f84..eb9f2fc52 100644 --- a/frontend/src/app/main/ui/formats.cljs +++ b/frontend/src/app/main/ui/formats.cljs @@ -21,6 +21,15 @@ (let [percent-val (mth/precision (* value 100) precision)] (dm/str percent-val "%")))))) +(defn format-frs + ([value] + (format-frs value nil)) + ([value {:keys [precision] :or {precision 2}}] + (let [value (if (string? value) (d/parse-double value) value)] + (when (d/num? value) + (let [value (mth/precision value precision)] + (dm/str value "fr")))))) + (defn format-number ([value] (format-number value nil)) diff --git a/frontend/src/app/main/ui/hooks.cljs b/frontend/src/app/main/ui/hooks.cljs index f1f607729..d15a87185 100644 --- a/frontend/src/app/main/ui/hooks.cljs +++ b/frontend/src/app/main/ui/hooks.cljs @@ -171,7 +171,7 @@ (cleanup) (rx/push! global-drag-end nil) (when (fn? on-drop) - (on-drop side drop-data)))) + (on-drop side drop-data event)))) on-drag-end (fn [event] 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 315c62401..a2f0764f4 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 @@ -24,10 +24,12 @@ [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar]] [app.main.ui.context :as ctx] + [app.main.ui.formats :as fmt] [app.main.ui.hooks :as h] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] + [app.util.keyboard :as kbd] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -951,9 +953,9 @@ (defn manage-values [{:keys [value type]}] (case type :auto "auto" - :percent (dm/str value "%") - :flex (dm/str value "fr") - :fixed (dm/str value "px") + :percent (fmt/format-percent value) + :flex (fmt/format-frs value) + :fixed (fmt/format-pixels value) value)) (mf/defc grid-track-info @@ -963,8 +965,8 @@ drop-track (mf/use-fn (mf/deps type reorder-track index) - (fn [drop-position data] - (reorder-track type (:index data) (if (= :top drop-position) (dec index) index)))) + (fn [drop-position data event] + (reorder-track type (:index data) (if (= :top drop-position) (dec index) index) (kbd/mod? event)))) pointer-enter (mf/use-fn @@ -1688,8 +1690,8 @@ reorder-track (mf/use-fn (mf/deps ids) - (fn [type from-index to-index] - (st/emit! (dwsl/reorder-layout-track ids type from-index to-index)))) + (fn [type from-index to-index move-content?] + (st/emit! (dwsl/reorder-layout-track ids type from-index to-index move-content?)))) hover-track (mf/use-fn From f6c2d0646dc32a361635e9c5ea288fe1afd494a1 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 7 Dec 2023 14:24:19 +0100 Subject: [PATCH 08/12] :bug: Fix problem with grid components thumbnails --- frontend/src/app/main/render.cljs | 71 +++++++++++++++++-- frontend/src/app/main/ui/shapes/frame.cljs | 8 +-- .../main/ui/shapes/grid_layout_viewer.cljs | 4 +- .../ui/workspace/sidebar/assets/common.cljs | 32 +++++---- 4 files changed, 89 insertions(+), 26 deletions(-) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index 89f1e3288..8e46f895a 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -26,6 +26,7 @@ [app.common.types.file :as ctf] [app.common.types.modifiers :as ctm] [app.common.types.shape-tree :as ctst] + [app.common.types.shape.layout :as ctl] [app.config :as cfg] [app.main.fonts :as fonts] [app.main.ui.context :as muc] @@ -34,6 +35,7 @@ [app.main.ui.shapes.embed :as embed] [app.main.ui.shapes.export :as export] [app.main.ui.shapes.frame :as frame] + [app.main.ui.shapes.grid-layout-viewer :refer [grid-layout-viewer]] [app.main.ui.shapes.group :as group] [app.main.ui.shapes.image :as image] [app.main.ui.shapes.path :as path] @@ -304,11 +306,22 @@ :fill "none"} [:& shape-wrapper {:shape frame}]]])) +(mf/defc empty-grids + {::mf/wrap-props false} + [{:keys [root-shape-id objects]}] + (let [empty-grids + (->> (cons root-shape-id (cfh/get-children-ids objects root-shape-id)) + (filter #(ctl/grid-layout? objects %)) + (map #(get objects %)) + (filter #(empty? (:shapes %))))] + (for [grid empty-grids] + [:& grid-layout-viewer {:shape grid :objects objects}]))) + ;; Component for rendering a thumbnail of a single componenent. Mainly ;; used to render thumbnails on assets panel. (mf/defc component-svg {::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]} - [{:keys [objects root-shape zoom] :or {zoom 1} :as props}] + [{:keys [objects root-shape show-grids? zoom] :or {zoom 1} :as props}] (when root-shape (let [root-shape-id (:id root-shape) include-metadata (mf/use-ctx export/include-metadata-ctx) @@ -350,9 +363,59 @@ :xmlns:penpot (when include-metadata "https://penpot.app/xmlns") :fill "none"} - [:> shape-container {:shape root-shape'} - [:& (mf/provider muc/is-component?) {:value true} - [:& root-shape-wrapper {:shape root-shape' :view-box vbox}]]]]))) + [:* + [:> shape-container {:shape root-shape'} + [:& (mf/provider muc/is-component?) {:value true} + [:& root-shape-wrapper {:shape root-shape' :view-box vbox}]]] + + (when show-grids? + [:& empty-grids {:root-shape-id root-shape-id :objects objects}])]]))) + +(mf/defc component-svg-thumbnail + {::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]} + [{:keys [thumbnail-uri on-error show-grids? + objects root-shape zoom] :or {zoom 1} :as props}] + + (when root-shape + (let [root-shape-id (:id root-shape) + + vector + (mf/use-memo + (mf/deps (:x root-shape) (:y root-shape)) + (fn [] + (-> (gpt/point (:x root-shape) (:y root-shape)) + (gpt/negate)))) + + objects + (mf/use-memo + (mf/deps vector objects root-shape-id) + (fn [] + (let [children-ids (cons root-shape-id (cfh/get-children-ids objects root-shape-id)) + update-fn #(update %1 %2 gsh/transform-shape (ctm/move-modifiers vector))] + (reduce update-fn objects children-ids)))) + + root-shape' (get objects root-shape-id) + + width (:width root-shape' 0) + height (:height root-shape' 0) + width-zoom (* (:width root-shape') zoom) + height-zoom (* (:height root-shape') zoom) + vbox (format-viewbox {:width width :height height})] + + [:svg {:view-box vbox + :width (ust/format-precision width-zoom viewbox-decimal-precision) + :height (ust/format-precision height-zoom viewbox-decimal-precision) + :version "1.1" + :xmlns "http://www.w3.org/2000/svg" + :xmlnsXlink "http://www.w3.org/1999/xlink" + :fill "none"} + [:foreignObject {:x 0 :y 0 :width width :height height } + [:img {:src thumbnail-uri + :on-error on-error + :loading "lazy" + :decoding "async"}]] + (when show-grids? + [:& empty-grids {:root-shape-id root-shape-id :objects objects}])]))) (mf/defc object-svg {::mf/wrap [mf/memo]} diff --git a/frontend/src/app/main/ui/shapes/frame.cljs b/frontend/src/app/main/ui/shapes/frame.cljs index 6d8753c12..c7398d130 100644 --- a/frontend/src/app/main/ui/shapes/frame.cljs +++ b/frontend/src/app/main/ui/shapes/frame.cljs @@ -15,7 +15,6 @@ [app.main.ui.context :as muc] [app.main.ui.shapes.attrs :as attrs] [app.main.ui.shapes.custom-stroke :refer [shape-fills shape-strokes]] - [app.main.ui.shapes.grid-layout-viewer :refer [grid-layout-viewer]] [app.util.debug :as dbg] [app.util.object :as obj] [rumext.v2 :as mf])) @@ -165,7 +164,6 @@ [props] (let [shape (unchecked-get props "shape") childs (unchecked-get props "childs") - is-component? (mf/use-ctx muc/is-component?) childs (cond-> childs (ctl/any-layout? shape) (cfh/sort-layout-children-z-index))] @@ -175,9 +173,5 @@ (for [item childs] (let [id (dm/get-prop item :id)] (when (some? id) - [:& shape-wrapper {:key (dm/str id) :shape item}])))] - - (when (and ^boolean is-component? - ^boolean (empty? childs)) - [:& grid-layout-viewer {:shape shape :childs childs}])]))) + [:& shape-wrapper {:key (dm/str id) :shape item}])))]]))) diff --git a/frontend/src/app/main/ui/shapes/grid_layout_viewer.cljs b/frontend/src/app/main/ui/shapes/grid_layout_viewer.cljs index a5d7486a3..6138d81ac 100644 --- a/frontend/src/app/main/ui/shapes/grid_layout_viewer.cljs +++ b/frontend/src/app/main/ui/shapes/grid_layout_viewer.cljs @@ -15,7 +15,6 @@ [app.common.geom.shapes.grid-layout :as gsg] [app.common.geom.shapes.points :as gpo] [app.common.types.shape.layout :as ctl] - [app.main.refs :as refs] [rumext.v2 :as mf])) (mf/defc grid-cell-area-label @@ -85,9 +84,8 @@ {::mf/wrap-props false} [props] (let [shape (unchecked-get props "shape") - objects (mf/deref refs/workspace-page-objects) + objects (unchecked-get props "objects") bounds (d/lazy-map (keys objects) #(gsh/shape->points (get objects %))) - children (->> (cfh/get-immediate-children objects (:id shape)) (remove :hidden) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs index 0409d4445..53cd48ac6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs @@ -19,7 +19,7 @@ [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.undo :as dwu] [app.main.refs :as refs] - [app.main.render :refer [component-svg]] + [app.main.render :refer [component-svg component-svg-thumbnail]] [app.main.store :as st] [app.main.ui.components.context-menu :refer [context-menu]] [app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]] @@ -283,18 +283,26 @@ {::mf/wrap-props false} [{:keys [file-id root-shape component container]}] (let [retry (mf/use-state 0) - thumbnail-uri (get-component-thumbnail-uri file-id component)] - (if (some? thumbnail-uri) - [:img {:src thumbnail-uri - :on-error (fn [] - (when (@retry < 3) - (inc retry))) - :loading "lazy" - :decoding "async" - :class (dom/classnames (css :thumbnail) true)}] - [:& component-svg {:root-shape root-shape - :objects (:objects container)}]))) + thumbnail-uri (get-component-thumbnail-uri file-id component) + handle-error + (mf/use-fn + (mf/deps @retry) + (fn [] + (when (@retry < 3) + (inc retry))))] + (if (some? thumbnail-uri) + [:& component-svg-thumbnail + {:thumbnail-uri thumbnail-uri + :on-error handle-error + :root-shape root-shape + :objects (:objects container) + :show-grids? true}] + + [:& component-svg + {:root-shape root-shape + :objects (:objects container) + :show-grids? true}]))) (defn generate-components-menu-entries [shapes components-v2] From dc2c83bb624e22220559b2a7476437e1e3329b27 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 7 Dec 2023 16:20:41 +0100 Subject: [PATCH 09/12] :bug: Fix problems with absolute positioning and hidden elements --- common/src/app/common/geom/modifiers.cljc | 7 +++---- .../src/app/common/geom/shapes/constraints.cljc | 13 +++++++------ .../geom/shapes/flex_layout/layout_data.cljc | 6 +++++- .../geom/shapes/grid_layout/layout_data.cljc | 2 +- .../geom/shapes/grid_layout/positions.cljc | 2 +- common/src/app/common/types/shape/layout.cljc | 17 ++++++++++++----- .../src/app/main/data/workspace/modifiers.cljs | 2 +- .../app/main/data/workspace/shape_layout.cljs | 2 +- .../src/app/main/data/workspace/transforms.cljs | 4 ++-- frontend/src/app/main/ui/measurements.cljs | 4 ++-- .../main/ui/viewer/inspect/left_sidebar.cljs | 2 +- .../main/ui/workspace/sidebar/layer_item.cljs | 2 +- .../sidebar/options/menus/layout_item.cljs | 4 ++-- .../sidebar/options/menus/measures.cljs | 2 +- .../workspace/sidebar/options/shapes/bool.cljs | 2 +- .../sidebar/options/shapes/circle.cljs | 2 +- .../workspace/sidebar/options/shapes/frame.cljs | 2 +- .../workspace/sidebar/options/shapes/group.cljs | 2 +- .../workspace/sidebar/options/shapes/image.cljs | 2 +- .../workspace/sidebar/options/shapes/path.cljs | 2 +- .../workspace/sidebar/options/shapes/rect.cljs | 2 +- .../sidebar/options/shapes/svg_raw.cljs | 2 +- .../workspace/sidebar/options/shapes/text.cljs | 2 +- frontend/src/app/util/code_gen/common.cljs | 2 +- frontend/src/app/util/code_gen/style_css.cljs | 2 +- .../src/app/util/code_gen/style_css_values.cljs | 10 +++++----- 26 files changed, 56 insertions(+), 45 deletions(-) diff --git a/common/src/app/common/geom/modifiers.cljc b/common/src/app/common/geom/modifiers.cljc index 6c76ff87c..58d694204 100644 --- a/common/src/app/common/geom/modifiers.cljc +++ b/common/src/app/common/geom/modifiers.cljc @@ -82,7 +82,6 @@ children (->> children (keep (d/getf objects)) - (remove :hidden) (remove gco/invalid-geometry?) (map (partial apply-modifiers bounds))) @@ -169,13 +168,13 @@ children-modifiers (if (or flex-layout? grid-layout?) (->> (:shapes parent) - (filter #(ctl/layout-absolute? objects %))) + (filter #(ctl/position-absolute? objects %))) (:shapes parent)) children-layout (when (or flex-layout? grid-layout?) (->> (:shapes parent) - (remove #(ctl/layout-absolute? objects %))))] + (remove #(ctl/position-absolute? objects %))))] (cond-> modif-tree (and has-modifiers? parent? (not root?)) @@ -222,7 +221,7 @@ (ctm/resize (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent))))) children (->> (cfh/get-immediate-children objects parent-id) - (remove :hidden) + (remove ctl/position-absolute?) (remove gco/invalid-geometry?)) content-bounds diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 995d97541..3a2ab58b2 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -299,7 +299,7 @@ ignore-constraints :scale - (and (ctl/any-layout? parent) (not (ctl/layout-absolute? child))) + (and (ctl/any-layout? parent) (not (ctl/position-absolute? child))) :left :else @@ -310,7 +310,7 @@ ignore-constraints :scale - (and (ctl/any-layout? parent) (not (ctl/layout-absolute? child))) + (and (ctl/any-layout? parent) (not (ctl/position-absolute? child))) :top :else @@ -335,13 +335,14 @@ child-bounds (gtr/transform-bounds child-bounds modifiers) parent-bounds transformed-parent-bounds)) - transformed-child-bounds (if reset-modifiers? - child-bounds - (gtr/transform-bounds child-bounds modifiers))] + transformed-child-bounds + (if reset-modifiers? + child-bounds + (gtr/transform-bounds child-bounds modifiers))] ;; If the parent is a layout we don't need to calculate its constraints. Finish ;; after normalize the children (to keep proper proportions) - (if (ctl/any-layout? parent) + (if (and (ctl/any-layout? parent) (not (ctl/position-absolute? child))) modifiers (let [child-points-before (gpo/parent-coords-bounds child-bounds parent-bounds) child-points-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds) diff --git a/common/src/app/common/geom/shapes/flex_layout/layout_data.cljc b/common/src/app/common/geom/shapes/flex_layout/layout_data.cljc index 9a8dafd5c..7d7b2da25 100644 --- a/common/src/app/common/geom/shapes/flex_layout/layout_data.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/layout_data.cljc @@ -421,8 +421,12 @@ reverse? (ctl/reverse? shape) children (cond->> children (not reverse?) reverse) + ignore-child? + (fn [[_ child]] + (ctl/position-absolute? child)) + ;; Don't take into account absolute children - children (->> children (remove (comp ctl/layout-absolute? second))) + children (->> children (remove ignore-child?)) ;; Creates the layout lines information layout-lines 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 fa07db760..bbec1aba7 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 @@ -424,7 +424,7 @@ children (->> children - (remove #(ctl/layout-absolute? (second %)))) + (remove #(ctl/position-absolute? (second %)))) children-map (into {} diff --git a/common/src/app/common/geom/shapes/grid_layout/positions.cljc b/common/src/app/common/geom/shapes/grid_layout/positions.cljc index 8fe6d7698..e6504519f 100644 --- a/common/src/app/common/geom/shapes/grid_layout/positions.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/positions.cljc @@ -178,7 +178,7 @@ position-delta (child-position-delta parent child child-bounds child-width child-height layout-data cell-data)] (cond-> (ctm/empty) - (not (ctl/layout-absolute? child)) + (not (ctl/position-absolute? child)) (-> (ctm/add-modifiers fill-modifiers) (ctm/move position-delta))))) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 358f94669..f384c96e3 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -491,12 +491,19 @@ (defn align-self-stretch? [{:keys [layout-item-align-self]}] (= :stretch layout-item-align-self)) -(defn layout-absolute? +(defn item-absolute? ([objects id] - (layout-absolute? (get objects id))) + (item-absolute? (get objects id))) ([shape] (true? (:layout-item-absolute shape)))) +(defn position-absolute? + ([objects id] + (position-absolute? (get objects id))) + ([shape] + (or (item-absolute? shape) + (:hidden shape)))) + (defn layout-z-index ([objects id] (layout-z-index (get objects id))) @@ -509,11 +516,11 @@ (auto-width? objects frame-id) (or (and (col? objects frame-id) (->> children-ids - (remove (partial layout-absolute? objects)) + (remove (partial position-absolute? objects)) (every? (partial fill-width? objects)))) (and (row? objects frame-id) (->> children-ids - (remove (partial layout-absolute? objects)) + (remove (partial position-absolute? objects)) (some (partial fill-width? objects))))))) (defn change-v-sizing? @@ -1169,7 +1176,7 @@ (update :shapes #(d/removev children %)) (assign-cells)) - children (->> children (remove #(layout-absolute? objects %)))] + children (->> children (remove #(position-absolute? objects %)))] (-> frame (update :shapes d/concat-vec children) diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index afbe0590f..4e36feefa 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -193,7 +193,7 @@ (update :shapes #(d/removev ids %)) (ctl/assign-cells)) - ids (->> ids (remove #(ctl/layout-absolute? objects %))) + ids (->> ids (remove #(ctl/position-absolute? objects %))) frame (-> frame (update :shapes d/concat-vec ids) (cond-> (some? cell) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index c0295a181..ea9b6c5fa 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -361,7 +361,7 @@ all-children (->> parent :shapes (map (d/getf objects)) - (remove ctl/layout-absolute?))] + (remove ctl/position-absolute?))] (cond-> shape ;; If the parent is hug width and the direction column diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 9f3434396..580d06367 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -721,7 +721,7 @@ selected (wsh/lookup-selected state {:omit-blocked? true}) selected-shapes (->> selected (map (d/getf objects)))] (if (every? #(and (ctl/any-layout-immediate-child? objects %) - (not (ctl/layout-absolute? %))) + (not (ctl/position-absolute? %))) selected-shapes) (rx/of (reorder-selected-layout-child direction)) (rx/of (nudge-selected-shapes direction shift?))))))) @@ -829,7 +829,7 @@ moving-shapes (->> moving-shapes (remove (fn [shape] - (and (ctl/layout-absolute? shape) + (and (ctl/position-absolute? shape) (= frame-id (:parent-id shape)))))) frame-component diff --git a/frontend/src/app/main/ui/measurements.cljs b/frontend/src/app/main/ui/measurements.cljs index bee6bf1d9..f1245d86d 100644 --- a/frontend/src/app/main/ui/measurements.cljs +++ b/frontend/src/app/main/ui/measurements.cljs @@ -16,6 +16,7 @@ [app.common.geom.shapes.points :as gpo] [app.common.math :as mth] [app.common.types.modifiers :as ctm] + [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.main.data.workspace.modifiers :as dwm] [app.main.data.workspace.state-helpers :as wsh] @@ -693,8 +694,7 @@ objects (wsh/lookup-page-objects @st/state) children (->> (cfh/get-immediate-children objects frame-id) - (remove :layout-item-absolute) - (remove :hidden)) + (remove ctl/position-absolute?)) children-to-display (if (or (= :row-reverse saved-dir) (= :column-reverse saved-dir)) diff --git a/frontend/src/app/main/ui/viewer/inspect/left_sidebar.cljs b/frontend/src/app/main/ui/viewer/inspect/left_sidebar.cljs index 0e858f2fc..9ab407a62 100644 --- a/frontend/src/app/main/ui/viewer/inspect/left_sidebar.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/left_sidebar.cljs @@ -46,7 +46,7 @@ (make-collapsed-iref id)) expanded? (not (mf/deref collapsed-iref)) - absolute? (ctl/layout-absolute? item) + absolute? (ctl/item-absolute? item) toggle-collapse (fn [event] (dom/stop-propagation event) diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs index c0bd4e527..0d65094eb 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs @@ -56,7 +56,7 @@ container? (or (cfh/frame-shape? item) (cfh/group-shape? item)) - absolute? (ctl/layout-absolute? item) + absolute? (ctl/item-absolute? item) components-v2 (mf/use-ctx ctx/components-v2) read-only? (mf/use-ctx ctx/workspace-read-only?) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index 08ca3fa2f..207423787 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -378,7 +378,7 @@ selection-parents-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) selection-parents (mf/deref selection-parents-ref) - is-absolute? (:layout-item-absolute values) + is-absolute? (:layout-item-absolute values) is-col? (every? ctl/col? selection-parents) @@ -510,7 +510,7 @@ (when open? [:div {:class (stl/css :flex-element-menu)} [:div {:class (stl/css :row)} - (when is-flex-parent? + (when (or is-layout-child? is-absolute?) [:div {:class (stl/css :position-options)} [:& radio-buttons {:selected (if is-absolute? "absolute" "static") :on-change on-change-position 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 cfbd1727f..fc408f592 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 @@ -93,7 +93,7 @@ selection-parents (mf/deref selection-parents-ref) flex-child? (->> selection-parents (some ctl/flex-layout?)) - absolute? (ctl/layout-absolute? shape) + absolute? (ctl/item-absolute? shape) flex-container? (ctl/flex-layout? shape) flex-auto-width? (ctl/auto-width? shape) flex-fill-width? (ctl/fill-width? 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 1eb56073c..40337bdc5 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 @@ -41,7 +41,7 @@ is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent? (mf/deref is-grid-parent-ref) - is-layout-child-absolute? (ctl/layout-absolute? shape) + is-layout-child-absolute? (ctl/item-absolute? shape) ids (hooks/use-equal-memo ids) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-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 e28fd2ff4..bf2128d87 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 @@ -43,7 +43,7 @@ is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent? (mf/deref is-grid-parent-ref) - is-layout-child-absolute? (ctl/layout-absolute? shape) + is-layout-child-absolute? (ctl/item-absolute? shape) ids (hooks/use-equal-memo ids) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-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 995bc35da..6a3110123 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 @@ -49,7 +49,7 @@ is-grid-parent? (mf/deref is-grid-parent-ref) is-layout-container? (ctl/any-layout? shape) - is-layout-child-absolute? (ctl/layout-absolute? shape) + is-layout-child-absolute? (ctl/item-absolute? shape) ids (hooks/use-equal-memo ids) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-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 8d2336b31..2a65a3e69 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 @@ -50,7 +50,7 @@ is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent? (mf/deref is-grid-parent-ref) - is-layout-child-absolute? (ctl/layout-absolute? shape) + is-layout-child-absolute? (ctl/item-absolute? shape) ids (hooks/use-equal-memo ids) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) 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 881ce65e1..0e08630bc 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 @@ -43,7 +43,7 @@ is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent? (mf/deref is-grid-parent-ref) - is-layout-child-absolute? (ctl/layout-absolute? shape) + is-layout-child-absolute? (ctl/item-absolute? shape) ids (hooks/use-equal-memo ids) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-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 929cb4e68..776e7f327 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 @@ -43,7 +43,7 @@ is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent? (mf/deref is-grid-parent-ref) - is-layout-child-absolute? (ctl/layout-absolute? shape) + is-layout-child-absolute? (ctl/item-absolute? shape) ids (hooks/use-equal-memo ids) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-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 7603870d6..33fbc2862 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 @@ -46,7 +46,7 @@ is-grid-parent* (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent? (mf/deref is-grid-parent*) - is-layout-child-absolute? (ctl/layout-absolute? shape) + is-layout-child-absolute? (ctl/item-absolute? shape) parents-by-ids* (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) parents (mf/deref parents-by-ids*)] 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 40cfc8083..66ff3f574 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 @@ -116,7 +116,7 @@ is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent? (mf/deref is-grid-parent-ref) - is-layout-child-absolute? (ctl/layout-absolute? shape) + is-layout-child-absolute? (ctl/item-absolute? shape) ids (hooks/use-equal-memo ids) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) 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 94f339d86..4fa04b35f 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 @@ -40,7 +40,7 @@ is-grid-parent? (mf/deref is-grid-parent-ref) layout-container-values (select-keys shape layout-container-flex-attrs) - is-layout-child-absolute? (ctl/layout-absolute? shape) + is-layout-child-absolute? (ctl/item-absolute? shape) ids (hooks/use-equal-memo ids) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) diff --git a/frontend/src/app/util/code_gen/common.cljs b/frontend/src/app/util/code_gen/common.cljs index 5292c11db..733543150 100644 --- a/frontend/src/app/util/code_gen/common.cljs +++ b/frontend/src/app/util/code_gen/common.cljs @@ -61,6 +61,6 @@ [objects shape] ;; Layout children with a transform should be wrapped (and (ctl/any-layout-immediate-child? objects shape) - (not (ctl/layout-absolute? shape)) + (not (ctl/position-absolute? shape)) (not (gmt/unit? (:transform shape))))) diff --git a/frontend/src/app/util/code_gen/style_css.cljs b/frontend/src/app/util/code_gen/style_css.cljs index 7a3f9d376..197e883ff 100644 --- a/frontend/src/app/util/code_gen/style_css.cljs +++ b/frontend/src/app/util/code_gen/style_css.cljs @@ -133,7 +133,7 @@ body { [:height height]] (or (not (ctl/any-layout-immediate-child? objects shape)) - (not (ctl/layout-absolute? shape))) + (not (ctl/position-absolute? shape))) (conj [:position "relative"]))))) (defn shape->wrapper-child-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 2b4586c8a..3659d33a2 100644 --- a/frontend/src/app/util/code_gen/style_css_values.cljs +++ b/frontend/src/app/util/code_gen/style_css_values.cljs @@ -31,7 +31,7 @@ [_ shape objects] (cond (or (and (ctl/any-layout-immediate-child? objects shape) - (not (ctl/layout-absolute? shape)) + (not (ctl/position-absolute? shape)) (or (cfh/group-like-shape? shape) (cfh/frame-shape? shape) (cgc/svg-markup? shape))) @@ -39,7 +39,7 @@ :relative (and (ctl/any-layout-immediate-child? objects shape) - (not (ctl/layout-absolute? shape))) + (not (ctl/position-absolute? shape))) nil :else @@ -50,7 +50,7 @@ (when (and (not (cfh/root-frame? shape)) (or (not (ctl/any-layout-immediate-child? objects shape)) - (ctl/layout-absolute? shape))) + (ctl/position-absolute? shape))) (let [parent (get objects (:parent-id shape)) @@ -291,7 +291,7 @@ (defn get-grid-coord [shape objects prop span-prop] (when (and (ctl/grid-layout-immediate-child? objects shape) - (not (ctl/layout-absolute? shape))) + (not (ctl/position-absolute? shape))) (let [parent (get objects (:parent-id shape)) cell (ctl/get-cell-by-shape-id parent (:id shape))] (when (and @@ -314,7 +314,7 @@ (defmethod get-value :grid-area [_ shape objects] (when (and (ctl/grid-layout-immediate-child? objects shape) - (not (ctl/layout-absolute? shape))) + (not (ctl/position-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))) From 92dc8ae416f715fcacde9b00b36f095acec49b25 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 7 Dec 2023 16:45:00 +0100 Subject: [PATCH 10/12] :bug: Select hidden layers on enter key --- frontend/src/app/main/data/workspace.cljs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 4cbfa451a..aa84170ed 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1039,9 +1039,7 @@ (rx/of (dwe/start-edition-mode id)) (:group :bool :frame) - (let [shapes-ids (into (d/ordered-set) - (remove #(dm/get-in objects [% :hidden])) - shapes)] + (let [shapes-ids (into (d/ordered-set) shapes)] (rx/of (dws/select-shapes shapes-ids))) :svg-raw From dfd8ff96b745ec59493c8ee1ac40638990610a1d Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 7 Dec 2023 16:47:17 +0100 Subject: [PATCH 11/12] :bug: Add change type of layout button --- .../sidebar/options/menus/layout_container.cljs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) 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 a2f0764f4..07d5f2c2f 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 @@ -1391,7 +1391,18 @@ [:div {:class (stl/css :title-actions)} [:button {:class (stl/css :remove-layout) :on-click on-remove-layout} - i/remove-refactor]] + i/remove-refactor] + + (when ^boolean grid-enabled? + [:* + [:button {:class (stl/css :add-layout) + :on-click handle-show-layout-dropdown} + i/menu-refactor] + + [:& dropdown {:show show-layout-dropdown? :on-close handle-close-layout-options} + [:div {:class (stl/css :layout-options)} + [:button {:class (stl/css :layout-option) :on-click set-flex} "Flex layout"] + [:button {:class (stl/css :layout-option) :on-click set-grid} "Grid layout"]]]])] [:div {:class (stl/css :title-actions)} (if ^boolean grid-enabled? From a0a479b08cf19cdd94ff15c18d14ba184c74c3e1 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 11 Dec 2023 13:06:17 +0100 Subject: [PATCH 12/12] :recycle: Changed layers component to reuse it in viewer --- .../main/ui/viewer/inspect/left_sidebar.cljs | 202 +++++++++----- .../main/ui/viewer/inspect/left_sidebar.scss | 22 ++ .../main/ui/workspace/sidebar/layer_item.cljs | 260 +++++++++++------- .../main/ui/workspace/sidebar/layer_item.scss | 18 +- .../app/main/ui/workspace/sidebar/layers.cljs | 2 +- 5 files changed, 325 insertions(+), 179 deletions(-) create mode 100644 frontend/src/app/main/ui/viewer/inspect/left_sidebar.scss diff --git a/frontend/src/app/main/ui/viewer/inspect/left_sidebar.cljs b/frontend/src/app/main/ui/viewer/inspect/left_sidebar.cljs index 9ab407a62..51c3d9dc7 100644 --- a/frontend/src/app/main/ui/viewer/inspect/left_sidebar.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/left_sidebar.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.viewer.inspect.left-sidebar + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -15,7 +16,9 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.shape-icon :as si] + [app.main.ui.context :as ctx] [app.main.ui.icons :as i] + [app.main.ui.workspace.sidebar.layer-item :refer [layer-item-inner]] [app.main.ui.workspace.sidebar.layer-name :refer [layer-name]] [app.util.dom :as dom] [app.util.keyboard :as kbd] @@ -28,43 +31,55 @@ (l/derived st/state))) (mf/defc layer-item - [{:keys [item selected objects disable-collapse?] :as props}] - (let [id (:id item) - name (:name item) - hidden? (:hidden item) - touched? (-> item :touched seq boolean) + [{:keys [item selected objects disable-collapse? depth component-child? hide-toggle?] :as props}] + (let [new-css-system (mf/use-ctx ctx/new-css-system) + id (:id item) + name (:name item) + hidden? (:hidden item) + touched? (-> item :touched seq boolean) selected? (contains? selected id) item-ref (mf/use-ref nil) + depth (+ depth 1) - file (mf/deref refs/viewer-file) - components-v2 (dm/get-in file [:data :options :components-v2]) - main-instance? (if components-v2 - (ctk/main-instance? item) - true) - collapsed-iref (mf/use-memo - (mf/deps id) - (make-collapsed-iref id)) + file (mf/deref refs/viewer-file) + components-v2 (dm/get-in file [:data :options :components-v2]) + + main-instance? + (if components-v2 + (ctk/main-instance? item) + true) + + component-tree? (or component-child? (:component-root item)) + + collapsed-iref + (mf/use-memo + (mf/deps id) + (make-collapsed-iref id)) expanded? (not (mf/deref collapsed-iref)) absolute? (ctl/item-absolute? item) + toggle-collapse - (fn [event] - (dom/stop-propagation event) - (st/emit! (dv/toggle-collapse id))) + (mf/use-callback + (mf/deps id) + (fn [event] + (dom/stop-propagation event) + (st/emit! (dv/toggle-collapse id)))) select-shape - (fn [event] - (dom/prevent-default event) - (let [id (:id item)] - (cond - (kbd/mod? event) - (st/emit! (dv/toggle-selection id)) + (mf/use-callback + (mf/deps id) + (fn [event] + (dom/prevent-default event) + (cond + (kbd/mod? event) + (st/emit! (dv/toggle-selection id)) - (kbd/shift? event) - (st/emit! (dv/shift-select-to id)) + (kbd/shift? event) + (st/emit! (dv/shift-select-to id)) - :else - (st/emit! (dv/select-shape id)))))] + :else + (st/emit! (dv/select-shape id)))))] (mf/use-effect (mf/deps selected) @@ -72,55 +87,102 @@ (when (and (= (count selected) 1) selected?) (dom/scroll-into-view-if-needed! (mf/ref-val item-ref) true)))) - [:li {:ref item-ref - :class (dom/classnames - :component (not (nil? (:component-id item))) - :masked (:masked-group item) - :selected selected?)} + (if new-css-system + [:& layer-item-inner + {:ref item-ref + :item item + :depth depth + :read-only? true + :highlighted? false + :selected? selected? + :component-tree? component-tree? + :hidden? hidden? + :filtered? false + :expanded? expanded? + :hide-toggle? hide-toggle? + :on-select-shape select-shape + :on-toggle-collapse toggle-collapse} - [:div.element-list-body {:class (dom/classnames :selected selected? - :icon-layer (= (:type item) :icon)) - :on-click select-shape} - [:div.icon - (when absolute? - [:div.absolute i/position-absolute]) - [:& si/element-icon {:shape item :main-instance? main-instance?}]] - [:& layer-name {:shape-id id - :shape-name name - :shape-touched? touched? - :hidden? hidden? - :selected? selected? - :type-frame (cfh/frame-shape? item) - :disabled-double-click true}] + (when (and (:shapes item) expanded?) + [:div {:class (stl/css-case + :element-children true + :parent-selected selected?)} + (for [[index id] (reverse (d/enumerate (:shapes item)))] + (when-let [item (get objects id)] + [:& layer-item + {:item item + :selected selected + :index index + :objects objects + :key (dm/str id) + :depth depth + :component-child? component-tree?}]))])] - (when (and (not disable-collapse?) (:shapes item)) - [:span.toggle-content - {:on-click toggle-collapse - :class (when expanded? "inverse")} - i/arrow-slide])] + ;; OLD + [:li {:ref item-ref + :class (dom/classnames + :component (not (nil? (:component-id item))) + :masked (:masked-group item) + :selected selected?)} - (when (and (:shapes item) expanded?) - [:ul.element-children - (for [[index id] (reverse (d/enumerate (:shapes item)))] - (when-let [item (get objects id)] - [:& layer-item - {:item item - :selected selected - :index index - :objects objects - :key (:id item)}]))])])) + [:div.element-list-body {:class (dom/classnames :selected selected? + :icon-layer (= (:type item) :icon)) + :on-click select-shape} + [:div.icon + (when absolute? + [:div.absolute i/position-absolute]) + [:& si/element-icon {:shape item :main-instance? main-instance?}]] + [:& layer-name {:shape-id id + :shape-name name + :shape-touched? touched? + :hidden? hidden? + :selected? selected? + :type-frame (cfh/frame-shape? item) + :disabled-double-click true}] + + (when (and (not disable-collapse?) (:shapes item)) + [:span.toggle-content + {:on-click toggle-collapse + :class (when expanded? "inverse")} + i/arrow-slide])] + + (when (and (:shapes item) expanded?) + [:ul.element-children + (for [[index id] (reverse (d/enumerate (:shapes item)))] + (when-let [item (get objects id)] + [:& layer-item + {:item item + :selected selected + :index index + :objects objects + :key (:id item)}]))])]))) (mf/defc left-sidebar [{:keys [frame page local]}] - (let [selected (:selected local) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + selected (:selected local) objects (:objects page)] - [:aside.settings-bar.settings-bar-left - [:div.settings-bar-inside - [:ul.element-list - [:& layer-item - {:item frame - :selected selected - :index 0 - :objects objects - :disable-collapse? true}]]]])) + (if new-css-system + [:aside {:class (stl/css :settings-bar-left)} + [:div {:class (stl/css :settings-bar-inside)} + [:div {:class (stl/css :element-list)} + [:& layer-item + {:item frame + :selected selected + :index 0 + :objects objects + :sortable? false + :filtered? false + :depth -2 + :hide-toggle? true}]]]] + + [:aside.settings-bar.settings-bar-left + [:div.settings-bar-inside + [:ul.element-list + [:& layer-item + {:item frame + :selected selected + :index 0 + :objects objects + :disable-collapse? true}]]]]))) diff --git a/frontend/src/app/main/ui/viewer/inspect/left_sidebar.scss b/frontend/src/app/main/ui/viewer/inspect/left_sidebar.scss new file mode 100644 index 000000000..889d480ad --- /dev/null +++ b/frontend/src/app/main/ui/viewer/inspect/left_sidebar.scss @@ -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 + +@use "common/refactor/common-refactor.scss" as *; + +.settings-bar-left { + background-color: $db-primary; + height: 100%; + width: $s-256; +} + +.settings-bar-inside { + display: grid; + grid-template-columns: 100%; + grid-template-rows: 100%; + height: calc(100% - $s-2); + overflow-y: auto; + padding-top: $s-8; +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs index 0d65094eb..ea01a4bae 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs @@ -32,6 +32,129 @@ [okulary.core :as l] [rumext.v2 :as mf])) +(mf/defc layer-item-inner + {::mf/wrap-props false + ::mf/forward-ref true} + [{:keys [item depth parent-size name-ref children + ;; Flags + read-only? highlighted? selected? component-tree? + filtered? expanded? dnd-over? dnd-over-top? dnd-over-bot? hide-toggle? + ;; Callbacks + on-select-shape on-context-menu on-pointer-enter on-pointer-leave on-zoom-to-selected + on-toggle-collapse on-enable-drag on-disable-drag on-toggle-visibility on-toggle-blocking]} + dref] + + (let [id (:id item) + name (:name item) + blocked? (:blocked item) + hidden? (:hidden item) + has-shapes? (-> item :shapes seq boolean) + touched? (-> item :touched seq boolean) + parent-board? (and (cfh/frame-shape? item) + (= uuid/zero (:parent-id item))) + absolute? (ctl/item-absolute? item) + components-v2 (mf/use-ctx ctx/components-v2) + main-instance? (or (not components-v2) (:main-instance item))] + [:* + [:div {:id id + :ref dref + :on-click on-select-shape + :on-context-menu on-context-menu + :class (stl/css-case + :layer-row true + :highlight highlighted? + :component (some? (:component-id item)) + :masked (:masked-group item) + :selected selected? + :type-frame (cfh/frame-shape? item) + :type-bool (cfh/bool-shape? item) + :type-comp component-tree? + :hidden hidden? + :dnd-over dnd-over? + :dnd-over-top dnd-over-top? + :dnd-over-bot dnd-over-bot? + :root-board parent-board?)} + [:span {:class (stl/css-case + :tab-indentation true + :filtered filtered?) + :style {"--depth" depth}}] + [:div {:class (stl/css-case + :element-list-body true + :filtered filtered? + :selected selected? + :icon-layer (= (:type item) :icon)) + :style {"--depth" depth} + :on-pointer-enter on-pointer-enter + :on-pointer-leave on-pointer-leave + :on-double-click dom/stop-propagation} + + (if (< 0 (count (:shapes item))) + [:div {:class (stl/css :button-content)} + (when (and (not hide-toggle?) (not filtered?)) + [:button {:class (stl/css-case + :toggle-content true + :inverse expanded?) + :on-click on-toggle-collapse} + i/arrow-refactor]) + + [:div {:class (stl/css :icon-shape) + :on-double-click on-zoom-to-selected} + (when absolute? + [:div {:class (stl/css :absolute)}]) + + [:& sic/element-icon-refactor + {:shape item + :main-instance? main-instance?}]]] + + [:div {:class (stl/css :button-content)} + (when (not ^boolean filtered?) + [:span {:class (stl/css :toggle-content)}]) + [:div {:class (stl/css :icon-shape) + :on-double-click on-zoom-to-selected} + (when ^boolean absolute? + [:div {:class (stl/css :absolute)}]) + [:& sic/element-icon-refactor + {:shape item + :main-instance? main-instance?}]]]) + + [:& layer-name {:ref name-ref + :shape-id id + :shape-name name + :shape-touched? touched? + :disabled-double-click read-only? + :on-start-edit on-disable-drag + :on-stop-edit on-enable-drag + :depth depth + :parent-size parent-size + :selected? selected? + :type-comp component-tree? + :type-frame (cfh/frame-shape? item) + :hidden? hidden?}] + (when (not read-only?) + [:div {:class (stl/css-case + :element-actions true + :is-parent has-shapes? + :selected hidden? + :selected blocked?)} + [:button {:class (stl/css-case + :toggle-element true + :selected hidden?) + :title (if hidden? + (tr "workspace.shape.menu.show") + (tr "workspace.shape.menu.hide")) + :on-click on-toggle-visibility} + (if ^boolean hidden? i/hide-refactor i/shown-refactor)] + [:button {:class (stl/css-case + :block-element true + :selected blocked?) + :title (if (:blocked item) + (tr "workspace.shape.menu.unlock") + (tr "workspace.shape.menu.lock")) + :on-click on-toggle-blocking} + (if ^boolean blocked? i/lock-refactor i/unlock-refactor)]])]] + + children])) + (mf/defc layer-item {::mf/wrap-props false} [{:keys [index item selected objects sortable? filtered? depth parent-size component-child? highlighted]}] @@ -211,114 +334,44 @@ (let [scroll-to @scroll-to-middle?] (ts/schedule 100 - #(let [scroll-distance-ratio (dom/get-scroll-distance-ratio node scroll-node) - scroll-behavior (if (> scroll-distance-ratio 1) "instant" "smooth")] - (if scroll-to - (dom/scroll-into-view! first-child-node #js {:block "center" :behavior scroll-behavior :inline "start"}) - (do - (dom/scroll-into-view-if-needed! first-child-node #js {:block "center" :behavior scroll-behavior :inline "start"}) - (reset! scroll-to-middle? true)))))))] + #(when (and node scroll-node) + (let [scroll-distance-ratio (dom/get-scroll-distance-ratio node scroll-node) + scroll-behavior (if (> scroll-distance-ratio 1) "instant" "smooth")] + (if scroll-to + (dom/scroll-into-view! first-child-node #js {:block "center" :behavior scroll-behavior :inline "start"}) + (do + (dom/scroll-into-view-if-needed! first-child-node #js {:block "center" :behavior scroll-behavior :inline "start"}) + (reset! scroll-to-middle? true))))))))] #(when (some? subid) (rx/dispose! subid)))) (if new-css-system - [:* - [:div {:on-context-menu on-context-menu - :ref dref - :on-click select-shape - :id id - :class (stl/css-case - :layer-row true - :highlight highlighted? - :component (some? (:component-id item)) - :masked (:masked-group item) - :selected selected? - :type-frame (cfh/frame-shape? item) - :type-bool (cfh/bool-shape? item) - :type-comp component-tree? - :hidden hidden? - :dnd-over (= (:over dprops) :center) - :dnd-over-top (= (:over dprops) :top) - :dnd-over-bot (= (:over dprops) :bot) - :root-board parent-board?)} - [:span {:class (stl/css-case - :tab-indentation true - :filtered filtered?) - :style {"--depth" depth}}] - [:div {:class (stl/css-case - :element-list-body true - :filtered filtered? - :selected selected? - :icon-layer (= (:type item) :icon)) - :style {"--depth" depth} - :on-pointer-enter on-pointer-enter - :on-pointer-leave on-pointer-leave - :on-double-click dom/stop-propagation} - - (if (< 0 (count (:shapes item))) - [:div {:class (stl/css :button-content)} - (when (not filtered?) - [:button {:class (stl/css-case - :toggle-content true - :inverse expanded?) - :on-click toggle-collapse} - i/arrow-refactor]) - - [:div {:class (stl/css :icon-shape) - :on-double-click zoom-to-selected} - (when absolute? - [:div {:class (stl/css :absolute)}]) - - [:& sic/element-icon-refactor - {:shape item - :main-instance? main-instance?}]]] - - [:div {:class (stl/css :button-content)} - (when (not ^boolean filtered?) - [:span {:class (stl/css :toggle-content)}]) - [:div {:class (stl/css :icon-shape) - :on-double-click zoom-to-selected} - (when ^boolean absolute? - [:div {:class (stl/css :absolute)}]) - [:& sic/element-icon-refactor - {:shape item - :main-instance? main-instance?}]]]) - - [:& layer-name {:ref ref - :shape-id id - :shape-name name - :shape-touched? touched? - :disabled-double-click read-only? - :on-start-edit disable-drag - :on-stop-edit enable-drag - :depth depth - :parent-size parent-size - :selected? selected? - :type-comp component-tree? - :type-frame (cfh/frame-shape? item) - :hidden? hidden?}] - [:div {:class (stl/css-case - :element-actions true - :is-parent has-shapes? - :selected hidden? - :selected blocked?)} - [:button {:class (stl/css-case - :toggle-element true - :selected hidden?) - :title (if hidden? - (tr "workspace.shape.menu.show") - (tr "workspace.shape.menu.hide")) - :on-click toggle-visibility} - (if ^boolean hidden? i/hide-refactor i/shown-refactor)] - [:button {:class (stl/css-case - :block-element true - :selected blocked?) - :title (if (:blocked item) - (tr "workspace.shape.menu.unlock") - (tr "workspace.shape.menu.lock")) - :on-click toggle-blocking} - (if ^boolean blocked? i/lock-refactor i/unlock-refactor)]]]] + [:& layer-item-inner + {:ref dref + :item item + :depth depth + :parent-size parent-size + :name-ref ref + :read-only? read-only? + :highlighted? highlighted? + :selected? selected? + :component-tree? component-tree? + :filtered? filtered? + :expanded? expanded? + :dnd-over? (= (:over dprops) :center) + :dnd-over-top? (= (:over dprops) :top) + :dnd-over-bot? (= (:over dprops) :bot) + :on-select-shape select-shape + :on-context-menu on-context-menu + :on-pointer-enter on-pointer-enter + :on-pointer-leave on-pointer-leave + :on-zoom-to-selected zoom-to-selected + :on-toggle-collapse toggle-collapse + :on-enable-drag enable-drag + :on-disable-drag disable-drag + :on-toggle-visibility toggle-visibility + :on-toggle-blocking toggle-blocking} (when (and (:shapes item) expanded?) [:div {:class (stl/css-case @@ -326,7 +379,6 @@ :parent-selected selected? :sticky-children parent-board?) :data-id (when ^boolean parent-board? id)} - (for [[index id] (reverse (d/enumerate (:shapes item)))] (when-let [item (get objects id)] [:& layer-item diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss b/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss index 876205aec..f3209a29d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.scss @@ -12,6 +12,7 @@ align-items: center; width: 100%; background-color: var(--layer-row-background-color); + border: 2px solid transparent; &.highlight, &:hover { @@ -43,6 +44,16 @@ .parent-selected &:hover { background-color: var(--layer-row-background-color-hover); } + + &.dnd-over-bot { + border-bottom: $s-2 solid var(--layer-row-foreground-color-hover); + } + &.dnd-over-top { + border-bottom: $s-2 solid var(--layer-row-foreground-color-hover); + } + &.dnd-over { + border: $s-2 solid var(--layer-row-foreground-color-hover); + } } .element-children { @@ -164,6 +175,9 @@ .layer-row.hidden & { opacity: $op-7; } + .layer-row.selected & { + stroke: var(--layer-row-foreground-color-selected); + } .layer-row.type-comp & { stroke: var(--layer-row-component-foreground-color); } @@ -172,10 +186,6 @@ opacity: $op-10; stroke: var(--layer-row-foreground-color-hover); } - - .layer-row.selected & { - stroke: var(--layer-row-foreground-color-selected); - } } .layer-row.selected & { diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs index 335676754..60f26c46d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs @@ -47,7 +47,7 @@ highlighted (hooks/use-equal-memo highlighted) root (get objects uuid/zero) new-css-system (mf/use-ctx ctx/new-css-system)] - [:ul + [:div {:class (stl/css new-css-system :element-list)} [:& hooks/sortable-container {} (for [[index id] (reverse (d/enumerate (:shapes root)))]