mirror of
https://github.com/penpot/penpot.git
synced 2025-12-12 06:24:17 +01:00
🐛 Fix drag & drop functionality is swapping instead or reordering (#7489)
* 🐛 Fix drag & drop functionality is swapping instead or reordering * ♻️ SCSS improvements
This commit is contained in:
@@ -59,6 +59,7 @@
|
|||||||
- Fix scroll on the inspect tab [Taiga #12293](https://tree.taiga.io/project/penpot/issue/12293)
|
- 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 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 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)
|
||||||
|
|
||||||
|
|
||||||
## 2.10.1
|
## 2.10.1
|
||||||
|
|||||||
@@ -1024,6 +1024,29 @@
|
|||||||
:clj
|
:clj
|
||||||
(sort comp-fn items))))
|
(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
|
;; String Functions
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
related-components (cfv/find-variant-components data objects variant-id)]
|
related-components (cfv/find-variant-components data objects variant-id)]
|
||||||
(reduce (fn [changes component]
|
(reduce (fn [changes component]
|
||||||
(let [props (:variant-properties 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)
|
main-id (:main-instance-id component)
|
||||||
name (ctv/properties-to-name props)]
|
name (ctv/properties-to-name props)]
|
||||||
(-> changes
|
(-> changes
|
||||||
|
|||||||
@@ -310,27 +310,3 @@
|
|||||||
the real name of the shape joined by the properties values separated by '/'"
|
the real name of the shape joined by the properties values separated by '/'"
|
||||||
[variant]
|
[variant]
|
||||||
(cpn/merge-path-item (:name variant) (str/replace (:variant-name 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)))))))
|
|
||||||
|
|||||||
@@ -102,3 +102,14 @@
|
|||||||
(t/is (= (d/insert-at-index [:a :b :c :d] 1 [:a])
|
(t/is (= (d/insert-at-index [:a :b :c :d] 1 [:a])
|
||||||
[:a :b :c :d])))
|
[: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"]))))
|
||||||
|
|||||||
@@ -159,48 +159,3 @@
|
|||||||
|
|
||||||
(t/testing "update-number-in-repeated-prop-names"
|
(t/testing "update-number-in-repeated-prop-names"
|
||||||
(t/is (= (ctv/update-number-in-repeated-prop-names props) numbered-props)))))
|
(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"}])))))
|
|
||||||
|
|||||||
@@ -154,23 +154,8 @@
|
|||||||
|
|
||||||
(transform-fill* state ids transform-attrs options))))
|
(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
|
(defn reorder-fills
|
||||||
[ids index new-index]
|
[ids from-pos to-space-between-pos]
|
||||||
(ptk/reify ::reorder-fills
|
(ptk/reify ::reorder-fills
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
@@ -182,7 +167,7 @@
|
|||||||
|
|
||||||
transform-attrs
|
transform-attrs
|
||||||
(fn [object]
|
(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/concat
|
||||||
(rx/from (map #(dwt/update-text-with-function % transform-attrs) text-ids))
|
(rx/from (map #(dwt/update-text-with-function % transform-attrs) text-ids))
|
||||||
@@ -515,22 +500,22 @@
|
|||||||
{:attrs [:strokes]}))))))
|
{:attrs [:strokes]}))))))
|
||||||
|
|
||||||
(defn reorder-shadows
|
(defn reorder-shadows
|
||||||
[ids index new-index]
|
[ids from-pos to-space-between-pos]
|
||||||
(ptk/reify ::reorder-shadow
|
(ptk/reify ::reorder-shadow
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/of (dwsh/update-shapes
|
(rx/of (dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
#(swap-attrs % :shadow index new-index))))))
|
#(update % :shadow d/reorder from-pos to-space-between-pos))))))
|
||||||
|
|
||||||
(defn reorder-strokes
|
(defn reorder-strokes
|
||||||
[ids index new-index]
|
[ids from-pos to-space-between-pos]
|
||||||
(ptk/reify ::reorder-strokes
|
(ptk/reify ::reorder-strokes
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(rx/of (dwsh/update-shapes
|
(rx/of (dwsh/update-shapes
|
||||||
ids
|
ids
|
||||||
#(swap-attrs % :strokes index new-index)
|
#(update % :strokes d/reorder from-pos to-space-between-pos)
|
||||||
{:attrs [:strokes]})))))
|
{:attrs [:strokes]})))))
|
||||||
|
|
||||||
(defn picker-for-selected-shape
|
(defn picker-for-selected-shape
|
||||||
|
|||||||
@@ -7,20 +7,20 @@
|
|||||||
(ns app.main.ui.workspace.sidebar.options.common
|
(ns app.main.ui.workspace.sidebar.options.common
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[rumext.v2 :as mf]))
|
[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)]
|
(let [ref (mf/use-ref nil)]
|
||||||
(mf/use-effect
|
(mf/use-effect
|
||||||
(mf/deps visible?)
|
(mf/deps is-visible)
|
||||||
(fn []
|
(fn []
|
||||||
(when-let [node (mf/ref-val ref)]
|
(when-let [node (mf/ref-val ref)]
|
||||||
(when visible?
|
(when is-visible
|
||||||
(dom/scroll-into-view-if-needed! node)))))
|
(dom/scroll-into-view-if-needed! node)))))
|
||||||
(when visible?
|
(when is-visible
|
||||||
[:div {:class (dm/str class " " (stl/css :advanced-options-wrapper))
|
[:div {:class [class (stl/css :advanced-options-wrapper)]
|
||||||
:ref ref}
|
:ref ref}
|
||||||
children])))
|
children])))
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) KALEIDOS INC
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
@use "refactor/common-refactor.scss" as deprecated;
|
|
||||||
|
|
||||||
.advanced-options-wrapper {
|
.advanced-options-wrapper {
|
||||||
@include deprecated.flexColumn;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,8 +131,8 @@
|
|||||||
on-reorder
|
on-reorder
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn [new-index index]
|
(fn [from-pos to-space-between-pos]
|
||||||
(st/emit! (dc/reorder-fills ids index new-index))))
|
(st/emit! (dc/reorder-fills ids from-pos to-space-between-pos))))
|
||||||
|
|
||||||
on-remove
|
on-remove
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@@ -211,13 +211,13 @@
|
|||||||
(dom/set-attribute! checkbox "indeterminate" true)
|
(dom/set-attribute! checkbox "indeterminate" true)
|
||||||
(dom/remove-attribute! checkbox "indeterminate"))))
|
(dom/remove-attribute! checkbox "indeterminate"))))
|
||||||
|
|
||||||
[:div {:class (stl/css :element-set)}
|
[:div {:class (stl/css :fill-section)}
|
||||||
[:div {:class (stl/css :element-title)}
|
[:div {:class (stl/css :fill-title)}
|
||||||
[:> title-bar* {:collapsable has-fills?
|
[:> title-bar* {:collapsable has-fills?
|
||||||
:collapsed (not open?)
|
:collapsed (not open?)
|
||||||
:on-collapsed toggle-content
|
:on-collapsed toggle-content
|
||||||
:title label
|
: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))
|
(when (not (= :multiple fills))
|
||||||
[:> icon-button* {:variant "ghost"
|
[:> icon-button* {:variant "ghost"
|
||||||
@@ -228,11 +228,11 @@
|
|||||||
:icon i/add}])]]
|
:icon i/add}])]]
|
||||||
|
|
||||||
(when open?
|
(when open?
|
||||||
[:div {:class (stl/css :element-content)}
|
[:div {:class (stl/css :fill-content)}
|
||||||
(cond
|
(cond
|
||||||
(= :multiple fills)
|
(= :multiple fills)
|
||||||
[:div {:class (stl/css :element-set-options-group)}
|
[:div {:class (stl/css :fill-multiple)}
|
||||||
[:div {:class (stl/css :group-label)}
|
[:div {:class (stl/css :fill-multiple-label)}
|
||||||
(tr "settings.multiple")]
|
(tr "settings.multiple")]
|
||||||
[:> icon-button* {:variant "ghost"
|
[:> icon-button* {:variant "ghost"
|
||||||
:aria-label (tr "workspace.options.fill.remove-fill")
|
:aria-label (tr "workspace.options.fill.remove-fill")
|
||||||
@@ -265,7 +265,7 @@
|
|||||||
(when (or (= type :frame)
|
(when (or (= type :frame)
|
||||||
(and (= type :multiple)
|
(and (= type :multiple)
|
||||||
(some? hide-on-export)))
|
(some? hide-on-export)))
|
||||||
[:div {:class (stl/css :checkbox)}
|
[:div {:class (stl/css :fill-checkbox)}
|
||||||
[:label {:for "show-fill-on-export"
|
[:label {:for "show-fill-on-export"
|
||||||
:class (stl/css-case :global/checked (not hide-on-export))}
|
:class (stl/css-case :global/checked (not hide-on-export))}
|
||||||
[:span {:class (stl/css-case :check-mark true
|
[:span {:class (stl/css-case :check-mark true
|
||||||
|
|||||||
@@ -4,44 +4,61 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) KALEIDOS INC
|
// 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;
|
@use "refactor/common-refactor.scss" as deprecated;
|
||||||
|
|
||||||
.element-set {
|
.fill-section {
|
||||||
margin: 0;
|
display: grid;
|
||||||
|
grid-template-columns: repeat(8, var(--sp-xxxl));
|
||||||
|
column-gap: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-title {
|
.fill-title {
|
||||||
margin: 0;
|
grid-column: span 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-spacing-fill {
|
.fill-title-bar {
|
||||||
padding-left: deprecated.$s-2;
|
padding-inline-start: var(--sp-xxs);
|
||||||
margin: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-content {
|
.fill-content {
|
||||||
|
grid-column: span 8;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: deprecated.$s-12;
|
gap: var(--sp-m);
|
||||||
margin: deprecated.$s-4 0 deprecated.$s-8 0;
|
margin: var(--sp-xs) 0 var(--sp-s) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-set-options-group {
|
.fill-multiple {
|
||||||
@include deprecated.flexRow;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-label {
|
.fill-multiple-label {
|
||||||
@extend .mixed-bar;
|
@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;
|
@extend .input-checkbox;
|
||||||
padding-left: deprecated.$s-8;
|
padding-inline-start: var(--sp-s);
|
||||||
span.checked {
|
span.checked {
|
||||||
background-color: var(--input-border-color-active);
|
background-color: var(--color-accent-primary);
|
||||||
svg {
|
svg {
|
||||||
@extend .button-icon-small;
|
@extend .button-icon-small;
|
||||||
stroke: var(--input-details-color);
|
stroke: var(--color-background-primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||||
[app.main.ui.icons :as deprecated-icon]
|
[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.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
@@ -190,8 +190,8 @@
|
|||||||
:icon i/remove}]]]
|
:icon i/remove}]]]
|
||||||
|
|
||||||
(when (:display grid)
|
(when (:display grid)
|
||||||
[:& advanced-options {:class (stl/css :grid-advanced-options)
|
[:> advanced-options* {:class (stl/css :grid-advanced-options)
|
||||||
:visible? open?
|
:is-visible open?
|
||||||
:on-close toggle-advanced-options}
|
:on-close toggle-advanced-options}
|
||||||
;; square
|
;; square
|
||||||
(when (= :square type)
|
(when (= :square type)
|
||||||
|
|||||||
@@ -15,17 +15,12 @@
|
|||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.colors :as dc]
|
[app.main.data.workspace.colors :as dc]
|
||||||
[app.main.data.workspace.shapes :as dwsh]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
[app.main.data.workspace.undo :as dwu]
|
|
||||||
[app.main.store :as st]
|
[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.components.title-bar :refer [title-bar*]]
|
||||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||||
[app.main.ui.hooks :as h]
|
[app.main.ui.hooks :as h]
|
||||||
[app.main.ui.workspace.sidebar.options.common :refer [advanced-options]]
|
[app.main.ui.workspace.sidebar.options.rows.shadow-row :refer [shadow-row*]]
|
||||||
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]]
|
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
@@ -49,199 +44,6 @@
|
|||||||
(filterv (fn [[idx _]] (not= idx index)))
|
(filterv (fn [[idx _]] (not= idx index)))
|
||||||
(mapv second)))
|
(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
|
(def ^:private xf:add-index
|
||||||
(map-indexed (fn [index shadow]
|
(map-indexed (fn [index shadow]
|
||||||
(assoc shadow ::index index))))
|
(assoc shadow ::index index))))
|
||||||
@@ -279,10 +81,10 @@
|
|||||||
|
|
||||||
handle-reorder
|
handle-reorder
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [new-index index]
|
(fn [from-pos to-space-between-pos]
|
||||||
(let [ids (mf/ref-val ids-ref)]
|
(let [ids (mf/ref-val ids-ref)]
|
||||||
(st/emit! (dw/trigger-bounding-box-cloaking ids))
|
(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
|
on-add-shadow
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@@ -325,8 +127,8 @@
|
|||||||
(-> shadow
|
(-> shadow
|
||||||
(assoc attr value)
|
(assoc attr value)
|
||||||
(ctss/check-shadow))))))))))]
|
(ctss/check-shadow))))))))))]
|
||||||
[:div {:class (stl/css :element-set)}
|
[:div {:class (stl/css :shadow-section)}
|
||||||
[:div {:class (stl/css :element-title)}
|
[:div {:class (stl/css :shadow-title)}
|
||||||
[:> title-bar* {:collapsable has-shadows?
|
[:> title-bar* {:collapsable has-shadows?
|
||||||
:collapsed (not show-content?)
|
:collapsed (not show-content?)
|
||||||
:on-collapsed toggle-content
|
:on-collapsed toggle-content
|
||||||
@@ -334,7 +136,7 @@
|
|||||||
:multiple (tr "workspace.options.shadow-options.title.multiple")
|
:multiple (tr "workspace.options.shadow-options.title.multiple")
|
||||||
:group (tr "workspace.options.shadow-options.title.group")
|
:group (tr "workspace.options.shadow-options.title.group")
|
||||||
(tr "workspace.options.shadow-options.title"))
|
(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)
|
(when-not (= :multiple shadows)
|
||||||
[:> icon-button* {:variant "ghost"
|
[:> icon-button* {:variant "ghost"
|
||||||
@@ -346,20 +148,20 @@
|
|||||||
(when show-content?
|
(when show-content?
|
||||||
(cond
|
(cond
|
||||||
(= :multiple shadows)
|
(= :multiple shadows)
|
||||||
[:div {:class (stl/css :element-set-content)}
|
[:div {:class (stl/css :shadow-content)}
|
||||||
[:div {:class (stl/css :multiple-shadows)}
|
[:div {:class (stl/css :shadow-multiple)}
|
||||||
[:div {:class (stl/css :label)} (tr "settings.multiple")]
|
[:div {:class (stl/css :shadow-multiple-label)}
|
||||||
[:div {:class (stl/css :actions)}
|
(tr "settings.multiple")]
|
||||||
[:> icon-button* {:variant "ghost"
|
[:> icon-button* {:variant "ghost"
|
||||||
:aria-label (tr "workspace.options.shadow-options.remove-shadow")
|
:aria-label (tr "workspace.options.shadow-options.remove-shadow")
|
||||||
:on-click on-remove-all
|
:on-click on-remove-all
|
||||||
:icon i/remove}]]]]
|
:icon i/remove}]]]
|
||||||
|
|
||||||
(some? shadows)
|
(some? shadows)
|
||||||
[:> h/sortable-container* {}
|
[:> h/sortable-container* {}
|
||||||
[:div {:class (stl/css :element-set-content)}
|
[:div {:class (stl/css :shadow-content)}
|
||||||
(for [{:keys [::index id] :as shadow} shadows]
|
(for [{:keys [::index id] :as shadow} shadows]
|
||||||
[:> shadow-entry*
|
[:> shadow-row*
|
||||||
{:key (dm/str index)
|
{:key (dm/str index)
|
||||||
:index index
|
:index index
|
||||||
:shadow shadow
|
:shadow shadow
|
||||||
|
|||||||
@@ -5,34 +5,39 @@
|
|||||||
// Copyright (c) KALEIDOS INC
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
@use "ds/_sizes.scss" as *;
|
@use "ds/_sizes.scss" as *;
|
||||||
@use "ds/typography.scss" as t;
|
|
||||||
@use "ds/_borders.scss" as *;
|
@use "ds/_borders.scss" as *;
|
||||||
@use "ds/_utils.scss" as *;
|
@use "ds/typography.scss" as t;
|
||||||
@use "refactor/common-refactor.scss" as deprecated;
|
|
||||||
|
|
||||||
.element-set {
|
.shadow-section {
|
||||||
margin: 0;
|
display: grid;
|
||||||
|
grid-template-columns: repeat(8, var(--sp-xxxl));
|
||||||
|
column-gap: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-spacing-shadow {
|
.shadow-title {
|
||||||
margin: 0;
|
grid-column: span 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shadow-title-bar {
|
||||||
padding-inline-start: var(--sp-xxs);
|
padding-inline-start: var(--sp-xxs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-set-content {
|
.shadow-content {
|
||||||
margin-block-start: var(--sp-xs);
|
grid-column: span 8;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--sp-xs);
|
gap: var(--sp-xs);
|
||||||
|
margin-block-start: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.multiple-shadows {
|
.shadow-multiple {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--sp-xs);
|
gap: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.shadow-multiple-label {
|
||||||
@include t.use-typography("body-small");
|
@include t.use-typography("body-small");
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -43,132 +48,3 @@
|
|||||||
background-color: var(--color-background-tertiary);
|
background-color: var(--color-background-tertiary);
|
||||||
color: var(--color-foreground-primary);
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||||
[app.main.ui.hooks :as h]
|
[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.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
@@ -89,10 +89,9 @@
|
|||||||
handle-reorder
|
handle-reorder
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn [new-index]
|
(fn [from-pos to-space-between-pos]
|
||||||
(fn [index]
|
|
||||||
(st/emit! (udw/trigger-bounding-box-cloaking ids))
|
(st/emit! (udw/trigger-bounding-box-cloaking ids))
|
||||||
(st/emit! (dc/reorder-strokes ids index new-index)))))
|
(st/emit! (dc/reorder-strokes ids from-pos to-space-between-pos))))
|
||||||
|
|
||||||
on-stroke-style-change
|
on-stroke-style-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@@ -177,13 +176,13 @@
|
|||||||
:token token
|
:token token
|
||||||
:shape-ids ids}))))]
|
:shape-ids ids}))))]
|
||||||
|
|
||||||
[:div {:class (stl/css :element-set)}
|
[:div {:class (stl/css :stroke-section)}
|
||||||
[:div {:class (stl/css :element-title)}
|
[:div {:class (stl/css :stroke-title)}
|
||||||
[:> title-bar* {:collapsable has-strokes?
|
[:> title-bar* {:collapsable has-strokes?
|
||||||
:collapsed (not open?)
|
:collapsed (not open?)
|
||||||
:on-collapsed toggle-content
|
:on-collapsed toggle-content
|
||||||
:title label
|
: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))
|
(when (not (= :multiple strokes))
|
||||||
[:> icon-button* {:variant "ghost"
|
[:> icon-button* {:variant "ghost"
|
||||||
:aria-label (tr "workspace.options.stroke.add-stroke")
|
:aria-label (tr "workspace.options.stroke.add-stroke")
|
||||||
@@ -191,12 +190,12 @@
|
|||||||
:icon i/add
|
:icon i/add
|
||||||
:data-testid "add-stroke"}])]]
|
:data-testid "add-stroke"}])]]
|
||||||
(when open?
|
(when open?
|
||||||
[:div {:class (stl/css-case :element-content true
|
[:div {:class (stl/css-case :stroke-content true
|
||||||
:empty-content (not has-strokes?))}
|
:stroke-content-empty (not has-strokes?))}
|
||||||
(cond
|
(cond
|
||||||
(= :multiple strokes)
|
(= :multiple strokes)
|
||||||
[:div {:class (stl/css :element-set-options-group)}
|
[:div {:class (stl/css :stroke-multiple)}
|
||||||
[:div {:class (stl/css :group-label)}
|
[:div {:class (stl/css :stroke-multiple-label)}
|
||||||
(tr "settings.multiple")]
|
(tr "settings.multiple")]
|
||||||
[:> icon-button* {:variant "ghost"
|
[:> icon-button* {:variant "ghost"
|
||||||
:aria-label (tr "workspace.options.stroke.remove-stroke")
|
:aria-label (tr "workspace.options.stroke.remove-stroke")
|
||||||
@@ -205,7 +204,7 @@
|
|||||||
(seq strokes)
|
(seq strokes)
|
||||||
[:> h/sortable-container* {}
|
[:> h/sortable-container* {}
|
||||||
(for [[index value] (d/enumerate (:strokes values []))]
|
(for [[index value] (d/enumerate (:strokes values []))]
|
||||||
[:& stroke-row {:key (dm/str "stroke-" index)
|
[:> stroke-row* {:key (dm/str "stroke-" index)
|
||||||
:stroke value
|
:stroke value
|
||||||
:title (tr "workspace.options.stroke-color")
|
:title (tr "workspace.options.stroke-color")
|
||||||
:index index
|
:index index
|
||||||
@@ -225,7 +224,7 @@
|
|||||||
:applied-tokens applied-tokens
|
:applied-tokens applied-tokens
|
||||||
:on-detach-token on-detach-token
|
:on-detach-token on-detach-token
|
||||||
:on-remove on-remove
|
:on-remove on-remove
|
||||||
:on-reorder (handle-reorder index)
|
:on-reorder handle-reorder
|
||||||
:disable-drag disable-drag
|
:disable-drag disable-drag
|
||||||
:on-focus on-focus
|
:on-focus on-focus
|
||||||
:select-on-focus (not @disable-drag)
|
:select-on-focus (not @disable-drag)
|
||||||
|
|||||||
@@ -4,35 +4,51 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) KALEIDOS INC
|
// 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 {
|
.stroke-section {
|
||||||
margin: 0;
|
display: grid;
|
||||||
|
grid-template-columns: repeat(8, var(--sp-xxxl));
|
||||||
|
column-gap: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-title {
|
.stroke-title {
|
||||||
margin: 0;
|
grid-column: span 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-spacing-stroke {
|
.stroke-title-bar {
|
||||||
padding-left: deprecated.$s-2;
|
padding-inline-start: var(--sp-xxs);
|
||||||
margin: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-content {
|
.stroke-content {
|
||||||
|
grid-column: span 8;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: deprecated.$s-12;
|
gap: var(--sp-m);
|
||||||
margin: deprecated.$s-4 0 deprecated.$s-8 0;
|
margin: var(--sp-xs) 0 var(--sp-s) 0;
|
||||||
&.empty-content {
|
|
||||||
|
&.stroke-content-empty {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-set-options-group {
|
.stroke-multiple {
|
||||||
@include deprecated.flexRow;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-label {
|
.stroke-multiple-label {
|
||||||
@extend .mixed-bar;
|
@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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -313,8 +313,10 @@
|
|||||||
on-drop
|
on-drop
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps on-reorder index)
|
(mf/deps on-reorder index)
|
||||||
(fn [_ data]
|
(fn [relative-pos data]
|
||||||
(on-reorder index (:index 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]
|
[dprops dref]
|
||||||
(if (some? on-reorder)
|
(if (some? on-reorder)
|
||||||
@@ -323,9 +325,7 @@
|
|||||||
:on-drop on-drop
|
:on-drop on-drop
|
||||||
:disabled disable-drag
|
:disabled disable-drag
|
||||||
:detect-center? false
|
:detect-center? false
|
||||||
:data {:id (str "color-row-" index)
|
:data {:index index})
|
||||||
:index index
|
|
||||||
:name (str "Color row" index)})
|
|
||||||
[nil nil])
|
[nil nil])
|
||||||
|
|
||||||
row-class
|
row-class
|
||||||
|
|||||||
@@ -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}]]])]]))
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -14,14 +14,14 @@
|
|||||||
[app.main.ui.components.numeric-input :refer [numeric-input*]]
|
[app.main.ui.components.numeric-input :refer [numeric-input*]]
|
||||||
[app.main.ui.components.reorder-handler :refer [reorder-handler*]]
|
[app.main.ui.components.reorder-handler :refer [reorder-handler*]]
|
||||||
[app.main.ui.components.select :refer [select]]
|
[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.hooks :as h]
|
||||||
[app.main.ui.icons :as deprecated-icon]
|
|
||||||
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]]
|
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc stroke-row
|
(mf/defc stroke-row*
|
||||||
{::mf/wrap-props false}
|
|
||||||
[{:keys [index
|
[{:keys [index
|
||||||
stroke
|
stroke
|
||||||
title
|
title
|
||||||
@@ -47,18 +47,21 @@
|
|||||||
objects]}]
|
objects]}]
|
||||||
|
|
||||||
(let [on-drop
|
(let [on-drop
|
||||||
(fn [_ data]
|
(mf/use-fn
|
||||||
(on-reorder (:index data)))
|
(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)
|
[dprops dref]
|
||||||
|
(if (some? on-reorder)
|
||||||
(h/use-sortable
|
(h/use-sortable
|
||||||
:data-type "penpot/stroke-row"
|
:data-type "penpot/stroke-row"
|
||||||
:on-drop on-drop
|
:on-drop on-drop
|
||||||
:disabled @disable-drag
|
:disabled @disable-drag
|
||||||
:detect-center? false
|
:detect-center? false
|
||||||
:data {:id (str "stroke-row-" index)
|
:data {:index index})
|
||||||
:index index
|
|
||||||
:name (str "Border row" index)})
|
|
||||||
[nil nil])
|
[nil nil])
|
||||||
|
|
||||||
stroke-color-token (:stroke-color applied-tokens)
|
stroke-color-token (:stroke-color applied-tokens)
|
||||||
@@ -203,52 +206,41 @@
|
|||||||
|
|
||||||
;; Stroke Width, Alignment & Style
|
;; Stroke Width, Alignment & Style
|
||||||
[:div {:class (stl/css :stroke-options)}
|
[: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")}
|
:title (tr "workspace.options.stroke-width")}
|
||||||
[:span {:class (stl/css :icon)}
|
[:> icon* {:icon-id i/stroke-size
|
||||||
deprecated-icon/stroke-size]
|
:size "s"}]
|
||||||
[:> numeric-input*
|
[:> numeric-input* {:value stroke-width
|
||||||
{:min 0
|
:min 0
|
||||||
:className (stl/css :stroke-width-input)
|
|
||||||
:value stroke-width
|
|
||||||
:placeholder (tr "settings.multiple")
|
:placeholder (tr "settings.multiple")
|
||||||
:on-change on-width-change
|
:on-change on-width-change
|
||||||
:on-focus on-focus
|
:on-focus on-focus
|
||||||
:select-on-focus select-on-focus
|
:select-on-focus select-on-focus
|
||||||
:on-blur on-blur}]]
|
:on-blur on-blur}]]
|
||||||
|
|
||||||
[:div {:class (stl/css :select-wrapper :stroke-alignment-select)
|
[:div {:class (stl/css :stroke-alignment-select)
|
||||||
:data-testid "stroke.alignment"}
|
:data-testid "stroke.alignment"}
|
||||||
[:& select
|
[:& select {:default-value stroke-alignment
|
||||||
{:default-value stroke-alignment
|
|
||||||
:options stroke-alignment-options
|
:options stroke-alignment-options
|
||||||
:on-change on-alignment-change}]]
|
:on-change on-alignment-change}]]
|
||||||
|
|
||||||
(when-not disable-stroke-style
|
(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"}
|
:data-testid "stroke.style"}
|
||||||
[:& select
|
[:& select {:default-value stroke-style
|
||||||
{:default-value stroke-style
|
|
||||||
:options stroke-style-options
|
:options stroke-style-options
|
||||||
:on-change on-style-change}]])]
|
:on-change on-style-change}]])]
|
||||||
|
|
||||||
;; Stroke Caps
|
;; Stroke Caps
|
||||||
(when show-caps
|
(when show-caps
|
||||||
[:div {:class (stl/css :stroke-caps-options)}
|
[:div {:class (stl/css :stroke-caps-options)}
|
||||||
[:div {:class (stl/css :cap-select)}
|
[:& select {:default-value (:stroke-cap-start stroke)
|
||||||
[:& select
|
|
||||||
{:default-value (:stroke-cap-start stroke)
|
|
||||||
:dropdown-class (stl/css :stroke-cap-dropdown-start)
|
|
||||||
:options stroke-caps-options
|
:options stroke-caps-options
|
||||||
:on-change on-caps-start-change}]]
|
:on-change on-caps-start-change}]
|
||||||
|
[:> icon-button* {:variant "secondary"
|
||||||
[:button {:class (stl/css :swap-caps-btn)
|
:aria-label (tr "labels.switch")
|
||||||
:on-click on-cap-switch}
|
:on-click on-cap-switch
|
||||||
deprecated-icon/switch]
|
:icon i/switch}]
|
||||||
|
[:& select {:default-value (:stroke-cap-end stroke)
|
||||||
[:div {:class (stl/css :cap-select)}
|
|
||||||
[:& select
|
|
||||||
{:default-value (:stroke-cap-end stroke)
|
|
||||||
:dropdown-class (stl/css :stroke-cap-dropdown)
|
|
||||||
:options stroke-caps-options
|
:options stroke-caps-options
|
||||||
:on-change on-caps-end-change}]]])]))
|
:on-change on-caps-end-change}]])]))
|
||||||
|
|||||||
@@ -4,10 +4,13 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) KALEIDOS INC
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
@use "ds/typography.scss" as t;
|
||||||
@use "refactor/common-refactor.scss" as deprecated;
|
@use "refactor/common-refactor.scss" as deprecated;
|
||||||
|
|
||||||
.stroke-data {
|
.stroke-data {
|
||||||
@include deprecated.flexColumn;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--sp-xs);
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
@@ -31,11 +34,16 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
grid-template-columns: repeat(8, var(--sp-xxxl));
|
grid-template-columns: repeat(8, var(--sp-xxxl));
|
||||||
gap: var(--sp-xs);
|
gap: var(--sp-xs);
|
||||||
|
}
|
||||||
|
|
||||||
.stroke-width-input-element {
|
.stroke-width-input {
|
||||||
@extend .input-element;
|
|
||||||
@include deprecated.bodySmallTypography;
|
|
||||||
grid-column: span 2;
|
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 {
|
.stroke-alignment-select {
|
||||||
@@ -45,32 +53,9 @@
|
|||||||
.stroke-style-select {
|
.stroke-style-select {
|
||||||
grid-column: span 3;
|
grid-column: span 3;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.stroke-caps-options {
|
.stroke-caps-options {
|
||||||
display: grid;
|
display: grid;
|
||||||
--input-width: calc(var(--sp-xxxl) * 3.5 + 3 * var(--sp-xs) - var(--sp-xs) / 2);
|
grid-template-columns: 1fr auto 1fr;
|
||||||
grid-template-columns: var(--input-width) var(--sp-xxxl) var(--input-width);
|
column-gap: var(--sp-xs);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2637,6 +2637,10 @@ msgstr "Styles"
|
|||||||
msgid "labels.svg"
|
msgid "labels.svg"
|
||||||
msgstr "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
|
#: src/app/main/ui/onboarding/questions.cljs:256
|
||||||
#, unused
|
#, unused
|
||||||
msgid "labels.team-leader"
|
msgid "labels.team-leader"
|
||||||
|
|||||||
@@ -2607,6 +2607,10 @@ msgstr "Estilos"
|
|||||||
msgid "labels.svg"
|
msgid "labels.svg"
|
||||||
msgstr "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
|
#: src/app/main/ui/onboarding/questions.cljs:256
|
||||||
#, unused
|
#, unused
|
||||||
msgid "labels.team-leader"
|
msgid "labels.team-leader"
|
||||||
|
|||||||
Reference in New Issue
Block a user