diff --git a/frontend/resources/images/icons/arrow-down.svg b/frontend/resources/images/icons/arrow-down.svg new file mode 100644 index 000000000..c947ef5b7 --- /dev/null +++ b/frontend/resources/images/icons/arrow-down.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/resources/images/icons/arrow-left.svg b/frontend/resources/images/icons/arrow-left.svg new file mode 100644 index 000000000..5fd7250b7 --- /dev/null +++ b/frontend/resources/images/icons/arrow-left.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/resources/images/icons/arrow-right.svg b/frontend/resources/images/icons/arrow-right.svg new file mode 100644 index 000000000..d95bda1ad --- /dev/null +++ b/frontend/resources/images/icons/arrow-right.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/resources/images/icons/arrow-up.svg b/frontend/resources/images/icons/arrow-up.svg new file mode 100644 index 000000000..505e91dcf --- /dev/null +++ b/frontend/resources/images/icons/arrow-up.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs b/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs index 50545e1e2..077083f28 100644 --- a/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs +++ b/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs @@ -50,6 +50,10 @@ (def ^:icon-id align-top "align-top") (def ^:icon-id align-vertical-center "align-vertical-center") (def ^:icon-id arrow "arrow") +(def ^:icon-id arrow-up "arrow-up") +(def ^:icon-id arrow-down "arrow-down") +(def ^:icon-id arrow-left "arrow-left") +(def ^:icon-id arrow-right "arrow-right") (def ^:icon-id asc-sort "asc-sort") (def ^:icon-id board "board") (def ^:icon-id boards-thumbnail "boards-thumbnail") diff --git a/frontend/src/app/main/ui/ds/foundations/typography/heading.cljs b/frontend/src/app/main/ui/ds/foundations/typography/heading.cljs index 515b529e6..9b3898b6c 100644 --- a/frontend/src/app/main/ui/ds/foundations/typography/heading.cljs +++ b/frontend/src/app/main/ui/ds/foundations/typography/heading.cljs @@ -32,17 +32,17 @@ (let [level (or level "1") tag (dm/str "h" level) - class (dm/str (or class "") " " (stl/css-case :display-typography (= typography t/display) - :title-large-typography (= typography t/title-large) - :title-medium-typography (= typography t/title-medium) - :title-small-typography (= typography t/title-small) - :headline-large-typography (= typography t/headline-large) - :headline-medium-typography (= typography t/headline-medium) - :headline-small-typography (= typography t/headline-small) - :body-large-typography (= typography t/body-large) - :body-medium-typography (= typography t/body-medium) - :body-small-typography (= typography t/body-small) - :code-font-typography (= typography t/code-font))) + class (dm/str class " " (stl/css-case :display-typography (= typography t/display) + :title-large-typography (= typography t/title-large) + :title-medium-typography (= typography t/title-medium) + :title-small-typography (= typography t/title-small) + :headline-large-typography (= typography t/headline-large) + :headline-medium-typography (= typography t/headline-medium) + :headline-small-typography (= typography t/headline-small) + :body-large-typography (= typography t/body-large) + :body-medium-typography (= typography t/body-medium) + :body-small-typography (= typography t/body-small) + :code-font-typography (= typography t/code-font))) props (mf/spread-props props {:class class})] [:> tag props children])) diff --git a/frontend/src/app/main/ui/workspace/tokens/form.cljs b/frontend/src/app/main/ui/workspace/tokens/form.cljs index 677439a04..1593f632d 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/form.cljs @@ -19,6 +19,7 @@ [app.main.ui.components.color-bullet :refer [color-bullet]] [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.foundations.assets.icon :as i] + [app.main.ui.ds.foundations.typography.heading :refer [heading*]] [app.main.ui.ds.foundations.typography.text :refer [text*]] [app.main.ui.workspace.colorpicker :as colorpicker] [app.main.ui.workspace.colorpicker.ramp :refer [ramp-selector]] @@ -353,14 +354,14 @@ Token names should only contain letters and digits separated by . characters.")} [:form {:class (stl/css :form-wrapper) :on-submit on-submit} [:div {:class (stl/css :token-rows)} - [:> text* {:as "span" :typography "headline-medium"} + [:> heading* {:level 2 :typography "headline-medium" :class (stl/css :form-modal-title)} (if (= action "edit") (tr "workspace.token.edit-token") (tr "workspace.token.create-token" token-type))] [:div {:class (stl/css :input-row)} ;; This should be remove when labeled-imput is modified - [:span "Name"] + [:span {:class (stl/css :labeled-input-label)} "Name"] [:& tokens.common/labeled-input {:label "Name" :error? @name-errors :input-props {:default-value @name-ref @@ -378,7 +379,7 @@ Token names should only contain letters and digits separated by . characters.")} [:div {:class (stl/css :input-row)} ;; This should be remove when labeled-imput is modified - [:span "value"] + [:span {:class (stl/css :labeled-input-label)} "value"] [:& tokens.common/labeled-input {:label "Value" :input-props {:default-value @value-ref :on-blur on-update-value @@ -401,7 +402,7 @@ Token names should only contain letters and digits separated by . characters.")} [:div {:class (stl/css :input-row)} ;; This should be remove when labeled-imput is modified - [:span "Description"] + [:span {:class (stl/css :labeled-input-label)} "Description"] [:& tokens.common/labeled-input {:label "Description" :input-props {:default-value @description-ref :on-change on-update-description}}] @@ -416,10 +417,12 @@ Token names should only contain letters and digits separated by . characters.")} (when (= action "edit") [:> button* {:on-click on-delete-token :class (stl/css :delete-btn) + :type "button" :icon i/delete :variant "secondary"} (tr "labels.delete")]) [:> button* {:on-click on-cancel + :type "button" :variant "secondary"} (tr "labels.cancel")] [:> button* {:type "submit" diff --git a/frontend/src/app/main/ui/workspace/tokens/form.scss b/frontend/src/app/main/ui/workspace/tokens/form.scss index dd35014ac..0c0dfff67 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.scss +++ b/frontend/src/app/main/ui/workspace/tokens/form.scss @@ -39,6 +39,10 @@ gap: $s-4; } +.labeled-input-label { + color: var(--color-foreground-primary); +} + .error { padding: $s-4 $s-6; margin-bottom: 0; @@ -75,3 +79,7 @@ border-radius: $br-4; cursor: pointer; } + +.form-modal-title { + color: var(--color-foreground-primary); +} diff --git a/frontend/src/app/main/ui/workspace/tokens/modals.cljs b/frontend/src/app/main/ui/workspace/tokens/modals.cljs index 06ef35af9..a34ccfe61 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modals.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/modals.cljs @@ -12,7 +12,6 @@ [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.workspace.tokens.form :refer [form]] - [app.main.ui.workspace.tokens.modals.themes :as wtmt] [app.util.i18n :refer [tr]] [okulary.core :as l] [rumext.v2 :as mf])) @@ -60,12 +59,6 @@ :selected-token-set-id selected-token-set-id :token-type token-type}]])) -(mf/defc token-themes-modal - {::mf/register modal/components - ::mf/register-as :tokens/themes} - [args] - [:& wtmt/modal args]) - ;; Modals ---------------------------------------------------------------------- (mf/defc boolean-modal diff --git a/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs b/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs index c70105df3..b90be4331 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs @@ -7,36 +7,49 @@ (ns app.main.ui.workspace.tokens.modals.themes (:require-macros [app.main.style :as stl]) (:require + [app.common.data.macros :as dm] [app.common.types.tokens-lib :as ctob] [app.main.data.modal :as modal] [app.main.data.tokens :as wdt] [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.foundations.assets.icon :refer [icon*] :as ic] + [app.main.ui.ds.foundations.typography.heading :refer [heading*]] + [app.main.ui.ds.foundations.typography.text :refer [text*]] [app.main.ui.icons :as i] [app.main.ui.workspace.tokens.common :refer [labeled-input] :as wtco] [app.main.ui.workspace.tokens.sets :as wts] [app.main.ui.workspace.tokens.sets-context :as sets-context] [app.util.dom :as dom] + [app.util.i18n :refer [tr]] [cuerdas.core :as str] [rumext.v2 :as mf])) -(def ^:private chevron-icon - (i/icon-xref :arrow (stl/css :chevron-icon))) - -(def ^:private close-icon - (i/icon-xref :close (stl/css :close-icon))) - (mf/defc empty-themes [{:keys [set-state]}] - [:div {:class (stl/css :empty-themes-wrapper)} - [:div {:class (stl/css :empty-themes-message)} - [:h1 "You currently have no themes."] - [:p "Create your first theme now."]] - [:div {:class (stl/css :button-footer)} - [:button {:class (stl/css :button-primary) - :on-click #(set-state (fn [_] {:type :create-theme}))} - "New theme"]]]) + (let [create-theme + (mf/use-fn + (mf/deps set-state) + #(set-state (fn [_] {:type :create-theme})))] + [:div {:class (stl/css :themes-modal-wrapper)} + [:> heading* {:level 2 :typography "headline-medium" :class (stl/css :themes-modal-title)} + (tr "workspace.token.themes")] + [:div {:class (stl/css :empty-themes-wrapper)} + [:div {:class (stl/css :empty-themes-message)} + [:> text* {:as "span" :typography "title-medium" :class (stl/css :empty-theme-title)} + (tr "workspace.token.no-themes-currently")] + [:> text* {:as "span" + :class (stl/css :empty-theme-subtitle) + :typography "body-medium"} + (tr "workspace.token.create-new-theme")]] + [:div {:class (stl/css :button-footer)} + [:> button* {:variant "primary" + :type "button" + :on-click create-theme} + (tr "workspace.token.new-theme")]]]])) (mf/defc switch [{:keys [selected? name on-change]}] @@ -57,60 +70,195 @@ [{:keys [set-state]}] (let [active-theme-ids (mf/deref refs/workspace-active-theme-paths) themes-groups (mf/deref refs/workspace-token-theme-tree-no-hidden) - on-edit-theme (fn [theme e] - (dom/prevent-default e) - (dom/stop-propagation e) - (set-state (fn [_] {:type :edit-theme - :theme-path [(:id theme) (:group theme) (:name theme)]})))] - [:div + + create-theme + (mf/use-fn + (mf/deps set-state) + (fn [e] + (dom/prevent-default e) + (dom/stop-propagation e) + (set-state (fn [_] {:type :create-theme}))))] + + [:div {:class (stl/css :themes-modal-wrapper)} + [:> heading* {:level 2 :typography "headline-medium" :class (stl/css :themes-modal-title)} + (tr "workspace.token.themes")] [:ul {:class (stl/css :theme-group-wrapper)} (for [[group themes] themes-groups] - [:li {:key (str "token-theme-group" group)} + [:li {:key (dm/str "token-theme-group" group)} (when (seq group) - [:span {:class (stl/css :theme-group-label)} group]) + [:> heading* {:level 3 + :class (stl/css :theme-group-label) + :typography "body-large"} + [:span {:class (stl/css :group-title)} + [:> icon* {:id "group"}] + group]]) [:ul {:class (stl/css :theme-group-rows-wrapper)} (for [[_ {:keys [group name] :as theme}] themes :let [theme-id (ctob/theme-path theme) - selected? (some? (get active-theme-ids theme-id))]] + selected? (some? (get active-theme-ids theme-id)) + delete-theme + (fn [e] + (dom/prevent-default e) + (dom/stop-propagation e) + (st/emit! (wdt/delete-token-theme group name))) + on-edit-theme + (fn [e] + (dom/prevent-default e) + (dom/stop-propagation e) + (set-state (fn [_] {:type :edit-theme + :theme-path [(:id theme) (:group theme) (:name theme)]})))]] [:li {:key theme-id :class (stl/css :theme-row)} [:div {:class (stl/css :theme-row-left)} + + ;; FIREEEEEEEEEE THIS [:div {:on-click (fn [e] (dom/prevent-default e) (dom/stop-propagation e) (st/emit! (wdt/toggle-token-theme-active? group name)))} - [:& switch {:name (str "Theme" name) + [:& switch {:name (tr "workspace.token.theme" name) :on-change (constantly nil) :selected? selected?}]] - [:span {:class (stl/css :theme-row-label)} name]] + [:> text* {:as "span" :typography "body-medium" :class (stl/css :theme-name)} name]] + + [:div {:class (stl/css :theme-row-right)} (if-let [sets-count (some-> theme :sets seq count)] - [:button {:class (stl/css :sets-count-button) - :on-click #(on-edit-theme theme %)} - (str sets-count " sets") - chevron-icon] - [:button {:class (stl/css :sets-count-empty-button) - :on-click #(on-edit-theme theme %)} - "No sets defined" - chevron-icon]) - [:div {:class (stl/css :delete-theme-button)} - [:button {:on-click (fn [e] - (dom/prevent-default e) - (dom/stop-propagation e) - (st/emit! (wdt/delete-token-theme group name)))} - i/delete]]]])]])] - [:div {:class (stl/css :button-footer)} - [:button {:class (stl/css :create-theme-button) - :on-click (fn [e] - (dom/prevent-default e) - (dom/stop-propagation e) - (set-state (fn [_] {:type :create-theme})))} - i/add - "Create theme"]]])) + [:> button* {:class (stl/css :sets-count-button) + :variant "secondary" + :type "button" + :on-click on-edit-theme} + [:div {:class (stl/css :label-wrapper)} + [:> text* {:as "span" :typography "body-medium"} + (tr "workspace.token.num-sets" sets-count)] + [:> icon* {:id "arrow-right"}]]] -(mf/defc edit-theme - [{:keys [edit? token-sets theme theme-groups on-back on-submit]}] - (let [{:keys [dropdown-open? on-open-dropdown on-close-dropdown on-toggle-dropdown]} (wtco/use-dropdown-open-state) + [:> button* {:class (stl/css :sets-count-empty-button) + :type "button" + :variant "secondary" + :on-click on-edit-theme} + [:div {:class (stl/css :label-wrapper)} + [:> text* {:as "span" :typography "body-medium"} + (tr "workspace.token.no-sets")] + [:> icon* {:id "arrow-right"}]]]) + + [:> icon-button* {:on-click delete-theme + :variant "ghost" + :aria-label (tr "workspace.token.delete-theme-title") + :icon "delete"}]]])]])] + + [:div {:class (stl/css :button-footer)} + [:> button* {:variant "primary" + :type "button" + :icon "add" + :on-click create-theme} + (tr "workspace.token.create-theme-title")]]])) + +(mf/defc theme-inputs + [{:keys [theme dropdown-open? on-close-dropdown on-toggle-dropdown on-change-field]}] + (let [theme-groups (mf/deref refs/workspace-token-theme-groups) + group-input-ref (mf/use-ref) + on-update-group (partial on-change-field :group) + on-update-name (partial on-change-field :name)] + [:div {:class (stl/css :edit-theme-inputs-wrapper)} + [:div {:class (stl/css :group-input-wrapper)} + (when dropdown-open? + [:& wtco/dropdown-select {:id ::groups-dropdown + :shortcuts-key ::groups-dropdown + :options (map (fn [group] + {:label group + :value group}) + theme-groups) + :on-select (fn [{:keys [value]}] + (set! (.-value (mf/ref-val group-input-ref)) value) + (on-update-group value)) + :on-close on-close-dropdown}]) + ;; TODO: This span should be remove when labeled-input is updated + [:span {:class (stl/css :labeled-input-label)} "Theme group"] + [:& labeled-input {:label "Group" + :input-props {:ref group-input-ref + :default-value (:group theme) + :on-change (comp on-update-group dom/get-target-val)} + :render-right (when (seq theme-groups) + (mf/fnc [] + [:button {:class (stl/css :group-drop-down-button) + :type "button" + :on-click (fn [e] + (dom/stop-propagation e) + (on-toggle-dropdown))} + [:> icon* {:id "arrow-down"}]]))}]] + [:div {:class (stl/css :group-input-wrapper)} + ;; TODO: This span should be remove when labeled-input is updated + [:span {:class (stl/css :labeled-input-label)} "Theme"] + [:& labeled-input {:label "Theme" + :input-props {:default-value (:name theme) + :on-change (comp on-update-name dom/get-target-val)}}]]])) + +(mf/defc theme-modal-buttons + [{:keys [close-modal on-save-form disabled?] :as props}] + [:* + [:> button* {:variant "secondary" + :type "button" + :on-click close-modal} + (tr "labels.cancel")] + [:> button* {:variant "primary" + :type "submit" + :on-click on-save-form + :disabled disabled?} + (tr "workspace.token.save-theme")]]) + +(mf/defc create-theme + [{:keys [set-state]}] + (let [{:keys [dropdown-open? _on-open-dropdown on-close-dropdown on-toggle-dropdown]} (wtco/use-dropdown-open-state) + theme (ctob/make-token-theme :name "") + on-back #(set-state (constantly {:type :themes-overview})) + on-submit #(st/emit! (wdt/create-token-theme %)) + theme-state (mf/use-state theme) + disabled? (-> (:name @theme-state) + (str/trim) + (str/empty?)) + on-change-field (fn [field value] + (swap! theme-state #(assoc % field value))) + on-save-form (mf/use-callback + (mf/deps theme-state on-submit) + (fn [e] + (dom/prevent-default e) + (let [theme (-> @theme-state + (update :name str/trim) + (update :group str/trim) + (update :description str/trim))] + (when-not (str/empty? (:name theme)) + (on-submit theme))) + (on-back))) + close-modal (mf/use-fn + (fn [e] + (dom/prevent-default e) + (st/emit! (modal/hide))))] + [:div {:class (stl/css :themes-modal-wrapper)} + [:> heading* {:level 2 :typography "headline-medium" :class (stl/css :themes-modal-title)} + (tr "workspace.token.create-theme-title")] + [:form {:on-submit on-save-form} + [:div {:class (stl/css :create-theme-wrapper)} + [:& theme-inputs {:dropdown-open? dropdown-open? + :on-close-dropdown on-close-dropdown + :on-toggle-dropdown on-toggle-dropdown + :theme theme + :on-change-field on-change-field}] + + [:div {:class (stl/css :button-footer)} + [:& theme-modal-buttons {:close-modal close-modal + :on-save-form on-save-form + :disabled? disabled?}]]]]])) + +(mf/defc controlled-edit-theme + [{:keys [state set-state]}] + (let [{:keys [theme-path]} @state + [_ theme-group theme-name] theme-path + token-sets (mf/deref refs/workspace-ordered-token-sets) + theme (mf/deref (refs/workspace-token-theme theme-group theme-name)) + on-back #(set-state (constantly {:type :themes-overview})) + on-submit #(st/emit! (wdt/update-token-theme [(:group theme) (:name theme)] %)) + {:keys [dropdown-open? _on-open-dropdown on-close-dropdown on-toggle-dropdown]} (wtco/use-dropdown-open-state) theme-state (mf/use-state theme) disabled? (-> (:name @theme-state) (str/trim) @@ -125,9 +273,6 @@ (swap! theme-state #(ctob/toggle-set % set-name)))) on-change-field (fn [field value] (swap! theme-state #(assoc % field value))) - group-input-ref (mf/use-ref) - on-update-group (partial on-change-field :group) - on-update-name (partial on-change-field :name) on-save-form (mf/use-callback (mf/deps theme-state on-submit) (fn [e] @@ -138,124 +283,83 @@ (update :description str/trim))] (when-not (str/empty? (:name theme)) (on-submit theme))) - (on-back)))] - [:form {:on-submit on-save-form} - [:div {:class (stl/css :edit-theme-wrapper)} - [:div - [:button {:class (stl/css :back-button) - :type "button" - :on-click on-back} - chevron-icon "Back"]] - [:div {:class (stl/css :edit-theme-inputs-wrapper)} - [:div {:class (stl/css :group-input-wrapper)} - (when dropdown-open? - [:& wtco/dropdown-select {:id ::groups-dropdown - :shortcuts-key ::groups-dropdown - :options (map (fn [group] - {:label group - :value group}) - theme-groups) - :on-select (fn [{:keys [value]}] - (set! (.-value (mf/ref-val group-input-ref)) value) - (on-update-group value)) - :on-close on-close-dropdown}]) - [:& labeled-input {:label "Group" - :input-props {:ref group-input-ref - :default-value (:group theme) - :on-change (comp on-update-group dom/get-target-val)} - :render-right (when (seq theme-groups) - (mf/fnc [] - [:button {:class (stl/css :group-drop-down-button) - :type "button" - :on-click (fn [e] - (dom/stop-propagation e) - (on-toggle-dropdown))} - i/arrow]))}]] - [:& labeled-input {:label "Theme" - :input-props {:default-value (:name theme) - :on-change (comp on-update-name dom/get-target-val)}}]] - [:div {:class (stl/css :sets-list-wrapper)} - [:& wts/controlled-sets-list - {:token-sets token-sets - :token-set-selected? (constantly false) - :token-set-active? token-set-active? - :on-select on-toggle-token-set - :on-toggle-token-set on-toggle-token-set - :context sets-context/static-context}]] - [:div {:class (stl/css :edit-theme-footer)} - (if edit? - [:button {:class (stl/css :button-secondary) - :type "button" - :on-click (fn [] - (st/emit! (wdt/delete-token-theme (:group theme) (:name theme))) - (on-back))} - "Delete"] - [:div]) - [:div {:class (stl/css :button-footer)} - [:button {:class (stl/css :button-secondary) - :type "button" - :on-click #(st/emit! (modal/hide))} - "Cancel"] - [:button {:class (stl/css :button-primary) - :type "submit" - :on-click on-save-form - :disabled disabled?} - "Save theme"]]]]])) + (on-back))) + close-modal + (mf/use-fn + (fn [e] + (dom/prevent-default e) + (st/emit! (modal/hide)))) -(mf/defc controlled-edit-theme - [{:keys [state set-state]}] - (let [{:keys [theme-path]} @state - [_ theme-group theme-name] theme-path - token-sets (mf/deref refs/workspace-ordered-token-sets) - theme (mf/deref (refs/workspace-token-theme theme-group theme-name)) - theme-groups (mf/deref refs/workspace-token-theme-groups)] - [:& edit-theme - {:edit? true - :token-sets token-sets - :theme theme - :theme-groups theme-groups - :on-back #(set-state (constantly {:type :themes-overview})) - :on-submit #(st/emit! (wdt/update-token-theme [(:group theme) (:name theme)] %))}])) + on-delete-token + (mf/use-fn + (mf/deps theme on-back) + (fn [] + (st/emit! (wdt/delete-token-theme (:group theme) (:name theme))) + (on-back)))] -(mf/defc create-theme - [{:keys [set-state]}] - (let [token-sets (mf/deref refs/workspace-ordered-token-sets) - theme (ctob/make-token-theme :name "") - theme-groups (mf/deref refs/workspace-token-theme-groups)] - [:& edit-theme - {:edit? false - :token-sets token-sets - :theme theme - :theme-groups theme-groups - :on-back #(set-state (constantly {:type :themes-overview})) - :on-submit #(st/emit! (wdt/create-token-theme %))}])) + [:div {:class (stl/css :themes-modal-wrapper)} + [:> heading* {:level 2 :typography "headline-medium" :class (stl/css :themes-modal-title)} + (tr "workspace.token.edit-theme-title")] -(mf/defc themes + [:form {:on-submit on-save-form} + [:div {:class (stl/css :edit-theme-wrapper)} + [:button {:on-click on-back + :class (stl/css :back-btn) + :type "button"} + [:> icon* {:id ic/arrow-left :aria-hidden true}] + (tr "workspace.token.back-to-themes")] + + [:& theme-inputs {:dropdown-open? dropdown-open? + :on-close-dropdown on-close-dropdown + :on-toggle-dropdown on-toggle-dropdown + :theme theme + :on-change-field on-change-field}] + + [:div {:class (stl/css :sets-list-wrapper)} + [:& wts/controlled-sets-list + {:token-sets token-sets + :token-set-selected? (constantly false) + :token-set-active? token-set-active? + :on-select on-toggle-token-set + :on-toggle-token-set on-toggle-token-set + :context sets-context/static-context}]] + + [:div {:class (stl/css :edit-theme-footer)} + [:> button* {:variant "secondary" + :type "button" + :on-click on-delete-token} + (tr "labels.delete")] + [:div {:class (stl/css :button-footer)} + [:& theme-modal-buttons {:close-modal close-modal + :on-save-form on-save-form + :disabled? disabled?}]]]]]])) + +(mf/defc themes-modal-body [_] (let [themes (mf/deref refs/workspace-token-themes-no-hidden) state (mf/use-state (if (empty? themes) {:type :create-theme} {:type :themes-overview})) set-state (mf/use-callback #(swap! state %)) - title (case (:type @state) - :edit-theme "Edit Theme" - "Themes") component (case (:type @state) :empty-themes empty-themes :themes-overview (if (empty? themes) empty-themes themes-overview) :edit-theme controlled-edit-theme :create-theme create-theme)] - [:div - [:div {:class (stl/css :modal-title)} title] - [:div {:class (stl/css :modal-content)} - [:& component {:state state - :set-state set-state}]]])) + [:& component {:state state + :set-state set-state}])) -(mf/defc modal - {::mf/wrap-props false} - [_] +(mf/defc token-themes-modal + {::mf/wrap-props false + ::mf/register modal/components + ::mf/register-as :tokens/themes} + [_args] (let [handle-close-dialog (mf/use-callback #(st/emit! (modal/hide)))] [:div {:class (stl/css :modal-overlay)} [:div {:class (stl/css :modal-dialog)} - [:button {:class (stl/css :close-btn) :on-click handle-close-dialog} close-icon] - [:& themes]]])) + [:> icon-button* {:class (stl/css :close-btn) + :on-click handle-close-dialog + :aria-label (tr "labels.close") + :variant "action" + :icon "close"}] + [:& themes-modal-body]]])) \ No newline at end of file diff --git a/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss b/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss index ca41bd82e..ca3d2e845 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss +++ b/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss @@ -10,10 +10,6 @@ @extend .modal-overlay-base; } -hr { - border-color: var(--color-background-tertiary); -} - .modal-dialog { @extend .modal-container-base; display: grid; @@ -23,16 +19,43 @@ hr { user-select: none; } -.modal-title { - @include headlineMediumTypography; - font-weight: 500; - margin-block-end: $s-16; - color: var(--color-foreground-secondary); -} - -.modal-content { +.empty-themes-message { display: flex; flex-direction: column; + justify-content: center; + align-items: center; + gap: $s-12; + padding: $s-72 0; +} + +.themes-modal-wrapper { + display: flex; + flex-direction: column; + gap: $s-24; +} + +.themes-modal-title { + color: var(--color-foreground-primary); +} + +.back-btn { + background-color: transparent; + border: none; + appearance: none; + color: var(--color-foreground-secondary); + width: fit-content; + display: grid; + grid-template-columns: auto auto; + gap: $s-4; + align-items: center; + padding: 0; + &:hover { + color: var(--color-accent-primary); + } +} + +.labeled-input-label { + color: var(--color-foreground-primary); } .button-footer { @@ -46,60 +69,41 @@ hr { justify-content: space-between; } -.button-primary { - @extend .button-primary; - padding: $s-6; -} - -.button-secondary { - @extend .button-secondary; - padding: $s-6; -} - .empty-themes-wrapper { display: flex; flex-direction: column; - - .empty-themes-message { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - gap: $s-12; - padding: $s-72 0; - - h1 { - @include headlineLargeTypography; - } - - p { - @include bodyMediumTypography; - font-weight: 500; - color: var(--color-foreground-secondary); - } - } + color: var(--color-foreground-secondary); } -.create-theme-button { - @extend .button-secondary; - padding: $s-6; - padding-right: $s-8; - svg { - margin-right: $s-6; - @extend .button-icon; - stroke: var(--icon-foreground); - } +.empty-theme-subtitle { + color: var(--color-foreground-secondary); +} + +.empty-theme-title { + color: var(--color-foreground-primary); +} + +.create-theme-wrapper { + display: flex; + flex-direction: column; + gap: $s-24; } .close-btn { - @extend .modal-close-btn-base; + position: absolute; + top: $s-8; + right: $s-6; } .theme-group-label { - display: block; - @include headlineMediumTypography; color: var(--color-foreground-secondary); - margin-bottom: $s-8; +} + +.group-title { + display: flex; + align-items: center; + justify-content: flex-start; + gap: $s-4; } .theme-group-rows-wrapper { @@ -127,34 +131,26 @@ hr { gap: $s-16; } +.theme-name { + color: var(--color-foreground-primary); +} + .theme-row-right { display: flex; align-items: center; gap: $s-6; } -.back-button { - @extend .button-tertiary; - padding: $s-6; - padding-left: 0; - display: flex; - svg { - scale: -1 1; - margin-left: 0; - @extend .button-icon; - stroke: var(--icon-foreground); - } -} - .sets-count-button { - @extend .button-secondary; + text-transform: lowercase; padding: $s-6; padding-left: $s-12; - svg { - margin-left: $s-6; - @extend .button-icon; - stroke: var(--icon-foreground); - } +} + +.label-wrapper { + display: flex; + align-items: center; + justify-content: center; } .edit-theme-wrapper { @@ -163,12 +159,6 @@ hr { gap: $s-12; } -.edit-theme-inputs-wrapper { - display: grid; - grid-template-columns: 0.6fr 1fr; - gap: $s-12; -} - .sets-list-wrapper { border: 1px solid color-mix(in hsl, var(--color-foreground-secondary) 30%, transparent); border-radius: $s-8; @@ -176,57 +166,29 @@ hr { } .sets-count-empty-button { - @extend .button-secondary; + text-transform: lowercase; padding: $s-6; padding-left: $s-12; - svg { - margin-left: $s-6; - @extend .button-icon; - stroke: var(--icon-foreground); - } -} - -.theme-row-label { - @include bodyMediumTypography; - font-weight: 500; - color: var(--color-foreground-primary); -} - -.delete-theme-button { - @extend .button-tertiary; - height: $s-28; - width: $s-28; - button { - @include buttonStyle; - @include flexCenter; - width: $s-24; - height: 100%; - svg { - @extend .button-icon-small; - height: $s-12; - width: $s-12; - color: transparent; - fill: none; - stroke: var(--icon-foreground); - } - } } .group-input-wrapper { position: relative; + display: flex; + flex-direction: column; + gap: $s-4; +} + +.edit-theme-inputs-wrapper { + display: grid; + grid-template-columns: 0.6fr 1fr; + gap: $s-12; } .group-drop-down-button { @include buttonStyle; + color: var(--color-foreground-secondary); width: $s-24; height: 100%; - padding: 0; margin: 0 $s-6; - - svg { - @extend .button-icon-small; - transform: rotate(90deg); - fill: var(--icon-foreground); - } } diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index e2c522f4c..9331def22 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -16,9 +16,10 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.color-bullet :refer [color-bullet]] - [app.main.ui.components.dropdown-menu :refer [dropdown-menu - dropdown-menu-item*]] + [app.main.ui.components.dropdown-menu :refer [dropdown-menu dropdown-menu-item*]] [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.ds.buttons.button :refer [button*]] + [app.main.ui.ds.foundations.typography.text :refer [text*]] [app.main.ui.hooks :as h] [app.main.ui.hooks.resize :refer [use-resize-hook]] [app.main.ui.icons :as i] @@ -173,22 +174,26 @@ {:empty (sort-by :token-key empty) :filled (sort-by :token-key filled)})) -(mf/defc edit-button - [{:keys [create?]}] - [:button {:class (stl/css :themes-button) - :on-click (fn [e] - (dom/stop-propagation e) - (modal/show! :tokens/themes {}))} - (if create? (tr "labels.create") (tr "labels.edit"))]) - (mf/defc themes-header [_props] - (let [ordered-themes (mf/deref refs/workspace-token-themes-no-hidden)] + (let [ordered-themes (mf/deref refs/workspace-token-themes-no-hidden) + open-modal + (mf/use-fn + (fn [e] + (dom/stop-propagation e) + (modal/show! :tokens/themes {})))] [:div {:class (stl/css :themes-wrapper)} [:span {:class (stl/css :themes-header)} (tr "labels.themes")] - [:div {:class (stl/css :theme-select-wrapper)} - [:& theme-select] - [:& edit-button {:create? (empty? ordered-themes)}]]])) + (if (empty? ordered-themes) + [:div {:class (stl/css :empty-theme-wrapper)} + [:> text* {:as "span" :typography "body-small"} (tr "workspace.token.no-themes")] + [:button {:on-click open-modal + :class (stl/css :create-theme-button)} (tr "workspace.token.create-a-theme")]] + [:div {:class (stl/css :theme-select-wrapper)} + [:& theme-select] + [:> button* {:variant "secondary" + :on-click open-modal} + (tr "labels.edit")]])])) (mf/defc add-set-button [{:keys [on-open]}] diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.scss b/frontend/src/app/main/ui/workspace/tokens/sidebar.scss index aede52260..f3608a903 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.scss +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.scss @@ -4,6 +4,7 @@ // // Copyright (c) KALEIDOS INC +@use "../../ds/typography.scss" as *; @import "refactor/common-refactor.scss"; @import "./common.scss"; @@ -37,9 +38,21 @@ position: relative; } +.themes-header { + display: block; + @include headlineSmallTypography; + margin-bottom: $s-8; + padding-left: $s-8; + color: var(--title-foreground-color); +} + .themes-wrapper { + padding: $s-12 0 0 $s-12; +} + +.empty-theme-wrapper { padding: $s-12; - padding-bottom: 0; + color: var(--color-foreground-secondary); } .sidebar-header { @@ -168,12 +181,13 @@ width: auto; } -.themes-header { - display: block; - @include headlineSmallTypography; - margin-bottom: $s-8; - padding-left: $s-8; - color: var(--title-foreground-color); +.create-theme-button { + @include use-typography("body-small"); + background-color: transparent; + border: none; + appearance: none; + color: var(--color-accent-primary); + cursor: pointer; } .resize-area-horiz { diff --git a/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs b/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs index 2805949b7..484c806c5 100644 --- a/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.workspace.tokens.theme-select (:require-macros [app.main.style :as stl]) (:require + [app.common.data.macros :as dm] [app.common.types.tokens-lib :as ctob] [app.common.uuid :as uuid] [app.main.data.modal :as modal] @@ -14,46 +15,62 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] - [app.main.ui.icons :as i] + [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] + [app.main.ui.ds.foundations.typography.text :refer [text*]] [app.util.dom :as dom] + [app.util.i18n :refer [tr]] [cuerdas.core :as str] [rumext.v2 :as mf])) (mf/defc themes-list [{:keys [themes active-theme-paths on-close grouped?]}] (when (seq themes) - [:ul + [:ul {:class (stl/css :theme-options)} (for [[_ {:keys [group name] :as theme}] themes :let [theme-id (ctob/theme-path theme) - selected? (get active-theme-paths theme-id)]] + selected? (get active-theme-paths theme-id) + select-theme (fn [e] + (dom/stop-propagation e) + (st/emit! (wdt/toggle-token-theme-active? group name)) + (on-close))]] [:li {:key theme-id + :role "option" + :aria-selected selected? :class (stl/css-case :checked-element true :sub-item grouped? :is-selected selected?) - :on-click (fn [e] - (dom/stop-propagation e) - (st/emit! (wdt/toggle-token-theme-active? group name)) - (on-close))} - [:span {:class (stl/css :label)} name] - [:span {:class (stl/css :check-icon)} i/tick]])])) + :on-click select-theme} + [:> text* {:as "span" :typography "body-small" :class (stl/css :label)} name] + [:> icon* {:id i/tick + :aria-hidden true + :class (stl/css-case :check-icon true + :check-icon-visible selected?)}]])])) (mf/defc theme-options [{:keys [active-theme-paths themes on-close]}] - [:ul - (for [[group themes] themes] - [:li {:key group} - (when (seq group) - [:span {:class (stl/css :group)} group]) - [:& themes-list {:themes themes - :active-theme-paths active-theme-paths - :on-close on-close - :grouped? true}]]) - [:li {:class (stl/css-case :checked-element true - :checked-element-button true) - :on-click #(modal/show! :tokens/themes {})} - [:span "Edit themes"] - [:span {:class (stl/css :icon)} i/arrow]]]) + (let [] + (let [on-edit-click #(modal/show! :tokens/themes {})] + [:ul {:class (stl/css :theme-options :custom-select-dropdown) + :role "listbox"} + (for [[group themes] themes] + [:li {:key group + :aria-labelledby (dm/str group "-label") + :role "group"} + (when (seq group) + [:> text* {:as "span" :typography "headline-small" :class (stl/css :group) :id (dm/str group "-label")} group]) + [:& themes-list {:themes themes + :active-theme-paths active-theme-paths + :on-close on-close + :grouped? true}]]) + [:li {:class (stl/css :separator) + :aria-hidden true}] + [:li {:class (stl/css-case :checked-element true + :checked-element-button true) + :role "option" + :on-click on-edit-click} + [:> text* {:as "span" :typography "body-small"} (tr "workspace.token.edit-themes")] + [:> icon* {:id i/arrow-right :aria-hidden true}]]]))) (mf/defc theme-select [{:keys []}] @@ -64,11 +81,11 @@ ;; Data current-label (cond - (> active-themes-count 1) (str active-themes-count " themes active") + (> active-themes-count 1) (tr "workspace.token.active-themes" active-themes-count) (= active-themes-count 1) (some->> (first active-theme-paths) (ctob/split-token-theme-path) (str/join " / ")) - :else "No theme active") + :else (tr "workspace.token.no-active-theme")) ;; State state* (mf/use-state @@ -81,13 +98,20 @@ dropdown-element* (mf/use-ref nil) on-close-dropdown (mf/use-fn #(swap! state* assoc :is-open? false)) on-open-dropdown (mf/use-fn #(swap! state* assoc :is-open? true))] + + ;; TODO: This element should be accessible by keyboard [:div {:on-click on-open-dropdown + :aria-expanded is-open? + :aria-haspopup "listbox" + :tab-index "0" + :role "combobox" :class (stl/css :custom-select)} - [:span {:class (stl/css :current-label)} current-label] - [:span {:class (stl/css :dropdown-button)} i/arrow] - [:& dropdown {:show is-open? :on-close on-close-dropdown} - [:div {:ref dropdown-element* - :class (stl/css :custom-select-dropdown)} - [:& theme-options {:active-theme-paths active-theme-paths - :themes themes - :on-close on-close-dropdown}]]]])) + [:> text* {:as "span" :typography "body-small" :class (stl/css :current-label)} + current-label] + [:> icon* {:id i/arrow-down :class (stl/css :dropdown-button) :aria-hidden true}] + [:& dropdown {:show is-open? + :on-close on-close-dropdown + :ref dropdown-element*} + [:& theme-options {:active-theme-paths active-theme-paths + :themes themes + :on-close on-close-dropdown}]]])) diff --git a/frontend/src/app/main/ui/workspace/tokens/theme_select.scss b/frontend/src/app/main/ui/workspace/tokens/theme_select.scss index da8a7b5a3..79c0f3fc2 100644 --- a/frontend/src/app/main/ui/workspace/tokens/theme_select.scss +++ b/frontend/src/app/main/ui/workspace/tokens/theme_select.scss @@ -7,12 +7,11 @@ @import "refactor/common-refactor.scss"; .custom-select { - --border-color: var(--menu-background-color); - --bg-color: var(--menu-background-color); - --icon-color: var(--icon-foreground); - --text-color: var(--menu-foreground-color); + --custom-select-border-color: var(--menu-background-color); + --custom-select-bg-color: var(--menu-background-color); + --custom-select-icon-color: var(--color-foreground-secondary); + --custom-select-text-color: var(--menu-foreground-color); @extend .new-scrollbar; - @include bodySmallTypography; position: relative; display: grid; grid-template-columns: 1fr auto; @@ -22,74 +21,60 @@ margin: 0; padding: $s-8; border-radius: $br-8; - background-color: var(--bg-color); - border: $s-1 solid var(--border-color); - color: var(--text-color); + background-color: var(--custom-select-bg-color); + border: $s-1 solid var(--custom-select-border-color); + color: var(--custom-select-text-color); cursor: pointer; - - ul { - margin-bottom: 0; - } - - .group { - display: block; - @include headlineSmallTypography; - padding: $s-8; - color: var(--color-foreground-secondary); - font-weight: 600; - } - - &.icon { - grid-template-columns: auto 1fr auto; - } - &:hover { - --bg-color: var(--menu-background-color-hover); - --border-color: var(--menu-background-color); - --icon-color: var(--menu-foreground-color-hover); + --custom-select-bg-color: var(--menu-background-color-hover); + --custom-select-border-color: var(--menu-background-color); + --custom-select-icon-color: var(--menu-foreground-color-hover); } &:focus { - --bg-color: var(--menu-background-color-focus); - --border-color: var(--menu-background-focus); + --custom-select-bg-color: var(--menu-background-color-focus); + --custom-select-border-color: var(--menu-background-focus); } } +.theme-options { + margin-bottom: 0; +} + +.group { + display: block; + padding: $s-8; + color: var(--color-foreground-secondary); +} + .disabled { - --bg-color: var(--menu-background-color-disabled); - --border-color: var(--menu-border-color-disabled); - --icon-color: var(--menu-foreground-color-disabled); - --text-color: var(--menu-foreground-color-disabled); + --custom-select-bg-color: var(--menu-background-color-disabled); + --custom-select-border-color: var(--menu-border-color-disabled); + --custom-select-icon-color: var(--menu-foreground-color-disabled); + --custom-select-text-color: var(--menu-foreground-color-disabled); pointer-events: none; cursor: default; } .dropdown-button { @include flexCenter; - svg { - @extend .button-icon-small; - transform: rotate(90deg); - stroke: var(--icon-color); - } + color: var(--color-foreground-secondary); } .current-icon { @include flexCenter; width: $s-24; padding-right: $s-4; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } } .custom-select-dropdown { @extend .dropdown-wrapper; - .separator { - margin: 0; - height: $s-12; - border-block-start: $s-1 solid var(--dropdown-separator-color); - } +} + +.separator { + margin: 0; + height: $s-2; + border-block-start: $s-1 solid color-mix(in hsl, var(--color-foreground-secondary) 20%, transparent); } .custom-select-dropdown[data-direction="up"] { @@ -109,59 +94,31 @@ padding-right: 0; } -li + .checked-element-button { - margin-top: $s-8; - &:before { - content: ""; - position: absolute; - top: -$s-4; - left: 0; - right: 0; - height: 1px; - background-color: color-mix(in hsl, var(--color-foreground-secondary) 20%, transparent); - } -} - .checked-element { @extend .dropdown-element-base; - - .icon { - @include flexCenter; - height: $s-24; - width: $s-24; - padding-right: $s-4; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } - } - - .label { - flex-grow: 1; - width: 100%; - } - - .check-icon { - @include flexCenter; - svg { - @extend .button-icon-small; - visibility: hidden; - stroke: var(--icon-foreground); - } - } - &.is-selected { color: var(--menu-foreground-color); - .check-icon svg { - stroke: var(--menu-foreground-color); - visibility: visible; - } } &.disabled { display: none; } } +.check-icon { + @include flexCenter; + color: var(--icon-foreground-primary); + visibility: hidden; +} + +.label { + flex-grow: 1; + width: 100%; +} + +.check-icon-visible { + visibility: visible; +} + .current-label { @include textEllipsis; } diff --git a/frontend/translations/en.po b/frontend/translations/en.po index bdec8767d..2df74f258 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -6163,4 +6163,72 @@ msgstr "Resolved value: " #: src/app/main/ui/workspace/tokens/sidebar.cljs msgid "workspace.token.original-value" -msgstr "Original value: " \ No newline at end of file +msgstr "Original value: " + +#: src/app/main/ui/workspace/tokens/sidebar.cljs +msgid "workspace.token.no-themes" +msgstr "There are no themes." + +#: src/app/main/ui/workspace/tokens/sidebar.cljs +msgid "workspace.token.create-a-theme" +msgstr "Create one." + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.save-theme" +msgstr "Save theme" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.create-theme-title" +msgstr "Create theme" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.edit-theme-title" +msgstr "Edit theme" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.delete-theme-title" +msgstr "Delete theme" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.no-themes-currently" +msgstr "You currently have no themes." + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.create-new-theme" +msgstr "Create your first theme now." + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.new-theme" +msgstr "New theme" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.themes" +msgstr "Themes" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.theme-name" +msgstr "Theme %s" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.no-sets" +msgstr "No sets defined" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.num-sets" +msgstr "%s sets" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.back-to-themes" +msgstr "Back to theme list" + +#: src/app/main/ui/workspace/tokens/theme_select.cljs +msgid "workspace.token.edit-themes" +msgstr "Edit themes" + +#: src/app/main/ui/workspace/tokens/theme_select.cljs +msgid "workspace.token.no-active-theme" +msgstr "No theme active" + +#: src/app/main/ui/workspace/tokens/theme_select.cljs +msgid "workspace.token.active-themes" +msgstr "%s active themes" \ No newline at end of file diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 02b19d584..f8c2afa04 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -6150,4 +6150,72 @@ msgstr "Valor resuelto: " #: src/app/main/ui/workspace/tokens/sidebar.cljs msgid "workspace.token.original-value" -msgstr "Valor original: " \ No newline at end of file +msgstr "Valor original: " + +#: src/app/main/ui/workspace/tokens/sidebar.cljs +msgid "workspace.token.no-themes" +msgstr "No hay temas." + +#: src/app/main/ui/workspace/tokens/sidebar.cljs +msgid "workspace.token.create-a-theme" +msgstr "Crear uno." + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.save-theme" +msgstr "Guardar tema" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.create-theme-title" +msgstr "Crear tema" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.edit-theme-title" +msgstr "Editar tema" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.delete-theme-title" +msgstr "Borrar theme" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.no-themes-currently" +msgstr "Actualmente no existen temas." + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.create-new-theme" +msgstr "Crea un nuevo tema ahora." + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.new-theme" +msgstr "Nuevo tema" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.themes" +msgstr "Temas" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.theme-name" +msgstr "Tema %s" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.no-sets" +msgstr "No hay sets definidos" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.num-sets" +msgstr "%s sets" + +#: src/app/main/ui/workspace/tokens/modals/themes.cljs +msgid "workspace.token.back-to-themes" +msgstr "Volver al listado de temas" + +#: src/app/main/ui/workspace/tokens/theme_select.cljs +msgid "workspace.token.edit-themes" +msgstr "Editar temas" + +#: src/app/main/ui/workspace/tokens/theme_select.cljs +msgid "workspace.token.no-active-theme" +msgstr "No hay temas activos" + +#: src/app/main/ui/workspace/tokens/theme_select.cljs +msgid "workspace.token.active-themes" +msgstr "%s temas activos" \ No newline at end of file