diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index a12bb40fe..c997c05c0 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -882,3 +882,15 @@ ([pred coll] (transduce (take-until pred) conj [] coll))) +(defn safe-subvec + "Wrapper around subvec so it doesn't throw an exception but returns nil instead" + ([v start] + (when (and (some? v) + (> start 0) (< start (count v))) + (subvec v start))) + ([v start end] + (let [size (count v)] + (when (and (some? v) + (>= start 0) (< start size) + (>= end 0) (<= start end) (<= end size)) + (subvec v start end))))) diff --git a/common/src/app/common/geom/point.cljc b/common/src/app/common/geom/point.cljc index 20680e816..bbb63ec2a 100644 --- a/common/src/app/common/geom/point.cljc +++ b/common/src/app/common/geom/point.cljc @@ -495,6 +495,12 @@ (pos->Point (if (mth/almost-zero? x) 0.001 x) (if (mth/almost-zero? y) 0.001 y)))) +(defn resize + "Creates a new vector with the same direction but different length" + [vector new-length] + (let [old-length (length vector)] + (scale vector (/ new-length old-length)))) + ;; FIXME: perfromance (defn abs [point] @@ -522,3 +528,4 @@ :class Point :wfn #(into {} %) :rfn map->Point}) + 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 eb7695615..c07aa9f7b 100644 --- a/common/src/app/common/geom/shapes/grid_layout/positions.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/positions.cljc @@ -25,32 +25,32 @@ (let [hv #(gpo/start-hv layout-bounds %) vv #(gpo/start-vv layout-bounds %) - span-column-tracks (subvec column-tracks (dec column) (+ (dec column) column-span)) - span-row-tracks (subvec row-tracks (dec row) (+ (dec row) row-span)) + span-column-tracks (d/safe-subvec column-tracks (dec column) (+ (dec column) column-span)) + span-row-tracks (d/safe-subvec row-tracks (dec row) (+ (dec row) row-span))] - p1 - (gpt/add - origin - (gpt/add - (gpt/to-vec origin (dm/get-in span-column-tracks [0 :start-p])) - (gpt/to-vec origin (dm/get-in span-row-tracks [0 :start-p])))) + (when (and span-column-tracks span-row-tracks) + (let [p1 + (gpt/add + origin + (gpt/add + (gpt/to-vec origin (dm/get-in span-column-tracks [0 :start-p])) + (gpt/to-vec origin (dm/get-in span-row-tracks [0 :start-p])))) - p2 - (as-> p1 $ - (reduce (fn [p track] (gpt/add p (hv (:size track)))) $ span-column-tracks) - (gpt/add $ (hv (* column-gap (dec (count span-column-tracks)))))) + p2 + (as-> p1 $ + (reduce (fn [p track] (gpt/add p (hv (:size track)))) $ span-column-tracks) + (gpt/add $ (hv (* column-gap (dec (count span-column-tracks)))))) - p3 - (as-> p2 $ - (reduce (fn [p track] (gpt/add p (vv (:size track)))) $ span-row-tracks) - (gpt/add $ (vv (* row-gap (dec (count span-row-tracks)))))) + p3 + (as-> p2 $ + (reduce (fn [p track] (gpt/add p (vv (:size track)))) $ span-row-tracks) + (gpt/add $ (vv (* row-gap (dec (count span-row-tracks)))))) - p4 - (as-> p1 $ - (reduce (fn [p track] (gpt/add p (vv (:size track)))) $ span-row-tracks) - (gpt/add $ (vv (* row-gap (dec (count span-row-tracks))))))] - - [p1 p2 p3 p4])) + p4 + (as-> p1 $ + (reduce (fn [p track] (gpt/add p (vv (:size track)))) $ span-row-tracks) + (gpt/add $ (vv (* row-gap (dec (count span-row-tracks))))))] + [p1 p2 p3 p4])))) (defn calc-fill-width-data "Calculates the size and modifiers for the width of an auto-fill child" diff --git a/frontend/gulpfile.js b/frontend/gulpfile.js index 6e561569a..82290f29a 100644 --- a/frontend/gulpfile.js +++ b/frontend/gulpfile.js @@ -28,6 +28,8 @@ paths.resources = "./resources/"; paths.output = "./resources/public/"; paths.dist = "./target/dist/"; +const touchSourceOnStyleChange = true; + /*********************************************** * Marked Extensions ***********************************************/ @@ -282,12 +284,15 @@ gulp.task("dev:dirs", async function(next) { }); gulp.task("watch:main", function() { - gulp.watch("src/**/**.scss", gulp.series("scss")) - .on("change", function(path) { + const watchTask = gulp.watch("src/**/**.scss", gulp.series("scss")); + + if (touchSourceOnStyleChange) { + watchTask.on("change", function(path) { // Replace ".scss" for ".cljs" to refresh the file - gulp.src(path.replace(".scss", ".cljs")) - .pipe(touch()); + gulp.src(path.replace(".scss", ".cljs")).pipe(touch()); }); + } + gulp.watch(paths.resources + "styles/**/**.scss", gulp.series("scss")); gulp.watch(paths.resources + "images/**/*", gulp.series("copy:assets:images")); diff --git a/frontend/resources/images/icons/align-content-column-stretch-refactor.svg b/frontend/resources/images/icons/align-content-column-stretch-refactor.svg new file mode 100644 index 000000000..3acb2ce22 --- /dev/null +++ b/frontend/resources/images/icons/align-content-column-stretch-refactor.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/images/icons/align-content-row-stretch-refactor.svg b/frontend/resources/images/icons/align-content-row-stretch-refactor.svg new file mode 100644 index 000000000..1dcf6c421 --- /dev/null +++ b/frontend/resources/images/icons/align-content-row-stretch-refactor.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/styles/common/refactor/basic-rules.scss b/frontend/resources/styles/common/refactor/basic-rules.scss index 553842f5d..8c84e486a 100644 --- a/frontend/resources/styles/common/refactor/basic-rules.scss +++ b/frontend/resources/styles/common/refactor/basic-rules.scss @@ -316,6 +316,10 @@ color: var(--input-foreground-color-active); background-color: var(--input-background-color-active); } + &[disabled] { + opacity: 0.5; + pointer-events: none; + } } .input-icon { diff --git a/frontend/resources/styles/common/refactor/color-defs.scss b/frontend/resources/styles/common/refactor/color-defs.scss index f9d7e1061..41b0077ce 100644 --- a/frontend/resources/styles/common/refactor/color-defs.scss +++ b/frontend/resources/styles/common/refactor/color-defs.scss @@ -16,7 +16,9 @@ --green: #91fadb; --green-30: rgba(145, 250, 219, 0.3); --lilac: #bb97d8; + --pink: #ff6fe0; --strong-green: #00d1b8; + // NOTIFICATION --dark-ok-color: var(--strong-green); --dark-warning-color: #ff9b49; diff --git a/frontend/resources/styles/common/refactor/design-tokens.scss b/frontend/resources/styles/common/refactor/design-tokens.scss index 8af861164..db7638b9f 100644 --- a/frontend/resources/styles/common/refactor/design-tokens.scss +++ b/frontend/resources/styles/common/refactor/design-tokens.scss @@ -250,4 +250,13 @@ --comment-bullet-foreground-color-resolved: var(--color-foreground-secondary); --comment-bullet-border-color-resolved: var(--color-background-quaternary); --comment-modal-background-color: var(--color-background-primary); + + // GRID LAYOUT + --grid-editor-marker-color: var(--color-foreground-tertiary); + --grid-editor-marker-text: var(--color-foreground-tertiary); + --grid-editor-area-background: var(--color-foreground-tertiary); + --grid-editor-area-text: var(--color-foreground-tertiary); + --grid-editor-line-color: var(--color-foreground-tertiary); + --grid-editor-plus-btn-foreground: var(--white); + --grid-editor-plus-btn-background: var(--color-foreground-tertiary); } diff --git a/frontend/resources/styles/common/refactor/spacing.scss b/frontend/resources/styles/common/refactor/spacing.scss index cdacbd4a4..b956d7cd1 100644 --- a/frontend/resources/styles/common/refactor/spacing.scss +++ b/frontend/resources/styles/common/refactor/spacing.scss @@ -74,6 +74,7 @@ $s-380: calc(var(--s-4) * 95); $s-400: calc(var(--s-4) * 100); $s-480: calc(var(--s-4) * 120); $s-500: calc(var(--s-4) * 125); +$s-512: calc(var(--s-4) * 128); $s-520: calc(var(--s-4) * 130); $s-664: calc(var(--s-4) * 166); $s-712: calc(var(--s-4) * 178); diff --git a/frontend/resources/styles/common/refactor/themes/default-theme.scss b/frontend/resources/styles/common/refactor/themes/default-theme.scss index 35b7e1b68..cfbead3b8 100644 --- a/frontend/resources/styles/common/refactor/themes/default-theme.scss +++ b/frontend/resources/styles/common/refactor/themes/default-theme.scss @@ -13,6 +13,7 @@ --color-background-disabled: var(--off-white); --color-foreground-primary: var(--white); --color-foreground-secondary: var(--off-white); + --color-foreground-tertiary: var(--pink); --color-foreground-disabled: var(--dark-gray-4); --color-accent-primary: var(--green); --color-accent-primary-muted: var(--green-30); diff --git a/frontend/resources/styles/common/refactor/themes/light-theme.scss b/frontend/resources/styles/common/refactor/themes/light-theme.scss index c41da5d0f..8c7698ddd 100644 --- a/frontend/resources/styles/common/refactor/themes/light-theme.scss +++ b/frontend/resources/styles/common/refactor/themes/light-theme.scss @@ -13,6 +13,7 @@ --color-background-disabled: var(--light-gray-4); --color-foreground-primary: var(--black); --color-foreground-secondary: var(--off-black); + --color-foreground-tertiary: var(--pink); --color-foreground-disabled: var(--light-gray-1); --color-accent-primary: var(--purple); --color-accent-primary-muted: var(--purple-30); diff --git a/frontend/src/app/main/data/workspace/edition.cljs b/frontend/src/app/main/data/workspace/edition.cljs index 0c5e4220e..f5e3b3486 100644 --- a/frontend/src/app/main/data/workspace/edition.cljs +++ b/frontend/src/app/main/data/workspace/edition.cljs @@ -7,6 +7,8 @@ (ns app.main.data.workspace.edition (:require [app.common.data.macros :as dm] + [app.common.types.shape.layout :as ctl] + [app.main.data.workspace.common :as dwc] [app.main.data.workspace.state-helpers :as wsh] [beicon.core :as rx] [potok.core :as ptk])) @@ -31,11 +33,16 @@ state))) ptk/WatchEvent - (watch [_ _ stream] - (->> stream - (rx/filter interrupt?) - (rx/take 1) - (rx/map (constantly clear-edition-mode)))))) + (watch [_ state stream] + (let [objects (wsh/lookup-page-objects state)] + (rx/concat + (if (ctl/grid-layout? objects id) + (rx/of (dwc/hide-toolbar)) + (rx/empty)) + (->> stream + (rx/filter interrupt?) + (rx/take 1) + (rx/map (constantly clear-edition-mode)))))))) ;; If these event change modules review /src/app/main/data/workspace/path/undo.cljs (def clear-edition-mode diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index 9d87eeff3..b24abe32d 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -9,6 +9,7 @@ (:require-macros [app.main.ui.icons :refer [icon-xref]]) (:require [app.common.data :as d] + [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -275,11 +276,13 @@ (def align-content-column-evenly-refactor (icon-xref :align-content-column-evenly-refactor)) (def align-content-column-start-refactor (icon-xref :align-content-column-start-refactor)) (def align-content-column-end-refactor (icon-xref :align-content-column-end-refactor)) +(def align-content-column-stretch-refactor (icon-xref :align-content-column-stretch-refactor)) (def align-content-row-end-refactor (icon-xref :align-content-row-end-refactor)) (def align-content-row-around-refactor (icon-xref :align-content-row-around-refactor)) (def align-content-row-between-refactor (icon-xref :align-content-row-between-refactor)) (def align-content-row-evenly-refactor (icon-xref :align-content-row-evenly-refactor)) (def align-content-row-start-refactor (icon-xref :align-content-row-start-refactor)) +(def align-content-row-stretch-refactor (icon-xref :align-content-row-stretch-refactor)) (def align-horizontal-center-refactor (icon-xref :align-horizontal-center-refactor)) (def align-vertical-center-refactor (icon-xref :align-vertical-center-refactor)) (def align-items-row-center-refactor (icon-xref :align-items-row-center-refactor)) @@ -474,12 +477,29 @@ (mf/defc debug-icons-preview {::mf/wrap-props false} [] - [:section.debug-icons-preview - (for [[key val] (sort-by first (ns-publics 'app.main.ui.icons))] - (when (not= key 'debug-icons-preview) - [:div.icon-item {:key key} - (deref val) - [:span (pr-str key)]]))]) + [:* + [:section.debug-icons-preview + [:h2 "Classic"] + [:* + (for [[key val] (->> (ns-publics 'app.main.ui.icons) + (sort-by first) + (remove (fn [[key _]] + (str/ends-with? (str key) "-refactor"))))] + (when (not= key 'debug-icons-preview) + [:div.icon-item {:key key} + (deref val) + [:span (pr-str key)]]))]] + + [:section.debug-icons-preview + [:h2 "Refactor"] + [:* + (for [[key val] (->> (ns-publics 'app.main.ui.icons) + (sort-by first) + (filter (fn [[key _]] (str/ends-with? (str key) "-refactor"))))] + (when (not= key 'debug-icons-preview) + [:div.icon-item {:key key} + (deref val) + [:span (pr-str key)]]))]]]) (defn key->icon [icon-key] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs index d1fb4e255..e19f46c1b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.grid-cell + (:require-macros [app.main.style :as stl]) (:require [app.common.attrs :as attrs] [app.common.data :as d] @@ -15,10 +16,14 @@ [app.main.data.workspace.shape-layout :as dwsl] [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input*]] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] + [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.hooks :as hooks] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.menus.layout-container :as lyc] [app.util.dom :as dom] + [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) (def cell-props [:id @@ -33,25 +38,58 @@ (mf/defc set-self-alignment [{:keys [is-col? alignment set-alignment] :as props}] - (let [dir-v [:auto :start :center :end :stretch #_:baseline] - alignment (or alignment :auto)] - [:div.align-self-style - (for [align dir-v] - [:button.align-self.tooltip.tooltip-bottom - {:class (dom/classnames :active (= alignment align) - :tooltip-bottom-left (not= align :start) - :tooltip-bottom (= align :start)) - :alt (dm/str "Align self " (d/name align)) ;; TODO fix this tooltip - :on-click #(set-alignment align) - :key (str "align-self" align)} - (lyc/get-layout-flex-icon :align-self align is-col?)])])) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + dir-v [:auto :start :center :end :stretch #_:baseline] + alignment (or alignment :auto) + type (if is-col? "col" "row")] + + (if new-css-system + [:div {:class (stl/css :self-align-menu)} + [:& radio-buttons {:selected (d/name alignment) + :on-change #(set-alignment (keyword %)) + :name (dm/str "flex-align-items-" type)} + [:& radio-button {:value "start" + :icon (if is-col? i/align-self-row-left-refactor i/align-self-column-top-refactor) + :title "Align self start" + :id (dm/str "align-self-start-" type)}] + + [:& radio-button {:value "center" + :icon (if is-col? i/align-self-row-center-refactor i/align-self-column-center-refactor) + :title "Align self center" + :id (dm/str "align-self-center-" type)}] + + [:& radio-button {:value "end" + :icon (if is-col? i/align-self-row-right-refactor i/align-self-column-bottom-refactor) + :title "Align self end" + :id (dm/str "align-self-end-" type)}] + + [:& radio-button {:value "stretch" + :icon (if is-col? i/align-self-row-strech i/align-self-column-strech) + :title "Align self stretch" + :id (dm/str "align-self-stretch-" type)}]]] + + [:div.align-self-style + (for [align dir-v] + [:button.align-self.tooltip.tooltip-bottom + {:class (dom/classnames :active (= alignment align) + :tooltip-bottom-left (not= align :start) + :tooltip-bottom (= align :start)) + :alt (dm/str "Align self " (d/name align)) ;; TODO fix this tooltip + :on-click #(set-alignment align) + :key (str "align-self" align)} + (lyc/get-layout-flex-icon :align-self align is-col?)])]))) (mf/defc options {::mf/wrap [mf/memo]} [{:keys [shape cell cells] :as props}] - (let [cells (hooks/use-equal-memo cells) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + + state* (mf/use-state {:open true}) + open? (:open @state*) + + cells (hooks/use-equal-memo cells) cell (or cell (attrs/get-attrs-multi cells cell-props)) multiple? (= :multiple (:id cell)) @@ -126,7 +164,8 @@ (mf/use-callback (mf/deps (:id shape) cell-ids) (fn [mode] - (st/emit! (dwsl/change-cells-mode (:id shape) cell-ids mode)))) + (let [mode (-> mode keyword)] + (st/emit! (dwsl/change-cells-mode (:id shape) cell-ids mode))))) toggle-edit-mode (mf/use-fn @@ -135,106 +174,207 @@ (st/emit! (dw/start-edition-mode (:id shape)) (dwge/clear-selection (:id shape)))))] - [:div.element-set - [:div.element-set-title - [:span "Grid Cell"]] - [:div.element-set-content.layout-grid-item-menu - [:div.layout-row - [:div.row-title.sizing "Position"] - [:div.position-wrapper - [:button.position-btn - {:on-click #(set-cell-mode :auto) - :class (dom/classnames :active (= :auto cell-mode))} "Auto"] - (when-not multiple? + (if new-css-system + [:div {:class (stl/css :grid-cell-menu)} + [:div {:class (stl/css :grid-cell-menu-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed #(swap! state* update :open not) + :title "Grid cell"}]] + + (when open? + [:div {:class (stl/css :grid-cell-menu-container)} + [:div {:class (stl/css :cell-mode :row)} + [:& radio-buttons {:selected (d/name cell-mode) + :on-change set-cell-mode + :name "cell-mode" + :wide true} + [:& radio-button {:value "auto" :id :auto}] + [:& radio-button {:value "manual" :id :manual}] + [:& radio-button {:value "area" :id :area}]]] + + (when (= :area cell-mode) + [:div {:class (stl/css :row)} + [:input + {:class (stl/css :area-input) + :key (dm/str "name-" (:id cell)) + :id "grid-area-name" + :type "text" + :aria-label "grid-area-name" + :placeholder "Area name" + :default-value area-name + :auto-complete "off" + :on-change on-area-name-change}]]) + + (when (and (not multiple?) (= :auto cell-mode)) + [:div {:class (stl/css :row)} + [:div {:class (stl/css :grid-coord-group)} + [:span {:class (stl/css :icon)} i/layout-rows] + [:div {:class (stl/css :coord-input)} + [:> numeric-input* + {:placeholder "--" + :on-click #(dom/select-target %) + :on-change (partial on-grid-coordinates :all :column) + :value column}]]] + + [:div {:class (stl/css :grid-coord-group)} + [:span {:class (stl/css :icon)} i/layout-columns] + [:div {:class (stl/css :coord-input)} + [:> numeric-input* + {:placeholder "--" + :on-click #(dom/select-target %) + :on-change (partial on-grid-coordinates :all :row) + :value row}]]]]) + + (when (and (not multiple?) (or (= :manual cell-mode) (= :area cell-mode))) + [:div {:class (stl/css :row)} + [:div {:class (stl/css :grid-coord-group)} + [:span {:class (stl/css :icon)} i/layout-rows] + [:div {:class (stl/css :coord-input)} + [:> numeric-input* + {:placeholder "--" + :on-pointer-down #(dom/select-target %) + :on-change (partial on-grid-coordinates :start :column) + :value column}]] + [:div {:class (stl/css :coord-input)} + [:> numeric-input* + {:placeholder "--" + :on-pointer-down #(dom/select-target %) + :on-change (partial on-grid-coordinates :end :column) + :value column-end}]]] + + [:div {:class (stl/css :grid-coord-group)} + [:span {:class (stl/css :icon)} i/layout-columns] + [:div {:class (stl/css :coord-input :double)} + [:> numeric-input* + {:placeholder "--" + :on-pointer-down #(dom/select-target %) + :on-change (partial on-grid-coordinates :start :row) + :value row}]] + [:div {:class (stl/css :coord-input)} + [:> numeric-input* + {:placeholder "--" + :on-pointer-down #(dom/select-target %) + :on-change (partial on-grid-coordinates :end :row) + :value row-end}]]]]) + + [:div {:class (stl/css :row)} + [:& set-self-alignment {:is-col? false + :alignment align-self + :set-alignment set-alignment}] + [:& set-self-alignment {:is-col? true + :alignment justify-self + :set-alignment set-justify-self}]] + + [:div {:class (stl/css :row)} + [:button + {:class (stl/css :edit-grid-btn) + :alt (tr "workspace.layout_grid.editor.options.edit-grid") + :on-click toggle-edit-mode} + (tr "workspace.layout_grid.editor.options.edit-grid")]]])] + + + [:div.element-set + [:div.element-set-title + [:span "Grid Cell"]] + + [:div.element-set-content.layout-grid-item-menu + [:div.layout-row + [:div.row-title.sizing "Position"] + [:div.position-wrapper [:button.position-btn - {:on-click #(set-cell-mode :manual) - :class (dom/classnames :active (= :manual cell-mode))} "Manual"]) - [:button.position-btn - {:on-click #(set-cell-mode :area) - :disabled (not valid-area-cells?) - :class (dom/classnames :active (= :area cell-mode))} "Area"]]] + {:on-click #(set-cell-mode :auto) + :class (dom/classnames :active (= :auto cell-mode))} "Auto"] + (when-not multiple? + [:button.position-btn + {:on-click #(set-cell-mode :manual) + :class (dom/classnames :active (= :manual cell-mode))} "Manual"]) + [:button.position-btn + {:on-click #(set-cell-mode :area) + :disabled (not valid-area-cells?) + :class (dom/classnames :active (= :area cell-mode))} "Area"]]] - [:div.manage-grid-columns - (when (and (not multiple?) (= :auto cell-mode)) - [:div.grid-auto - [:div.grid-columns-auto - [:span.icon i/layout-rows] + [:div.manage-grid-columns + (when (and (not multiple?) (= :auto cell-mode)) + [:div.grid-auto + [:div.grid-columns-auto + [:span.icon i/layout-rows] + [:div.input-wrapper + [:> numeric-input* + {:placeholder "--" + :on-click #(dom/select-target %) + :on-change (partial on-grid-coordinates :all :column) + :value column}]]] + [:div.grid-rows-auto + [:span.icon i/layout-columns] + [:div.input-wrapper + [:> numeric-input* + {:placeholder "--" + :on-click #(dom/select-target %) + :on-change (partial on-grid-coordinates :all :row) + :value row}]]]]) + + (when (= :area cell-mode) [:div.input-wrapper - [:> numeric-input* - {:placeholder "--" - :on-click #(dom/select-target %) - :on-change (partial on-grid-coordinates :all :column) - :value column}]]] - [:div.grid-rows-auto - [:span.icon i/layout-columns] - [:div.input-wrapper - [:> numeric-input* - {:placeholder "--" - :on-click #(dom/select-target %) - :on-change (partial on-grid-coordinates :all :row) - :value row}]]]]) + [:input.input-text + {:key (dm/str "name-" (:id cell)) + :id "grid-area-name" + :type "text" + :aria-label "grid-area-name" + :placeholder "--" + :default-value area-name + :auto-complete "off" + :on-change on-area-name-change}]]) - (when (= :area cell-mode) - [:div.input-wrapper - [:input.input-text - {:key (dm/str "name-" (:id cell)) - :id "grid-area-name" - :type "text" - :aria-label "grid-area-name" - :placeholder "--" - :default-value area-name - :auto-complete "off" - :on-change on-area-name-change}]]) + (when (and (not multiple?) (or (= :manual cell-mode) (= :area cell-mode))) + [:div.grid-manual + [:div.grid-columns-auto + [:span.icon i/layout-rows] + [:div.input-wrapper + [:> numeric-input* + {:placeholder "--" + :on-pointer-down #(dom/select-target %) + :on-change (partial on-grid-coordinates :start :column) + :value column}] + [:> numeric-input* + {:placeholder "--" + :on-pointer-down #(dom/select-target %) + :on-change (partial on-grid-coordinates :end :column) + :value column-end}]]] + [:div.grid-rows-auto + [:span.icon i/layout-columns] + [:div.input-wrapper + [:> numeric-input* + {:placeholder "--" + :on-pointer-down #(dom/select-target %) + :on-change (partial on-grid-coordinates :start :row) + :value row}] + [:> numeric-input* + {:placeholder "--" + :on-pointer-down #(dom/select-target %) + :on-change (partial on-grid-coordinates :end :row) + :value row-end}]]]])] - (when (and (not multiple?) (or (= :manual cell-mode) (= :area cell-mode))) - [:div.grid-manual - [:div.grid-columns-auto - [:span.icon i/layout-rows] - [:div.input-wrapper - [:> numeric-input* - {:placeholder "--" - :on-pointer-down #(dom/select-target %) - :on-change (partial on-grid-coordinates :start :column) - :value column}] - [:> numeric-input* - {:placeholder "--" - :on-pointer-down #(dom/select-target %) - :on-change (partial on-grid-coordinates :end :column) - :value column-end}]]] - [:div.grid-rows-auto - [:span.icon i/layout-columns] - [:div.input-wrapper - [:> numeric-input* - {:placeholder "--" - :on-pointer-down #(dom/select-target %) - :on-change (partial on-grid-coordinates :start :row) - :value row}] - [:> numeric-input* - {:placeholder "--" - :on-pointer-down #(dom/select-target %) - :on-change (partial on-grid-coordinates :end :row) - :value row-end}]]]])] + [:div.layout-row + [:div.row-title "Align"] + [:div.btn-wrapper + [:& set-self-alignment {:is-col? false + :alignment align-self + :set-alignment set-alignment}]]] + [:div.layout-row + [:div.row-title "Justify"] + [:div.btn-wrapper + [:& set-self-alignment {:is-col? true + :alignment justify-self + :set-alignment set-justify-self}]]] - [:div.layout-row - [:div.row-title "Align"] - [:div.btn-wrapper - [:& set-self-alignment {:is-col? false - :alignment align-self - :set-alignment set-alignment}]]] - [:div.layout-row - [:div.row-title "Justify"] - [:div.btn-wrapper - [:& set-self-alignment {:is-col? true - :alignment justify-self - :set-alignment set-justify-self}]]] - - [:div.layout-row.single-button - [:div.btn-wrapper - [:div.edit-mode - [:button.tooltip.tooltip-bottom-left - {:alt "Grid edit mode" - :on-click toggle-edit-mode - :style {:padding 0}} - "Edit grid" - i/grid-layout-mode]]]]]])) + [:div.layout-row.single-button + [:div.btn-wrapper + [:div.edit-mode + [:button.tooltip.tooltip-bottom-left + {:alt "Grid edit mode" + :on-click toggle-edit-mode + :style {:padding 0}} + "Edit grid" + i/grid-layout-mode]]]]]]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.scss new file mode 100644 index 000000000..0240eed2a --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/grid_cell.scss @@ -0,0 +1,59 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.grid-cell-menu { + .grid-cell-menu-container { + @include flexColumn; + margin-top: $s-8; + gap: $s-16; + } + + .grid-cell-menu-title { + font-size: $fs-11; + } + + .row { + @include flexRow; + } + + .cell-mode :global(label) { + padding: 0 $s-12; + } + + .edit-grid-btn { + @extend .button-secondary; + @include tabTitleTipography; + width: 100%; + padding: $s-8; + } + + .area-input { + @extend .input-element; + width: 100%; + padding: $s-8; + } +} + +.grid-coord-group { + @include flexRow; + + border-radius: $br-8; + padding-left: $s-4; + background-color: var(--input-background-color); + + .icon svg { + @extend .button-icon; + stroke: var(--icon-foreground); + fill: var(--icon-foreground); + } + .coord-input { + @extend .input-element; + border-radius: 0 $br-8 $br-8 0; + border-left: 1px solid var(--panel-background-color); + } +} 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 1e78a482b..ba479c5c1 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,6 +24,7 @@ [app.main.ui.hooks :as h] [app.main.ui.icons :as i] [app.util.dom :as dom] + [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -231,6 +232,43 @@ :stretch i/align-self-column-strech :baseline i/align-self-column-baseline)))) +(defn get-layout-grid-icon-refactor + [type val is-col?] + (case type + :align-items + (if is-col? + (case val + :auto i/remove-refactor + :start i/align-self-row-left-refactor + :end i/align-self-row-right-refactor + :center i/align-self-row-center-refactor + :stretch i/align-self-row-strech + :baseline i/align-self-row-baseline) + (case val + :auto i/remove-refactor + :start i/align-self-column-top-refactor + :end i/align-self-column-bottom-refactor + :center i/align-self-column-center-refactor + :stretch i/align-self-column-strech + :baseline i/align-self-column-baseline)) + + :justify-items + (if (not is-col?) + (case val + :start i/align-content-column-start-refactor + :center i/align-content-column-center-refactor + :end i/align-content-column-end-refactor + :space-around i/align-content-column-around-refactor + :space-between i/align-content-column-between-refactor + :stretch i/align-content-column-stretch-refactor) + (case val + :start i/align-content-row-start-refactor + :center i/align-content-row-center-refactor + :end i/align-content-row-end-refactor + :space-around i/align-content-row-around-refactor + :space-between i/align-content-row-between-refactor + :stretch i/align-content-row-stretch-refactor)))) + (mf/defc direction-row-flex [{:keys [saved-dir on-change] :as props}] (let [new-css-system (mf/use-ctx ctx/new-css-system)] @@ -310,7 +348,7 @@ :id "align-items-end"}]] [:div.align-items-style - [:button.align-start.tooltip.tooltip-bottom + [:button.align-start.tooltip.tooltip-bottom {:class (dom/classnames :active (= align-items :start)) :alt "Align items start" :data-value :start @@ -687,8 +725,7 @@ [:div {:class (stl/css-case :row-gap true :disabled (and (= :nowrap wrap-type) (not is-col?))) :title "Row gap"} - [:span {:class (stl/css :icon)} - i/gap-vertical-refactor] + [:span {:class (stl/css :icon)} i/gap-vertical-refactor] [:> numeric-input* {:className (stl/css :numeric-input true) :no-validate true :placeholder "--" @@ -704,6 +741,7 @@ :min 0 :value (:row-gap gap-value) :disabled (and (= :nowrap wrap-type) (not is-col?))}]] + [:div {:class (stl/css-case :column-gap true :disabled (and (= :nowrap wrap-type) is-col?)) :title "Column gap"} @@ -792,11 +830,11 @@ :space-evenly i/grid-justify-content-row-between)))) (mf/defc direction-row-grid - [{:keys [saved-dir on-change-refactor on-click] :as props}] + [{:keys [saved-dir on-change on-click] :as props}] (let [new-css-system (mf/use-ctx ctx/new-css-system)] (if new-css-system [:& radio-buttons {:selected (d/name saved-dir) - :on-change on-change-refactor + :on-change on-change :name "grid-direction"} [:& radio-button {:value "row" :id "grid-direction-row" @@ -832,13 +870,18 @@ (st/emit! (udw/start-edition-mode id)) (st/emit! :interrupt))))] (if new-css-system - [:div "new-edit-mode"] + [:button + {:class (stl/css :edit-mode-btn) + :alt "Grid edit mode" + :on-click toggle-edit-mode} + (tr "workspace.layout_grid.editor.options.edit-grid")] + [:button.tooltip.tooltip-bottom-left {:class (dom/classnames :active active?) :alt "Grid edit mode" - :on-click #(toggle-edit-mode) + :on-click toggle-edit-mode :style {:padding 0}} - "Edit grid" + (tr "workspace.layout_grid.editor.options.edit-grid") i/grid-layout-mode]))) (mf/defc align-grid-row @@ -847,20 +890,20 @@ type (if is-col? :column :row)] (if new-css-system [:& radio-buttons {:selected (d/name align-items) - :on-change set-align - :name "flex-align-items"} + :on-change #(set-align % type) + :name (dm/str "flex-align-items-" (d/name type))} [:& radio-button {:value "start" - :icon (get-layout-flex-icon-refactor :align-items :start is-col?) + :icon (get-layout-grid-icon-refactor :align-items :start is-col?) :title "Align items start" - :id "align-items-start"}] + :id (dm/str "align-items-start-" (d/name type))}] [:& radio-button {:value "center" - :icon (get-layout-flex-icon-refactor :align-items :center is-col?) + :icon (get-layout-grid-icon-refactor :align-items :center is-col?) :title "Align items center" - :id "align-items-center"}] + :id (dm/str "align-items-center-" (d/name type))}] [:& radio-button {:value "end" - :icon (get-layout-flex-icon-refactor :align-items :end is-col?) + :icon (get-layout-grid-icon-refactor :align-items :end is-col?) :title "Align items end" - :id "align-items-end"}]] + :id (dm/str "align-items-end-" (d/name type))}]] [:div.align-items-style (for [align [:start :center :end]] [:button.align-start.tooltip @@ -876,19 +919,31 @@ (mf/defc justify-grid-row [{:keys [is-col? justify-items set-justify] :as props}] - (let [type (if is-col? :column :row)] - [:div.justify-content-style - (for [align [:start :center :end :space-around :space-between :stretch]] - [:button.align-start.tooltip - {:class (dom/classnames :active (= justify-items align) - :tooltip-bottom-left (not= align :start) - :tooltip-bottom (= align :start)) - :alt (if is-col? - (dm/str "align-content: " (d/name align)) - (dm/str "justify-content: " (d/name align))) - :on-click #(set-justify align type) - :key (dm/str "justify-content" (d/name align))} - (get-layout-grid-icon :justify-items align is-col?)])])) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + type (if is-col? :column :row)] + + (if new-css-system + [:& radio-buttons {:selected (d/name justify-items) + :on-change #(set-justify % type) + :name (dm/str "grid-justify-items-" (d/name type))} + (for [justify [:start :center :end :space-around :space-between :stretch]] + [:& radio-button {:value (d/name justify) + :icon (get-layout-grid-icon-refactor :justify-items justify is-col?) + :title (dm/str "Justify items " (d/name justify)) + :id (dm/str "justify-items-" (d/name justify) "-" (d/name type))}])] + + [:div.justify-content-style + (for [align [:start :center :end :space-around :space-between :stretch]] + [:button.align-start.tooltip + {:class (dom/classnames :active (= justify-items align) + :tooltip-bottom-left (not= align :start) + :tooltip-bottom (= align :start)) + :alt (if is-col? + (dm/str "align-content: " (d/name align)) + (dm/str "justify-content: " (d/name align))) + :on-click #(set-justify align type) + :key (dm/str "justify-content" (d/name align))} + (get-layout-grid-icon :justify-items align is-col?)])]))) (defn manage-values [{:keys [value type]}] (case type @@ -900,7 +955,9 @@ (mf/defc grid-track-info [{:keys [is-col? type index column set-column-value set-column-type remove-element reorder-track hover-track]}] - (let [drop-track + (let [new-css-system (mf/use-ctx ctx/new-css-system) + + drop-track (mf/use-fn (mf/deps type reorder-track index) (fn [drop-position data] @@ -926,74 +983,139 @@ :index index :column column} :draggable? true)] - [:div.column-info - {:ref dref - :class (dom/classnames - :dnd-over-top (or (= (:over dprops) :top) - (= (:over dprops) :center)) - :dnd-over-bot (= (:over dprops) :bot)) - :on-pointer-enter pointer-enter - :on-pointer-leave pointer-leave} - [:div.direction-grid-icon - (if is-col? - i/layout-rows - i/layout-columns)] - [:div.grid-column-value - [:> numeric-input* {:no-validate true - :value (:value column) - :on-change #(set-column-value type index %) - :placeholder "--" - :disabled (= :auto (:type column))}]] - [:div.grid-column-unit - [:& select - {:class "grid-column-unit-selector" - :default-value (:type column) - :options [{:value :flex :label "FR"} - {:value :auto :label "AUTO"} - {:value :fixed :label "PX"} - {:value :percent :label "%"}] - :on-change #(set-column-type type index %)}]] - [:button.remove-grid-column - {:on-click #(remove-element type index)} - i/minus]])) + (if new-css-system + [:div {:class + (stl/css-case :track-info true + :dnd-over-top (or (= (:over dprops) :top) + (= (:over dprops) :center)) + :dnd-over-bot (= (:over dprops) :bot)) + :ref dref + :on-pointer-enter pointer-enter + :on-pointer-leave pointer-leave} + + [:div {:class (stl/css :track-info-container)} + [:div {:class (stl/css :track-info-dir-icon)} + (if is-col? i/flex-vertical-refactor i/flex-horizontal-refactor)] + + [:div {:class (stl/css :track-info-value)} + [:> numeric-input* {:no-validate true + :value (:value column) + :on-change #(set-column-value type index %) + :placeholder "--" + :disabled (= :auto (:type column))}]] + + [:div {:class (stl/css :track-info-unit)} + [:& select + {:class (stl/css :track-info-unit-selector) + :default-value (:type column) + :options [{:value :flex :label "FR"} + {:value :auto :label "AUTO"} + {:value :fixed :label "PX"} + {:value :percent :label "%"}] + :on-change #(set-column-type type index %)}]]] + + [:button + {:class (stl/css :remove-track-btn) + :on-click #(remove-element type index)} + i/remove-refactor]] + + [:div.column-info + {:ref dref + :class (dom/classnames + :dnd-over-top (or (= (:over dprops) :top) + (= (:over dprops) :center)) + :dnd-over-bot (= (:over dprops) :bot)) + :on-pointer-enter pointer-enter + :on-pointer-leave pointer-leave} + [:div.direction-grid-icon + (if is-col? + i/layout-rows + i/layout-columns)] + + [:div.grid-column-value + [:> numeric-input* {:no-validate true + :value (:value column) + :on-change #(set-column-value type index %) + :placeholder "--" + :disabled (= :auto (:type column))}]] + [:div.grid-column-unit + [:& select + {:class "grid-column-unit-selector" + :default-value (:type column) + :options [{:value :flex :label "FR"} + {:value :auto :label "AUTO"} + {:value :fixed :label "PX"} + {:value :percent :label "%"}] + :on-change #(set-column-type type index %)}]] + [:button.remove-grid-column + {:on-click #(remove-element type index)} + 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}] - (let [column-num (count column-values) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + + column-num (count column-values) direction (if (> column-num 1) (if is-col? "Columns " "Rows ") (if is-col? "Column " "Row ")) - column-vals (str/join ", " (map manage-values column-values)) - generated-name (dm/str direction (if (= column-num 0) " - empty" (dm/str column-num " (" column-vals ")"))) - type (if is-col? :column :row)] + track-name (dm/str direction (if (= column-num 0) " - empty" column-num)) + track-detail (str/join ", " (map manage-values column-values)) + generated-name (dm/str direction (if (= column-num 0) " - empty" (dm/str column-num " (" track-detail ")"))) - [:div.grid-columns - [:div.grid-columns-header - [:button.expand-icon - {:on-click toggle} i/actions] + type (if is-col? :column :row) - [:div.columns-info {:title generated-name - :on-click toggle} generated-name] - [:button.add-column {:on-click #(do - (when-not expanded? (toggle)) - (add-new-element type ctl/default-track-value))} i/plus]] + add-track + #(do + (when-not expanded? (toggle)) + (add-new-element type ctl/default-track-value))] - (when expanded? - [:& h/sortable-container {} - [:div.columns-info-wrapper - (for [[index column] (d/enumerate column-values)] - [:& grid-track-info {:key (dm/str index "-" (name type) "-" column) - :type type - :is-col? is-col? - :index index - :column column - :set-column-value set-column-value - :set-column-type set-column-type - :remove-element remove-element - :reorder-track reorder-track - :hover-track hover-track}])]])])) + (if new-css-system + [:div {:class (stl/css :grid-tracks)} + [:div {:class (stl/css :grid-track-header)} + [:button {:class (stl/css :expand-icon) :on-click toggle} i/menu-refactor] + [:div {:class (stl/css :track-title) :on-click toggle} + [:div {:class (stl/css :track-name) :title track-name} track-name] + [:div {:class (stl/css :track-detail) :title track-detail} track-detail]] + [:button {:class (stl/css :add-column) :on-click add-track} i/add-refactor]] + + (when expanded? + [:& h/sortable-container {} + [:div {:class (stl/css :grid-tracks-info-container)} + (for [[index column] (d/enumerate column-values)] + [:& grid-track-info {:key (dm/str index "-" (name type)) + :type type + :is-col? is-col? + :index index + :column column + :set-column-value set-column-value + :set-column-type set-column-type + :remove-element remove-element + :reorder-track reorder-track + :hover-track hover-track}])]])] + + [:div.grid-columns + [:div.grid-columns-header + [:button.expand-icon {:on-click toggle} i/actions] + [:div.columns-info {:title generated-name :on-click toggle} generated-name] + [:button.add-column {:on-click add-track} i/plus]] + + (when expanded? + [:& h/sortable-container {} + [:div.columns-info-wrapper + (for [[index column] (d/enumerate column-values)] + [:& grid-track-info {:key (dm/str index "-" (name type)) + :type type + :is-col? is-col? + :index index + :column column + :set-column-value set-column-value + :set-column-type set-column-type + :remove-element remove-element + :reorder-track reorder-track + :hover-track hover-track}])]])]))) ;; LAYOUT COMPONENT @@ -1169,16 +1291,16 @@ (mf/use-fn (mf/deps ids) (fn [type prop val] - (let [val (mth/finite val 0)] - (cond - (and (= type :simple) (= prop :p1)) - (st/emit! (dwsl/update-layout ids {:layout-padding {:p1 val :p3 val}})) + (let [val (mth/finite val 0)] + (cond + (and (= type :simple) (= prop :p1)) + (st/emit! (dwsl/update-layout ids {:layout-padding {:p1 val :p3 val}})) - (and (= type :simple) (= prop :p2)) - (st/emit! (dwsl/update-layout ids {:layout-padding {:p2 val :p4 val}})) + (and (= type :simple) (= prop :p2)) + (st/emit! (dwsl/update-layout ids {:layout-padding {:p2 val :p4 val}})) - :else - (st/emit! (dwsl/update-layout ids {:layout-padding {prop val}})))))) + :else + (st/emit! (dwsl/update-layout ids {:layout-padding {prop val}})))))) ;; Grid-direction @@ -1188,9 +1310,9 @@ (mf/use-fn (mf/deps [layout-type ids new-css-system]) (fn [dir] - (let [dir (if new-css-system (keyword dir) dir)] + (let [dir (cond-> dir new-css-system keyword)] (if (= :flex layout-type) - (st/emit! (dwsl/update-layout ids {:layout-flex-dir dir})) + (st/emit! (dwsl/update-layout ids {:layout-grid-dir dir})) (st/emit! (dwsl/update-layout ids {:layout-grid-dir dir})))))) ;; Align grid @@ -1198,10 +1320,13 @@ align-items-column (:layout-justify-items values) set-align-grid - (fn [value type] - (if (= type :row) - (st/emit! (dwsl/update-layout ids {:layout-align-items value})) - (st/emit! (dwsl/update-layout ids {:layout-justify-items value})))) + (mf/use-fn + (mf/deps ids new-css-system) + (fn [value type] + (let [value (cond-> value new-css-system keyword)] + (if (= type :row) + (st/emit! (dwsl/update-layout ids {:layout-align-items value})) + (st/emit! (dwsl/update-layout ids {:layout-justify-items value})))))) ;; Justify grid grid-justify-content-row (:layout-justify-content values) @@ -1211,11 +1336,12 @@ set-justify-grid (mf/use-fn - (mf/deps ids) + (mf/deps ids new-css-system) (fn [value type] - (if (= type :row) - (st/emit! (dwsl/update-layout ids {:layout-justify-content value})) - (st/emit! (dwsl/update-layout ids {:layout-align-content value})))))] + (let [value (cond-> value new-css-system keyword)] + (if (= type :row) + (st/emit! (dwsl/update-layout ids {:layout-justify-content value})) + (st/emit! (dwsl/update-layout ids {:layout-align-content value}))))))] (if new-css-system [:div {:class (stl/css :element-set)} @@ -1265,7 +1391,7 @@ [:div {:class (stl/css :second-row)} [:& justify-content-row {:is-col? is-col? :justify-content justify-content - :on-change set-justify-content-refactor}]] + :on-change set-justify-content-refactor}]] (when (= :wrap wrap-type) [:div {:class (stl/css :third-row)} [:& align-content-row {:is-col? is-col? @@ -1281,37 +1407,33 @@ [:& padding-section {:values values :on-change-style change-padding-type :on-change on-padding-change}]]] - :grid ;; TODO Finish this with new UI + + + :grid [:div {:class (stl/css :grid-layout-menu)} - [:div {:class (stl/css :first-row)} - [:div (stl/css :direction-edit) - [:div {:class (stl/css :direction)} - [:& direction-row-grid {:set-direction set-direction - :on-click saved-dir}] - (when (= 1 (count ids)) - [:div {:class (stl/css :edit)} - [:& grid-edit-mode {:id (first ids)}]])]] + [:div {:class (stl/css :row :first-row)} + [:div {:class (stl/css :direction-edit)} + [:div {:class (stl/css :direction)} + [:& direction-row-grid {:saved-dir saved-grid-dir + :on-change set-direction}]]] - [:div.layout-row - [:div.align-items-grid.row-title "Items"] - [:div.btn-wrapper.align-grid-items - [:& align-grid-row {:is-col? false - :align-items align-items-row - :set-align set-align-grid}] + [:& align-grid-row {:is-col? false + :align-items align-items-row + :set-align set-align-grid}] - [:& align-grid-row {:is-col? true - :align-items align-items-column - :set-align set-align-grid}]]] + [:& align-grid-row {:is-col? true + :align-items align-items-column + :set-align set-align-grid}]] - [:div.layout-row - [:div.jusfiy-content-grid.row-title "Content"] - [:div.btn-wrapper.align-grid-content - [:& justify-grid-row {:is-col? true - :justify-items grid-justify-content-column - :set-justify set-justify-grid}] - [:& justify-grid-row {:is-col? false - :justify-items grid-justify-content-row - :set-justify set-justify-grid}]]]]] + [:div {:class (stl/css :row :grid-layout-align)} + [:& justify-grid-row {:is-col? true + :justify-items grid-justify-content-column + :set-justify set-justify-grid}] + [:& justify-grid-row {:is-col? false + :justify-items grid-justify-content-row + :set-justify set-justify-grid}]] + (when (= 1 (count ids)) + [:& grid-edit-mode {:id (first ids)}])] nil)))] [:div.element-set @@ -1427,13 +1549,15 @@ :justify-items grid-justify-content-row :set-justify set-justify-grid}]]]] - ;; Default if not grid or flex + ;; Default if not grid or flex nil)))]))) (mf/defc grid-layout-edition {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values"]))]} [{:keys [ids values] :as props}] - (let [;; Gap + (let [new-css-system (mf/use-ctx ctx/new-css-system) + + ;; Gap gap-selected? (mf/use-state :none) saved-grid-dir (:layout-grid-dir values) @@ -1468,23 +1592,28 @@ align-items-row (:layout-align-items values) align-items-column (:layout-justify-items values) - set-items-grid - (fn [value type] - (if (= type :row) - (st/emit! (dwsl/update-layout ids {:layout-align-items value})) - (st/emit! (dwsl/update-layout ids {:layout-justify-items value})))) + set-align-grid + (mf/use-fn + (mf/deps ids new-css-system) + (fn [value type] + (let [value (cond-> value new-css-system keyword)] + (if (= type :row) + (st/emit! (dwsl/update-layout ids {:layout-align-items value})) + (st/emit! (dwsl/update-layout ids {:layout-justify-items value})))))) + ;; Justify grid - grid-justify-content-row (:layout-align-content values) - grid-justify-content-column (:layout-justify-content values) + grid-justify-content-row (:layout-justify-content values) + grid-justify-content-column (:layout-align-content values) - set-content-grid + set-justify-grid (mf/use-fn - (mf/deps ids) + (mf/deps ids new-css-system) (fn [value type] - (if (= type :row) - (st/emit! (dwsl/update-layout ids {:layout-justify-content value})) - (st/emit! (dwsl/update-layout ids {:layout-align-content value}))))) + (let [value (cond-> value new-css-system keyword)] + (if (= type :row) + (st/emit! (dwsl/update-layout ids {:layout-justify-content value})) + (st/emit! (dwsl/update-layout ids {:layout-align-content value})))))) ;;Grid columns column-grid-values (:layout-grid-columns values) @@ -1543,72 +1672,133 @@ (st/emit! (dwsl/change-layout-track ids type index {:value value :type track-type})))))] - [:div.element-set - [:div.element-set-title - [:span "Grid Layout"]] + (if new-css-system + [:div {:class (stl/css :grid-layout-menu)} + [:div {:class (stl/css :row)} + [:div {:class (stl/css :grid-layout-menu-title)} "GRID LAYOUT"] + [:button {:class (stl/css :exit-btn) + :on-click #(st/emit! udw/clear-edition-mode)} + (tr "workspace.layout_grid.editor.options.exit")]] - [:div.element-set-content.layout-menu - [:div.layout-row - [:div.direction-wrap.row-title "Direction"] - [:div.btn-wrapper - [:div.direction - (for [dir [:row :column]] - [:& direction-btn {:key (d/name dir) - :dir dir - :saved-dir saved-grid-dir - :on-click set-direction - :icon? true}])] + [:div {:class (stl/css :row :first-row)} + [:div {:class (stl/css :direction-edit)} + [:div {:class (stl/css :direction)} + [:& direction-row-grid {:saved-dir saved-grid-dir + :on-change set-direction}]]] - (when (= 1 (count ids)) - [:div.edit-mode - [:& grid-edit-mode {:id (first ids)}]])]] - - [:div.layout-row - [:div.align-items-grid.row-title "Items"] - [:div.btn-wrapper.align-grid [:& align-grid-row {:is-col? false :align-items align-items-row - :set-align set-items-grid}] + :set-align set-align-grid}] [:& align-grid-row {:is-col? true :align-items align-items-column - :set-align set-items-grid}]]] + :set-align set-align-grid}]] - [:div.layout-row - [:div.jusfiy-content-grid.row-title "Content"] - [:div.btn-wrapper.align-grid-content + [:div {:class (stl/css :row :grid-layout-align)} [:& justify-grid-row {:is-col? true - :justify-items grid-justify-content-row - :set-justify set-content-grid}] - [:& justify-grid-row {:is-col? false :justify-items grid-justify-content-column - :set-justify set-content-grid}]]] - [:& grid-columns-row {:is-col? true - :expanded? @grid-columns-open? - :toggle toggle-columns-info - :column-values column-grid-values - :add-new-element add-new-element - :set-column-value set-column-value - :set-column-type set-column-type - :remove-element remove-element - :reorder-track reorder-track - :hover-track hover-track}] + :set-justify set-justify-grid}] + [:& justify-grid-row {:is-col? false + :justify-items grid-justify-content-row + :set-justify set-justify-grid}]] + [:div {:class (stl/css :row :grid-tracks-row)} + [:& grid-columns-row {:is-col? true + :expanded? @grid-columns-open? + :toggle toggle-columns-info + :column-values column-grid-values + :add-new-element add-new-element + :set-column-value set-column-value + :set-column-type set-column-type + :remove-element remove-element + :reorder-track reorder-track + :hover-track hover-track}] - [:& grid-columns-row {:is-col? false - :expanded? @grid-rows-open? - :toggle toggle-rows-info - :column-values rows-grid-values - :add-new-element add-new-element - :set-column-value set-column-value - :set-column-type set-column-type - :remove-element remove-element - :reorder-track reorder-track - :hover-track hover-track}] + [:& grid-columns-row {:is-col? false + :expanded? @grid-rows-open? + :toggle toggle-rows-info + :column-values rows-grid-values + :add-new-element add-new-element + :set-column-value set-column-value + :set-column-type set-column-type + :remove-element remove-element + :reorder-track reorder-track + :hover-track hover-track}]] + [:div {:class (stl/css :row)} + [:& gap-section {:gap-selected? gap-selected? + :on-change set-gap + :gap-value (:layout-gap values)}]] - [:& gap-section {:gap-selected? gap-selected? - :on-change set-gap - :gap-value (:layout-gap values)}] + [:div {:class (stl/css :row :padding-section)} + [:& padding-section {:values values + :on-change-style change-padding-type + :on-change on-padding-change}]]] - [:& padding-section {:values values - :on-change-style change-padding-type - :on-change on-padding-change}]]])) + [:div.element-set + [:div.element-set-title + [:span "Grid Layout"]] + + [:div.element-set-content.layout-menu + [:div.layout-row + [:div.direction-wrap.row-title "Direction"] + [:div.btn-wrapper + [:div.direction + (for [dir [:row :column]] + [:& direction-btn {:key (d/name dir) + :dir dir + :saved-dir saved-grid-dir + :on-click set-direction + :icon? true}])] + + (when (= 1 (count ids)) + [:div.edit-mode + [:& grid-edit-mode {:id (first ids)}]])]] + + [:div.layout-row + [:div.align-items-grid.row-title "Items"] + [:div.btn-wrapper.align-grid + [:& align-grid-row {:is-col? false + :align-items align-items-row + :set-align set-align-grid}] + + [:& align-grid-row {:is-col? true + :align-items align-items-column + :set-align set-align-grid}]]] + + [:div.layout-row + [:div.jusfiy-content-grid.row-title "Content"] + [:div.btn-wrapper.align-grid-content + [:& justify-grid-row {:is-col? true + :justify-items grid-justify-content-row + :set-justify set-justify-grid}] + [:& justify-grid-row {:is-col? false + :justify-items grid-justify-content-column + :set-justify set-justify-grid}]]] + [:& grid-columns-row {:is-col? true + :expanded? @grid-columns-open? + :toggle toggle-columns-info + :column-values column-grid-values + :add-new-element add-new-element + :set-column-value set-column-value + :set-column-type set-column-type + :remove-element remove-element + :reorder-track reorder-track + :hover-track hover-track}] + + [:& grid-columns-row {:is-col? false + :expanded? @grid-rows-open? + :toggle toggle-rows-info + :column-values rows-grid-values + :add-new-element add-new-element + :set-column-value set-column-value + :set-column-type set-column-type + :remove-element remove-element + :reorder-track reorder-track + :hover-track hover-track}] + + [:& gap-section {:gap-selected? gap-selected? + :on-change set-gap + :gap-value (:layout-gap values)}] + + [:& padding-section {:values values + :on-change-style change-padding-type + :on-change on-padding-change}]]]))) 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 f0e856994..8affcbd3c 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 @@ -63,65 +63,242 @@ } .forth-row { @include flexColumn; - .gap-group { - display: flex; - gap: $s-4; - .column-gap { - @extend .input-element; - width: $s-108; - &.disabled { - @extend .disabled-input; - } - } - .row-gap { - @extend .input-element; - width: $s-108; - &.disabled { - @extend .disabled-input; - } - } - } - .padding-group { - display: flex; - gap: $s-4; - .padding-inputs { - display: flex; - gap: $s-4; - .paddings-simple { - display: flex; - gap: $s-4; - .padding-simple { - @extend .input-element; - width: $s-108; - } - } - .paddings-multiple { - display: grid; - grid-template-columns: 1fr 1fr; - gap: $s-4; - .padding-multiple { - @extend .input-element; - width: $s-108; - } - } - } - .padding-toggle { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - border-radius: $br-8; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } - &.selected { - background-color: var(--button-tertiary-background-color-hover); - svg { - stroke: var(--button-tertiary-foreground-color-active); - } - } - } + } + } +} + +.gap-group { + display: flex; + gap: $s-4; + .column-gap { + @extend .input-element; + width: $s-108; + &.disabled { + @extend .disabled-input; + } + } + .row-gap { + @extend .input-element; + width: $s-108; + &.disabled { + @extend .disabled-input; + } + } +} + +.padding-group { + display: flex; + gap: $s-4; + + .padding-inputs { + display: flex; + gap: $s-4; + } + + .paddings-simple { + display: flex; + gap: $s-4; + + .padding-simple { + @extend .input-element; + width: $s-108; + } + } + + .paddings-multiple { + display: grid; + grid-template-columns: 1fr 1fr; + gap: $s-4; + + .padding-multiple { + @extend .input-element; + width: $s-108; + } + } + + .padding-toggle { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + border-radius: $br-8; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + &.selected { + background-color: var(--button-tertiary-background-color-hover); + svg { + stroke: var(--button-tertiary-foreground-color-active); } } } } + +.grid-layout-menu { + @include flexColumn; + gap: $s-8; + + .row { + @include flexRow; + } + + .first-row { + margin-bottom: $s-8; + } + + .grid-layout-align { + @include flexColumn; + gap: $s-4; + align-items: flex-start; + } + + .grid-layout-menu-title { + flex: 1; + font-size: $fs-11; + } + + .edit-mode-btn { + @extend .button-secondary; + @include tabTitleTipography; + margin-top: $s-8; + width: 100%; + padding: $s-8; + } + + .exit-btn { + @extend .button-secondary; + @include tabTitleTipography; + padding: $s-8 $s-20; + } + + .grid-tracks-info-container { + @include flexColumn; + margin-top: $s-4; + } + + .padding-section { + margin-top: $s-8; + } + + .grid-tracks-row { + @include flexColumn; + margin: $s-8 0; + gap: $s-12; + } +} + +.track-info { + display: flex; + + &.dnd-over-top { + border-top: $s-2 solid var(--button-foreground-hover); + } + + &.dnd-over-bot { + border-bottom: $s-2 solid var(--button-foreground-hover); + } + + .track-info-container { + display: flex; + } + + .track-info-dir-icon { + border-radius: $br-8 0 0 $br-8; + background-color: var(--input-background-color); + padding-left: $s-12; + + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + height: 100%; + } + } + + .track-info-value { + @extend .input-element; + border-radius: 0; + border-right: $s-1 solid var(--panel-background-color); + } + + .track-info-unit { + } + + .track-info-unit-selector { + border-radius: 0 $br-8 $br-8 0; + width: $s-96; + } + + .remove-track-btn { + @extend .button-tertiary; + padding: $s-8; + + svg { + @extend .button-icon; + width: $s-12; + height: $s-12; + stroke: var(--icon-foreground); + fill: var(--icon-foreground); + } + } +} + +.grid-tracks { + width: 100%; + margin-top: $s-8; + + .grid-track-header { + @include flexRow; + font-size: $fs-12; + border-radius: $br-8; + overflow: hidden; + background: var(--button-secondary-background-color-rest); + height: $s-52; + } + + .track-title { + @include flexColumn; + flex-grow: 1; + padding: $s-8; + gap: 0; + } + + .track-name { + color: var(--color-foreground-secondary); + } + + .expand-icon { + @extend .button-secondary; + height: $s-52; + + border-radius: $s-8 0 0 $s-8; + border-right: $s-1 solid var(--panel-background-color); + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + fill: var(--icon-foreground); + } + &:hover, + &:active { + svg { + stroke: var(--button-foreground-hover); + fill: var(--button-foreground-hover); + } + } + } + + .columns-info { + } + + .add-column { + @extend .button-tertiary; + height: $s-52; + + svg { + @extend .button-icon; + height: $s-12; + width: $s-12; + stroke: var(--icon-foreground); + fill: var(--icon-foreground); + } + } +} 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 4076b8131..c62c0a385 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 @@ -5,7 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.viewport.grid-layout-editor - (:require-macros [app.main.style :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -18,17 +18,20 @@ [app.common.pages.helpers :as cph] [app.common.types.modifiers :as ctm] [app.common.types.shape.layout :as ctl] + [app.main.data.workspace :as dw] [app.main.data.workspace.grid-layout.editor :as dwge] [app.main.data.workspace.modifiers :as dwm] [app.main.data.workspace.shape-layout :as dwsl] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.context :as ctx] [app.main.ui.css-cursors :as cur] [app.main.ui.formats :as fmt] [app.main.ui.hooks :as hooks] [app.main.ui.icons :as i] [app.main.ui.workspace.viewport.viewport-ref :as uwvv] [app.util.dom :as dom] + [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] [app.util.object :as obj] [cuerdas.core :as str] @@ -47,30 +50,56 @@ :flex (dm/str (fmt/format-number value) "FR") :auto "AUTO")) +(mf/defc grid-edition-actions + {::mf/wrap-props false} + [{:keys [shape]}] + (let [new-css-system (mf/use-ctx ctx/new-css-system)] + (if new-css-system + [:div {:class (stl/css :grid-actions)} + [:div {:class (stl/css :grid-actions-container)} + [:div {:class (stl/css :grid-actions-title)} + (tr "workspace.layout_grid.editor.title") " " [:span {:stl/css :board-name} (:name shape)]] + [:button {:class (stl/css :locate-btn) + :on-click #(st/emit! (dwge/locate-board (:id shape)))} + (tr "workspace.layout_grid.editor.top-bar.locate")] + [:button {:class (stl/css :done-btn) + :on-click #(st/emit! dw/clear-edition-mode)} + (tr "workspace.layout_grid.editor.top-bar.done")]]] + + [:div.viewport-actions + [:div.viewport-actions-container + [:div.viewport-actions-title + (tr "workspace.layout_grid.editor.title") " " [:span.grid-edit-board-name (:name shape)]] + [:button.btn-secondary {:on-click #(st/emit! (dwge/locate-board (:id shape)))} + (tr "workspace.layout_grid.editor.top-bar.locate")] + [:button.btn-primary {:on-click #(st/emit! dw/clear-edition-mode)} + (tr "workspace.layout_grid.editor.top-bar.done")] + [:button.btn-icon-basic {:on-click #(st/emit! dw/clear-edition-mode)} i/close]]]))) + (mf/defc grid-editor-frame {::mf/wrap-props false} [props] (let [bounds (unchecked-get props "bounds") + width (unchecked-get props "width") + height (unchecked-get props "height") zoom (unchecked-get props "zoom") hv #(gpo/start-hv bounds %) vv #(gpo/start-vv bounds %) - width (gpo/width-points bounds) - height (gpo/height-points bounds) origin (gpo/origin bounds) frame-points (reduce apply-to-point [origin] - [#(gpt/add % (hv width)) + [#(gpt/add % (hv (+ width (/ 70 zoom)))) #(gpt/subtract % (vv (/ 40 zoom))) - #(gpt/subtract % (hv (+ width (/ 40 zoom)))) - #(gpt/add % (vv (+ height (/ 40 zoom)))) + #(gpt/subtract % (hv (+ width (/ 110 zoom)))) + #(gpt/add % (vv (+ height (/ 110 zoom)))) #(gpt/add % (hv (/ 40 zoom)))])] [:polygon - {:class (css :grid-frame) + {:class (stl/css :grid-frame) :points (->> frame-points (map #(dm/fmt "%,%" (:x %) (:y %))) (str/join " "))}])) @@ -78,7 +107,6 @@ (mf/defc plus-btn {::mf/wrap-props false} [props] - (let [start-p (unchecked-get props "start-p") zoom (unchecked-get props "zoom") type (unchecked-get props "type") @@ -88,34 +116,36 @@ (if (= type :column) [(:x start-p) (- (:y start-p) (/ 40 zoom)) - (+ (:x start-p) (/ 12 zoom)) - (- (:y start-p) (/ 28 zoom))] + (+ (:x start-p) (/ 9 zoom)) + (- (:y start-p) (/ 31 zoom))] [(- (:x start-p) (/ 40 zoom)) (:y start-p) - (- (:x start-p) (/ 28 zoom)) - (+ (:y start-p) (/ 12 zoom))]) + (- (:x start-p) (/ 31 zoom)) + (+ (:y start-p) (/ 9 zoom))]) handle-click (mf/use-callback (mf/deps on-click) #(when on-click (on-click)))] - [:g {:class (css :grid-plus-button) + [:g {:class (stl/css :grid-plus-button) :on-click handle-click} - [:rect {:class (css :grid-plus-shape) - :x rect-x - :y rect-y - :width (/ 40 zoom) - :height (/ 40 zoom)}] + [:rect {:class (stl/css :grid-plus-shape) + :x (+ rect-x (/ 6 zoom)) + :y (+ rect-y (/ 6 zoom)) + :width (/ (- 40 12) zoom) + :height (/ (- 40 12) zoom) + :rx (/ 4 zoom) + :ry (/ 4 zoom)}] - [:use {:class (css :grid-plus-icon) + [:use {:class (stl/css :grid-plus-icon) :x icon-x :y icon-y - :width (/ 16 zoom) - :height (/ 16 zoom) - :href (dm/str "#icon-plus")}]])) + :width (/ 22 zoom) + :height (/ 22 zoom) + :href "#icon-add-refactor"}]])) (defn use-drag [{:keys [on-drag-start on-drag-end on-drag-delta on-drag-position]}] @@ -260,11 +290,11 @@ :y area-y :width area-width :height area-height - :style {:fill "var(--color-distance)" + :style {:fill "var(--grid-editor-area-background)" :fill-opacity 0.3}}] [:text {:x area-text-x :y area-text-y - :style {:fill "var(--color-distance)" + :style {:fill "var(--grid-editor-area-text)" :font-family "worksans" :font-weight 600 :font-size (/ 14 zoom) @@ -313,9 +343,9 @@ [:g.cell-editor [:rect {:transform (dm/str (gmt/transform-in cell-center (:transform shape))) - :class (dom/classnames (css :grid-cell-outline) true - (css :hover) hover? - (css :selected) selected?) + :class (dom/classnames (stl/css :grid-cell-outline) true + (stl/css :hover) hover? + (stl/css :selected) selected?) :x (:x cell-origin) :y (:y cell-origin) :width cell-width @@ -475,6 +505,78 @@ :style {:fill "transparent" :stroke-width 0}}])) +(def marker-width 24) +(def marker-h1 20) +(def marker-h2 10) +(def marker-bradius 2) + +(defn marker-shape-d + [center zoom] + (let [marker-width (/ marker-width zoom) + marker-h1 (/ marker-h1 zoom) + marker-h2 (/ marker-h2 zoom) + + marker-bradius (/ marker-bradius zoom) + marker-half-width (/ marker-width 2) + marker-half-height (/ (+ marker-h1 marker-h2) 2) + + start-p + (gpt/subtract center (gpt/point marker-half-width marker-half-height)) + + [a b c d e] + (reduce + apply-to-point + [start-p] + [#(gpt/add % (gpt/point marker-width 0)) + #(gpt/add % (gpt/point 0 marker-h1)) + #(gpt/add % (gpt/point (- marker-half-width) marker-h2)) + #(gpt/subtract % (gpt/point marker-half-width marker-h2))]) + + vea (gpt/to-vec e a) + vab (gpt/to-vec a b) + vbc (gpt/to-vec b c) + vcd (gpt/to-vec c d) + vde (gpt/to-vec d e) + + lea (gpt/length vea) + lab (gpt/length vab) + lbc (gpt/length vbc) + lcd (gpt/length vcd) + lde (gpt/length vde) + + a1 (gpt/add e (gpt/resize vea (- lea marker-bradius))) + a2 (gpt/add a (gpt/resize vab marker-bradius)) + + b1 (gpt/add a (gpt/resize vab (- lab marker-bradius))) + b2 (gpt/add b (gpt/resize vbc marker-bradius)) + + c1 (gpt/add b (gpt/resize vbc (- lbc marker-bradius))) + c2 (gpt/add c (gpt/resize vcd marker-bradius)) + + d1 (gpt/add c (gpt/resize vcd (- lcd marker-bradius))) + d2 (gpt/add d (gpt/resize vde marker-bradius)) + + e1 (gpt/add d (gpt/resize vde (- lde marker-bradius))) + e2 (gpt/add e (gpt/resize vea marker-bradius))] + (dm/str + (dm/fmt "M%,%" (:x a1) (:y a1)) + (dm/fmt "Q%,%,%,%" (:x a) (:y a) (:x a2) (:y a2)) + + (dm/fmt "L%,%" (:x b1) (:y b1)) + (dm/fmt "Q%,%,%,%" (:x b) (:y b) (:x b2) (:y b2)) + + (dm/fmt "L%,%" (:x c1) (:y c1)) + (dm/fmt "Q%,%,%,%" (:x c) (:y c) (:x c2) (:y c2)) + + (dm/fmt "L%,%" (:x d1) (:y d1)) + (dm/fmt "Q%,%,%,%" (:x d) (:y d) (:x d2) (:y d2)) + + (dm/fmt "L%,%" (:x e1) (:y e1)) + (dm/fmt "Q%,%,%,%" (:x e) (:y e) (:x e2) (:y e2)) + + (dm/fmt "L%,%" (:x a1) (:y a1)) + "Z"))) + (mf/defc track-marker {::mf/wrap-props false} [props] @@ -489,23 +591,6 @@ track-after (unchecked-get props "track-after") snap-pixel? (unchecked-get props "snap-pixel?") - marker-width (/ 24 zoom) - marker-h1 (/ 22 zoom) - marker-h2 (/ 8 zoom) - - marker-half-width (/ marker-width 2) - marker-half-height (/ (+ marker-h1 marker-h2) 2) - - marker-points - (reduce - apply-to-point - [(gpt/subtract center - (gpt/point marker-half-width marker-half-height))] - [#(gpt/add % (gpt/point marker-width 0)) - #(gpt/add % (gpt/point 0 marker-h1)) - #(gpt/add % (gpt/point (- marker-half-width) marker-h2)) - #(gpt/subtract % (gpt/point marker-half-width marker-h2))]) - text-x (:x center) text-y (:y center) @@ -515,16 +600,14 @@ [:g {:on-pointer-down handle-pointer-down :on-lost-pointer-capture handle-lost-pointer-capture :on-pointer-move handle-pointer-move - :class (dom/classnames (css :grid-track-marker) true + :class (dom/classnames (stl/css :grid-track-marker) true (cur/get-dynamic "resize-ew" (:rotation shape)) (= type :column) (cur/get-dynamic "resize-ns" (:rotation shape)) (= type :row)) :transform (dm/str (gmt/transform-in center (:transform shape)))} - [:polygon {:class (css :marker-shape) - :points (->> marker-points - (map #(dm/fmt "%,%" (:x %) (:y %))) - (str/join " "))}] - [:text {:class (css :marker-text) + [:path {:class (stl/css :marker-shape) + :d (marker-shape-d center zoom)}] + [:text {:class (stl/css :marker-text) :x text-x :y text-y :width (/ 26.26 zoom) @@ -656,23 +739,23 @@ :width (- text-width (/ 36 zoom)) :height (- text-height (/ 5 zoom)) :rx (/ 3 zoom) - :fill "var(--color-distance)" + :fill "var(--grid-editor-marker-color)" :opacity 0.2}]) (when (not small?) [:foreignObject {:x text-x :y text-y :width text-width :height text-height} - [:div {:class (css :grid-editor-wrapper)} + [:div {:class (stl/css :grid-editor-wrapper)} [:input {:ref track-input-ref :style {} - :class (css :grid-editor-label) + :class (stl/css :grid-editor-label) :type "text" :default-value (format-size track-data) :data-default-value (format-size track-data) :on-key-down handle-keydown-track-input :on-blur handle-blur-track-input}] (when (and hovering? (not medium?) (not small?)) - [:button {:class (css :grid-editor-button) - :on-click handle-remove-track} i/trash])]])] + [:button {:class (stl/css :grid-editor-button) + :on-click handle-remove-track} i/delete-refactor])]])] [:g {:transform (when (= type :row) (dm/fmt "rotate(-90 % %)" (:x marker-p) (:y marker-p)))} [:& track-marker @@ -757,17 +840,20 @@ bounds (:points shape) hv #(gpo/start-hv bounds %) vv #(gpo/start-vv bounds %) - width (gpo/width-points bounds) - height (gpo/height-points bounds) origin (gpo/origin bounds) all-bounds (d/lazy-map (keys objects) #(gsh/shape->points (get objects %))) - {:keys [row-tracks column-tracks] :as layout-data} + {:keys [row-tracks column-tracks + column-total-size column-total-gap + row-total-size row-total-gap] :as layout-data} (mf/use-memo (mf/deps shape children) #(gsg/calc-layout-data shape bounds children all-bounds objects)) + width (max (gpo/width-points bounds) (+ column-total-size column-total-gap)) + height (max (gpo/height-points bounds) (+ row-total-size row-total-gap)) + handle-pointer-down (mf/use-callback (fn [event] @@ -806,15 +892,17 @@ (when-not view-only [:* [:& grid-editor-frame {:zoom zoom - :bounds bounds}] - (let [start-p (-> origin (gpt/add (hv width)))] + :bounds bounds + :width width + :height height}] + (let [start-p (-> origin (gpt/add (hv (+ width (/ 30 zoom)))))] [:g {:transform (dm/str (gmt/transform-in start-p (:transform shape)))} [:& plus-btn {:start-p start-p :zoom zoom :type :column :on-click handle-add-column}]]) - (let [start-p (-> origin (gpt/add (vv height)))] + (let [start-p (-> origin (gpt/add (vv (+ height (/ 30 zoom)))))] [:g {:transform (dm/str (gmt/transform-in start-p (:transform shape)))} [:& plus-btn {:start-p start-p :zoom zoom diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.scss b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.scss index db53c71cf..c519a0356 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.scss +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.scss @@ -1,13 +1,19 @@ +// 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 + +@import "refactor/common-refactor.scss"; + .grid-track-marker { .marker-shape { - fill: var(--color-distance); - fill-opacity: 0.3; + fill: var(--grid-editor-marker-color); } .marker-text { - fill: var(--color-distance); - font-size: calc(12px / var(--zoom)); + fill: var(--white); + font-size: calc($s-12 / var(--zoom)); font-family: worksans; - font-weight: 600; } } @@ -21,21 +27,21 @@ .grid-editor-label { background: none; - border-bottom: calc(1px / var(--zoom)) solid transparent; + border-bottom: calc($s-1 / var(--zoom)) solid transparent; border: 0; - color: var(--color-distance); + color: var(--grid-editor-marker-text); font-family: worksans; - font-size: calc(12px / var(--zoom)); - font-weight: 600; + font-size: calc($fs-12 / var(--zoom)); + font-weight: 400; margin: 0; - max-width: calc(80px / var(--zoom)); + max-width: calc($s-80 / var(--zoom)); padding: 0; - padding: 4px; + padding: $s-4; text-align: center; &:focus { outline: none; - border-bottom: calc(1px / var(--zoom)) solid var(--color-distance); + border-bottom: calc($s-1 / var(--zoom)) solid var(--grid-editor-marker-text); } } @@ -46,40 +52,48 @@ margin: 0; padding: 0; position: absolute; - right: calc(20px / var(--zoom)); - width: calc(20px / var(--zoom)); - height: calc(20px / var(--zoom)); + top: calc($s-6 / var(--zoom)); + right: calc($s-20 / var(--zoom)); + width: calc($s-20 / var(--zoom)); + height: calc($s-20 / var(--zoom)); svg { - width: calc(16px / var(--zoom)); + position: absolute; + top: 0; + left: 0; + width: calc($s-16 / var(--zoom)); height: auto; - fill: var(--color-distance); + stroke: var(--grid-editor-marker-color); } } .grid-frame { - fill: #f6f6f6; - stroke: var(--color-distance); - stroke-width: calc(1 / var(--zoom)); + fill: var(--grid-editor-marker-color); + fill-opacity: 0.1; } .grid-plus-button { cursor: pointer; + opacity: 0.5; .grid-plus-shape { - fill: var(--color-distance); - stroke: var(--color-distance); - stroke-width: calc(1 / var(--zoom)); + fill: var(--grid-editor-plus-btn-background); + stroke: var(--grid-editor-plus-btn-background); + stroke-width: calc($s-1 / var(--zoom)); } .grid-plus-icon { - fill: white; + stroke: var(--grid-editor-plus-btn-foreground); + } + + &:hover { + opacity: 1; } } .grid-cell-outline { fill: transparent; - stroke: var(--color-distance); + stroke: var(--grid-editor-line-color); stroke-opacity: 0.5; stroke-width: calc(1 / var(--zoom)); @@ -89,3 +103,52 @@ stroke-width: calc(2 / var(--zoom)); } } + +.grid-actions { + pointer-events: none; + position: absolute; + top: $s-44; + left: 50%; + + .grid-actions-container { + @include flexRow; + background: var(--panel-background-color); + border-radius: $br-12; + box-shadow: 0px 0px $s-12 0px var(--menu-shadow-color); + gap: $s-8; + height: $s-48; + margin-left: -50%; + padding: $s-8; + pointer-events: initial; + width: $s-512; + } + + .grid-actions-title { + flex: 1; + font-size: $fs-12; + color: var(--color-foreground-secondary); + padding-left: $s-8; + } + + .board-name { + } + + .locate-btn { + @extend .button-secondary; + text-transform: uppercase; + padding: $s-8 $s-20; + font-size: $fs-11; + } + .done-btn { + @extend .button-primary; + text-transform: uppercase; + padding: $s-8 $s-20; + font-size: $fs-11; + } + .close-btn { + @extend .button-tertiary; + svg { + @extend .button-icon; + } + } +} diff --git a/frontend/src/app/main/ui/workspace/viewport/rules.cljs b/frontend/src/app/main/ui/workspace/viewport/rules.cljs index 0e4420eaf..87ec78766 100644 --- a/frontend/src/app/main/ui/workspace/viewport/rules.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/rules.cljs @@ -157,7 +157,8 @@ step (calculate-step-size zoom) clip-id (str "clip-rule-" (d/name axis)) new-css-system (mf/use-ctx ctx/new-css-system) - font-color (if new-css-system new-css-font-color font-color)] + font-color (if new-css-system new-css-font-color font-color) + rules-background (if new-css-system new-css-rules-background rules-background)] [:* (let [{:keys [x y width height]} (get-background-area vbox zoom-inverse axis)] diff --git a/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs b/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs index 1413693a9..82356e252 100644 --- a/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs @@ -9,11 +9,11 @@ [app.common.pages.helpers :as cph] [app.common.types.shape.layout :as ctl] [app.main.data.workspace :as dw] - [app.main.data.workspace.grid-layout.editor :as dwge] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.context :as ctx] [app.main.ui.icons :as i] + [app.main.ui.workspace.viewport.grid-layout-editor :refer [grid-edition-actions]] [app.main.ui.workspace.viewport.path-actions :refer [path-actions]] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) @@ -56,7 +56,7 @@ [:div.viewport-actions-title [:& i18n/tr-html {:tag-name "span" :label "workspace.top-bar.read-only"}]] - [:button.btn-primary {:on-click handle-close-view-mode} "Done"] + [:button.btn-primary {:on-click handle-close-view-mode} (tr "workspace.top-bar.read-only.done")] [:button.btn-icon-basic {:on-click handle-close-view-mode} i/close]]] path-edition? @@ -64,10 +64,4 @@ [:& path-actions {:shape shape}]] grid-edition? - [:div.viewport-actions - [:div.viewport-actions-container - [:div.viewport-actions-title - (tr "workspace.layout_grid.editor.title") " " [:span.grid-edit-board-name (:name shape)]] - [:button.btn-secondary {:on-click #(st/emit! (dwge/locate-board (:id shape)))} "Locate"] - [:button.btn-primary {:on-click #(st/emit! dw/clear-edition-mode)} "Done"] - [:button.btn-icon-basic {:on-click #(st/emit! dw/clear-edition-mode)} i/close]]]))) + [:& grid-edition-actions {:shape shape}]))) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 7bb654829..cda611ae5 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -3462,6 +3462,18 @@ msgstr "Zoom to selected" msgid "workspace.layout_grid.editor.title" msgstr "Editing grid" +msgid "workspace.layout_grid.editor.top-bar.locate" +msgstr "Locate" + +msgid "workspace.layout_grid.editor.top-bar.done" +msgstr "Done" + +msgid "workspace.layout_grid.editor.options.edit-grid" +msgstr "Edit grid" + +msgid "workspace.layout_grid.editor.options.exit" +msgstr "Exit" + #: src/app/main/ui/workspace/libraries.cljs msgid "workspace.libraries.add" msgstr "Add" @@ -4994,6 +5006,9 @@ msgstr "Click to close the path" msgid "workspace.top-bar.read-only" msgstr "**Inspect mode** (View Only)" +msgid "workspace.top-bar.read-only.done" +msgstr "Done" + msgid "media.image" msgstr "Image" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 68cc7036d..c547166cb 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -3536,6 +3536,18 @@ msgstr "Zoom a selección" msgid "workspace.layout_grid.editor.title" msgstr "Editando rejilla" +msgid "workspace.layout_grid.editor.top-bar.locate" +msgstr "Mostrar" + +msgid "workspace.layout_grid.editor.top-bar.done" +msgstr "Hecho" + +msgid "workspace.layout_grid.editor.options.edit-grid" +msgstr "Editar rejilla" + +msgid "workspace.layout_grid.editor.options.exit" +msgstr "Salir" + #: src/app/main/ui/workspace/libraries.cljs msgid "workspace.libraries.add" msgstr "Añadir" @@ -5095,6 +5107,9 @@ msgstr "Pulsar para cerrar la ruta" msgid "workspace.top-bar.read-only" msgstr "**Modo inspección** (View only)" +msgid "workspace.top-bar.read-only.done" +msgstr "Hecho" + msgid "media.image" msgstr "Imagen"