mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
🎉 Show tokens on color inputs (#7377)
* 🎉 Add tokens to color row * 🎉 Add color-token to stroke input * 🐛 FIx change token on multiselection with groups * 🔧 Add config flag * 🐛 Fix comments
This commit is contained in:
@@ -534,4 +534,6 @@
|
||||
:sided-margins #{:spacing :dimensions}
|
||||
:line-height #{:line-height :number}
|
||||
:font-size #{:font-size}
|
||||
:letter-spacing #{:letter-spacing}})
|
||||
:letter-spacing #{:letter-spacing}
|
||||
:fill #{:color}
|
||||
:stroke-color #{:color}})
|
||||
|
||||
@@ -93,7 +93,7 @@ test("Create a LINEAR gradient", async ({ page }) => {
|
||||
await expect(inputOpacityGlobal).toHaveValue("50");
|
||||
await expect(inputOpacityGlobal).toBeVisible();
|
||||
|
||||
await expect(workspacePage.page.getByText("Linear gradient")).toBeVisible();
|
||||
await expect(workspacePage.page.getByText("Linear gradient").nth(1)).toBeVisible();
|
||||
});
|
||||
|
||||
test("Create a RADIAL gradient", async ({ page }) => {
|
||||
@@ -175,7 +175,7 @@ test("Create a RADIAL gradient", async ({ page }) => {
|
||||
await expect(inputOpacityGlobal).toHaveValue("50");
|
||||
await expect(inputOpacityGlobal).toBeVisible();
|
||||
|
||||
await expect(workspacePage.page.getByText("Radial gradient")).toBeVisible();
|
||||
await expect(workspacePage.page.getByText("Radial gradient").nth(1)).toBeVisible();
|
||||
});
|
||||
|
||||
test("Gradient stops limit", async ({ page }) => {
|
||||
|
||||
@@ -46,7 +46,7 @@ const setupTokensFile = async (page, options = {}) => {
|
||||
} = options;
|
||||
|
||||
const workspacePage = new WorkspacePage(page);
|
||||
if (flags.length) {
|
||||
if (flags.length > 0) {
|
||||
await workspacePage.mockConfigFlags(flags);
|
||||
}
|
||||
|
||||
@@ -879,7 +879,10 @@ test.describe("Tokens: Themes modal", () => {
|
||||
});
|
||||
|
||||
test.describe("Tokens: Apply token", () => {
|
||||
test("User applies color token to a shape", async ({ page }) => {
|
||||
// When deleting the "enable-token-color" flag, permanently remove this test.
|
||||
test("User applies color token to a shape without tokens on design-tab", async ({
|
||||
page,
|
||||
}) => {
|
||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
||||
await setupTokensFile(page);
|
||||
|
||||
@@ -909,6 +912,35 @@ test.describe("Tokens: Themes modal", () => {
|
||||
await expect(inputColor).toHaveValue("000000");
|
||||
});
|
||||
|
||||
test("User applies color token to a shape", async ({ page }) => {
|
||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
||||
await setupTokensFile(page, { flags: ["enable-token-color"] });
|
||||
|
||||
await page.getByRole("tab", { name: "Layers" }).click();
|
||||
|
||||
await workspacePage.layers
|
||||
.getByTestId("layer-row")
|
||||
.filter({ hasText: "Button" })
|
||||
.click();
|
||||
|
||||
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
||||
await tokensTabButton.click();
|
||||
|
||||
await tokensSidebar
|
||||
.getByRole("button")
|
||||
.filter({ hasText: "Color" })
|
||||
.click();
|
||||
|
||||
await tokensSidebar
|
||||
.getByRole("button", { name: "colors.black" })
|
||||
.click({ button: "right" });
|
||||
await tokenContextMenuForToken.getByText("Fill").click();
|
||||
|
||||
await expect(
|
||||
workspacePage.page.getByLabel("Name: colors.black"),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("User applies typography token to a text shape", async ({ page }) => {
|
||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
||||
await setupTypographyTokensFile(page);
|
||||
@@ -1024,9 +1056,7 @@ test.describe("Tokens: Themes modal", () => {
|
||||
await expect(letterSpacingField).toHaveValue(
|
||||
originalValues.letterSpacing,
|
||||
);
|
||||
await expect(lineHeightField).toHaveValue(
|
||||
originalValues.lineHeight,
|
||||
);
|
||||
await expect(lineHeightField).toHaveValue(originalValues.lineHeight);
|
||||
await expect(textCaseField).toHaveValue(originalValues.textCase);
|
||||
await expect(textDecorationField).toHaveValue(
|
||||
originalValues.textDecoration,
|
||||
|
||||
@@ -8,16 +8,16 @@
|
||||
cursor: grab;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100% + var(--sp-m));
|
||||
block-size: calc(100% + var(--sp-m));
|
||||
justify-content: center;
|
||||
left: var(--reorder-left-position, calc(-1 * var(--sp-l)));
|
||||
inset-inline-start: var(--reorder-left-position, -11px);
|
||||
position: absolute;
|
||||
top: calc(-1 * (var(--sp-m) / 2));
|
||||
inset-block-start: calc(-1 * (var(--sp-m) / 2));
|
||||
z-index: var(--z-index-panels);
|
||||
}
|
||||
|
||||
.reorder-icon {
|
||||
height: var(--sp-l);
|
||||
block-size: var(--sp-l);
|
||||
pointer-events: none;
|
||||
visibility: var(--reorder-icon-visibility, hidden);
|
||||
--icon-stroke-color: var(--color-foreground-secondary);
|
||||
@@ -28,15 +28,15 @@
|
||||
border-color: var(--color-accent-primary);
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
inline-size: 100%;
|
||||
}
|
||||
|
||||
.reorder-separator-top {
|
||||
display: var(--reorder-top-display, none);
|
||||
top: calc(-1 * var(--sp-xxs));
|
||||
inset-block-start: calc(-1 * var(--sp-xxs));
|
||||
}
|
||||
|
||||
.reorder-separator-bottom {
|
||||
display: var(--reorder-bottom-display, none);
|
||||
bottom: calc(-1 * var(--sp-xxs));
|
||||
inset-block-end: calc(-1 * var(--sp-xxs));
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ $sz-32: px2rem(32);
|
||||
$sz-36: px2rem(36);
|
||||
$sz-40: px2rem(40);
|
||||
$sz-48: px2rem(48);
|
||||
$sz-80: px2rem(80);
|
||||
$sz-88: px2rem(88);
|
||||
$sz-120: px2rem(120);
|
||||
$sz-154: px2rem(154);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
//
|
||||
// Copyright (c) KALEIDOS INC
|
||||
|
||||
@use "ds/_utils.scss" as *;
|
||||
|
||||
@keyframes line-pencil {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
@@ -44,8 +46,8 @@
|
||||
// Tips container
|
||||
.tips-container {
|
||||
text-align: center;
|
||||
min-width: var(--sp-600);
|
||||
max-width: var(--sp-800);
|
||||
min-width: px2rem(600);
|
||||
max-width: px2rem(800);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sp-s);
|
||||
|
||||
@@ -14,8 +14,6 @@ $_sp-16: px2rem(16);
|
||||
$_sp-20: px2rem(20);
|
||||
$_sp-24: px2rem(24);
|
||||
$_sp-32: px2rem(32);
|
||||
$_sp-600: px2rem(600);
|
||||
$_sp-800: px2rem(800);
|
||||
|
||||
:global(:root) {
|
||||
--sp-xxs: #{$_sp-2};
|
||||
@@ -26,6 +24,4 @@ $_sp-800: px2rem(800);
|
||||
--sp-xl: #{$_sp-20};
|
||||
--sp-xxl: #{$_sp-24};
|
||||
--sp-xxxl: #{$_sp-32};
|
||||
--sp-600: #{$_sp-600};
|
||||
--sp-800: #{$_sp-800};
|
||||
}
|
||||
|
||||
@@ -63,11 +63,12 @@
|
||||
[:class {:optional true} :string]
|
||||
[:size {:optional true} [:enum "small" "medium" "large"]]
|
||||
[:active {:optional true} ::sm/boolean]
|
||||
[:has-errors {:optional true} [:maybe ::sm/boolean]]
|
||||
[:on-click {:optional true} ::sm/fn]])
|
||||
|
||||
(mf/defc swatch*
|
||||
{::mf/schema (sm/schema schema:swatch)}
|
||||
[{:keys [background on-click size active class tooltip-content]
|
||||
[{:keys [background on-click size active class tooltip-content has-errors]
|
||||
:rest props}]
|
||||
(let [;; NOTE: this code is only relevant for storybook, because
|
||||
;; storybook is unable to pass in a comfortable way a complex
|
||||
@@ -92,6 +93,12 @@
|
||||
image (:image background)
|
||||
format (if id? "rounded" "square")
|
||||
element-id (mf/use-id)
|
||||
on-click
|
||||
(mf/use-fn
|
||||
(mf/deps background on-click)
|
||||
(fn [event]
|
||||
(when (fn? on-click)
|
||||
(^function on-click background event))))
|
||||
|
||||
class
|
||||
(dm/str class " " (stl/css-case
|
||||
@@ -124,6 +131,8 @@
|
||||
(let [uri (cfg/resolve-file-media image)]
|
||||
[:span {:class (stl/css :swatch-image)
|
||||
:style {:background-image (str/ffmt "url(%)" uri)}}])
|
||||
has-errors
|
||||
[:span {:class (stl/css :swatch-error)}]
|
||||
|
||||
:else
|
||||
[:span {:class (stl/css :swatch-opacity)}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
border: $b-1 solid var(--border-color);
|
||||
border-radius: var(--border-radius);
|
||||
overflow: hidden;
|
||||
|
||||
&:focus {
|
||||
--border-color: var(--color-accent-primary);
|
||||
}
|
||||
@@ -109,3 +108,7 @@
|
||||
flex: 1;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.swatch-error {
|
||||
background: var(--color-background-primary);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,8 @@
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
[rumext.v2 :as mf]
|
||||
[rumext.v2.util :as mfu]))
|
||||
|
||||
;; --- Refs
|
||||
|
||||
@@ -93,13 +94,13 @@
|
||||
(dom/set-css-property! node "--saturation-grad-to" (format-hsl hsl-to)))))
|
||||
|
||||
(mf/defc colorpicker
|
||||
[{:keys [data disable-gradient disable-opacity disable-image on-change on-accept origin combined-tokens color-origin on-token-change]}]
|
||||
[{:keys [data disable-gradient disable-opacity disable-image on-change on-accept origin combined-tokens color-origin on-token-change tab]}]
|
||||
(let [state (mf/deref refs/colorpicker)
|
||||
node-ref (mf/use-ref)
|
||||
|
||||
should-update? (mf/use-var true)
|
||||
token-color (contains? cfg/flags :token-color)
|
||||
color-style* (mf/use-state :direct-color)
|
||||
color-style* (mf/use-state (d/nilv tab :direct-color))
|
||||
color-style (deref color-style*)
|
||||
toggle-token-color
|
||||
(mf/use-fn
|
||||
@@ -364,7 +365,7 @@
|
||||
:icon i/hsva
|
||||
:id "hsva"}])
|
||||
|
||||
show-tokens? (contains? #{:fill :stroke :color-selection} color-origin)]
|
||||
show-tokens? (contains? #{:fill :stroke-color :color-selection} color-origin)]
|
||||
|
||||
;; Initialize colorpicker state
|
||||
(mf/with-effect []
|
||||
@@ -726,12 +727,16 @@
|
||||
color-origin
|
||||
on-token-change
|
||||
on-close
|
||||
tab
|
||||
on-accept]}]
|
||||
(let [vport (mf/deref viewport)
|
||||
dirty? (mf/use-var false)
|
||||
last-change (mf/use-var nil)
|
||||
position (d/nilv position :left)
|
||||
style (calculate-position vport position x y (some? (:gradient data)))
|
||||
active-tokens (if (object? active-tokens)
|
||||
(mfu/bean active-tokens)
|
||||
active-tokens)
|
||||
|
||||
on-change'
|
||||
(mf/use-fn
|
||||
@@ -752,6 +757,10 @@
|
||||
(some-> tokens-lib
|
||||
(ctob/get-active-themes-set-names)))
|
||||
|
||||
active-tokens (if (delay? active-tokens)
|
||||
@active-tokens
|
||||
active-tokens)
|
||||
|
||||
color-tokens (:color active-tokens)
|
||||
|
||||
grouped-tokens-by-set
|
||||
@@ -762,7 +771,7 @@
|
||||
(filter-active-sets active-sets-names)
|
||||
(filter-non-empty-sets)
|
||||
(group-sets)
|
||||
(combine-groups-with-resolved color-tokens)))]
|
||||
(combine-groups-with-resolved color-tokens)))]
|
||||
|
||||
(mf/with-effect []
|
||||
(st/emit! (st/emit! (dsc/push-shortcuts ::colorpicker sc/shortcuts)))
|
||||
@@ -783,5 +792,6 @@
|
||||
:on-token-change on-token-change
|
||||
:on-change on-change'
|
||||
:origin origin
|
||||
:tab tab
|
||||
:color-origin color-origin
|
||||
:on-accept on-accept}]]))
|
||||
|
||||
@@ -135,24 +135,11 @@
|
||||
|
||||
on-token-pill-click
|
||||
(mf/use-fn
|
||||
(mf/deps selected-shapes selected color-origin)
|
||||
(mf/deps selected-shapes)
|
||||
(fn [event token]
|
||||
(dom/stop-propagation event)
|
||||
(when (seq selected-shapes)
|
||||
(if (= :color-selection color-origin)
|
||||
(on-token-change event token)
|
||||
(let [attributes (if (= color-origin :stroke) #{:stroke-color} #{:fill})
|
||||
shape-ids (into #{} (map :id selected-shapes))]
|
||||
(if (or
|
||||
(and (= (:name token) has-stroke-tokens?) (= color-origin :stroke))
|
||||
(and (= (:name token) has-color-tokens?) (= color-origin :fill)))
|
||||
(st/emit! (dwta/unapply-token {:attributes attributes
|
||||
:token token
|
||||
:shape-ids shape-ids}))
|
||||
(st/emit! (dwta/apply-token {:shape-ids shape-ids
|
||||
:attributes attributes
|
||||
:token token
|
||||
:on-update-shape dwta/update-fill-stroke}))))))))
|
||||
(on-token-change event token))))
|
||||
|
||||
create-token-on-set
|
||||
(mf/use-fn
|
||||
|
||||
@@ -52,6 +52,10 @@
|
||||
(str/join ", ")
|
||||
(str/ffmt "linear-gradient(90deg, %1)")))
|
||||
|
||||
(defn- stop->hex-color
|
||||
[stop]
|
||||
(select-keys stop [:color :opacity]))
|
||||
|
||||
(mf/defc stop-input-row*
|
||||
{::mf/private true}
|
||||
[{:keys [stop
|
||||
@@ -156,7 +160,7 @@
|
||||
[:> color-row*
|
||||
{:disable-gradient true
|
||||
:disable-picker true
|
||||
:color stop
|
||||
:color (stop->hex-color stop)
|
||||
:index index
|
||||
:origin :gradient
|
||||
:on-change handle-change-stop-color
|
||||
|
||||
@@ -454,7 +454,7 @@
|
||||
.sample-library-button {
|
||||
@include t.use-typography("headline-small");
|
||||
height: $sz-32;
|
||||
width: $sz-80;
|
||||
width: px2rem(80);
|
||||
margin: 0;
|
||||
border-radius: $br-8;
|
||||
white-space: nowrap;
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
(mf/defc single-shape-options*
|
||||
{::mf/private true}
|
||||
[{:keys [shape page-id file-id libraries] :as props}]
|
||||
[{:keys [shape page-id file-id libraries] :rest props}]
|
||||
(let [shape-type (dm/get-prop shape :type)
|
||||
shape-id (dm/get-prop shape :id)
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@
|
||||
color-operations (get groups color)
|
||||
ids (into (d/ordered-set) xf:map-shape-id color-operations)]
|
||||
(st/emit! (dws/select-shapes ids)))))
|
||||
|
||||
on-token-change
|
||||
(mf/use-fn
|
||||
(fn [_ token old-color]
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
[app.config :as cfg]
|
||||
[app.main.data.workspace :as udw]
|
||||
[app.main.data.workspace.colors :as dc]
|
||||
[app.main.data.workspace.tokens.application :as dwta]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.title-bar :refer [title-bar*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
@@ -68,16 +69,24 @@
|
||||
n-vals (unchecked-get n-props "values")
|
||||
o-fills (get o-vals :fills)
|
||||
n-fills (get n-vals :fills)
|
||||
o-objects (get o-vals :objects)
|
||||
n-objects (get n-vals :objects)
|
||||
o-applied-tokens (get o-vals :applied-tokens)
|
||||
n-applied-tokens (get n-vals :applied-tokens)
|
||||
o-hide (get o-vals :hide-fill-on-export)
|
||||
n-hide (get n-vals :hide-fill-on-export)]
|
||||
(and (identical? o-hide n-hide)
|
||||
(identical? o-fills n-fills)))))
|
||||
(identical? o-applied-tokens n-applied-tokens)
|
||||
(identical? o-fills n-fills)
|
||||
(identical? o-objects n-objects)))))
|
||||
|
||||
(mf/defc fill-menu*
|
||||
{::mf/wrap [#(mf/memo' % check-props)]}
|
||||
[{:keys [ids type values]}]
|
||||
[{:keys [ids type values applied-tokens shapes objects]}]
|
||||
|
||||
(let [fills (get values :fills)
|
||||
hide-on-export (get values :hide-fill-on-export false)
|
||||
fill-token-applied (:fill applied-tokens)
|
||||
|
||||
^boolean
|
||||
multiple? (= :multiple fills)
|
||||
@@ -172,7 +181,37 @@
|
||||
#(reset! disable-drag* true))
|
||||
|
||||
on-blur
|
||||
(mf/use-fn #(reset! disable-drag* false))]
|
||||
(mf/use-fn #(reset! disable-drag* false))
|
||||
|
||||
on-token-change
|
||||
(mf/use-fn
|
||||
(mf/deps shapes objects)
|
||||
(fn [_ token]
|
||||
(let [expanded-shapes
|
||||
(if (= 1 (count shapes))
|
||||
(let [shape (first shapes)]
|
||||
(if (= (:type shape) :group)
|
||||
(keep objects (:shapes shape))
|
||||
[shape]))
|
||||
|
||||
(mapcat (fn [shape]
|
||||
(if (= (:type shape) :group)
|
||||
(keep objects (:shapes shape))
|
||||
[shape]))
|
||||
shapes))]
|
||||
|
||||
(st/emit!
|
||||
(dwta/toggle-token {:token token
|
||||
:attrs #{:fill}
|
||||
:shapes expanded-shapes})))))
|
||||
|
||||
on-detach-token
|
||||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
(fn [token]
|
||||
(st/emit! (dwta/unapply-token {:attributes #{:fill}
|
||||
:token token
|
||||
:shape-ids ids}))))]
|
||||
|
||||
(mf/with-layout-effect [hide-on-export]
|
||||
(when-let [checkbox (mf/ref-val checkbox-ref)]
|
||||
@@ -223,9 +262,12 @@
|
||||
:on-change on-change
|
||||
:on-reorder on-reorder
|
||||
:on-detach on-detach
|
||||
:on-detach-token on-detach-token
|
||||
:on-remove on-remove
|
||||
:disable-drag disable-drag?
|
||||
:on-focus on-focus
|
||||
:applied-token fill-token-applied
|
||||
:on-token-change on-token-change
|
||||
:origin :fill
|
||||
:select-on-focus (not disable-drag?)
|
||||
:on-blur on-blur}]))])
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
[app.common.types.stroke :as cts]
|
||||
[app.main.data.workspace :as udw]
|
||||
[app.main.data.workspace.colors :as dc]
|
||||
[app.main.data.workspace.tokens.application :as dwta]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.title-bar :refer [title-bar*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
@@ -37,8 +38,8 @@
|
||||
:stroke-cap-end])
|
||||
|
||||
(mf/defc stroke-menu
|
||||
{::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "type" "show-caps"]))]}
|
||||
[{:keys [ids type values show-caps disable-stroke-style] :as props}]
|
||||
{::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "type" "show-caps" "applied-tokens" "shapes" "objects"]))]}
|
||||
[{:keys [ids type values show-caps disable-stroke-style applied-tokens shapes objects] :as props}]
|
||||
(let [label (case type
|
||||
:multiple (tr "workspace.options.selection-stroke")
|
||||
:group (tr "workspace.options.group-stroke")
|
||||
@@ -167,7 +168,14 @@
|
||||
(reset! disable-drag true))
|
||||
|
||||
on-blur (fn [_]
|
||||
(reset! disable-drag false))]
|
||||
(reset! disable-drag false))
|
||||
on-detach-token
|
||||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
(fn [token attrs]
|
||||
(st/emit! (dwta/unapply-token {:attributes attrs
|
||||
:token token
|
||||
:shape-ids ids}))))]
|
||||
|
||||
[:div {:class (stl/css :element-set)}
|
||||
[:div {:class (stl/css :element-title)}
|
||||
@@ -201,6 +209,8 @@
|
||||
:stroke value
|
||||
:title (tr "workspace.options.stroke-color")
|
||||
:index index
|
||||
:shapes shapes
|
||||
:objects objects
|
||||
:show-caps show-caps
|
||||
:on-color-change on-color-change
|
||||
:on-color-detach on-color-detach
|
||||
@@ -212,6 +222,8 @@
|
||||
: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
|
||||
|
||||
@@ -11,28 +11,27 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.types.color :as clr]
|
||||
[app.common.types.shape.attrs :refer [default-color]]
|
||||
[app.common.types.token :as tk]
|
||||
[app.config :as cfg]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.workspace.colors :as dwc]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.color-bullet :as cb]
|
||||
[app.main.ui.components.color-input :refer [color-input*]]
|
||||
[app.main.ui.components.numeric-input :refer [numeric-input*]]
|
||||
[app.main.ui.components.reorder-handler :refer [reorder-handler*]]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.tooltip.tooltip :refer [tooltip*]]
|
||||
[app.main.ui.ds.utilities.swatch :refer [swatch*]]
|
||||
[app.main.ui.formats :as fmt]
|
||||
[app.main.ui.hooks :as h]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.util.color :as uc]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private detach-icon
|
||||
(deprecated-icon/icon-xref :detach (stl/css :detach-icon)))
|
||||
|
||||
(defn opacity->string
|
||||
[opacity]
|
||||
(if (= opacity :multiple)
|
||||
@@ -42,45 +41,139 @@
|
||||
(* 100)
|
||||
(fmt/format-number)))))
|
||||
|
||||
(defn remove-multiple
|
||||
[v]
|
||||
(if (= v :multiple) nil v))
|
||||
(mf/defc color-info-wrapper*
|
||||
{::mf/private true}
|
||||
[{:keys [color class handle-click-color children select-on-focus opacity on-focus on-blur on-opacity-change]}]
|
||||
[:div {:class (stl/css :color-info)}
|
||||
[:div {:class class}
|
||||
[:div {:class (stl/css :color-bullet-wrapper)}
|
||||
[:> swatch* {:background color
|
||||
:on-click handle-click-color
|
||||
:size "small"}]]
|
||||
children]
|
||||
(when opacity
|
||||
[:div {:class (stl/css :opacity-element-wrapper)}
|
||||
[:span {:class (stl/css :icon-text)} "%"]
|
||||
[:> numeric-input* {:value (-> color :opacity opacity->string)
|
||||
:class (stl/css :opacity-input)
|
||||
:placeholder "--"
|
||||
:select-on-focus select-on-focus
|
||||
:on-focus on-focus
|
||||
:on-blur on-blur
|
||||
:on-change on-opacity-change
|
||||
:data-testid "opacity-input"
|
||||
:default 100
|
||||
:min 0
|
||||
:max 100}]])])
|
||||
|
||||
(mf/defc color-token-row*
|
||||
{::mf/private true}
|
||||
[{:keys [active-tokens color-token color on-swatch-click-token detach-token open-modal-from-token]}]
|
||||
(let [;; `active-tokens` may be provided as a `delay` (lazy computation).
|
||||
;; In that case we must deref it (`@active-tokens`) to force evaluation
|
||||
;; and obtain the actual value. If it’s already realized (not a delay),
|
||||
;; we just use it directly.
|
||||
active-tokens (if (delay? active-tokens)
|
||||
@active-tokens
|
||||
active-tokens)
|
||||
|
||||
color-tokens (:color active-tokens)
|
||||
|
||||
token (some #(when (= (:name %) color-token) %) color-tokens)
|
||||
|
||||
on-detach-token
|
||||
(mf/use-fn
|
||||
(mf/deps detach-token token)
|
||||
#(detach-token token))
|
||||
|
||||
has-errors (some? (:errors token))
|
||||
token-name (:name token)
|
||||
resolved (:resolved-value token)
|
||||
not-active (and (some? active-tokens) (nil? token))
|
||||
id (dm/str (:id token) "-name")
|
||||
swatch-tooltip-content (cond
|
||||
not-active
|
||||
(tr "ds.inputs.token-field.no-active-token-option")
|
||||
has-errors
|
||||
(tr "color-row.token-color-row.deleted-token")
|
||||
:else
|
||||
(tr "workspace.tokens.resolved-value" resolved))
|
||||
name-tooltip-content (cond
|
||||
not-active
|
||||
(tr "ds.inputs.token-field.no-active-token-option")
|
||||
has-errors
|
||||
(tr "color-row.token-color-row.deleted-token")
|
||||
:else
|
||||
(mf/html
|
||||
[:div
|
||||
[:span (dm/str (tr "workspace.tokens.token-name") ": ")]
|
||||
[:span {:class (stl/css :token-name-tooltip)} color-token]]))]
|
||||
|
||||
[:div {:class (stl/css :color-info)}
|
||||
[:div {:class (stl/css-case :token-color-wrapper true
|
||||
:token-color-with-errors has-errors
|
||||
:token-color-not-active not-active)}
|
||||
[:div {:class (stl/css :color-bullet-wrapper)}
|
||||
(when (or has-errors not-active)
|
||||
[:div {:class (stl/css :error-dot)}])
|
||||
[:> swatch* {:background color
|
||||
:tooltip-content swatch-tooltip-content
|
||||
:on-click on-swatch-click-token
|
||||
:has-errors (or has-errors not-active)
|
||||
:size "small"}]]
|
||||
[:> tooltip* {:content name-tooltip-content
|
||||
:id id
|
||||
:class (stl/css :token-tooltip)}
|
||||
[:div {:class (stl/css :token-name)
|
||||
:aria-labelledby id}
|
||||
(or token-name color-token)]]
|
||||
[:div {:class (stl/css :token-actions)}
|
||||
[:> icon-button*
|
||||
{:variant "action"
|
||||
:aria-label (tr "ds.inputs.token-field.detach-token")
|
||||
:on-click on-detach-token
|
||||
:icon i/detach}]
|
||||
[:> icon-button*
|
||||
{:variant "action"
|
||||
:aria-label (tr "ds.inputs.numeric-input.open-token-list-dropdown")
|
||||
:on-click open-modal-from-token
|
||||
:icon i/tokens}]]]]))
|
||||
|
||||
(mf/defc color-row*
|
||||
[{:keys [index color class disable-gradient disable-opacity disable-image disable-picker hidden
|
||||
on-change on-reorder on-detach on-open on-close on-remove origin
|
||||
disable-drag on-focus on-blur select-only select-on-focus on-token-change]}]
|
||||
(let [libraries (mf/deref refs/files)
|
||||
on-change on-reorder on-detach on-open on-close on-remove origin on-detach-token
|
||||
disable-drag on-focus on-blur select-only select-on-focus on-token-change applied-token]}]
|
||||
(let [token-color (contains? cfg/flags :token-color)
|
||||
libraries (mf/deref refs/files)
|
||||
on-change (h/use-ref-callback on-change)
|
||||
on-token-change (h/use-ref-callback on-token-change)
|
||||
color-without-hash (mf/use-memo
|
||||
(mf/deps color)
|
||||
#(-> color :color clr/remove-hash))
|
||||
|
||||
file-id (or (:ref-file color) (:file-id color))
|
||||
color-id (or (:ref-id color) (:id color))
|
||||
src-colors (dm/get-in libraries [file-id :data :colors])
|
||||
color-name (dm/get-in src-colors [color-id :name])
|
||||
|
||||
multiple-colors? (uc/multiple? color)
|
||||
library-color? (and (or (:id color) (:ref-id color)) color-name (not multiple-colors?))
|
||||
gradient-color? (and (not multiple-colors?)
|
||||
has-multiple-colors (uc/multiple? color)
|
||||
library-color? (and (or (:id color) (:ref-id color)) color-name (not has-multiple-colors))
|
||||
gradient-color? (and (not has-multiple-colors)
|
||||
(:gradient color)
|
||||
(dm/get-in color [:gradient :type]))
|
||||
image-color? (and (not multiple-colors?)
|
||||
image-color? (and (not has-multiple-colors)
|
||||
(:image color))
|
||||
|
||||
editing-text* (mf/use-state false)
|
||||
editing-text? (deref editing-text*)
|
||||
|
||||
class (if (some? class) (dm/str class " ") "")
|
||||
is-editing-text (deref editing-text*)
|
||||
|
||||
active-tokens* (mf/use-ctx ctx/active-tokens-by-type)
|
||||
active-tokens (if active-tokens*
|
||||
@active-tokens*
|
||||
{})
|
||||
|
||||
opacity?
|
||||
(and (not multiple-colors?)
|
||||
(not library-color?)
|
||||
(not disable-opacity))
|
||||
tokens (mf/with-memo [active-tokens* origin]
|
||||
(delay
|
||||
(-> (deref active-tokens*)
|
||||
(select-keys (get tk/tokens-by-input origin))
|
||||
(not-empty))))
|
||||
|
||||
on-focus'
|
||||
(mf/use-fn
|
||||
@@ -138,12 +231,12 @@
|
||||
(st/emit! (dwc/add-recent-color color)
|
||||
(on-change color index)))))
|
||||
|
||||
handle-click-color
|
||||
open-modal
|
||||
(mf/use-fn
|
||||
(mf/deps disable-gradient disable-opacity disable-image disable-picker on-change on-close on-open active-tokens)
|
||||
(fn [color event]
|
||||
(mf/deps disable-gradient disable-opacity disable-image disable-picker on-change on-close on-open tokens)
|
||||
(fn [color pos tab]
|
||||
(let [color (cond
|
||||
multiple-colors?
|
||||
has-multiple-colors
|
||||
{:color default-color
|
||||
:opacity 1}
|
||||
|
||||
@@ -152,13 +245,8 @@
|
||||
|
||||
:else
|
||||
color)
|
||||
|
||||
cpos (dom/get-client-position event)
|
||||
x (dm/get-prop cpos :x)
|
||||
y (dm/get-prop cpos :y)
|
||||
|
||||
props {:x x
|
||||
:y y
|
||||
props {:x (:x pos)
|
||||
:y (:y pos)
|
||||
:disable-gradient disable-gradient
|
||||
:disable-opacity disable-opacity
|
||||
:disable-image disable-image
|
||||
@@ -168,8 +256,9 @@
|
||||
:on-close (fn [value opacity id file-id]
|
||||
(when on-close
|
||||
(on-close value opacity id file-id)))
|
||||
:active-tokens active-tokens
|
||||
:active-tokens tokens
|
||||
:color-origin origin
|
||||
:tab tab
|
||||
:origin :sidebar
|
||||
:data color}]
|
||||
|
||||
@@ -179,6 +268,38 @@
|
||||
(when-not disable-picker
|
||||
(modal/show! :colorpicker props)))))
|
||||
|
||||
handle-click-color
|
||||
(mf/use-fn
|
||||
(mf/deps open-modal)
|
||||
(fn [color event]
|
||||
(let [cpos (dom/get-client-position event)]
|
||||
(open-modal color cpos nil))))
|
||||
|
||||
open-modal-from-token
|
||||
(mf/use-fn
|
||||
(mf/deps open-modal color)
|
||||
(fn [event]
|
||||
(let [cpos (dom/get-client-position event)
|
||||
x (:x cpos)
|
||||
y (:y cpos)
|
||||
pos {:x (- x 215)
|
||||
:y y}]
|
||||
(open-modal color pos :token-color))))
|
||||
|
||||
on-swatch-click-token
|
||||
(mf/use-fn
|
||||
(mf/deps open-modal)
|
||||
(fn [color event]
|
||||
(let [cpos (dom/get-client-position event)]
|
||||
(open-modal color cpos :token-color))))
|
||||
|
||||
detach-token
|
||||
(mf/use-fn
|
||||
(mf/deps on-detach-token)
|
||||
(fn [token]
|
||||
(when on-detach-token
|
||||
(on-detach-token token))))
|
||||
|
||||
on-remove'
|
||||
(mf/use-fn
|
||||
(mf/deps index)
|
||||
@@ -207,88 +328,95 @@
|
||||
:name (str "Color row" index)})
|
||||
[nil nil])
|
||||
|
||||
|
||||
row-class
|
||||
(stl/css-case :color-data true
|
||||
:hidden hidden
|
||||
:dnd-over-top (= (:over dprops) :top)
|
||||
:dnd-over-bot (= (:over dprops) :bot))]
|
||||
|
||||
|
||||
(mf/with-effect [color prev-color disable-picker]
|
||||
(when (and (not disable-picker) (not= prev-color color))
|
||||
(modal/update-props! :colorpicker {:data (parse-color color)})))
|
||||
|
||||
[:div {:class [class row-class]}
|
||||
|
||||
;; Drag handler
|
||||
(when (some? on-reorder)
|
||||
[:> reorder-handler* {:ref dref}])
|
||||
(cond
|
||||
(and token-color applied-token)
|
||||
[:> color-token-row* {:active-tokens tokens
|
||||
:color-token applied-token
|
||||
:color (dissoc color :ref-id :ref-file)
|
||||
:on-swatch-click-token on-swatch-click-token
|
||||
:detach-token detach-token
|
||||
:open-modal-from-token open-modal-from-token}]
|
||||
|
||||
[:div {:class (stl/css :color-info)}
|
||||
[:div {:class (stl/css-case :color-name-wrapper true
|
||||
:no-opacity (or disable-opacity
|
||||
(not opacity?))
|
||||
:library-name-wrapper library-color?
|
||||
:editing editing-text?
|
||||
:gradient-name-wrapper gradient-color?)}
|
||||
[:div {:class (stl/css :color-bullet-wrapper)}
|
||||
[:& cb/color-bullet {:color (cond-> color
|
||||
(nil? color-name) (dissoc :ref-id :ref-file))
|
||||
:mini true
|
||||
:on-click handle-click-color}]]
|
||||
(cond
|
||||
;; Rendering a color with ID
|
||||
library-color?
|
||||
[:*
|
||||
[:div {:class (stl/css :color-name)
|
||||
:title (str color-name)}
|
||||
library-color?
|
||||
[:> color-info-wrapper* {:class (stl/css-case :color-name-wrapper true
|
||||
:library-name-wrapper true)
|
||||
:handle-click-color handle-click-color
|
||||
:color color}
|
||||
[:*
|
||||
[:div {:class (stl/css :color-name)
|
||||
:title (str color-name)}
|
||||
(str color-name)]
|
||||
[:> icon-button*
|
||||
{:variant "ghost"
|
||||
:class (stl/css :detach-btn)
|
||||
:aria-label (tr "settings.detach")
|
||||
:on-click detach-value
|
||||
:icon i/detach}]]]
|
||||
|
||||
(str color-name)]
|
||||
(when on-detach
|
||||
[:button
|
||||
{:class (stl/css :detach-btn)
|
||||
:title (tr "settings.detach")
|
||||
:on-click detach-value}
|
||||
detach-icon])]
|
||||
gradient-color?
|
||||
[:> color-info-wrapper* {:class (stl/css-case :color-name-wrapper true
|
||||
:no-opacity disable-opacity
|
||||
:gradient-name-wrapper true)
|
||||
:handle-click-color handle-click-color
|
||||
:color color
|
||||
:opacity true
|
||||
:select-on-focus select-on-focus
|
||||
:on-focus on-focus'
|
||||
:on-blur on-blur'
|
||||
:on-opacity-change on-opacity-change}
|
||||
[:div {:class (stl/css :color-name)}
|
||||
(uc/gradient-type->string (dm/get-in color [:gradient :type]))]]
|
||||
|
||||
;; Rendering a gradient
|
||||
gradient-color?
|
||||
[:div {:class (stl/css :color-name)}
|
||||
(uc/gradient-type->string (dm/get-in color [:gradient :type]))]
|
||||
image-color?
|
||||
[:> color-info-wrapper* {:class (stl/css-case :color-name-wrapper true
|
||||
:no-opacity disable-opacity)
|
||||
:handle-click-color handle-click-color
|
||||
:color color
|
||||
:opacity true
|
||||
:select-on-focus select-on-focus
|
||||
:on-focus on-focus'
|
||||
:on-blur on-blur'
|
||||
:on-opacity-change on-opacity-change}
|
||||
[:div {:class (stl/css :color-name)}
|
||||
(tr "media.image")]]
|
||||
|
||||
;; Rendering an image
|
||||
image-color?
|
||||
[:div {:class (stl/css :color-name)}
|
||||
(tr "media.image")]
|
||||
:else
|
||||
[:> color-info-wrapper* {:class (stl/css-case :color-name-wrapper true
|
||||
:no-opacity (or disable-opacity
|
||||
has-multiple-colors)
|
||||
:editing is-editing-text)
|
||||
:handle-click-color handle-click-color
|
||||
:color color
|
||||
:opacity true
|
||||
:select-on-focus select-on-focus
|
||||
:on-focus on-focus'
|
||||
:on-blur on-blur'
|
||||
:on-opacity-change on-opacity-change}
|
||||
|
||||
;; Rendering a plain color
|
||||
:else
|
||||
[:span {:class (stl/css :color-input-wrapper)}
|
||||
[:> color-input* {:value (if multiple-colors?
|
||||
""
|
||||
(-> color :color clr/remove-hash))
|
||||
:placeholder (tr "settings.multiple")
|
||||
:data-index index
|
||||
:class (stl/css :color-input)
|
||||
:on-focus on-focus'
|
||||
:on-blur on-blur'
|
||||
:on-change on-color-change}]])]
|
||||
|
||||
(when opacity?
|
||||
[:div {:class (stl/css :opacity-element-wrapper)}
|
||||
[:span {:class (stl/css :icon-text)} "%"]
|
||||
[:> numeric-input* {:value (-> color :opacity opacity->string)
|
||||
:class (stl/css :opacity-input)
|
||||
:placeholder "--"
|
||||
:select-on-focus select-on-focus
|
||||
:on-focus on-focus'
|
||||
:on-blur on-blur'
|
||||
:on-change on-opacity-change
|
||||
:data-testid "opacity-input"
|
||||
:default 100
|
||||
:min 0
|
||||
:max 100}]])]
|
||||
[:span {:class (stl/css :color-input-wrapper)}
|
||||
[:> color-input* {:value (if has-multiple-colors
|
||||
""
|
||||
color-without-hash)
|
||||
:placeholder (tr "settings.multiple")
|
||||
:data-index index
|
||||
:class (stl/css :color-input)
|
||||
:on-focus on-focus'
|
||||
:on-blur on-blur'
|
||||
:on-change on-color-change}]]])
|
||||
|
||||
(when (some? on-remove)
|
||||
[:> icon-button* {:variant "ghost"
|
||||
@@ -299,5 +427,4 @@
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "settings.select-this-color")
|
||||
:on-click handle-select
|
||||
:icon i/move}])]))
|
||||
|
||||
:icon i/move}])]))
|
||||
@@ -4,15 +4,18 @@
|
||||
//
|
||||
// Copyright (c) KALEIDOS INC
|
||||
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
@use "ds/typography.scss" as t;
|
||||
@use "ds/_sizes.scss" as *;
|
||||
@use "ds/_borders.scss" as *;
|
||||
@use "ds/mixins.scss" as *;
|
||||
@use "ds/_utils.scss" as *;
|
||||
|
||||
.color-data {
|
||||
@include deprecated.flexRow;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--sp-xs);
|
||||
position: relative;
|
||||
|
||||
--reorder-left-position: calc(-1 * var(--sp-m) - var(--sp-xxs));
|
||||
|
||||
&:hover {
|
||||
--reorder-icon-visibility: visible;
|
||||
}
|
||||
@@ -34,156 +37,289 @@
|
||||
--detach-icon-foreground-color: none;
|
||||
|
||||
display: grid;
|
||||
flex: 1;
|
||||
grid-template-columns: 1fr auto;
|
||||
align-items: center;
|
||||
gap: deprecated.$s-2;
|
||||
border-radius: deprecated.$s-8;
|
||||
background-color: var(--input-details-color);
|
||||
height: deprecated.$s-32;
|
||||
flex: 1;
|
||||
gap: var(--sp-xxs);
|
||||
block-size: $sz-32;
|
||||
border-radius: $br-8;
|
||||
background-color: var(--color-background-primary);
|
||||
|
||||
&:hover {
|
||||
--detach-icon-foreground-color: var(--input-foreground-color-active);
|
||||
|
||||
.detach-btn,
|
||||
.select-btn {
|
||||
background-color: transparent;
|
||||
}
|
||||
--detach-icon-foreground-color: var(--color-foreground-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.color-name-wrapper {
|
||||
@extend .input-element;
|
||||
@include deprecated.bodySmallTypography;
|
||||
--color-name-wrapper-background-color: var(--color-background-tertiary);
|
||||
--color-name-wrapper-foreground-color: var(--color-foreground-primary);
|
||||
--color-name-wrapper-boder-color: var(--color-background-tertiary);
|
||||
@include t.use-typography("body-small");
|
||||
@include textEllipsis;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
border-radius: deprecated.$br-8 0 0 deprecated.$br-8;
|
||||
gap: var(--sp-xs);
|
||||
block-size: $sz-32;
|
||||
min-inline-size: 0;
|
||||
inline-size: 100%;
|
||||
padding: 0;
|
||||
margin-inline-end: 0;
|
||||
gap: deprecated.$s-4;
|
||||
border: $b-1 solid var(--color-name-wrapper-boder-color);
|
||||
border-radius: $br-8;
|
||||
background-color: var(--color-name-wrapper-background-color);
|
||||
color: var(--color-name-wrapper-foreground-color);
|
||||
border-radius: $br-8 0 0 $br-8;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
input {
|
||||
padding: 0;
|
||||
}
|
||||
.color-bullet-wrapper {
|
||||
height: deprecated.$s-28;
|
||||
padding: 0 deprecated.$s-2 0 deprecated.$s-8;
|
||||
border-radius: deprecated.$br-8 0 0 deprecated.$br-8;
|
||||
background-color: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
.color-name {
|
||||
@include deprecated.bodySmallTypography;
|
||||
@include deprecated.textEllipsis;
|
||||
padding-inline: deprecated.$s-6;
|
||||
border-radius: deprecated.$br-8;
|
||||
color: var(--input-foreground-color-active);
|
||||
}
|
||||
.detach-btn {
|
||||
@extend .button-tertiary;
|
||||
height: deprecated.$s-28;
|
||||
width: deprecated.$s-28;
|
||||
margin-inline-start: auto;
|
||||
border-radius: 0 deprecated.$br-8 deprecated.$br-8 0;
|
||||
display: none;
|
||||
}
|
||||
.detach-icon {
|
||||
@extend .button-icon;
|
||||
stroke: var(--detach-icon-foreground-color);
|
||||
}
|
||||
.color-input-wrapper {
|
||||
@include deprecated.bodySmallTypography;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: deprecated.$s-28;
|
||||
padding: 0 deprecated.$s-0;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
background-color: var(--input-background-color);
|
||||
color: var(--input-foreground-color);
|
||||
border-radius: deprecated.$br-0;
|
||||
}
|
||||
&.no-opacity {
|
||||
border-radius: deprecated.$br-8;
|
||||
border-radius: $br-8;
|
||||
.color-input-wrapper {
|
||||
border-radius: deprecated.$br-8;
|
||||
border-radius: $br-8;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
--detach-icon-foreground-color: var(--input-foreground-color-active);
|
||||
--color-name-wrapper-background-color: var(--color-background-quaternary);
|
||||
--color-name-wrapper-boder-color: var(--color-background-quaternary);
|
||||
|
||||
background-color: var(--input-background-color-hover);
|
||||
border: deprecated.$s-1 solid var(--input-border-color-hover);
|
||||
.color-bullet-wrapper,
|
||||
.color-name,
|
||||
.detach-btn,
|
||||
.color-input-wrapper {
|
||||
background-color: var(--input-background-color-hover);
|
||||
}
|
||||
.detach-btn {
|
||||
display: flex;
|
||||
display: grid;
|
||||
}
|
||||
&.editing {
|
||||
background-color: var(--input-background-color-active);
|
||||
.color-bullet-wrapper,
|
||||
.color-name,
|
||||
.detach-btn,
|
||||
.color-input-wrapper {
|
||||
background-color: var(--input-background-color-active);
|
||||
}
|
||||
--color-name-wrapper-background-color: var(--color-background-primary);
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:focus-within {
|
||||
background-color: var(--input-background-color-focus);
|
||||
border: deprecated.$s-1 solid var(--input-border-color-focus);
|
||||
--color-name-wrapper-background-color: var(--color-background-tertiary);
|
||||
--color-name-wrapper-boder-color: var(--color-accent-primary);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:focus-within {
|
||||
background-color: var(--input-background-color-focus);
|
||||
border: deprecated.$s-1 solid var(--input-border-color-focus);
|
||||
--color-name-wrapper-background-color: var(--color-background-tertiary);
|
||||
--color-name-wrapper-boder-color: var(--color-accent-primary);
|
||||
&:hover {
|
||||
background-color: var(--input-background-color-hover);
|
||||
border: deprecated.$s-1 solid var(--input-border-color-focus);
|
||||
--color-name-wrapper-background-color: var(--color-background-quaternary);
|
||||
}
|
||||
}
|
||||
|
||||
&.editing {
|
||||
background-color: var(--input-background-color-active);
|
||||
--color-name-wrapper-background-color: var(--color-background-primary);
|
||||
&:hover {
|
||||
border: deprecated.$s-1 solid var(--input-border-color-active);
|
||||
--color-name-wrapper-boder-color: var(--color-accent-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.detach-btn {
|
||||
display: none;
|
||||
background: var(--color-name-wrapper-background-color);
|
||||
}
|
||||
|
||||
.color-input-wrapper {
|
||||
@include t.use-typography("body-small");
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
block-size: $sz-28;
|
||||
inline-size: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: var(--color-name-wrapper-background-color);
|
||||
color: var(--color-name-wrapper-foreground-color);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.color-name {
|
||||
@include t.use-typography("body-small");
|
||||
@include textEllipsis;
|
||||
flex-grow: 1;
|
||||
padding-inline: px2rem(6);
|
||||
border-radius: $br-8;
|
||||
color: var(--color-name-wrapper-foreground-color);
|
||||
}
|
||||
|
||||
.color-bullet-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
block-size: $sz-28;
|
||||
padding: 0 var(--sp-xxs) 0 var(--sp-s);
|
||||
border-radius: $br-8 0 0 $br-8;
|
||||
background-color: transparent;
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.color-input {
|
||||
@include textEllipsis;
|
||||
border: none;
|
||||
background: none;
|
||||
outline: none;
|
||||
block-size: $sz-28;
|
||||
inline-size: 100%;
|
||||
flex-grow: 1;
|
||||
margin: var(--sp-xxs) 0;
|
||||
padding: 0 0 0 px2rem(6);
|
||||
border-radius: $br-8;
|
||||
color: var(--input-foreground-color-active);
|
||||
&[disabled] {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.library-name-wrapper {
|
||||
border-radius: deprecated.$br-8;
|
||||
border-radius: $br-8;
|
||||
}
|
||||
|
||||
.opacity-element-wrapper {
|
||||
@extend .input-element;
|
||||
@include deprecated.bodySmallTypography;
|
||||
width: deprecated.$s-60;
|
||||
border-radius: 0 deprecated.$br-8 deprecated.$br-8 0;
|
||||
.opacity-input {
|
||||
padding: 0;
|
||||
border-radius: 0 deprecated.$br-8 deprecated.$br-8 0;
|
||||
min-width: deprecated.$s-28;
|
||||
--opacity-input-background-color: var(--color-background-tertiary);
|
||||
--opacity-input-boder-color: var(--color-background-tertiary);
|
||||
|
||||
@include t.use-typography("body-small");
|
||||
display: flex;
|
||||
align-items: center;
|
||||
block-size: $sz-32;
|
||||
inline-size: px2rem(60);
|
||||
border-radius: 0 $br-8 $br-8 0;
|
||||
border: $b-1 solid var(--opacity-input-boder-color);
|
||||
background-color: var(--opacity-input-background-color);
|
||||
|
||||
&:hover {
|
||||
--opacity-input-background-color: var(--color-background-quaternary);
|
||||
--opacity-input-boder-color: var(--color-background-quaternary);
|
||||
|
||||
.detach-btn {
|
||||
display: grid;
|
||||
}
|
||||
&.editing {
|
||||
--opacity-input-background-color: var(--color-background-primary);
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:focus-within {
|
||||
--opacity-input-background-color: var(--color-background-tertiary);
|
||||
--opacity-input-boder-color: var(--color-accent-primary);
|
||||
}
|
||||
}
|
||||
.icon-text {
|
||||
@include deprecated.flexCenter;
|
||||
height: deprecated.$s-32;
|
||||
margin-inline-end: deprecated.$s-4;
|
||||
margin-block-start: deprecated.$s-2;
|
||||
|
||||
&:focus,
|
||||
&:focus-within {
|
||||
--opacity-input-background-color: var(--color-background-tertiary);
|
||||
--opacity-input-boder-color: var(--color-accent-primary);
|
||||
&:hover {
|
||||
--opacity-input-background-color: var(--color-background-quaternary);
|
||||
}
|
||||
}
|
||||
|
||||
&.editing {
|
||||
--opacity-input-background-color: var(--color-background-primary);
|
||||
&:hover {
|
||||
--opacity-input-boder-color: var(--color-accent-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.opacity-input {
|
||||
@include textEllipsis;
|
||||
block-size: $sz-28;
|
||||
min-inline-size: $sz-28;
|
||||
flex-grow: 1;
|
||||
inline-size: 100%;
|
||||
padding: 0;
|
||||
border-radius: 0 $br-8 $br-8 0;
|
||||
border: none;
|
||||
background: none;
|
||||
outline: none;
|
||||
margin: var(--sp-xxs) 0;
|
||||
padding: 0 0 0 px2rem(6);
|
||||
color: var(--color-foreground-primary);
|
||||
&[disabled] {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-text {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
block-size: $sz-32;
|
||||
margin-inline-end: var(--sp-xs);
|
||||
margin-block-start: var(--sp-xxs);
|
||||
color: var(--color-foreground-secondary);
|
||||
}
|
||||
|
||||
// TOKEN ROW
|
||||
|
||||
.token-color-wrapper {
|
||||
--token-color-wrapper-background-color: var(--color-background-tertiary);
|
||||
--token-color-wrapper-foreground-color: var(--color-token-foreground);
|
||||
--token-color-wrapper-border-color: var(--color-token-border);
|
||||
--token-actions-display: none;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
gap: var(--sp-xs);
|
||||
block-size: $sz-32;
|
||||
min-inline-size: 0;
|
||||
inline-size: 100%;
|
||||
padding: 0;
|
||||
margin-inline-end: 0;
|
||||
background: var(--token-color-wrapper-background-color);
|
||||
border: $b-1 solid var(--token-color-wrapper-border-color);
|
||||
border-radius: $br-8;
|
||||
&:hover {
|
||||
--token-color-wrapper-background-color: var(--color-token-background);
|
||||
--token-color-wrapper-foreground-color: var(--color-foreground-primary);
|
||||
--token-color-wrapper-border-color: var(--color-token-background);
|
||||
--token-actions-display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.token-color-with-errors,
|
||||
.token-color-not-active {
|
||||
--token-color-wrapper-background-color: var(--color-background-primary);
|
||||
--token-color-wrapper-foreground-color: var(--color-foreground-secondary);
|
||||
--token-color-wrapper-border-color: var(--color-token-border);
|
||||
&:hover {
|
||||
--token-color-wrapper-background-color: var(--color-background-primary);
|
||||
--token-color-wrapper-foreground-color: var(--color-foreground-secondary);
|
||||
--token-color-wrapper-border-color: var(--color-token-background);
|
||||
--token-actions-display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.token-name {
|
||||
@include t.use-typography("body-small");
|
||||
@include textEllipsis;
|
||||
color: var(--token-color-wrapper-foreground-color);
|
||||
block-size: $sz-32;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.token-name-tooltip {
|
||||
color: var(--color-foreground-primary);
|
||||
}
|
||||
|
||||
.token-actions {
|
||||
display: var(--token-actions-display);
|
||||
justify-self: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.error-dot {
|
||||
inline-size: px2rem(4);
|
||||
block-size: px2rem(4);
|
||||
border-radius: 50%;
|
||||
background-color: var(--color-foreground-error);
|
||||
margin-inline-start: var(--sp-xs);
|
||||
position: absolute;
|
||||
inset-inline-end: px2rem(1);
|
||||
inset-block-start: px2rem(5);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.types.color :as ctc]
|
||||
[app.main.data.workspace.tokens.application :as dwta]
|
||||
[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]]
|
||||
@@ -37,8 +39,12 @@
|
||||
disable-drag
|
||||
on-focus
|
||||
on-blur
|
||||
applied-tokens
|
||||
on-detach-token
|
||||
disable-stroke-style
|
||||
select-on-focus]}]
|
||||
select-on-focus
|
||||
shapes
|
||||
objects]}]
|
||||
|
||||
(let [on-drop
|
||||
(fn [_ data]
|
||||
@@ -55,27 +61,29 @@
|
||||
:name (str "Border row" index)})
|
||||
[nil nil])
|
||||
|
||||
stroke-color-token (:stroke-color applied-tokens)
|
||||
|
||||
on-color-change-refactor
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps index on-color-change)
|
||||
(fn [color]
|
||||
(on-color-change index color)))
|
||||
|
||||
on-color-detach
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps index on-color-detach)
|
||||
(fn [color]
|
||||
(on-color-detach index color)))
|
||||
|
||||
on-remove
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps index on-remove)
|
||||
#(on-remove index))
|
||||
|
||||
stroke-width (:stroke-width stroke)
|
||||
|
||||
on-width-change
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps index on-stroke-width-change)
|
||||
#(on-stroke-width-change index %))
|
||||
|
||||
@@ -91,12 +99,35 @@
|
||||
{:value :outer :label (tr "workspace.options.stroke.outer")}]))
|
||||
|
||||
on-alignment-change
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps index on-stroke-alignment-change)
|
||||
#(on-stroke-alignment-change index (keyword %)))
|
||||
|
||||
on-token-change
|
||||
(mf/use-fn
|
||||
(mf/deps shapes objects)
|
||||
(fn [_ token]
|
||||
(let [expanded-shapes
|
||||
(if (= 1 (count shapes))
|
||||
(let [shape (first shapes)]
|
||||
(if (= (:type shape) :group)
|
||||
(keep objects (:shapes shape))
|
||||
[shape]))
|
||||
|
||||
(mapcat (fn [shape]
|
||||
(if (= (:type shape) :group)
|
||||
(keep objects (:shapes shape))
|
||||
[shape]))
|
||||
shapes))]
|
||||
|
||||
(st/emit!
|
||||
(dwta/toggle-token {:token token
|
||||
:attrs #{:stroke-color}
|
||||
:shapes expanded-shapes})))))
|
||||
|
||||
stroke-style (or (:stroke-style stroke) :solid)
|
||||
|
||||
|
||||
stroke-style-options
|
||||
(mf/with-memo [stroke-style]
|
||||
(d/concat-vec
|
||||
@@ -108,20 +139,26 @@
|
||||
{:value :mixed :label (tr "workspace.options.stroke.mixed")}]))
|
||||
|
||||
on-style-change
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps index on-stroke-style-change)
|
||||
#(on-stroke-style-change index (keyword %)))
|
||||
|
||||
on-caps-start-change
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps index on-stroke-cap-start-change)
|
||||
#(on-stroke-cap-start-change index (keyword %)))
|
||||
|
||||
on-caps-end-change
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps index on-stroke-cap-end-change)
|
||||
#(on-stroke-cap-end-change index (keyword %)))
|
||||
|
||||
on-detach-token-color
|
||||
(mf/use-fn
|
||||
(mf/deps on-detach-token)
|
||||
(fn [token]
|
||||
(on-detach-token token #{:stroke-color})))
|
||||
|
||||
stroke-caps-options
|
||||
[{:value nil :label (tr "workspace.options.stroke-cap.none")}
|
||||
:separator
|
||||
@@ -135,7 +172,7 @@
|
||||
{:value :square :label (tr "workspace.options.stroke-cap.square") :icon :stroke-squared}]
|
||||
|
||||
on-cap-switch
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps index on-stroke-cap-switch)
|
||||
#(on-stroke-cap-switch index))]
|
||||
|
||||
@@ -156,8 +193,11 @@
|
||||
:on-detach on-color-detach
|
||||
:on-remove on-remove
|
||||
:disable-drag disable-drag
|
||||
:applied-token stroke-color-token
|
||||
:on-detach-token on-detach-token-color
|
||||
:on-token-change on-token-change
|
||||
:on-focus on-focus
|
||||
:origin :stroke
|
||||
:origin :stroke-color
|
||||
:select-on-focus select-on-focus
|
||||
:on-blur on-blur}]
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
shapes (mf/with-memo [shape] [shape])
|
||||
|
||||
applied-tokens
|
||||
(get shape :applied-tokens)
|
||||
(when (seq (get shape :applied-tokens))
|
||||
(get shape :applied-tokens))
|
||||
|
||||
measure-values
|
||||
(select-keys shape measure-attrs)
|
||||
@@ -120,12 +121,16 @@
|
||||
[:> fill/fill-menu*
|
||||
{:ids ids
|
||||
:type type
|
||||
:values shape}]
|
||||
:values shape
|
||||
:shapes shapes
|
||||
:applied-tokens applied-tokens}]
|
||||
|
||||
[:& stroke-menu {:ids ids
|
||||
:type type
|
||||
:show-caps true
|
||||
:values stroke-values}]
|
||||
:values stroke-values
|
||||
:shapes shapes
|
||||
:applied-tokens applied-tokens}]
|
||||
|
||||
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
|
||||
[:& blur-menu {:ids ids
|
||||
|
||||
@@ -120,10 +120,15 @@
|
||||
[:> fill/fill-menu*
|
||||
{:ids ids
|
||||
:type type
|
||||
:values shape}]
|
||||
:values shape
|
||||
:shapes shapes
|
||||
:applied-tokens applied-tokens}]
|
||||
|
||||
[:& stroke-menu {:ids ids
|
||||
:type type
|
||||
:values stroke-values}]
|
||||
:values stroke-values
|
||||
:shapes shapes
|
||||
:applied-tokens applied-tokens}]
|
||||
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
|
||||
[:& blur-menu {:ids ids
|
||||
:values (select-keys shape [:blur])}]
|
||||
|
||||
@@ -143,11 +143,15 @@
|
||||
[:> fill/fill-menu*
|
||||
{:ids ids
|
||||
:type shape-type
|
||||
:values shape}]
|
||||
:values shape
|
||||
:shapes shapes
|
||||
:applied-tokens applied-tokens}]
|
||||
|
||||
[:& stroke-menu {:ids ids
|
||||
:type shape-type
|
||||
:values stroke-values}]
|
||||
:values stroke-values
|
||||
:shapes shapes
|
||||
:applied-tokens applied-tokens}]
|
||||
[:> color-selection-menu* {:type shape-type
|
||||
:shapes shapes-with-children
|
||||
:file-id file-id
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
[constraint-ids constraint-values]
|
||||
(get-attrs shapes objects :constraint)
|
||||
|
||||
[fill-ids fill-values]
|
||||
[fill-ids fill-values fill-tokens]
|
||||
(get-attrs shapes objects :fill)
|
||||
|
||||
[shadow-ids]
|
||||
@@ -99,7 +99,7 @@
|
||||
[blur-ids blur-values]
|
||||
(get-attrs shapes objects :blur)
|
||||
|
||||
[stroke-ids stroke-values]
|
||||
[stroke-ids stroke-values stroke-tokens]
|
||||
(get-attrs shapes objects :stroke)
|
||||
|
||||
[text-ids text-values]
|
||||
@@ -143,10 +143,21 @@
|
||||
[:& constraints-menu {:ids constraint-ids :values constraint-values}])
|
||||
|
||||
(when-not (empty? fill-ids)
|
||||
[:> fill/fill-menu* {:type type :ids fill-ids :values fill-values}])
|
||||
[:> fill/fill-menu*
|
||||
{:type type
|
||||
:ids fill-ids
|
||||
:values fill-values
|
||||
:shapes shapes
|
||||
:objects objects
|
||||
:applied-tokens fill-tokens}])
|
||||
|
||||
(when-not (empty? stroke-ids)
|
||||
[:& stroke-menu {:type type :ids stroke-ids :values stroke-values}])
|
||||
[:& stroke-menu {:type type
|
||||
:ids stroke-ids
|
||||
:values stroke-values
|
||||
:shapes shapes
|
||||
:objects objects
|
||||
:applied-tokens stroke-tokens}])
|
||||
|
||||
[:> color-selection-menu*
|
||||
{:type type
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
[app.common.types.shape.attrs :refer [editable-attrs]]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.types.text :as txt]
|
||||
[app.common.types.token :as tt]
|
||||
[app.common.weak :as weak]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-attrs blur-menu]]
|
||||
@@ -211,18 +212,34 @@
|
||||
(= attr-group :blur) (attrs/get-attrs-multi [v1 v2] attrs blur-eq blur-sel)
|
||||
:else (attrs/get-attrs-multi [v1 v2] attrs)))
|
||||
|
||||
merge-attr
|
||||
(fn [acc applied-tokens t-attr]
|
||||
"Merges a single token attribute (`t-attr`) into the accumulator map.
|
||||
- If the attribute is not present, associates it with the new value.
|
||||
- If the existing value equals the new value, keeps the accumulator unchanged.
|
||||
- If there is a conflict, sets the value to `:multiple`."
|
||||
(let [new-val (get applied-tokens t-attr)
|
||||
existing (get acc t-attr ::not-found)]
|
||||
(cond
|
||||
(= existing ::not-found) (assoc acc t-attr new-val)
|
||||
(= existing new-val) acc
|
||||
:else (assoc acc t-attr :multiple))))
|
||||
|
||||
merge-shape-attr
|
||||
(fn [acc applied-tokens shape-attr]
|
||||
"Merges all token attributes derived from a single shape attribute
|
||||
into the accumulator map using `merge-attr`."
|
||||
(let [token-attrs (tt/shape-attr->token-attrs shape-attr)]
|
||||
(reduce #(merge-attr %1 applied-tokens %2) acc token-attrs)))
|
||||
|
||||
merge-token-values
|
||||
(fn [acc keys attrs]
|
||||
(reduce
|
||||
(fn [accum key]
|
||||
(let [new-val (get attrs key)
|
||||
existing (get accum key ::not-found)]
|
||||
(cond
|
||||
(= existing ::not-found) (assoc accum key new-val)
|
||||
(= existing new-val) accum
|
||||
:else (assoc accum key :multiple))))
|
||||
acc
|
||||
keys))
|
||||
(fn [acc shape-attrs applied-tokens]
|
||||
"Merges token values across all shape attributes.
|
||||
For each shape attribute, its corresponding token attributes are merged
|
||||
into the accumulator. If applied tokens are empty, the accumulator is returned unchanged."
|
||||
(if (seq applied-tokens)
|
||||
(reduce #(merge-shape-attr %1 applied-tokens %2) acc shape-attrs)
|
||||
acc))
|
||||
|
||||
extract-attrs
|
||||
(fn [[ids values token-acc] {:keys [id type applied-tokens] :as shape}]
|
||||
@@ -263,8 +280,8 @@
|
||||
|
||||
:children
|
||||
(let [children (->> (:shapes shape []) (map #(get objects %)))
|
||||
[new-ids new-values] (get-attrs* children objects attr-group)]
|
||||
[(d/concat-vec ids new-ids) (merge-attrs values new-values) {}])
|
||||
[new-ids new-values tokens] (get-attrs* children objects attr-group)]
|
||||
[(d/concat-vec ids new-ids) (merge-attrs values new-values) tokens])
|
||||
|
||||
[])))]
|
||||
|
||||
@@ -376,7 +393,7 @@
|
||||
[constraint-ids constraint-values]
|
||||
(get-attrs shapes objects :constraint)
|
||||
|
||||
[fill-ids fill-values]
|
||||
[fill-ids fill-values fill-tokens]
|
||||
(get-attrs shapes objects :fill)
|
||||
|
||||
[shadow-ids shadow-values]
|
||||
@@ -385,7 +402,7 @@
|
||||
[blur-ids blur-values]
|
||||
(get-attrs shapes objects :blur)
|
||||
|
||||
[stroke-ids stroke-values]
|
||||
[stroke-ids stroke-values stroke-tokens]
|
||||
(get-attrs shapes objects :stroke)
|
||||
|
||||
[exports-ids exports-values]
|
||||
@@ -463,14 +480,22 @@
|
||||
[:& ot/text-menu {:type type :ids text-ids :values text-values}])
|
||||
|
||||
(when-not (empty? fill-ids)
|
||||
[:> fill/fill-menu* {:type type :ids fill-ids :values fill-values}])
|
||||
[:> fill/fill-menu* {:type type
|
||||
:ids fill-ids
|
||||
:values fill-values
|
||||
:shapes shapes
|
||||
:objects objects
|
||||
:applied-tokens fill-tokens}])
|
||||
|
||||
(when-not (empty? stroke-ids)
|
||||
[:& stroke-menu {:type type
|
||||
:ids stroke-ids
|
||||
:show-caps show-caps?
|
||||
:values stroke-values
|
||||
:disable-stroke-style has-text?}])
|
||||
:shapes shapes
|
||||
:objects objects
|
||||
:disable-stroke-style has-text?
|
||||
:applied-tokens stroke-tokens}])
|
||||
|
||||
(when-not (empty? shapes)
|
||||
[:> color-selection-menu*
|
||||
|
||||
@@ -120,12 +120,16 @@
|
||||
[:> fill/fill-menu*
|
||||
{:ids ids
|
||||
:type type
|
||||
:values shape}]
|
||||
:values shape
|
||||
:shapes shapes
|
||||
:applied-tokens applied-tokens}]
|
||||
|
||||
[:& stroke-menu {:ids ids
|
||||
:type type
|
||||
:show-caps true
|
||||
:values stroke-values}]
|
||||
:values stroke-values
|
||||
:shapes shapes
|
||||
:applied-tokens applied-tokens}]
|
||||
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
|
||||
[:& blur-menu {:ids ids
|
||||
:values (select-keys shape [:blur])}]
|
||||
|
||||
@@ -120,11 +120,15 @@
|
||||
[:> fill/fill-menu*
|
||||
{:ids ids
|
||||
:type type
|
||||
:values shape}]
|
||||
:shapes shapes
|
||||
:values shape
|
||||
:applied-tokens applied-tokens}]
|
||||
|
||||
[:& stroke-menu {:ids ids
|
||||
:type type
|
||||
:values stroke-values}]
|
||||
:shapes shapes
|
||||
:values stroke-values
|
||||
:applied-tokens applied-tokens}]
|
||||
|
||||
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
|
||||
|
||||
|
||||
@@ -188,11 +188,15 @@
|
||||
[:> fill/fill-menu*
|
||||
{:ids ids
|
||||
:type type
|
||||
:values fill-values}]
|
||||
:values fill-values
|
||||
:shapes shapes
|
||||
:applied-tokens applied-tokens}]
|
||||
|
||||
[:& stroke-menu {:ids ids
|
||||
:type type
|
||||
:values stroke-values}]
|
||||
:values stroke-values
|
||||
:shapes shapes
|
||||
:applied-tokens applied-tokens}]
|
||||
|
||||
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
|
||||
|
||||
|
||||
@@ -173,12 +173,16 @@
|
||||
[:> fill/fill-menu*
|
||||
{:ids ids
|
||||
:type type
|
||||
:values fill-values}]
|
||||
:values fill-values
|
||||
:shapes shapes
|
||||
:applied-tokens applied-tokens}]
|
||||
|
||||
[:& stroke-menu {:ids ids
|
||||
:type type
|
||||
:values stroke-values
|
||||
:disable-stroke-style true}]
|
||||
:shapes shapes
|
||||
:disable-stroke-style true
|
||||
:applied-tokens applied-tokens}]
|
||||
|
||||
(when (= :multiple (:fills fill-values))
|
||||
[:> color-selection-menu*
|
||||
|
||||
@@ -1184,7 +1184,11 @@ msgstr "Detach token"
|
||||
|
||||
#: src/app/main/ui/ds/controls/utilities/token_field.cljs:39
|
||||
msgid "ds.inputs.token-field.no-active-token-option"
|
||||
msgstr "This token is not available in any active set or theme."
|
||||
msgstr "This token is not in any active set or has an invalid value."
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs
|
||||
msgid "color-row.token-color-row.deleted-token"
|
||||
msgstr "This token does not exists or has been deleted."
|
||||
|
||||
#: src/app/main/data/auth.cljs:314
|
||||
msgid "errors.auth-provider-not-allowed"
|
||||
|
||||
@@ -1196,7 +1196,11 @@ msgstr "Desvincular token"
|
||||
|
||||
#: src/app/main/ui/ds/controls/utilities/token_field.cljs:39
|
||||
msgid "ds.inputs.token-field.no-active-token-option"
|
||||
msgstr "Este token no está disponible en ningún set ni tema activo."
|
||||
msgstr "Este token no está disponible en ningún set o tiene un valor inválido."
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs
|
||||
msgid "color-row.token-color-row.deleted-token"
|
||||
msgstr "Este token no existe o ha sido borrado."
|
||||
|
||||
#: src/app/main/data/auth.cljs:314
|
||||
msgid "errors.auth-provider-not-allowed"
|
||||
|
||||
Reference in New Issue
Block a user