mirror of
https://github.com/penpot/penpot.git
synced 2025-12-12 06:24:17 +01:00
♻️ Refactor composite token UI (#7287)
* ♻️ Refactor composite token UI * 🐛 Fix comments
This commit is contained in:
@@ -997,13 +997,9 @@ test.describe("Tokens: Themes modal", () => {
|
||||
};
|
||||
|
||||
// Switch to reference tab and back to composite tab
|
||||
const referenceTabButton = tokensUpdateCreateModal.getByRole("button", {
|
||||
name: "Reference",
|
||||
});
|
||||
const referenceTabButton = tokensUpdateCreateModal.getByTestId("reference-opt");
|
||||
await referenceTabButton.click();
|
||||
const compositeTabButton = tokensUpdateCreateModal.getByRole("button", {
|
||||
name: "Composite",
|
||||
});
|
||||
const compositeTabButton = tokensUpdateCreateModal.getByTestId("composite-opt");
|
||||
await compositeTabButton.click();
|
||||
|
||||
// Verify all values are preserved after switching tabs
|
||||
@@ -1053,9 +1049,7 @@ test.describe("Tokens: Themes modal", () => {
|
||||
await expect(submitButton).toBeDisabled();
|
||||
|
||||
// Switch to reference tab, should not be submittable either
|
||||
const referenceTabButton = tokensUpdateCreateModal.getByRole("button", {
|
||||
name: "Reference",
|
||||
});
|
||||
const referenceTabButton = tokensUpdateCreateModal.getByTestId("reference-opt");
|
||||
await referenceTabButton.click();
|
||||
await expect(submitButton).toBeDisabled();
|
||||
});
|
||||
@@ -1076,9 +1070,7 @@ test.describe("Tokens: Themes modal", () => {
|
||||
const nameField = tokensUpdateCreateModal.getByLabel("Name");
|
||||
await nameField.fill(newTokenTitle);
|
||||
|
||||
const referenceTabButton = tokensUpdateCreateModal.getByRole("button", {
|
||||
name: "Reference",
|
||||
});
|
||||
const referenceTabButton = tokensUpdateCreateModal.getByTestId("reference-opt");
|
||||
referenceTabButton.click();
|
||||
|
||||
const referenceField = tokensUpdateCreateModal.getByLabel("Reference");
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
|
||||
[:label {:html-for id
|
||||
:data-testid id
|
||||
:title title
|
||||
:class (stl/css-case
|
||||
:radio-icon true
|
||||
|
||||
@@ -24,6 +24,7 @@ $sz-252: px2rem(252);
|
||||
$sz-284: px2rem(284);
|
||||
$sz-318: px2rem(318);
|
||||
$sz-352: px2rem(352);
|
||||
$sz-384: px2rem(384);
|
||||
$sz-400: px2rem(400);
|
||||
$sz-480: px2rem(480);
|
||||
$sz-500: px2rem(500);
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
[app.common.data :as d]
|
||||
[app.main.constants :refer [max-input-length]]
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
|
||||
[app.main.ui.ds.tooltip :refer [tooltip*]]
|
||||
[app.util.dom :as dom]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private schema:input-field
|
||||
[:map
|
||||
[:class {:optional true} :string]
|
||||
[:aria-label {:optional true} [:maybe :string]]
|
||||
[:id :string]
|
||||
[:icon {:optional true}
|
||||
[:maybe [:and :string [:fn #(contains? icon-list %)]]]]
|
||||
@@ -35,10 +37,13 @@
|
||||
[{:keys [id icon class type
|
||||
has-hint hint-type
|
||||
max-length variant
|
||||
slot-start slot-end] :rest props} ref]
|
||||
slot-start slot-end
|
||||
aria-label] :rest props} ref]
|
||||
(let [input-ref (mf/use-ref)
|
||||
type (d/nilv type "text")
|
||||
variant (d/nilv variant "dense")
|
||||
tooltip-id (mf/use-id)
|
||||
|
||||
props (mf/spread-props props
|
||||
{:class (stl/css-case
|
||||
:input true
|
||||
@@ -49,10 +54,10 @@
|
||||
"true")
|
||||
:aria-describedby (when has-hint
|
||||
(str id "-hint"))
|
||||
:aria-labelledby tooltip-id
|
||||
:type (d/nilv type "text")
|
||||
:id id
|
||||
:max-length (d/nilv max-length max-input-length)})
|
||||
|
||||
on-icon-click
|
||||
(mf/use-fn
|
||||
(mf/deps ref)
|
||||
@@ -72,7 +77,11 @@
|
||||
(when (some? slot-start)
|
||||
slot-start)
|
||||
(when (some? icon)
|
||||
[:> icon* {:icon-id icon :class (stl/css :icon) :on-click on-icon-click}])
|
||||
(if aria-label
|
||||
[:> tooltip* {:content aria-label
|
||||
:id tooltip-id}
|
||||
[:> icon* {:icon-id icon :class (stl/css :icon) :on-click on-icon-click}]]
|
||||
[:> icon* {:icon-id icon :class (stl/css :icon) :on-click on-icon-click}]))
|
||||
[:> "input" props]
|
||||
(when (some? slot-end)
|
||||
slot-end)]))
|
||||
|
||||
@@ -260,6 +260,7 @@
|
||||
(def ^:icon text-uppercase (icon-xref :text-uppercase))
|
||||
(def ^:icon thumbnail (icon-xref :thumbnail))
|
||||
(def ^:icon tick (icon-xref :tick))
|
||||
(def ^:icon tokens (icon-xref :tokens))
|
||||
(def ^:icon to-corner (icon-xref :to-corner))
|
||||
(def ^:icon to-curve (icon-xref :to-curve))
|
||||
(def ^:icon tree (icon-xref :tree))
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
[app.main.fonts :as fonts]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]]
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.controls.input :refer [input*]]
|
||||
@@ -31,11 +32,12 @@
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
|
||||
[app.main.ui.ds.notifications.context-notification :refer [context-notification*]]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.main.ui.workspace.colorpicker :as colorpicker]
|
||||
[app.main.ui.workspace.colorpicker.ramp :refer [ramp-selector*]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.typography :refer [font-selector*]]
|
||||
[app.main.ui.workspace.tokens.management.create.input-token-color-bullet :refer [input-token-color-bullet*]]
|
||||
[app.main.ui.workspace.tokens.management.create.input-tokens-value :refer [input-tokens-value*
|
||||
[app.main.ui.workspace.tokens.management.create.input-tokens-value :refer [input-token*
|
||||
token-value-hint*]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.functions :as uf]
|
||||
@@ -594,7 +596,7 @@ custom-input-token-value-props: Custom props passed to the custom-input-token-va
|
||||
:custom-input-token-value-props custom-input-token-value-props
|
||||
:token-resolve-result token-resolve-result
|
||||
:clear-resolve-value clear-resolve-value}]
|
||||
[:> input-tokens-value*
|
||||
[:> input-token*
|
||||
{:placeholder placeholder
|
||||
:label label
|
||||
:default-value default-value
|
||||
@@ -737,7 +739,7 @@ custom-input-token-value-props: Custom props passed to the custom-input-token-va
|
||||
(on-external-update-value color-value))))]
|
||||
|
||||
[:*
|
||||
[:> input-tokens-value*
|
||||
[:> input-token*
|
||||
{:placeholder placeholder
|
||||
:label label
|
||||
:default-value default-value
|
||||
@@ -800,8 +802,8 @@ custom-input-token-value-props: Custom props passed to the custom-input-token-va
|
||||
:on-close on-close-font-selector
|
||||
:full-size true}]]))
|
||||
|
||||
(mf/defc font-picker*
|
||||
[{:keys [default-value input-ref on-blur on-update-value on-external-update-value token-resolve-result]}]
|
||||
(mf/defc font-picker-combobox*
|
||||
[{:keys [default-value label aria-label input-ref on-blur on-update-value on-external-update-value token-resolve-result placeholder]}]
|
||||
(let [font* (mf/use-state (fonts/find-font-family default-value))
|
||||
font (deref font*)
|
||||
set-font (mf/use-fn
|
||||
@@ -847,9 +849,10 @@ custom-input-token-value-props: Custom props passed to the custom-input-token-va
|
||||
:variant "action"
|
||||
:type "button"}])]
|
||||
[:*
|
||||
[:> input-tokens-value*
|
||||
{:placeholder (tr "workspace.tokens.token-font-family-value-enter")
|
||||
:label (tr "workspace.tokens.token-font-family-value")
|
||||
[:> input-token*
|
||||
{:placeholder (or placeholder (tr "workspace.tokens.token-font-family-value-enter"))
|
||||
:label label
|
||||
:aria-label aria-label
|
||||
:default-value default-value
|
||||
:ref input-ref
|
||||
:on-blur on-blur
|
||||
@@ -872,7 +875,7 @@ custom-input-token-value-props: Custom props passed to the custom-input-token-va
|
||||
(ctt/join-font-family value))))]
|
||||
[:> form*
|
||||
(mf/spread-props props {:token (when token (update token :value ctt/join-font-family))
|
||||
:custom-input-token-value font-picker*
|
||||
:custom-input-token-value font-picker-combobox*
|
||||
:on-value-resolve on-value-resolve
|
||||
:validate-token validate-font-family-token})]))
|
||||
|
||||
@@ -896,23 +899,29 @@ custom-input-token-value-props: Custom props passed to the custom-input-token-va
|
||||
|
||||
(def ^:private typography-inputs
|
||||
#(d/ordered-map
|
||||
:font-size
|
||||
{:label "Font Size"
|
||||
:placeholder (tr "workspace.tokens.token-value-enter")}
|
||||
:font-family
|
||||
{:label (tr "workspace.tokens.token-font-family-value")
|
||||
:icon i/text-font-family
|
||||
:placeholder (tr "workspace.tokens.token-font-family-value-enter")}
|
||||
:font-size
|
||||
{:label "Font Size"
|
||||
:icon i/text-font-size
|
||||
:placeholder (tr "workspace.tokens.token-value-enter")}
|
||||
:font-weight
|
||||
{:label "Font Weight"
|
||||
:icon i/text-font-weight
|
||||
:placeholder (tr "workspace.tokens.font-weight-value-enter")}
|
||||
:letter-spacing
|
||||
{:label "Letter Spacing"
|
||||
:placeholder (tr "workspace.tokens.token-value-enter")}
|
||||
:icon i/text-letterspacing
|
||||
:placeholder (tr "workspace.tokens.letter-spacing-value-enter-composite")}
|
||||
:text-case
|
||||
{:label "Text Case"
|
||||
:icon i/text-mixed
|
||||
:placeholder (tr "workspace.tokens.text-case-value-enter")}
|
||||
:text-decoration
|
||||
{:label "Text Decoration"
|
||||
:icon i/text-underlined
|
||||
:placeholder (tr "workspace.tokens.text-decoration-value-enter")}))
|
||||
|
||||
(mf/defc typography-value-inputs*
|
||||
@@ -920,7 +929,7 @@ custom-input-token-value-props: Custom props passed to the custom-input-token-va
|
||||
(let [typography-inputs (mf/use-memo typography-inputs)
|
||||
errors-by-key (sd/collect-typography-errors token-resolve-result)]
|
||||
[:div {:class (stl/css :nested-input-row)}
|
||||
(for [[k {:keys [label placeholder]}] typography-inputs]
|
||||
(for [[k {:keys [label placeholder icon]}] typography-inputs]
|
||||
(let [value (get default-value k)
|
||||
token-resolve-result
|
||||
(-> {:resolved-value (let [v (get-in token-resolve-result [:resolved-value k])]
|
||||
@@ -950,8 +959,8 @@ custom-input-token-value-props: Custom props passed to the custom-input-token-va
|
||||
:class (stl/css :input-row)}
|
||||
(case k
|
||||
:font-family
|
||||
[:> font-picker*
|
||||
{:label label
|
||||
[:> font-picker-combobox*
|
||||
{:aria-label label
|
||||
:placeholder placeholder
|
||||
:input-ref input-ref
|
||||
:default-value (when value (ctt/join-font-family value))
|
||||
@@ -959,19 +968,21 @@ custom-input-token-value-props: Custom props passed to the custom-input-token-va
|
||||
:on-update-value on-change
|
||||
:on-external-update-value on-external-update-value
|
||||
:token-resolve-result (when (seq token-resolve-result) token-resolve-result)}]
|
||||
[:> input-tokens-value*
|
||||
{:label label
|
||||
[:> input-token*
|
||||
{:aria-label label
|
||||
:placeholder placeholder
|
||||
:default-value value
|
||||
:on-blur on-blur
|
||||
:icon icon
|
||||
:on-change on-change
|
||||
:token-resolve-result (when (seq token-resolve-result) token-resolve-result)}])]))]))
|
||||
|
||||
(mf/defc typography-reference-input*
|
||||
[{:keys [default-value on-blur on-update-value token-resolve-result]}]
|
||||
[:> input-tokens-value*
|
||||
{:label "Reference"
|
||||
:placeholder "Reference"
|
||||
[:> input-token*
|
||||
{:aria-label (tr "labels.reference")
|
||||
:placeholder (tr "workspace.tokens.reference-composite")
|
||||
:icon i/text-typography
|
||||
:default-value (when (ctt/typography-composite-token-reference? default-value) default-value)
|
||||
:on-blur on-blur
|
||||
:on-change on-update-value
|
||||
@@ -1018,12 +1029,26 @@ custom-input-token-value-props: Custom props passed to the custom-input-token-va
|
||||
|
||||
input-props (mf/spread-props props {:default-value default-value
|
||||
:on-update-value on-update-reference-value})]
|
||||
[:div {:class (stl/css :nested-input-row)}
|
||||
[:button {:on-click on-toggle-tab :type "button"}
|
||||
(if reference-tab-active? "Composite" "Reference")]
|
||||
(if reference-tab-active?
|
||||
[:> typography-reference-input* input-props]
|
||||
[:> typography-value-inputs* input-props])]))
|
||||
[:div {:class (stl/css :typography-inputs-row)}
|
||||
[:div {:class (stl/css :title-bar)}
|
||||
[:div {:class (stl/css :title)}
|
||||
(tr "labels.typography")]
|
||||
[:& radio-buttons {:class (stl/css :listing-options)
|
||||
:selected (if reference-tab-active? "reference" "composite")
|
||||
:on-change on-toggle-tab
|
||||
:name "reference-composite-tab"}
|
||||
[:& radio-button {:icon deprecated-icon/layers
|
||||
:value "composite"
|
||||
:title (tr "workspace.tokens.individual-tokens")
|
||||
:id "composite-opt"}]
|
||||
[:& radio-button {:icon deprecated-icon/tokens
|
||||
:value "reference"
|
||||
:title (tr "workspace.tokens.use-reference")
|
||||
:id "reference-opt"}]]]
|
||||
[:div {:class (stl/css :typography-inputs)}
|
||||
(if reference-tab-active?
|
||||
[:> typography-reference-input* input-props]
|
||||
[:> typography-value-inputs* input-props])]]))
|
||||
|
||||
(mf/defc typography-form*
|
||||
[{:keys [token] :rest props}]
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
//
|
||||
// Copyright (c) KALEIDOS INC
|
||||
|
||||
@import "refactor/common-refactor.scss";
|
||||
@use "../../../../ds/typography.scss" as t;
|
||||
@use "../../../../ds/_sizes.scss" as *;
|
||||
@use "../../../../ds/_borders.scss" as *;
|
||||
|
||||
.form-wrapper {
|
||||
width: $s-384;
|
||||
width: $sz-384;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -15,8 +17,8 @@
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
justify-content: end;
|
||||
gap: $s-12;
|
||||
padding-block-start: $s-8;
|
||||
gap: var(--sp-m);
|
||||
padding-block-start: var(--sp-s);
|
||||
}
|
||||
|
||||
.with-delete {
|
||||
@@ -30,28 +32,50 @@
|
||||
.token-rows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $s-16;
|
||||
gap: var(--sp-l);
|
||||
}
|
||||
|
||||
.input-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $s-4;
|
||||
gap: var(--sp-xs);
|
||||
}
|
||||
|
||||
.nested-input-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $s-12;
|
||||
gap: var(--sp-m);
|
||||
}
|
||||
|
||||
.typography-inputs-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sp-m);
|
||||
}
|
||||
|
||||
.typography-inputs {
|
||||
border-inline-start: $b-1 solid var(--color-accent-primary-muted);
|
||||
padding-inline-start: var(--sp-l);
|
||||
}
|
||||
|
||||
.title-bar {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
.title {
|
||||
@include t.use-typography("body-small");
|
||||
color: var(--color-foreground-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.warning-name-change-notification-wrapper {
|
||||
margin-block-start: $s-16;
|
||||
margin-block-start: var(--sp-l);
|
||||
}
|
||||
|
||||
.error {
|
||||
padding: $s-4 $s-6;
|
||||
margin-bottom: 0;
|
||||
padding: var(--sp-xs) $sz-6;
|
||||
margin-block-end: 0;
|
||||
color: var(--status-color-error-500);
|
||||
}
|
||||
|
||||
@@ -77,5 +101,5 @@
|
||||
inset: 0;
|
||||
// This padding from the modal should be shared as a variable
|
||||
// Need to set this or the font-select will cause scroll
|
||||
bottom: $s-32;
|
||||
bottom: var(--sp-xxxl);
|
||||
}
|
||||
|
||||
@@ -19,9 +19,10 @@
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private schema::input-tokens-value
|
||||
(def ^:private schema::input-token
|
||||
[:map
|
||||
[:label :string]
|
||||
[:label {:optional true} [:maybe :string]]
|
||||
[:aria-label {:optional true} [:maybe :string]]
|
||||
[:placeholder {:optional true} :string]
|
||||
[:value {:optional true} [:maybe :string]]
|
||||
[:class {:optional true} :string]
|
||||
@@ -54,10 +55,9 @@
|
||||
:class (stl/css-case :resolved-value (not (or empty-message? (seq warnings) (seq errors))))
|
||||
:type type}]))
|
||||
|
||||
(mf/defc input-tokens-value*
|
||||
{::mf/props :obj
|
||||
::mf/forward-ref true
|
||||
::mf/schema schema::input-tokens-value}
|
||||
(mf/defc input-token*
|
||||
{::mf/forward-ref true
|
||||
::mf/schema schema::input-token}
|
||||
[{:keys [class label placeholder value icon slot-start token-resolve-result] :rest props} ref]
|
||||
(let [error (not (nil? (:errors token-resolve-result)))
|
||||
id (mf/use-id)
|
||||
@@ -75,7 +75,8 @@
|
||||
[:*
|
||||
[:div {:class (dm/str class " " (stl/css-case :wrapper true
|
||||
:input-error error))}
|
||||
[:> label* {:for id} label]
|
||||
(when label
|
||||
[:> label* {:for id} label])
|
||||
[:> input-field* props]]
|
||||
(when token-resolve-result
|
||||
[:> token-value-hint* {:result token-resolve-result}])]))
|
||||
|
||||
@@ -2378,6 +2378,10 @@ msgstr "Profile"
|
||||
msgid "labels.projects"
|
||||
msgstr "Projects"
|
||||
|
||||
#:src/app/main/ui/workspace/tokens/management/create/form.cljs
|
||||
msgid "labels.reference"
|
||||
msgstr "Reference"
|
||||
|
||||
#: src/app/main/data/common.cljs:83
|
||||
msgid "labels.refresh"
|
||||
msgstr "Refresh"
|
||||
@@ -2554,6 +2558,10 @@ msgstr "Themes"
|
||||
msgid "labels.tutorials"
|
||||
msgstr "Tutorials"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs
|
||||
msgid "labels.typography"
|
||||
msgstr "Typography"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:93
|
||||
msgid "labels.unknown-error"
|
||||
msgstr "Unknown error"
|
||||
@@ -7739,6 +7747,22 @@ msgstr "Enter: none | uppercase | lowercase | capitalize or {alias}"
|
||||
msgid "workspace.tokens.text-decoration-value-enter"
|
||||
msgstr "Enter text decoration: none | underline | strike-through"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs
|
||||
msgid "workspace.tokens.letter-spacing-value-enter-composite"
|
||||
msgstr "Add letter spacing or {alias}"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs
|
||||
msgid "workspace.tokens.individual-tokens"
|
||||
msgstr "Use individual tokens"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs
|
||||
msgid "workspace.tokens.use-reference"
|
||||
msgstr "Use a reference"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs
|
||||
msgid "workspace.tokens.reference-composite"
|
||||
msgstr "Enter a token typography alias"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/themes/create_modal.cljs:130
|
||||
msgid "workspace.tokens.theme-name"
|
||||
msgstr "Theme %s"
|
||||
|
||||
@@ -2380,6 +2380,10 @@ msgstr "Perfil"
|
||||
msgid "labels.projects"
|
||||
msgstr "Proyectos"
|
||||
|
||||
#:src/app/main/ui/workspace/tokens/management/create/form.cljs
|
||||
msgid "labels.reference"
|
||||
msgstr "Referencia"
|
||||
|
||||
#: src/app/main/ui/dashboard/sidebar.cljs:909, src/app/main/ui/settings/sidebar.cljs:129, src/app/main/ui/workspace/main_menu.cljs:132
|
||||
msgid "labels.release-notes"
|
||||
msgstr "Notas de versión"
|
||||
@@ -2552,6 +2556,10 @@ msgstr "Temas"
|
||||
msgid "labels.tutorials"
|
||||
msgstr "Tutoriales"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs
|
||||
msgid "labels.typography"
|
||||
msgstr "Tipografía"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:93
|
||||
msgid "labels.unknown-error"
|
||||
msgstr "Error desconocido"
|
||||
@@ -7655,6 +7663,18 @@ msgstr "Introduce: none | uppercase | lowercase | capitalize o {alias}"
|
||||
msgid "workspace.tokens.text-decoration-value-enter"
|
||||
msgstr "Introduce text decoration: none | underline | strike-through"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs
|
||||
msgid "workspace.tokens.letter-spacing-value-enter-composite"
|
||||
msgstr "Introduce letter spacing o {alias}"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs
|
||||
msgid "workspace.tokens.individual-tokens"
|
||||
msgstr "Usa tokens individuales"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs
|
||||
msgid "workspace.tokens.use-reference"
|
||||
msgstr "Usa una referencia"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/themes/create_modal.cljs:130
|
||||
msgid "workspace.tokens.theme-name"
|
||||
msgstr "Tema %s"
|
||||
|
||||
Reference in New Issue
Block a user