diff --git a/CHANGES.md b/CHANGES.md index 785f111acb..b5d0ca562b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -76,7 +76,8 @@ - Fix scroll on the inspect tab [Taiga #12293](https://tree.taiga.io/project/penpot/issue/12293) - Fix lock proportion tooltip [Taiga #12326](https://tree.taiga.io/project/penpot/issue/12326) - Fix internal Error when selecting a set by name in the token theme editor [Taiga #12310](https://tree.taiga.io/project/penpot/issue/12310) - +- Fix drag & drop functionality is swapping instead or reordering [Taiga #12254](https://tree.taiga.io/project/penpot/issue/12254) +- Fix variants not syncronizing tokens on switch [Taiga #12290](https://tree.taiga.io/project/penpot/issue/12290) ## 2.10.1 @@ -84,12 +85,10 @@ - Improve workpace file loading [Github 7366](https://github.com/penpot/penpot/pull/7366) - ### :bug: Bugs fixed - Fix regression with text shapes creation with Plugins API [Taiga #12244](https://tree.taiga.io/project/penpot/issue/12244) - ## 2.10.0 ### :rocket: Epics and highlights @@ -105,7 +104,7 @@ - Add efficiency enhancements to right sidebar [Github #7182](https://github.com/penpot/penpot/pull/7182) - Add defaults for artboard drawing [Taiga #494](https://tree.taiga.io/project/penpot/us/494?milestone=465047) - Continuous display of distances between elements when moving a layer with the keyboard [Taiga #1780](https://tree.taiga.io/project/penpot/us/1780) -- New Number token - unitless values [Taiga #10936](https://tree.taiga.io/project/penpot/us/10936) +- New Number token - unitless values [Taiga #10936](https://tree.taiga.io/project/penpot/us/10936) - New font-family token [Taiga #10937](https://tree.taiga.io/project/penpot/us/10937) - New text case token [Taiga #10942](https://tree.taiga.io/project/penpot/us/10942) - New text-decoration token [Taiga #10941](https://tree.taiga.io/project/penpot/us/10941) @@ -186,7 +185,6 @@ - Add info to apply-token event [Taiga #11710](https://tree.taiga.io/project/penpot/task/11710) - Fix double click on set name input [Taiga #11747](https://tree.taiga.io/project/penpot/issue/11747) - ### :bug: Bugs fixed - Copying font size does not copy the unit [Taiga #11143](https://tree.taiga.io/project/penpot/issue/11143) diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj index 7043064cfc..b3cd18783e 100644 --- a/backend/src/app/rpc/commands/comments.clj +++ b/backend/src/app/rpc/commands/comments.clj @@ -296,7 +296,8 @@ notify (or (-> profile :props :notifications :dashboard-comments) :all) result (case notify :all (db/exec! cfg [sql:unread-all-comment-threads-by-team profile-id team-id]) - :partial (db/exec! cfg [sql:unread-partial-comment-threads-by-team profile-id team-id profile-id profile-id]))] + :partial (db/exec! cfg [sql:unread-partial-comment-threads-by-team profile-id team-id profile-id profile-id]) + [])] (into [] xf-decode-row result))) (def ^:private diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index d06da2ae4c..ea81ca238d 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -1024,6 +1024,29 @@ :clj (sort comp-fn items)))) +(defn reorder + "Reorder a vector by moving one of their items from some position to some space between positions. + It clamps the position numbers to a valid range." + [v from-pos to-space-between-pos] + (let [max-space-pos (count v) + max-prop-pos (dec max-space-pos) + + from-pos (max 0 (min max-prop-pos from-pos)) + to-space-between-pos (max 0 (min max-space-pos to-space-between-pos))] + + (if (= from-pos to-space-between-pos) + v + (let [elem (nth v from-pos) + without-elem (-> [] + (into (subvec v 0 from-pos)) + (into (subvec v (inc from-pos)))) + insert-pos (if (< from-pos to-space-between-pos) + (dec to-space-between-pos) + to-space-between-pos)] + (-> [] + (into (subvec without-elem 0 insert-pos)) + (into [elem]) + (into (subvec without-elem insert-pos))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; String Functions diff --git a/common/src/app/common/logic/variant_properties.cljc b/common/src/app/common/logic/variant_properties.cljc index 1a066cd096..e2052a12c7 100644 --- a/common/src/app/common/logic/variant_properties.cljc +++ b/common/src/app/common/logic/variant_properties.cljc @@ -88,7 +88,7 @@ related-components (cfv/find-variant-components data objects variant-id)] (reduce (fn [changes component] (let [props (:variant-properties component) - props (ctv/reorder-by-moving-to-position props from-pos to-space-between-pos) + props (d/reorder props from-pos to-space-between-pos) main-id (:main-instance-id component) name (ctv/properties-to-name props)] (-> changes diff --git a/common/src/app/common/types/variant.cljc b/common/src/app/common/types/variant.cljc index cfb90eeae0..bbac03d24a 100644 --- a/common/src/app/common/types/variant.cljc +++ b/common/src/app/common/types/variant.cljc @@ -310,27 +310,3 @@ the real name of the shape joined by the properties values separated by '/'" [variant] (cpn/merge-path-item (:name variant) (str/replace (:variant-name variant) #", " " / "))) - -(defn reorder-by-moving-to-position - "Reorder a vector by moving one of their items from some position to some space between positions. - It clamps the position numbers to a valid range." - [props from-pos to-space-between-pos] - (let [max-space-pos (count props) - max-prop-pos (dec max-space-pos) - - from-pos (max 0 (min max-prop-pos from-pos)) - to-space-between-pos (max 0 (min max-space-pos to-space-between-pos))] - - (if (= from-pos to-space-between-pos) - props - (let [elem (nth props from-pos) - without-elem (-> [] - (into (subvec props 0 from-pos)) - (into (subvec props (inc from-pos)))) - insert-pos (if (< from-pos to-space-between-pos) - (dec to-space-between-pos) - to-space-between-pos)] - (-> [] - (into (subvec without-elem 0 insert-pos)) - (into [elem]) - (into (subvec without-elem insert-pos))))))) diff --git a/common/test/common_tests/data_test.cljc b/common/test/common_tests/data_test.cljc index 686ae8980c..f2885c07f7 100644 --- a/common/test/common_tests/data_test.cljc +++ b/common/test/common_tests/data_test.cljc @@ -102,3 +102,14 @@ (t/is (= (d/insert-at-index [:a :b :c :d] 1 [:a]) [:a :b :c :d]))) +(t/deftest reorder + (let [v ["a" "b" "c" "d"]] + (t/is (= (d/reorder v 0 2) ["b" "a" "c" "d"])) + (t/is (= (d/reorder v 0 3) ["b" "c" "a" "d"])) + (t/is (= (d/reorder v 0 4) ["b" "c" "d" "a"])) + (t/is (= (d/reorder v 3 0) ["d" "a" "b" "c"])) + (t/is (= (d/reorder v 3 2) ["a" "b" "d" "c"])) + (t/is (= (d/reorder v 0 5) ["b" "c" "d" "a"])) + (t/is (= (d/reorder v 3 -1) ["d" "a" "b" "c"])) + (t/is (= (d/reorder v 5 -1) ["d" "a" "b" "c"])) + (t/is (= (d/reorder v -1 5) ["b" "c" "d" "a"])))) diff --git a/common/test/common_tests/variant_test.cljc b/common/test/common_tests/variant_test.cljc index 71587e3e58..05bc748703 100644 --- a/common/test/common_tests/variant_test.cljc +++ b/common/test/common_tests/variant_test.cljc @@ -159,48 +159,3 @@ (t/testing "update-number-in-repeated-prop-names" (t/is (= (ctv/update-number-in-repeated-prop-names props) numbered-props))))) - - -(t/deftest reorder-by-moving-to-position - (let [props [{:name "border" :value "no"} - {:name "color" :value "blue"} - {:name "shadow" :value "yes"} - {:name "background" :value "none"}]] - - (t/testing "reorder-by-moving-to-position" - (t/is (= (ctv/reorder-by-moving-to-position props 0 2) [{:name "color" :value "blue"} - {:name "border" :value "no"} - {:name "shadow" :value "yes"} - {:name "background" :value "none"}])) - (t/is (= (ctv/reorder-by-moving-to-position props 0 3) [{:name "color" :value "blue"} - {:name "shadow" :value "yes"} - {:name "border" :value "no"} - {:name "background" :value "none"}])) - (t/is (= (ctv/reorder-by-moving-to-position props 0 4) [{:name "color" :value "blue"} - {:name "shadow" :value "yes"} - {:name "background" :value "none"} - {:name "border" :value "no"}])) - (t/is (= (ctv/reorder-by-moving-to-position props 3 0) [{:name "background" :value "none"} - {:name "border" :value "no"} - {:name "color" :value "blue"} - {:name "shadow" :value "yes"}])) - (t/is (= (ctv/reorder-by-moving-to-position props 3 2) [{:name "border" :value "no"} - {:name "color" :value "blue"} - {:name "background" :value "none"} - {:name "shadow" :value "yes"}])) - (t/is (= (ctv/reorder-by-moving-to-position props 0 5) [{:name "color" :value "blue"} - {:name "shadow" :value "yes"} - {:name "background" :value "none"} - {:name "border" :value "no"}])) - (t/is (= (ctv/reorder-by-moving-to-position props 3 -1) [{:name "background" :value "none"} - {:name "border" :value "no"} - {:name "color" :value "blue"} - {:name "shadow" :value "yes"}])) - (t/is (= (ctv/reorder-by-moving-to-position props 5 -1) [{:name "background" :value "none"} - {:name "border" :value "no"} - {:name "color" :value "blue"} - {:name "shadow" :value "yes"}])) - (t/is (= (ctv/reorder-by-moving-to-position props -1 5) [{:name "color" :value "blue"} - {:name "shadow" :value "yes"} - {:name "background" :value "none"} - {:name "border" :value "no"}]))))) diff --git a/frontend/src/app/main/data/workspace/colors.cljs b/frontend/src/app/main/data/workspace/colors.cljs index bab73f42d6..38cfe651ac 100644 --- a/frontend/src/app/main/data/workspace/colors.cljs +++ b/frontend/src/app/main/data/workspace/colors.cljs @@ -154,23 +154,8 @@ (transform-fill* state ids transform-attrs options)))) -(defn swap-attrs [shape attr index new-index] - (let [first (get-in shape [attr index]) - second (get-in shape [attr new-index])] - (-> shape - (assoc-in [attr index] second) - (assoc-in [attr new-index] first)))) - -(defn- swap-fills-index - [fills index new-index] - (let [first (get fills index) - second (get fills new-index)] - (-> fills - (assoc index second) - (assoc new-index first)))) - (defn reorder-fills - [ids index new-index] + [ids from-pos to-space-between-pos] (ptk/reify ::reorder-fills ptk/WatchEvent (watch [_ state _] @@ -182,7 +167,7 @@ transform-attrs (fn [object] - (update object :fills types.fills/update swap-fills-index index new-index))] + (update object :fills types.fills/update d/reorder from-pos to-space-between-pos))] (rx/concat (rx/from (map #(dwt/update-text-with-function % transform-attrs) text-ids)) @@ -515,22 +500,22 @@ {:attrs [:strokes]})))))) (defn reorder-shadows - [ids index new-index] + [ids from-pos to-space-between-pos] (ptk/reify ::reorder-shadow ptk/WatchEvent (watch [_ _ _] (rx/of (dwsh/update-shapes ids - #(swap-attrs % :shadow index new-index)))))) + #(update % :shadow d/reorder from-pos to-space-between-pos)))))) (defn reorder-strokes - [ids index new-index] + [ids from-pos to-space-between-pos] (ptk/reify ::reorder-strokes ptk/WatchEvent (watch [_ _ _] (rx/of (dwsh/update-shapes ids - #(swap-attrs % :strokes index new-index) + #(update % :strokes d/reorder from-pos to-space-between-pos) {:attrs [:strokes]}))))) (defn picker-for-selected-shape diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs index 1efb38e5a0..7ea8e42132 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs @@ -7,20 +7,20 @@ (ns app.main.ui.workspace.sidebar.options.common (:require-macros [app.main.style :as stl]) (:require - [app.common.data.macros :as dm] [app.util.dom :as dom] [rumext.v2 :as mf])) -(mf/defc advanced-options [{:keys [visible? class children]}] +(mf/defc advanced-options* + [{:keys [class is-visible children]}] (let [ref (mf/use-ref nil)] (mf/use-effect - (mf/deps visible?) + (mf/deps is-visible) (fn [] (when-let [node (mf/ref-val ref)] - (when visible? + (when is-visible (dom/scroll-into-view-if-needed! node))))) - (when visible? - [:div {:class (dm/str class " " (stl/css :advanced-options-wrapper)) + (when is-visible + [:div {:class [class (stl/css :advanced-options-wrapper)] :ref ref} children]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/common.scss b/frontend/src/app/main/ui/workspace/sidebar/options/common.scss index eda06842b0..abad10d4af 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/common.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/common.scss @@ -4,8 +4,8 @@ // // Copyright (c) KALEIDOS INC -@use "refactor/common-refactor.scss" as deprecated; - .advanced-options-wrapper { - @include deprecated.flexColumn; + display: flex; + flex-direction: column; + gap: var(--sp-xs); } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs index 30cfa503fe..326c5dfa18 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs @@ -128,8 +128,8 @@ on-reorder (mf/use-fn (mf/deps ids) - (fn [new-index index] - (st/emit! (dc/reorder-fills ids index new-index)))) + (fn [from-pos to-space-between-pos] + (st/emit! (dc/reorder-fills ids from-pos to-space-between-pos)))) on-remove (mf/use-fn @@ -196,13 +196,13 @@ (dom/set-attribute! checkbox "indeterminate" true) (dom/remove-attribute! checkbox "indeterminate")))) - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} + [:div {:class (stl/css :fill-section)} + [:div {:class (stl/css :fill-title)} [:> title-bar* {:collapsable has-fills? :collapsed (not open?) :on-collapsed toggle-content :title label - :class (stl/css-case :title-spacing-fill (not has-fills?))} + :class (stl/css-case :fill-title-bar (not has-fills?))} (when (not (= :multiple fills)) [:> icon-button* {:variant "ghost" @@ -213,11 +213,11 @@ :icon i/add}])]] (when open? - [:div {:class (stl/css :element-content)} + [:div {:class (stl/css :fill-content)} (cond (= :multiple fills) - [:div {:class (stl/css :element-set-options-group)} - [:div {:class (stl/css :group-label)} + [:div {:class (stl/css :fill-multiple)} + [:div {:class (stl/css :fill-multiple-label)} (tr "settings.multiple")] [:> icon-button* {:variant "ghost" :aria-label (tr "workspace.options.fill.remove-fill") @@ -252,7 +252,7 @@ (when (or (= type :frame) (and (= type :multiple) (some? hide-on-export))) - [:div {:class (stl/css :checkbox)} + [:div {:class (stl/css :fill-checkbox)} [:label {:for "show-fill-on-export" :class (stl/css-case :global/checked (not hide-on-export))} [:span {:class (stl/css-case :check-mark true diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss index a1fb4b0483..82e182b54d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss @@ -4,44 +4,61 @@ // // Copyright (c) KALEIDOS INC +@use "ds/_sizes.scss" as *; +@use "ds/_borders.scss" as *; +@use "ds/typography.scss" as t; @use "refactor/common-refactor.scss" as deprecated; -.element-set { - margin: 0; +.fill-section { + display: grid; + grid-template-columns: repeat(8, var(--sp-xxxl)); + column-gap: var(--sp-xs); } -.element-title { - margin: 0; +.fill-title { + grid-column: span 8; } -.title-spacing-fill { - padding-left: deprecated.$s-2; - margin: 0; +.fill-title-bar { + padding-inline-start: var(--sp-xxs); } -.element-content { +.fill-content { + grid-column: span 8; + display: flex; flex-direction: column; - gap: deprecated.$s-12; - margin: deprecated.$s-4 0 deprecated.$s-8 0; + gap: var(--sp-m); + margin: var(--sp-xs) 0 var(--sp-s) 0; } -.element-set-options-group { - @include deprecated.flexRow; +.fill-multiple { + display: flex; + align-items: center; + gap: var(--sp-xs); } -.group-label { - @extend .mixed-bar; +.fill-multiple-label { + @include t.use-typography("body-small"); + display: flex; + align-items: center; + flex-grow: 1; + border-radius: $br-8; + block-size: $sz-32; + padding: var(--sp-s); + background-color: var(--color-background-tertiary); + color: var(--color-foreground-primary); } -.checkbox { +.fill-checkbox { + // TODO create a checkbox component in the DS @extend .input-checkbox; - padding-left: deprecated.$s-8; + padding-inline-start: var(--sp-s); span.checked { - background-color: var(--input-border-color-active); + background-color: var(--color-accent-primary); svg { @extend .button-icon-small; - stroke: var(--input-details-color); + stroke: var(--color-background-primary); } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs index 67cf41449b..d1783aed29 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs @@ -19,7 +19,7 @@ [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.icons :as deprecated-icon] - [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] + [app.main.ui.workspace.sidebar.options.common :refer [advanced-options*]] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]] [app.util.i18n :as i18n :refer [tr]] [okulary.core :as l] @@ -190,9 +190,9 @@ :icon i/remove}]]] (when (:display grid) - [:& advanced-options {:class (stl/css :grid-advanced-options) - :visible? open? - :on-close toggle-advanced-options} + [:> advanced-options* {:class (stl/css :grid-advanced-options) + :is-visible open? + :on-close toggle-advanced-options} ;; square (when (= :square type) [:div {:class (stl/css :square-row)} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs index 40feb597dc..d517dc675b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs @@ -15,17 +15,12 @@ [app.main.data.workspace :as dw] [app.main.data.workspace.colors :as dc] [app.main.data.workspace.shapes :as dwsh] - [app.main.data.workspace.undo :as dwu] [app.main.store :as st] - [app.main.ui.components.numeric-input :refer [numeric-input*]] - [app.main.ui.components.reorder-handler :refer [reorder-handler*]] - [app.main.ui.components.select :refer [select]] [app.main.ui.components.title-bar :refer [title-bar*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.hooks :as h] - [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] - [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]] + [app.main.ui.workspace.sidebar.options.rows.shadow-row :refer [shadow-row*]] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) @@ -49,199 +44,6 @@ (filterv (fn [[idx _]] (not= idx index))) (mapv second))) -(mf/defc shadow-entry* - [{:keys [index shadow is-open - on-reorder - on-toggle-open - on-detach-color - on-update - on-remove - on-toggle-visibility]}] - (let [shadow-style (:style shadow) - shadow-id (:id shadow) - - hidden? (:hidden shadow) - - on-drop - (mf/use-fn - (mf/deps on-reorder index) - (fn [_ data] - (on-reorder index (:index data)))) - - [dprops dref] - (h/use-sortable - :data-type "penpot/shadow-entry" - :on-drop on-drop - :detect-center? false - :data {:id (dm/str "shadow-" index) - :index index - :name (dm/str "Border row" index)}) - - on-remove - (mf/use-fn (mf/deps index) #(on-remove index)) - - on-update-offset-x - (mf/use-fn - (mf/deps index) - (fn [value] - (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) - (on-update index :offset-x value))) - - on-update-offset-y - (mf/use-fn - (mf/deps index) - (fn [value] - (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) - (on-update index :offset-y value))) - - on-update-spread - (mf/use-fn - (mf/deps index) - (fn [value] - (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) - (on-update index :spread value))) - - on-update-blur - (mf/use-fn - (mf/deps index) - (fn [value] - (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) - (on-update index :blur value))) - - on-update-color - (mf/use-fn - (mf/deps index on-update) - (fn [color] - (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) - (on-update index :color color))) - - on-detach-color - (mf/use-fn (mf/deps index) #(on-detach-color index)) - - on-style-change - (mf/use-fn - (mf/deps index) - (fn [value] - (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) - (on-update index :style (keyword value)))) - - on-toggle-visibility - (mf/use-fn - (mf/deps index) - (fn [] - (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) - (on-toggle-visibility index))) - - on-toggle-open - (mf/use-fn - (mf/deps shadow-id on-toggle-open) - #(on-toggle-open shadow-id)) - - type-options - (mf/with-memo [] - [{:value "drop-shadow" :label (tr "workspace.options.shadow-options.drop-shadow")} - {:value "inner-shadow" :label (tr "workspace.options.shadow-options.inner-shadow")}]) - - on-open-row - (mf/use-fn #(st/emit! (dwu/start-undo-transaction :color-row))) - - on-close-row - (mf/use-fn #(st/emit! (dwu/commit-undo-transaction :color-row)))] - - [:div {:class (stl/css-case :global/shadow-option true - :shadow-element true - :dnd-over-top (= (:over dprops) :top) - :dnd-over-bot (= (:over dprops) :bot))} - (when (some? on-reorder) - [:> reorder-handler* {:ref dref}]) - - [:* - [:div {:class (stl/css :basic-options)} - [:div {:class (stl/css-case :shadow-info true - :hidden hidden?)} - [:> icon-button* {:on-click on-toggle-open - :variant "secondary" - :disabled hidden? - :class (stl/css-case - :disabled hidden? - :more-options true - :selected is-open) - :aria-label "open more options" - :icon i/menu}] - [:div {:class (stl/css :type-select)} - [:& select - {:class (stl/css :shadow-type-select) - :default-value (d/name shadow-style) - :options type-options - :on-change on-style-change}]]] - [:div {:class (stl/css :actions)} - [:> icon-button* {:variant "ghost" - :aria-label (tr "workspace.options.shadow-options.toggle-shadow") - :on-click on-toggle-visibility - :icon (if hidden? "hide" "shown")}] - [:> icon-button* {:variant "ghost" - :aria-label (tr "workspace.options.shadow-options.remove-shadow") - :on-click on-remove - :icon i/remove}]]] - (when is-open - [:& advanced-options {:class (stl/css :shadow-advanced-options) - :visible? is-open - :on-close on-toggle-open} - - [:div {:class (stl/css :first-row)} - [:div {:class (stl/css :offset-x-input) - :title (tr "workspace.options.shadow-options.offsetx")} - [:span {:class (stl/css :input-label)} - "X"] - [:> numeric-input* {:class (stl/css :numeric-input) - :no-validate true - :placeholder "--" - :on-change on-update-offset-x - :value (:offset-x shadow)}]] - - [:div {:class (stl/css :blur-input) - :title (tr "workspace.options.shadow-options.blur")} - [:span {:class (stl/css :input-label)} - (tr "workspace.options.shadow-options.blur")] - [:> numeric-input* {:class (stl/css :numeric-input) - :no-validate true - :placeholder "--" - :on-change on-update-blur - :min 0 - :value (:blur shadow)}]] - - [:div {:class (stl/css :spread-input) - :title (tr "workspace.options.shadow-options.spread")} - [:span {:class (stl/css :input-label)} - (tr "workspace.options.shadow-options.spread")] - [:> numeric-input* {:class (stl/css :numeric-input) - :no-validate true - :placeholder "--" - :on-change on-update-spread - :value (:spread shadow)}]]] - - [:div {:class (stl/css :second-row)} - [:div {:class (stl/css :offset-y-input) - :title (tr "workspace.options.shadow-options.offsety")} - [:span {:class (stl/css :input-label)} - "Y"] - [:> numeric-input* {:class (stl/css :numeric-input) - :no-validate true - :placeholder "--" - :on-change on-update-offset-y - :value (:offset-y shadow)}]] - - [:> color-row* {:class (stl/css :shadow-color) - :color (:color shadow) - :title (tr "workspace.options.shadow-options.color") - :disable-gradient true - :disable-image true - :origin :shadow - :on-change on-update-color - :on-detach on-detach-color - :on-open on-open-row - :on-close on-close-row}]]])]])) - (def ^:private xf:add-index (map-indexed (fn [index shadow] (assoc shadow ::index index)))) @@ -279,10 +81,10 @@ handle-reorder (mf/use-fn - (fn [new-index index] + (fn [from-pos to-space-between-pos] (let [ids (mf/ref-val ids-ref)] (st/emit! (dw/trigger-bounding-box-cloaking ids)) - (st/emit! (dc/reorder-shadows ids index new-index))))) + (st/emit! (dc/reorder-shadows ids from-pos to-space-between-pos))))) on-add-shadow (mf/use-fn @@ -325,8 +127,8 @@ (-> shadow (assoc attr value) (ctss/check-shadow))))))))))] - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} + [:div {:class (stl/css :shadow-section)} + [:div {:class (stl/css :shadow-title)} [:> title-bar* {:collapsable has-shadows? :collapsed (not show-content?) :on-collapsed toggle-content @@ -334,7 +136,7 @@ :multiple (tr "workspace.options.shadow-options.title.multiple") :group (tr "workspace.options.shadow-options.title.group") (tr "workspace.options.shadow-options.title")) - :class (stl/css-case :title-spacing-shadow (not has-shadows?))} + :class (stl/css-case :shadow-title-bar (not has-shadows?))} (when-not (= :multiple shadows) [:> icon-button* {:variant "ghost" @@ -346,20 +148,20 @@ (when show-content? (cond (= :multiple shadows) - [:div {:class (stl/css :element-set-content)} - [:div {:class (stl/css :multiple-shadows)} - [:div {:class (stl/css :label)} (tr "settings.multiple")] - [:div {:class (stl/css :actions)} - [:> icon-button* {:variant "ghost" - :aria-label (tr "workspace.options.shadow-options.remove-shadow") - :on-click on-remove-all - :icon i/remove}]]]] + [:div {:class (stl/css :shadow-content)} + [:div {:class (stl/css :shadow-multiple)} + [:div {:class (stl/css :shadow-multiple-label)} + (tr "settings.multiple")] + [:> icon-button* {:variant "ghost" + :aria-label (tr "workspace.options.shadow-options.remove-shadow") + :on-click on-remove-all + :icon i/remove}]]] (some? shadows) [:> h/sortable-container* {} - [:div {:class (stl/css :element-set-content)} + [:div {:class (stl/css :shadow-content)} (for [{:keys [::index id] :as shadow} shadows] - [:> shadow-entry* + [:> shadow-row* {:key (dm/str index) :index index :shadow shadow diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.scss index 86ec39aab7..bc922763ca 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.scss @@ -5,34 +5,39 @@ // Copyright (c) KALEIDOS INC @use "ds/_sizes.scss" as *; -@use "ds/typography.scss" as t; @use "ds/_borders.scss" as *; -@use "ds/_utils.scss" as *; -@use "refactor/common-refactor.scss" as deprecated; +@use "ds/typography.scss" as t; -.element-set { - margin: 0; +.shadow-section { + display: grid; + grid-template-columns: repeat(8, var(--sp-xxxl)); + column-gap: var(--sp-xs); } -.title-spacing-shadow { - margin: 0; +.shadow-title { + grid-column: span 8; +} + +.shadow-title-bar { padding-inline-start: var(--sp-xxs); } -.element-set-content { - margin-block-start: var(--sp-xs); +.shadow-content { + grid-column: span 8; + display: flex; flex-direction: column; gap: var(--sp-xs); + margin-block-start: var(--sp-xs); } -.multiple-shadows { +.shadow-multiple { display: flex; align-items: center; gap: var(--sp-xs); } -.label { +.shadow-multiple-label { @include t.use-typography("body-small"); display: flex; align-items: center; @@ -43,132 +48,3 @@ background-color: var(--color-background-tertiary); color: var(--color-foreground-primary); } - -.actions { - display: grid; - grid-template-columns: subgrid; - grid-column: span 2; -} - -.shadow-element { - display: flex; - flex-direction: column; - gap: var(--sp-xs); - position: relative; - - &:hover { - --reorder-icon-visibility: visible; - } - - &.dnd-over-top { - --reorder-top-display: block; - } - - &.dnd-over-bot { - --reorder-bottom-display: block; - } -} - -.basic-options { - display: grid; - grid-template-columns: repeat(8, var(--sp-xxxl)); - gap: var(--sp-xs); -} - -.shadow-info { - grid-column: span 6; - display: flex; - align-items: center; - gap: px2rem(1); -} - -.type-select { - padding: 0; - border-radius: 0 $br-8 $br-8 0; - flex-grow: 1; -} - -.shadow-type-select { - flex-grow: 1; - border-radius: 0 $br-8 $br-8 0; -} - -// TODO: Remove these nested classes by using DS component -.hidden { - .type-select { - cursor: default; - pointer-events: none; - box-sizing: border-box; - color: var(--color-foreground-secondary); - stroke: var(--color-foreground-secondary); - background-color: transparent; - } - .shadow-type-select { - cursor: default; - pointer-events: none; - box-sizing: border-box; - color: var(--color-foreground-secondary); - stroke: var(--color-foreground-secondary); - background-color: transparent; - border: $b-1 solid var(--color-background-quaternary); - } -} - -.shadow-advanced-options { - display: grid; - grid-template-columns: repeat(8, var(--sp-xxxl)); - gap: var(--sp-xs); -} - -.first-row, -.second-row { - display: grid; - grid-column: 1 / -1; - grid-template-columns: subgrid; -} - -.offset-x-input, -.blur-input, -.spread-input, -.offset-y-input { - // TODO remove this input by changing the input to DS component - @extend .input-element; - @include t.use-typography("body-small"); - .input-label { - padding-inline-start: var(--sp-s); - inline-size: px2rem(60); - } -} - -.offset-x-input { - grid-column: span 2; -} - -.offset-y-input { - grid-column: span 2; -} - -.blur-input { - grid-column: span 3; -} - -.spread-input { - grid-column: span 3; -} - -.shadow-color { - grid-column: span 6; -} - -.more-options { - border-radius: $br-8 0 0 $br-8; -} - -.selected { - --button-bg-color: var(--color-background-quaternary); - --button-fg-color: var(--color-accent-primary); -} - -.disabled { - border: $b-1 solid var(--color-background-quaternary); -} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs index 52a66b9053..4e4c13cd9c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs @@ -18,7 +18,7 @@ [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.hooks :as h] - [app.main.ui.workspace.sidebar.options.rows.stroke-row :refer [stroke-row]] + [app.main.ui.workspace.sidebar.options.rows.stroke-row :refer [stroke-row*]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] @@ -89,10 +89,9 @@ handle-reorder (mf/use-fn (mf/deps ids) - (fn [new-index] - (fn [index] - (st/emit! (udw/trigger-bounding-box-cloaking ids)) - (st/emit! (dc/reorder-strokes ids index new-index))))) + (fn [from-pos to-space-between-pos] + (st/emit! (udw/trigger-bounding-box-cloaking ids)) + (st/emit! (dc/reorder-strokes ids from-pos to-space-between-pos)))) on-stroke-style-change (mf/use-fn @@ -177,13 +176,13 @@ :token token :shape-ids ids}))))] - [:div {:class (stl/css :element-set)} - [:div {:class (stl/css :element-title)} + [:div {:class (stl/css :stroke-section)} + [:div {:class (stl/css :stroke-title)} [:> title-bar* {:collapsable has-strokes? :collapsed (not open?) :on-collapsed toggle-content :title label - :class (stl/css-case :title-spacing-stroke (not has-strokes?))} + :class (stl/css-case :stroke-title-bar (not has-strokes?))} (when (not (= :multiple strokes)) [:> icon-button* {:variant "ghost" :aria-label (tr "workspace.options.stroke.add-stroke") @@ -191,12 +190,12 @@ :icon i/add :data-testid "add-stroke"}])]] (when open? - [:div {:class (stl/css-case :element-content true - :empty-content (not has-strokes?))} + [:div {:class (stl/css-case :stroke-content true + :stroke-content-empty (not has-strokes?))} (cond (= :multiple strokes) - [:div {:class (stl/css :element-set-options-group)} - [:div {:class (stl/css :group-label)} + [:div {:class (stl/css :stroke-multiple)} + [:div {:class (stl/css :stroke-multiple-label)} (tr "settings.multiple")] [:> icon-button* {:variant "ghost" :aria-label (tr "workspace.options.stroke.remove-stroke") @@ -205,28 +204,28 @@ (seq strokes) [:> h/sortable-container* {} (for [[index value] (d/enumerate (:strokes values []))] - [:& stroke-row {:key (dm/str "stroke-" index) - :stroke value - :title (tr "workspace.options.stroke-color") - :index index - :ids ids - :show-caps show-caps - :on-color-change on-color-change - :on-color-detach on-color-detach - :on-stroke-width-change on-stroke-width-change - :on-stroke-style-change on-stroke-style-change - :on-stroke-alignment-change on-stroke-alignment-change - :open-caps-select open-caps-select - :close-caps-select close-caps-select - :on-stroke-cap-start-change on-stroke-cap-start-change - :on-stroke-cap-end-change on-stroke-cap-end-change - :on-stroke-cap-switch on-stroke-cap-switch - :applied-tokens applied-tokens - :on-detach-token on-detach-token - :on-remove on-remove - :on-reorder (handle-reorder index) - :disable-drag disable-drag - :on-focus on-focus - :select-on-focus (not @disable-drag) - :on-blur on-blur - :disable-stroke-style disable-stroke-style}])])])])) + [:& stroke-row* {:key (dm/str "stroke-" index) + :stroke value + :title (tr "workspace.options.stroke-color") + :index index + :ids ids + :show-caps show-caps + :on-color-change on-color-change + :on-color-detach on-color-detach + :on-stroke-width-change on-stroke-width-change + :on-stroke-style-change on-stroke-style-change + :on-stroke-alignment-change on-stroke-alignment-change + :open-caps-select open-caps-select + :close-caps-select close-caps-select + :on-stroke-cap-start-change on-stroke-cap-start-change + :on-stroke-cap-end-change on-stroke-cap-end-change + :on-stroke-cap-switch on-stroke-cap-switch + :applied-tokens applied-tokens + :on-detach-token on-detach-token + :on-remove on-remove + :on-reorder (handle-reorder index) + :disable-drag disable-drag + :on-focus on-focus + :select-on-focus (not @disable-drag) + :on-blur on-blur + :disable-stroke-style disable-stroke-style}])])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.scss index 9dec902ec6..e85f576b45 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.scss @@ -4,35 +4,51 @@ // // Copyright (c) KALEIDOS INC -@use "refactor/common-refactor.scss" as deprecated; +@use "ds/_sizes.scss" as *; +@use "ds/_borders.scss" as *; +@use "ds/typography.scss" as t; -.element-set { - margin: 0; +.stroke-section { + display: grid; + grid-template-columns: repeat(8, var(--sp-xxxl)); + column-gap: var(--sp-xs); } -.element-title { - margin: 0; +.stroke-title { + grid-column: span 8; } -.title-spacing-stroke { - padding-left: deprecated.$s-2; - margin: 0; +.stroke-title-bar { + padding-inline-start: var(--sp-xxs); } -.element-content { +.stroke-content { + grid-column: span 8; + display: flex; flex-direction: column; - gap: deprecated.$s-12; - margin: deprecated.$s-4 0 deprecated.$s-8 0; - &.empty-content { + gap: var(--sp-m); + margin: var(--sp-xs) 0 var(--sp-s) 0; + + &.stroke-content-empty { margin: 0; } } -.element-set-options-group { - @include deprecated.flexRow; +.stroke-multiple { + display: flex; + align-items: center; + gap: var(--sp-xs); } -.group-label { - @extend .mixed-bar; +.stroke-multiple-label { + @include t.use-typography("body-small"); + display: flex; + align-items: center; + flex-grow: 1; + border-radius: $br-8; + block-size: $sz-32; + padding: var(--sp-s); + background-color: var(--color-background-tertiary); + color: var(--color-foreground-primary); } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs index f416763497..43d85f9610 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs @@ -319,8 +319,10 @@ on-drop (mf/use-fn (mf/deps on-reorder index) - (fn [_ data] - (on-reorder index (:index data)))) + (fn [relative-pos data] + (let [from-pos (:index data) + to-space-between-pos (if (= relative-pos :bot) (inc index) index)] + (on-reorder from-pos to-space-between-pos)))) [dprops dref] (if (some? on-reorder) @@ -329,9 +331,7 @@ :on-drop on-drop :disabled disable-drag :detect-center? false - :data {:id (str "color-row-" index) - :index index - :name (str "Color row" index)}) + :data {:index index}) [nil nil]) row-class diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.cljs new file mode 100644 index 0000000000..e361615511 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.cljs @@ -0,0 +1,210 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns app.main.ui.workspace.sidebar.options.rows.shadow-row + (:require-macros [app.main.style :as stl]) + (:require + [app.common.data :as d] + [app.main.data.workspace :as dw] + [app.main.data.workspace.undo :as dwu] + [app.main.store :as st] + [app.main.ui.components.numeric-input :refer [numeric-input*]] + [app.main.ui.components.reorder-handler :refer [reorder-handler*]] + [app.main.ui.components.select :refer [select]] + [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] + [app.main.ui.ds.foundations.assets.icon :as i] + [app.main.ui.hooks :as h] + [app.main.ui.workspace.sidebar.options.common :refer [advanced-options*]] + [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]] + [app.util.i18n :as i18n :refer [tr]] + [rumext.v2 :as mf])) + +(mf/defc shadow-row* + [{:keys [index shadow is-open + on-reorder + on-toggle-open + on-detach-color + on-update + on-remove + on-toggle-visibility]}] + (let [shadow-style (:style shadow) + shadow-id (:id shadow) + + hidden? (:hidden shadow) + + on-drop + (mf/use-fn + (mf/deps on-reorder index) + (fn [relative-pos data] + (let [from-pos (:index data) + to-space-between-pos (if (= relative-pos :bot) (inc index) index)] + (on-reorder from-pos to-space-between-pos)))) + + [dprops dref] + (h/use-sortable + :data-type "penpot/shadow-entry" + :on-drop on-drop + :detect-center? false + :data {:index index}) + + on-remove + (mf/use-fn (mf/deps index) #(on-remove index)) + + on-update-offset-x + (mf/use-fn + (mf/deps index) + (fn [value] + (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) + (on-update index :offset-x value))) + + on-update-offset-y + (mf/use-fn + (mf/deps index) + (fn [value] + (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) + (on-update index :offset-y value))) + + on-update-spread + (mf/use-fn + (mf/deps index) + (fn [value] + (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) + (on-update index :spread value))) + + on-update-blur + (mf/use-fn + (mf/deps index) + (fn [value] + (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) + (on-update index :blur value))) + + on-update-color + (mf/use-fn + (mf/deps index on-update) + (fn [color] + (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) + (on-update index :color color))) + + on-detach-color + (mf/use-fn (mf/deps index) #(on-detach-color index)) + + on-style-change + (mf/use-fn + (mf/deps index) + (fn [value] + (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) + (on-update index :style (keyword value)))) + + on-toggle-visibility + (mf/use-fn + (mf/deps index) + (fn [] + (st/emit! (dw/trigger-bounding-box-cloaking [shadow-id])) + (on-toggle-visibility index))) + + on-toggle-open + (mf/use-fn + (mf/deps shadow-id on-toggle-open) + #(on-toggle-open shadow-id)) + + type-options + (mf/with-memo [] + [{:value "drop-shadow" :label (tr "workspace.options.shadow-options.drop-shadow")} + {:value "inner-shadow" :label (tr "workspace.options.shadow-options.inner-shadow")}]) + + on-open-row + (mf/use-fn #(st/emit! (dwu/start-undo-transaction :color-row))) + + on-close-row + (mf/use-fn #(st/emit! (dwu/commit-undo-transaction :color-row)))] + + [:div {:class (stl/css-case :global/shadow-option true + :shadow-element true + :dnd-over-top (= (:over dprops) :top) + :dnd-over-bot (= (:over dprops) :bot))} + (when (some? on-reorder) + [:> reorder-handler* {:ref dref}]) + + [:* + [:div {:class (stl/css :shadow-basic)} + [:div {:class (stl/css :shadow-basic-info)} + [:> icon-button* {:variant "secondary" + :icon i/menu + :class (stl/css-case :shadow-basic-button true + :selected is-open) + :aria-label "open more options" + :disabled hidden? + :on-click on-toggle-open}] + [:& select {:class (stl/css :shadow-basic-select) + :default-value (d/name shadow-style) + :options type-options + :disabled hidden? + :on-change on-style-change}]] + + [:div {:class (stl/css :shadow-basic-actions)} + [:> icon-button* {:variant "ghost" + :aria-label (tr "workspace.options.shadow-options.toggle-shadow") + :on-click on-toggle-visibility + :icon (if hidden? "hide" "shown")}] + [:> icon-button* {:variant "ghost" + :aria-label (tr "workspace.options.shadow-options.remove-shadow") + :on-click on-remove + :icon i/remove}]]] + + (when is-open + [:> advanced-options* {:class (stl/css :shadow-advanced) + :is-visible is-open + :on-close on-toggle-open} + + [:div {:class (stl/css :shadow-advanced-row)} + [:div {:class (stl/css :shadow-advanced-offset-x) + :title (tr "workspace.options.shadow-options.offsetx")} + [:span {:class (stl/css :shadow-advanced-label)} + "X"] + [:> numeric-input* {:no-validate true + :placeholder "--" + :on-change on-update-offset-x + :value (:offset-x shadow)}]] + + [:div {:class (stl/css :shadow-advanced-blur) + :title (tr "workspace.options.shadow-options.blur")} + [:span {:class (stl/css :shadow-advanced-label)} + (tr "workspace.options.shadow-options.blur")] + [:> numeric-input* {:no-validate true + :placeholder "--" + :on-change on-update-blur + :min 0 + :value (:blur shadow)}]] + + [:div {:class (stl/css :shadow-advanced-spread) + :title (tr "workspace.options.shadow-options.spread")} + [:span {:class (stl/css :shadow-advanced-label)} + (tr "workspace.options.shadow-options.spread")] + [:> numeric-input* {:no-validate true + :placeholder "--" + :on-change on-update-spread + :value (:spread shadow)}]]] + + [:div {:class (stl/css :shadow-advanced-row)} + [:div {:class (stl/css :shadow-advanced-offset-y) + :title (tr "workspace.options.shadow-options.offsety")} + [:span {:class (stl/css :shadow-advanced-label)} + "Y"] + [:> numeric-input* {:no-validate true + :placeholder "--" + :on-change on-update-offset-y + :value (:offset-y shadow)}]] + + [:> color-row* {:class (stl/css :shadow-advanced-color) + :color (:color shadow) + :title (tr "workspace.options.shadow-options.color") + :disable-gradient true + :disable-image true + :origin :shadow + :on-change on-update-color + :on-detach on-detach-color + :on-open on-open-row + :on-close on-close-row}]]])]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.scss b/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.scss new file mode 100644 index 0000000000..79c9b5b0f4 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/shadow_row.scss @@ -0,0 +1,112 @@ +// 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 "ds/_sizes.scss" as *; +@use "ds/typography.scss" as t; +@use "ds/_borders.scss" as *; +@use "ds/_utils.scss" as *; +@use "refactor/common-refactor.scss" as deprecated; + +.shadow-element { + display: flex; + flex-direction: column; + gap: var(--sp-xs); + position: relative; + + &:hover { + --reorder-icon-visibility: visible; + } + + &.dnd-over-top { + --reorder-top-display: block; + } + + &.dnd-over-bot { + --reorder-bottom-display: block; + } +} + +.shadow-basic { + display: grid; + grid-template-columns: repeat(8, var(--sp-xxxl)); + gap: var(--sp-xs); +} + +.shadow-basic-info { + grid-column: span 6; + display: flex; + align-items: center; + gap: px2rem(1); +} + +.shadow-basic-button { + border-radius: $br-8 0 0 $br-8; + + &.selected { + --button-bg-color: var(--color-background-quaternary); + --button-fg-color: var(--color-accent-primary); + } + + &:disabled { + border: $b-1 solid var(--color-background-quaternary); + } +} + +.shadow-basic-select { + flex-grow: 1; + border-radius: 0 $br-8 $br-8 0; +} + +.shadow-basic-actions { + display: grid; + grid-template-columns: subgrid; + grid-column: span 2; +} + +.shadow-advanced { + display: grid; + grid-template-columns: repeat(8, var(--sp-xxxl)); + gap: var(--sp-xs); +} + +.shadow-advanced-row { + display: grid; + grid-column: 1 / -1; + grid-template-columns: subgrid; +} + +.shadow-advanced-offset-x, +.shadow-advanced-blur, +.shadow-advanced-spread, +.shadow-advanced-offset-y { + // TODO remove this input by changing the input to DS component + @extend .input-element; + @include t.use-typography("body-small"); + .shadow-advanced-label { + padding-inline-start: var(--sp-s); + inline-size: px2rem(60); + } +} + +.shadow-advanced-offset-x { + grid-column: span 2; +} + +.shadow-advanced-blur { + grid-column: span 3; +} + +.shadow-advanced-spread { + grid-column: span 3; +} + +.shadow-advanced-offset-y { + grid-column: span 2; +} + +.shadow-advanced-color { + grid-column: span 6; +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs index 54c9bd0072..1e3207d80e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs @@ -14,14 +14,14 @@ [app.main.ui.components.numeric-input :refer [numeric-input*]] [app.main.ui.components.reorder-handler :refer [reorder-handler*]] [app.main.ui.components.select :refer [select]] + [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] + [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] [app.main.ui.hooks :as h] - [app.main.ui.icons :as deprecated-icon] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) -(mf/defc stroke-row - {::mf/wrap-props false} +(mf/defc stroke-row* [{:keys [index stroke title @@ -46,19 +46,22 @@ ids]}] (let [on-drop - (fn [_ data] - (on-reorder (:index data))) + (mf/use-fn + (mf/deps on-reorder index) + (fn [relative-pos data] + (let [from-pos (:index data) + to-space-between-pos (if (= relative-pos :bot) (inc index) index)] + (on-reorder from-pos to-space-between-pos)))) - [dprops dref] (if (some? on-reorder) - (h/use-sortable - :data-type "penpot/stroke-row" - :on-drop on-drop - :disabled @disable-drag - :detect-center? false - :data {:id (str "stroke-row-" index) - :index index - :name (str "Border row" index)}) - [nil nil]) + [dprops dref] + (if (some? on-reorder) + (h/use-sortable + :data-type "penpot/stroke-row" + :on-drop on-drop + :disabled @disable-drag + :detect-center? false + :data {:index index}) + [nil nil]) stroke-color-token (:stroke-color applied-tokens) @@ -191,52 +194,41 @@ ;; Stroke Width, Alignment & Style [:div {:class (stl/css :stroke-options)} - [:div {:class (stl/css :stroke-width-input-element) + [:div {:class (stl/css :stroke-width-input) :title (tr "workspace.options.stroke-width")} - [:span {:class (stl/css :icon)} - deprecated-icon/stroke-size] - [:> numeric-input* - {:min 0 - :className (stl/css :stroke-width-input) - :value stroke-width - :placeholder (tr "settings.multiple") - :on-change on-width-change - :on-focus on-focus - :select-on-focus select-on-focus - :on-blur on-blur}]] + [:> icon* {:icon-id i/stroke-size + :size "s"}] + [:> numeric-input* {:value stroke-width + :min 0 + :placeholder (tr "settings.multiple") + :on-change on-width-change + :on-focus on-focus + :select-on-focus select-on-focus + :on-blur on-blur}]] - [:div {:class (stl/css :select-wrapper :stroke-alignment-select) + [:div {:class (stl/css :stroke-alignment-select) :data-testid "stroke.alignment"} - [:& select - {:default-value stroke-alignment - :options stroke-alignment-options - :on-change on-alignment-change}]] + [:& select {:default-value stroke-alignment + :options stroke-alignment-options + :on-change on-alignment-change}]] (when-not disable-stroke-style - [:div {:class (stl/css :select-wrapper :stroke-style-select) + [:div {:class (stl/css :stroke-style-select) :data-testid "stroke.style"} - [:& select - {:default-value stroke-style - :options stroke-style-options - :on-change on-style-change}]])] + [:& select {:default-value stroke-style + :options stroke-style-options + :on-change on-style-change}]])] ;; Stroke Caps (when show-caps [:div {:class (stl/css :stroke-caps-options)} - [:div {:class (stl/css :cap-select)} - [:& select - {:default-value (:stroke-cap-start stroke) - :dropdown-class (stl/css :stroke-cap-dropdown-start) - :options stroke-caps-options - :on-change on-caps-start-change}]] - - [:button {:class (stl/css :swap-caps-btn) - :on-click on-cap-switch} - deprecated-icon/switch] - - [:div {:class (stl/css :cap-select)} - [:& select - {:default-value (:stroke-cap-end stroke) - :dropdown-class (stl/css :stroke-cap-dropdown) - :options stroke-caps-options - :on-change on-caps-end-change}]]])])) + [:& select {:default-value (:stroke-cap-start stroke) + :options stroke-caps-options + :on-change on-caps-start-change}] + [:> icon-button* {:variant "secondary" + :aria-label (tr "labels.switch") + :on-click on-cap-switch + :icon i/switch}] + [:& select {:default-value (:stroke-cap-end stroke) + :options stroke-caps-options + :on-change on-caps-end-change}]])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.scss b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.scss index f6f6090981..1d2fe1198a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.scss @@ -4,10 +4,13 @@ // // Copyright (c) KALEIDOS INC +@use "ds/typography.scss" as t; @use "refactor/common-refactor.scss" as deprecated; .stroke-data { - @include deprecated.flexColumn; + display: flex; + flex-direction: column; + gap: var(--sp-xs); position: relative; @@ -31,64 +34,28 @@ align-items: center; grid-template-columns: repeat(8, var(--sp-xxxl)); gap: var(--sp-xs); - - .stroke-width-input-element { - @extend .input-element; - @include deprecated.bodySmallTypography; - grid-column: span 2; - } - - .stroke-alignment-select { - grid-column: span 3; - } - - .stroke-style-select { - grid-column: span 3; - } } + +.stroke-width-input { + grid-column: span 2; + + // TODO replace with numeric-input* from DS + @extend .input-element; + + @include t.use-typography("body-small"); + padding-inline-start: var(--sp-xs); +} + +.stroke-alignment-select { + grid-column: span 3; +} + +.stroke-style-select { + grid-column: span 3; +} + .stroke-caps-options { - /* - This element do not match the 8 column grid of sidebar - - |___|-|___|-|___|-|___|-|___|-|___|-|___|-|___| -> 8 column grid, (--sp-xxxl) width each - - |__________________|-|__________________|-|___| -> 2 inputs blocks + 1 button. - - We need to calculate the total width of each input block: - - 3.5 columns of the the base grid (--sp-xxxl) - - plus 3 inter-column gaps (3 * --sp-xs) - - minus half a gap (--sp-xs / 2) because the last spacing is shared - with the next block, keeping the overall visual rhythm consistent. - */ - - --input-width: calc(var(--sp-xxxl) * 3.5 + 3 * var(--sp-xs) - (var(--sp-xs) / 2)); - display: grid; - grid-template-columns: - var(--input-width) /* first input block */ - var(--input-width) /* second input block */ - var(--sp-xxxl); /* action button */ - gap: var(--sp-xs); -} - -.stroke-cap-dropdown, -.stroke-cap-dropdown-start { - min-width: deprecated.$s-124; - width: fit-content; - max-width: deprecated.$s-252; - right: 0; - left: unset; -} - -.stroke-cap-dropdown-start { - left: 0; - right: unset; -} -.swap-caps-btn { - @extend .button-secondary; - height: var(--sp-xxxl); - width: var(--sp-xxxl); - svg { - @extend .button-icon; - } + grid-template-columns: 1fr auto 1fr; + column-gap: var(--sp-xs); } diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 376cd0cf0d..e4b9d44b15 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -2660,6 +2660,10 @@ msgstr "Styles" msgid "labels.svg" msgstr "SVG" +#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:250 +msgid "labels.switch" +msgstr "Switch" + #: src/app/main/ui/onboarding/questions.cljs:256 #, unused msgid "labels.team-leader" @@ -7577,7 +7581,7 @@ msgstr "" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1024, src/app/main/ui/workspace/tokens/management/create/form.cljs:1039 msgid "workspace.tokens.font-weight-value-enter" -msgstr "Enter a value (300, Bold, Regular Italic...) or an {alias}" +msgstr "Font weight (300, Bold Italic...) or an {alias}" #: src/app/main/ui/workspace/tokens/management/context_menu.cljs:228 msgid "workspace.tokens.gaps" @@ -7713,11 +7717,11 @@ msgstr "Add a theme (i.e. Light)" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1047 msgid "workspace.tokens.letter-spacing-value-enter-composite" -msgstr "Add letter spacing or {alias}" +msgstr "Letter spacing or {alias}" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1043 msgid "workspace.tokens.line-height-value-enter" -msgstr "Enter line height — multiplier, px, %, or {alias}" +msgstr "Line height (multiplier, px, %) or {alias}" #: src/app/main/ui/workspace/tokens/management/context_menu.cljs:220 msgid "workspace.tokens.margins" @@ -7865,11 +7869,11 @@ msgstr "Stroke width must be greater than or equal to 0." #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1012, src/app/main/ui/workspace/tokens/management/create/form.cljs:1051 msgid "workspace.tokens.text-case-value-enter" -msgstr "Enter: none | uppercase | lowercase | capitalize or {alias}" +msgstr "none | uppercase | lowercase | capitalize or {alias}" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1018, src/app/main/ui/workspace/tokens/management/create/form.cljs:1055 msgid "workspace.tokens.text-decoration-value-enter" -msgstr "Enter text decoration: none | underline | strike-through" +msgstr "none | underline | strike-through or {alias}" #: src/app/main/ui/workspace/tokens/themes/create_modal.cljs:130 msgid "workspace.tokens.theme-name" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index a33be1b5c9..1149dae3ca 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -2630,6 +2630,10 @@ msgstr "Estilos" msgid "labels.svg" msgstr "SVG" +#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:250 +msgid "labels.switch" +msgstr "Intercambiar" + #: src/app/main/ui/onboarding/questions.cljs:256 #, unused msgid "labels.team-leader" @@ -7514,7 +7518,7 @@ msgstr "" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1024, src/app/main/ui/workspace/tokens/management/create/form.cljs:1039 msgid "workspace.tokens.font-weight-value-enter" -msgstr "Introduce un valor (300, Bold, Regular Italic...) o un {alias}" +msgstr "Font weight (300, Bold, Regular Italic...) o un {alias}" #: src/app/main/ui/workspace/tokens/style_dictionary.cljs #, unused @@ -7625,11 +7629,11 @@ msgstr "Añade un Tema (p. ej. Claro)" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1047 msgid "workspace.tokens.letter-spacing-value-enter-composite" -msgstr "Introduce letter spacing o {alias}" +msgstr "Letter spacing o {alias}" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1043 msgid "workspace.tokens.line-height-value-enter" -msgstr "Introduce line height — multiplicador, px o % — o {alias}" +msgstr "Line height (multiplicador, px o %) o {alias}" #: src/app/main/data/workspace/tokens/errors.cljs:57 msgid "workspace.tokens.missing-references" @@ -7743,11 +7747,11 @@ msgstr "Stroke width debe ser mayor o igual a 0." #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1012, src/app/main/ui/workspace/tokens/management/create/form.cljs:1051 msgid "workspace.tokens.text-case-value-enter" -msgstr "Introduce: none | uppercase | lowercase | capitalize o {alias}" +msgstr "none | uppercase | lowercase | capitalize o {alias}" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1018, src/app/main/ui/workspace/tokens/management/create/form.cljs:1055 msgid "workspace.tokens.text-decoration-value-enter" -msgstr "Introduce text decoration: none | underline | strike-through" +msgstr "none | underline | strike-through o {alias}" #: src/app/main/ui/workspace/tokens/themes/create_modal.cljs:130 msgid "workspace.tokens.theme-name" diff --git a/frontend/translations/fr.po b/frontend/translations/fr.po index f1f4255e13..f8bbc92ea8 100644 --- a/frontend/translations/fr.po +++ b/frontend/translations/fr.po @@ -7230,7 +7230,7 @@ msgstr "Fichier unique" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1024, src/app/main/ui/workspace/tokens/management/create/form.cljs:1039 msgid "workspace.tokens.font-weight-value-enter" -msgstr "Entrer : 400, Bold, 700 Italic ou {alias}" +msgstr "Font weight (300, Bold, Regular, Italic...) ou {alias}" #: src/app/main/ui/workspace/tokens/management/context_menu.cljs:228 msgid "workspace.tokens.gaps" @@ -7507,7 +7507,7 @@ msgstr "La largueur du tracé doit être plus grand ou égal à 0." #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1018, src/app/main/ui/workspace/tokens/management/create/form.cljs:1055 msgid "workspace.tokens.text-decoration-value-enter" -msgstr "Entrez la décoration de texte : Aucune | Souligné | Barré" +msgstr "none | underline | strike-through ou {alias}" #: src/app/main/ui/workspace/tokens/themes/create_modal.cljs:130 msgid "workspace.tokens.theme-name" diff --git a/frontend/translations/he.po b/frontend/translations/he.po index 1cf9098bde..8e7a405a37 100644 --- a/frontend/translations/he.po +++ b/frontend/translations/he.po @@ -7589,10 +7589,6 @@ msgstr "ערכת עיצוב" msgid "workspace.tokens.label.theme-placeholder" msgstr "הוספת ערכת עיצוב (למשל: בהירה)" -#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1047 -msgid "workspace.tokens.letter-spacing-value-enter-composite" -msgstr "הוספת ריווח תווים או {alias}" - #: src/app/main/ui/workspace/tokens/management/context_menu.cljs:220 msgid "workspace.tokens.margins" msgstr "שוליים" @@ -7737,10 +7733,6 @@ msgstr "גודל" msgid "workspace.tokens.stroke-width-range" msgstr "עובי הקו חייב להיות גדול או שווה ל־0." -#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1018, src/app/main/ui/workspace/tokens/management/create/form.cljs:1055 -msgid "workspace.tokens.text-decoration-value-enter" -msgstr "נא למלא עיצוב טקסט: none | underline | strike-through" - #: src/app/main/ui/workspace/tokens/themes/create_modal.cljs:130 msgid "workspace.tokens.theme-name" msgstr "ערכת עיצוב %s" diff --git a/frontend/translations/it.po b/frontend/translations/it.po index 454761e40f..77070de679 100644 --- a/frontend/translations/it.po +++ b/frontend/translations/it.po @@ -7578,7 +7578,7 @@ msgstr "" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1024, src/app/main/ui/workspace/tokens/management/create/form.cljs:1039 msgid "workspace.tokens.font-weight-value-enter" -msgstr "Inserisci: 400, Bold, 700 Italico, o {alias}" +msgstr "Font weight (300, Bold, Regular Italic...) o {alias}" #: src/app/main/ui/workspace/tokens/management/context_menu.cljs:228 msgid "workspace.tokens.gaps" @@ -7723,11 +7723,11 @@ msgstr "Aggiungi un tema (es. Chiaro)" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1047 msgid "workspace.tokens.letter-spacing-value-enter-composite" -msgstr "Aggiungi spaziatura tra lettere o {alias" +msgstr "Letter spacing o {alias}" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1043 msgid "workspace.tokens.line-height-value-enter" -msgstr "Inserisci interlinea — moltiplicatore, px, %, o {alias}" +msgstr "Line height (moltiplicatore, px, %) o {alias}" #: src/app/main/ui/workspace/tokens/management/context_menu.cljs:220 msgid "workspace.tokens.margins" @@ -7879,11 +7879,11 @@ msgstr "La larghezza della traccia deve essere maggiore o uguale a 0." #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1012, src/app/main/ui/workspace/tokens/management/create/form.cljs:1051 msgid "workspace.tokens.text-case-value-enter" -msgstr "Inserisci: none | uppercase | lowercase | capitalize or {alias}" +msgstr "none | uppercase | lowercase | capitalize o {alias}" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1018, src/app/main/ui/workspace/tokens/management/create/form.cljs:1055 msgid "workspace.tokens.text-decoration-value-enter" -msgstr "Inserisci decorazione del testo: none | underline | strike-through" +msgstr "none | underline | strike-through o {alias}" #: src/app/main/ui/workspace/tokens/themes/create_modal.cljs:130 msgid "workspace.tokens.theme-name" diff --git a/frontend/translations/nl.po b/frontend/translations/nl.po index 0ade9a0ed5..a8f6083879 100644 --- a/frontend/translations/nl.po +++ b/frontend/translations/nl.po @@ -7588,7 +7588,7 @@ msgstr "" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1024, src/app/main/ui/workspace/tokens/management/create/form.cljs:1039 msgid "workspace.tokens.font-weight-value-enter" -msgstr "Voer een waarde in (300, vet, normaal cursief...) of een {alias}" +msgstr "Font weight (300, Bold Italic...) of een {alias}" #: src/app/main/ui/workspace/tokens/management/context_menu.cljs:228 msgid "workspace.tokens.gaps" @@ -7733,11 +7733,11 @@ msgstr "Een thema toevoegen (bijv. Licht)" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1047 msgid "workspace.tokens.letter-spacing-value-enter-composite" -msgstr "Letterafstand of {alias} toevoegen" +msgstr "Letter spacing of {alias}" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1043 msgid "workspace.tokens.line-height-value-enter" -msgstr "Voer de regelafstand in — vermenigvuldigingsfactor, px, % of {alias}" +msgstr "Line height (vermenigvuldigingsfactor, px, %) of {alias}" #: src/app/main/ui/workspace/tokens/management/context_menu.cljs:220 msgid "workspace.tokens.margins" @@ -7889,11 +7889,11 @@ msgstr "De dikte van de streek moet groter zijn dan of gelijk zijn aan 0." #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1012, src/app/main/ui/workspace/tokens/management/create/form.cljs:1051 msgid "workspace.tokens.text-case-value-enter" -msgstr "Voer in: none | uppercase | lowercase | capitalize of {alias}" +msgstr "none | uppercase | lowercase | capitalize of {alias}" #: src/app/main/ui/workspace/tokens/management/create/form.cljs:1018, src/app/main/ui/workspace/tokens/management/create/form.cljs:1055 msgid "workspace.tokens.text-decoration-value-enter" -msgstr "Voer tekstdecoratie in: none | underline | strike-through" +msgstr "none | underline | strike-through of {alias}" #: src/app/main/ui/workspace/tokens/themes/create_modal.cljs:130 msgid "workspace.tokens.theme-name"