diff --git a/frontend/resources/images/icons/broken-link.svg b/frontend/resources/images/icons/broken-link.svg new file mode 100644 index 000000000..4e6ed1273 --- /dev/null +++ b/frontend/resources/images/icons/broken-link.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/images/icons/token-status-full.svg b/frontend/resources/images/icons/token-status-full.svg new file mode 100644 index 000000000..a24ba0ce7 --- /dev/null +++ b/frontend/resources/images/icons/token-status-full.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/frontend/resources/images/icons/token-status-non-applied.svg b/frontend/resources/images/icons/token-status-non-applied.svg new file mode 100644 index 000000000..6c9838f0a --- /dev/null +++ b/frontend/resources/images/icons/token-status-non-applied.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/frontend/resources/images/icons/token-status-partial.svg b/frontend/resources/images/icons/token-status-partial.svg new file mode 100644 index 000000000..de17718d2 --- /dev/null +++ b/frontend/resources/images/icons/token-status-partial.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index 4c72b6852..ccd9de197 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -180,7 +180,7 @@ [:& bc/color-bullet {:color {:color (:color color) :id (:id color) :opacity (:opacity color)} - :mini? true}] + :mini true}] [:div {:class (stl/css :name-block)} [:span {:class (stl/css :color-name)} (:name color)] (when-not (= (:name color) default-name) diff --git a/frontend/src/app/main/ui/ds.cljs b/frontend/src/app/main/ui/ds.cljs index 89f8a4961..dff48b329 100644 --- a/frontend/src/app/main/ui/ds.cljs +++ b/frontend/src/app/main/ui/ds.cljs @@ -16,6 +16,7 @@ [app.main.ui.ds.foundations.typography :refer [typography-list]] [app.main.ui.ds.foundations.typography.heading :refer [heading*]] [app.main.ui.ds.foundations.typography.text :refer [text*]] + [app.main.ui.ds.foundations.utilities.token.token-status :refer [token-status-icon* token-status-list]] [app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]] [app.main.ui.ds.notifications.toast :refer [toast*]] [app.main.ui.ds.product.empty-placeholder :refer [empty-placeholder*]] @@ -40,8 +41,10 @@ :Text text* :TabSwitcher tab-switcher* :Toast toast* + :TokenStatusIcon token-status-icon* ;; meta / misc :meta #js {:icons (clj->js (sort icon-list)) + :tokenStatus (clj->js (sort token-status-list)) :svgs (clj->js (sort raw-svg-list)) :typography (clj->js typography-list)} :storybook #js {:StoryGrid sb/story-grid* diff --git a/frontend/src/app/main/ui/ds/colors.scss b/frontend/src/app/main/ui/ds/colors.scss index 6d0823c93..773ee1afc 100644 --- a/frontend/src/app/main/ui/ds/colors.scss +++ b/frontend/src/app/main/ui/ds/colors.scss @@ -22,6 +22,7 @@ $orange-950: #440806; $red-200: #ffcada; $red-400: #c80857; +$red-500: #ff3277; $red-950: #500124; $pink-400: #ff6fe0; @@ -33,6 +34,16 @@ $purple-700: #6911d4; $purple-600-10: #8c33eb1a; $purple-700-60: #6911d499; +$aqua-200: #ddf7ff; +$aqua-400: #77e1f3; +$aqua-600: #59acbb; +$aqua-800: #1d4464; + +$violet-300: #a7a9ff; +$violet-600: #6c6dad; +$violet-700: #484c74; +$violet-800: #272941; + $blue-200: #bae3fd; $blue-500: #0e9be9; $blue-950: #082c49; @@ -72,6 +83,7 @@ $grayish-red: #bfbfbf; --color-background-warning: #{$orange-200}; --color-accent-error: #{$red-400}; --color-background-error: #{$red-200}; + --color-foreground-error: #{$red-500}; --color-accent-info: #{$blue-500}; --color-background-info: #{$blue-200}; @@ -87,6 +99,11 @@ $grayish-red: #bfbfbf; --color-overlay-default: #{$white-60}; --color-overlay-onboarding: #{$white-90}; --color-canvas: #{$grayish-red}; + + --color-token-background: #{$aqua-200}; + --color-token-border: #{$aqua-400}; + --color-token-accent: #{$aqua-600}; + --color-token-foreground: #{$aqua-800}; } :global(.default) { @@ -104,6 +121,7 @@ $grayish-red: #bfbfbf; --color-background-warning: #{$orange-950}; --color-accent-error: #{$red-400}; --color-background-error: #{$red-950}; + --color-foreground-error: #{$red-500}; --color-accent-info: #{$blue-500}; --color-background-info: #{$blue-950}; @@ -119,4 +137,9 @@ $grayish-red: #bfbfbf; --color-overlay-default: #{$gray-950-60}; --color-overlay-onboarding: #{$gray-950-90}; --color-canvas: #{$grayish-red}; + + --color-token-background: #{$violet-800}; + --color-token-border: #{$violet-700}; + --color-token-accent: #{$violet-600}; + --color-token-foreground: #{$violet-300}; } 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 6411cff7e..a08630a91 100644 --- a/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs +++ b/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs @@ -62,6 +62,7 @@ (def ^:icon-id boolean-flatten "boolean-flatten") (def ^:icon-id boolean-intersection "boolean-intersection") (def ^:icon-id boolean-union "boolean-union") +(def ^:icon-id broken-link "broken-link") (def ^:icon-id bug "bug") (def ^:icon-id character-a "character-a") (def ^:icon-id character-b "character-b") diff --git a/frontend/src/app/main/ui/ds/foundations/utilities/token/token_status.cljs b/frontend/src/app/main/ui/ds/foundations/utilities/token/token_status.cljs new file mode 100644 index 000000000..482087f0e --- /dev/null +++ b/frontend/src/app/main/ui/ds/foundations/utilities/token/token_status.cljs @@ -0,0 +1,28 @@ +(ns app.main.ui.ds.foundations.utilities.token.token-status + (:require-macros + [app.common.data.macros :as dm] + [app.main.style :as stl]) + (:require + [app.main.ui.ds.foundations.assets.icon :refer [collect-icons]] + [rumext.v2 :as mf])) + +(def ^:icon-id token-status-partial "token-status-partial") +(def ^:icon-id token-status-full "token-status-full") +(def ^:icon-id token-status-non-applied "token-status-non-applied") + +(def token-status-list "A collection of all status" (collect-icons)) + +(def ^:private schema:token-status-icon + [:map + [:class {:optional true} :string] + [:id [:and :string [:fn #(contains? token-status-list %)]]]]) + +(mf/defc token-status-icon* + {::mf/props :obj + ::mf/schema schema:token-status-icon} + [{:keys [id class] :rest props}] + (let [class (dm/str (or class "") " " (stl/css :token-icon)) + props (mf/spread-props props {:class class :width "14px" :height "14px"}) + offset 0] + [:> "svg" props + [:use {:href (dm/str "#icon-" id) :width "14px" :height "14px" :x offset :y offset}]])) diff --git a/frontend/src/app/main/ui/ds/foundations/utilities/token/token_status.mdx b/frontend/src/app/main/ui/ds/foundations/utilities/token/token_status.mdx new file mode 100644 index 000000000..5d4fe3b59 --- /dev/null +++ b/frontend/src/app/main/ui/ds/foundations/utilities/token/token_status.mdx @@ -0,0 +1,31 @@ +import { Canvas, Meta } from '@storybook/blocks'; +import * as TokenStatusIconStories from "./token_status.stories" + + + +# Token status icons + +## Technical notes + +There are some SVG that are not regular icons, and that are only +meant to be used on token components. + +They represent the applied status of a token over a shape. + +The assets are located in the `frontend/resources/images/icons` folder. + +### Using asset IDs + +For convenience, icons IDs are available in the component namespace. + +```clj +(ns app.main.ui.foo + (:require + [app.main.ui.ds.foundations.utilities.token.token-status :refer [token-status-icon*] :as ts])) +``` + +```clj +[:> token-status-icon* + {:id ts/token-status-partial + :class (stl/css :token-pill-icon)}] +``` diff --git a/frontend/src/app/main/ui/ds/foundations/utilities/token/token_status.scss b/frontend/src/app/main/ui/ds/foundations/utilities/token/token_status.scss new file mode 100644 index 000000000..207b2236a --- /dev/null +++ b/frontend/src/app/main/ui/ds/foundations/utilities/token/token_status.scss @@ -0,0 +1,10 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +.token-icon { + fill: currentColor; + stroke: none; +} diff --git a/frontend/src/app/main/ui/ds/foundations/utilities/token/token_status.stories.jsx b/frontend/src/app/main/ui/ds/foundations/utilities/token/token_status.stories.jsx new file mode 100644 index 000000000..84cce010c --- /dev/null +++ b/frontend/src/app/main/ui/ds/foundations/utilities/token/token_status.stories.jsx @@ -0,0 +1,23 @@ +import * as React from "react"; +import Components from "@target/components"; + +const { TokenStatusIcon } = Components; +const { tokenStatus } = Components.meta; + +export default { + title: "Foundations/Utilities/TokenStatus", + component: TokenStatusIcon, + argTypes: { + id: { + options: tokenStatus, + control: { type: "select" }, + }, + }, + render: ({ ...args }) => , +}; + +export const Default = { + args: { + id: "token-status-full", + }, +}; diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/common.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/common.cljs index b5c26b07f..99b32b9ee 100644 --- a/frontend/src/app/main/ui/viewer/inspect/attributes/common.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/attributes/common.cljs @@ -70,7 +70,7 @@ [:div {:class (stl/css :bullet-wrapper) :style #js {"--bullet-size" "16px"}} [:& cb/color-bullet {:color color - :mini? true}]] + :mini true}]] [:div {:class (stl/css :format-wrapper)} [:div {:class (stl/css :image-format)} @@ -102,7 +102,7 @@ [:div {:class (stl/css :bullet-wrapper) :style #js {"--bullet-size" "16px"}} [:& cb/color-bullet {:color color - :mini? true}]] + :mini true}]] [:div {:class (stl/css :format-wrapper)} (when-not (and on-change-format (or (:gradient color) image)) diff --git a/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs b/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs index 17dbb9450..c62498ca6 100644 --- a/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs +++ b/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs @@ -44,7 +44,7 @@ :style #js {"--bullet-size" "20px"}} (for [[i {:keys [color id gradient]}] (map-indexed vector (take 7 colors))] [:& cb/color-bullet {:key (dm/str "color-" i) - :mini? true + :mini true :color {:color color :id id :gradient gradient}}])]]])) [:li {:class (stl/css-case :file-library true @@ -68,7 +68,7 @@ :style #js {"--bullet-size" "20px"}} (for [[i color] (map-indexed vector (take 7 (vals file-colors)))] [:& cb/color-bullet {:key (dm/str "color-" i) - :mini? true + :mini true :color color}])]]] [:li {:class (stl/css :recent-colors true @@ -90,5 +90,5 @@ :style #js {"--bullet-size" "20px"}} (for [[idx color] (map-indexed vector (take 7 (reverse recent-colors)))] [:& cb/color-bullet {:key (str "color-" idx) - :mini? true + :mini true :color color}])]]]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs index 7f91cf495..5c38dab9a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs @@ -211,7 +211,7 @@ [:div {:class (stl/css :bullet-block)} [:& cb/color-bullet {:color color - :mini? true}]] + :mini true}]] (if ^boolean editing? [:input diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs index 578d08af2..5d03f3cfe 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs @@ -25,7 +25,7 @@ [app.main.ui.components.context-menu-a11y :refer [context-menu*]] [app.main.ui.components.title-bar :refer [title-bar]] [app.main.ui.context :as ctx] - [app.main.ui.icons :as i] + [app.main.ui.ds.foundations.assets.icon :refer [icon*]] [app.util.array :as array] [app.util.dom :as dom] [app.util.dom.dnd :as dnd] @@ -119,14 +119,13 @@ :left (:left state) :options options}]) -(mf/defc section-icon - {::mf/wrap-props false} - [{:keys [section]}] +(defn section-icon + [section] (case section - :colors i/drop-icon - :components i/component - :typographies i/text-palette - i/add)) + :colors "drop" + :components "component" + :typographies "text-palette" + "add")) (mf/defc asset-section {::mf/wrap-props false} @@ -151,7 +150,7 @@ (mf/html [:span {:class (stl/css :title-name)} [:span {:class (stl/css :section-icon)} - [:& (or icon section-icon) {:section section}]] + [:> icon* {:id (or icon (section-icon section)) :size "s"}]] [:span {:class (stl/css :section-name)} title] @@ -167,10 +166,12 @@ :all-clickable true :on-collapsed on-collapsed :add-icon-gap (= 0 assets-count) - :class (stl/css-case :title-spacing open?) :title title} buttons] - (when ^boolean open? content)])) + (when ^boolean (and (< 0 assets-count) + open?) + [:div {:class (stl/css-case :title-spacing open?)} + content])])) (mf/defc asset-section-block {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss index bbc0c7d70..14ae8aa10 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss @@ -39,7 +39,7 @@ } .title-spacing { - margin-bottom: $s-4; + padding-block-start: $s-4; } .asset-section.opened { diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs index e513f1c0f..a5ca4ac79 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs @@ -208,7 +208,7 @@ (nil? color-name) (assoc :id nil :file-id nil)) - :mini? true + :mini true :on-click handle-click-color}]] (cond ;; Rendering a color with ID diff --git a/frontend/src/app/main/ui/workspace/tokens/form.cljs b/frontend/src/app/main/ui/workspace/tokens/form.cljs index 0b089a277..bae45a303 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/form.cljs @@ -9,7 +9,6 @@ (:require [app.common.colors :as c] [app.common.data :as d] - [app.common.data.macros :as dm] [app.common.types.tokens-lib :as ctob] [app.main.data.modal :as modal] [app.main.data.tokens :as dt] @@ -191,10 +190,10 @@ Token names should only contain letters and digits separated by . characters.")} empty-message? (or (nil? result-or-errors) (wte/has-error-code? :error/empty-input errors)) message (cond - empty-message? (dm/str (tr "workspace.token.resolved-value") "-") + empty-message? (tr "workspace.token.resolved-value" "-") errors (->> (wte/humanize-errors errors) (str/join "\n")) - :else (dm/str (tr "workspace.token.resolved-value") result-or-errors))] + :else (tr "workspace.token.resolved-value" result-or-errors))] [:> text* {:as "p" :typography "body-small" :class (stl/css-case :resolved-value true 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 0bb41b365..a3bb43803 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss +++ b/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss @@ -158,7 +158,6 @@ } .sets-count-button { - text-transform: lowercase; padding: $s-6; padding-left: $s-12; } diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index be028c8cd..ba5c84950 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -14,7 +14,6 @@ [app.main.data.tokens :as dt] [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.title-bar :refer [title-bar]] [app.main.ui.ds.buttons.button :refer [button*]] @@ -22,7 +21,6 @@ [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] [app.main.ui.workspace.sidebar.assets.common :as cmm] [app.main.ui.workspace.tokens.changes :as wtch] [app.main.ui.workspace.tokens.context-menu :refer [token-context-menu]] @@ -33,12 +31,12 @@ [app.main.ui.workspace.tokens.style-dictionary :as sd] [app.main.ui.workspace.tokens.theme-select :refer [theme-select]] [app.main.ui.workspace.tokens.token :as wtt] + [app.main.ui.workspace.tokens.token-pill :refer [token-pill]] [app.main.ui.workspace.tokens.token-types :as wtty] [app.util.dom :as dom] [app.util.i18n :refer [tr]] [app.util.webapi :as wapi] [beicon.v2.core :as rx] - [cuerdas.core :as str] [okulary.core :as l] [rumext.v2 :as mf] [shadow.resource])) @@ -46,57 +44,30 @@ (def lens:token-type-open-status (l/derived (l/in [:workspace-tokens :open-status]) st/state)) -(def ^:private download-icon - (i/icon-xref :download (stl/css :download-icon))) - ;; Components ------------------------------------------------------------------ -(mf/defc token-pill - {::mf/wrap-props false} - [{:keys [on-click token theme-token highlighted? on-context-menu]}] - (let [{:keys [name value resolved-value errors]} token - errors? (and (seq errors) (seq (:errors theme-token)))] - [:button - {:class (stl/css-case :token-pill true - :token-pill-highlighted highlighted? - :token-pill-invalid errors?) - :title (cond - errors? (sd/humanize-errors token) - :else (->> [(str "Token: " name) - (str (tr "workspace.token.original-value") value) - (str (tr "workspace.token.resolved-value") resolved-value)] - (str/join "\n"))) - :on-click on-click - :on-context-menu on-context-menu - :disabled errors?} - (when-let [color (if (seq (ctob/find-token-value-references (:value token))) - (or - (wtt/resolved-value-hex theme-token) - ;; Fallback when the current set is inactive and has a reference that resolves in this inactive set - (wtt/resolved-value-hex token)) - (wtt/resolved-value-hex token))] - [:& color-bullet {:color color - :mini? true}]) - name])) - -(mf/defc token-section-icon - {::mf/wrap-props false} - [{:keys [type]}] +(defn token-section-icon + [type] (case type - :border-radius i/corner-radius - :numeric [:span {:class (stl/css :section-text-icon)} "123"] - :color i/drop-icon - :boolean i/boolean-difference - :opacity [:span {:class (stl/css :section-text-icon)} "%"] - :rotation i/rotation - :spacing i/padding-extended - :string i/text-mixed - :stroke-width i/stroke-size - :typography i/text - ;; TODO: Add diagonal icon here when it's available - :dimensions [:div {:style {:rotate "45deg"}} i/constraint-horizontal] - :sizing [:div {:style {:rotate "45deg"}} i/constraint-horizontal] - i/add)) + :border-radius "corner-radius" + :color "drop" + :boolean "boolean-difference" + :opacity "percentage" + :rotation "rotation" + :spacing "padding-extended" + :string "text-mixed" + :stroke-width "stroke-size" + :typography "text" + :dimensions "expand" + :sizing "expand" + "add")) + +(defn attribute-actions [token selected-shapes attributes] + (let [ids-by-attributes (wtt/shapes-ids-by-applied-attributes token selected-shapes attributes) + shape-ids (into #{} (map :id selected-shapes))] + {:all-selected? (wtt/shapes-applied-all? ids-by-attributes shape-ids attributes) + :shape-ids shape-ids + :selected-pred #(seq (% ids-by-attributes))})) (mf/defc token-component [{:keys [type tokens selected-shapes token-type-props active-theme-tokens]}] @@ -140,29 +111,37 @@ :token-type-props token-type-props}))))) tokens-count (count tokens)] [:div {:on-click on-toggle-open-click} - [:& cmm/asset-section {:icon (mf/fnc icon-wrapper [] - [:div {:class (stl/css :section-icon)} - [:& token-section-icon {:type type}]]) + [:& cmm/asset-section {:icon (token-section-icon type) :title title :assets-count tokens-count :open? open?} [:& cmm/asset-section-block {:role :title-button} - [:button {:class (stl/css :action-button) - :on-click on-popover-open-click - :title (str "Add token: " title)} - i/add]] + [:> icon-button* {:on-click on-popover-open-click + :variant "ghost" + :icon "add" + :aria-label (str "Add token: " title)}]] (when open? [:& cmm/asset-section-block {:role :content} [:div {:class (stl/css :token-pills-wrapper)} (for [token (sort-by :name tokens)] - (let [theme-token (get active-theme-tokens (wtt/token-identifier token))] + (let [theme-token (get active-theme-tokens (wtt/token-identifier token)) + multiple-selection (< 1 (count selected-shapes)) + full-applied (:all-selected? (attribute-actions token selected-shapes (or all-attributes attributes))) + applied (wtt/shapes-token-applied? token selected-shapes (or all-attributes attributes)) + on-token-click (fn [e] + (on-token-pill-click e token)) + on-context-menu (fn [e] (on-context-menu e token))] [:& token-pill {:key (:name token) :token token :theme-token theme-token - :highlighted? (wtt/shapes-token-applied? token selected-shapes (or all-attributes attributes)) - :on-click #(on-token-pill-click % token) - :on-context-menu #(on-context-menu % token)}]))]])]])) + :half-applied (and applied (not full-applied)) + ;; Multiple selected shapes behavior should be reviewed after MVP + :full-applied (if multiple-selection + false + applied) + :on-click on-token-click + :on-context-menu on-context-menu}]))]])]])) (defn sorted-token-groups "Separate token-types into groups of `:empty` or `:filled` depending if tokens exist for that type. @@ -270,24 +249,13 @@ [:& token-context-menu] [:& title-bar {:all-clickable true :title "TOKENS"}] - [:div.assets-bar - (for [{:keys [token-key token-type-props tokens]} (concat (:filled token-groups) - (:empty token-groups))] - [:& token-component {:key token-key - :type token-key - :selected-shapes selected-shapes - :active-theme-tokens active-theme-tokens - :tokens tokens - :token-type-props token-type-props}])]])) - -(mf/defc json-import-button [] - (let [] - [:div - - [:button {:class (stl/css :download-json-button) - :on-click #(.click (js/document.getElementById "file-input"))} - download-icon - "Import JSON"]])) + (for [{:keys [token-key token-type-props tokens]} (concat (:filled token-groups) (:empty token-groups))] + [:& token-component {:key token-key + :type token-key + :selected-shapes selected-shapes + :active-theme-tokens active-theme-tokens + :tokens tokens + :token-type-props token-type-props}])])) (mf/defc import-export-button {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.scss b/frontend/src/app/main/ui/workspace/tokens/sidebar.scss index 81ce6b270..62010417d 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.scss +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.scss @@ -80,25 +80,6 @@ flex-wrap: wrap; } -.token-pill { - @extend .button-secondary; - gap: $s-8; - padding: $s-4 $s-8; - border-radius: $br-6; - font-size: $fs-14; - - &.token-pill-highlighted { - color: var(--button-primary-foreground-color-rest); - background: var(--button-primary-background-color-rest); - } - - &.token-pill-invalid { - background-color: var(--button-secondary-background-color-rest); - color: var(--status-color-error-500); - opacity: 0.8; - } -} - .section-text-icon { font-size: $fs-12; width: 16px; diff --git a/frontend/src/app/main/ui/workspace/tokens/token.cljs b/frontend/src/app/main/ui/workspace/tokens/token.cljs index 215f9ca51..3fd66ed7a 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token.cljs @@ -47,12 +47,12 @@ (= (token-identifier token) id))) (defn token-applied? - "Test if `token` is applied to a `shape` with at least one of the one of the given `token-attributes`." + "Test if `token` is applied to a `shape` with at least one of the given `token-attributes`." [token shape token-attributes] (some #(token-attribute-applied? token shape %) token-attributes)) (defn shapes-token-applied? - "Test if `token` is applied to to any of `shapes` with at least one of the one of the given `token-attributes`." + "Test if `token` is applied to to any of `shapes` with at least one of the given `token-attributes`." [token shapes token-attributes] (some #(token-applied? token % token-attributes) shapes)) diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs new file mode 100644 index 000000000..d84f6fa64 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs @@ -0,0 +1,59 @@ +(ns app.main.ui.workspace.tokens.token-pill + (:require-macros [app.main.style :as stl]) + (:require + [app.common.types.tokens-lib :as ctob] + [app.main.ui.components.color-bullet :refer [color-bullet]] + [app.main.ui.ds.foundations.assets.icon :refer [icon*]] + [app.main.ui.ds.foundations.utilities.token.token-status :refer [token-status-icon*]] + [app.main.ui.workspace.tokens.style-dictionary :as sd] + [app.main.ui.workspace.tokens.token :as wtt] + [app.util.i18n :refer [tr]] + [cuerdas.core :as str] + [rumext.v2 :as mf])) + +(mf/defc token-pill + {::mf/wrap-props false} + [{:keys [on-click token theme-token full-applied on-context-menu half-applied]}] + (let [{:keys [name value resolved-value errors]} token + errors? (or (nil? theme-token) (and (seq errors) (seq (:errors theme-token)))) + + color (when (seq (ctob/find-token-value-references value)) + (wtt/resolved-value-hex theme-token)) + + color (or color (wtt/resolved-value-hex token)) + + token-status-id (cond + half-applied + "token-status-partial" + full-applied + "token-status-full" + :else + "token-status-non-applied")] + [:button {:class (stl/css-case :token-pill true + :token-pill-applied full-applied + :token-pill-invalid errors? + :token-pill-invalid-applied (and full-applied errors?)) + :type "button" + :title (cond + errors? (sd/humanize-errors token) + :else (->> [(str "Token: " name) + (tr "workspace.token.original-value" value) + (tr "workspace.token.resolved-value" resolved-value)] + (str/join "\n"))) + :on-click on-click + :on-context-menu on-context-menu + :disabled errors?} + (cond + color + [:& color-bullet {:color color + :mini true}] + errors? + [:> icon* + {:id "broken-link" + :class (stl/css :token-pill-icon)}] + + :else + [:> token-status-icon* + {:id token-status-id + :class (stl/css :token-pill-icon)}]) + name])) \ No newline at end of file diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.scss b/frontend/src/app/main/ui/workspace/tokens/token_pill.scss new file mode 100644 index 000000000..138fc15b9 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.scss @@ -0,0 +1,106 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +@use "../../ds/typography.scss" as *; +@import "refactor/common-refactor.scss"; +@import "./common.scss"; + +.token-pill { + --token-pill-background: var(--color-background-tertiary); + --token-pill-foreground: var(--color-foreground-secondary); + --token-pill-border: var(--color-background-tertiary); + --token-pill-outline: none; + --token-pill-accent: var(--color-background-quaternary); + + @include use-typography("code-font"); + border: none; + background: none; + cursor: pointer; + display: grid; + grid-template-columns: auto 1fr; + align-items: center; + gap: $s-6; + border: $s-1 solid var(--token-pill-border); + outline: $s-2 solid var(--token-pill-outline); + height: $s-24; + border-radius: $br-8; + padding: $s-3 $s-8; + color: var(--token-pill-foreground); + background: var(--token-pill-background); + + &:hover { + --token-pill-background: var(--color-token-background); + --token-pill-foreground: var(--color-foreground-primary); + --token-pill-border: var(--color-token-background); + --token-pill-outline: none; + --token-pill-accent: var(--color-background-quaternary); + } + + &:focus-visible { + --token-pill-outline: var(--color-background-primary); + --token-pill-border: var(--color-accent-primary); + outline-offset: -3px; + } + + &:disabled { + --token-pill-background: var(--color-background-primary); + --token-pill-foreground: var(--color-foreground-secondary); + --token-pill-border: var(--color-background-tertiary); + --token-pill-outline: none; + --token-pill-accent: var(--color-background-tertiary); + } +} + +.token-pill-applied { + --token-pill-background: var(--color-token-background); + --token-pill-foreground: var(--color-token-foreground); + --token-pill-border: var(--color-token-border); + --token-pill-accent: var(--color-token-accent); + + &:hover { + --token-pill-background: var(--color-token-background); + --token-pill-foreground: var(--color-foreground-primary); + --token-pill-border: var(--color-token-foreground); + --token-pill-accent: var(--color-token-accent); + } + + &:focus-visible { + --token-pill-background: var(--color-token-background); + --token-pill-foreground: var(--color-token-foreground); + --token-pill-outline: var(--color-accent-primary); + --token-pill-border: var(--color-token-background); + --token-pill-accent: var(--color-token-accent); + } + + &:disabled { + --token-pill-background: var(--color-background-primary); + --token-pill-foreground: var(--color-token-foreground); + --token-pill-border: var(--color-token-accent); + --token-pill-outline: none; + --token-pill-accent: var(--color-token-accent); + } +} + +.token-pill-invalid, +.token-pill-invalid-applied { + --token-pill-background: var(--color-background-tertiary); + --token-pill-foreground: var(--color-foreground-error); + --token-pill-border: var(--color-background-tertiary); + --token-pill-accent: var(--color-foreground-error); + + &:hover, + &:focus-visible, + &:disabled { + --token-pill-background: var(--color-background-tertiary); + --token-pill-foreground: var(--color-foreground-error); + --token-pill-border: var(--color-background-tertiary); + --token-pill-accent: var(--color-foreground-error); + } +} + +.token-pill-icon { + color: var(--token-pill-accent); +} diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 78ce30c85..7d20c40ce 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -6240,10 +6240,6 @@ msgstr "%s sets" msgid "workspace.token.original-value" msgstr "Original value: " -#: src/app/main/ui/workspace/tokens/form.cljs:193, src/app/main/ui/workspace/tokens/form.cljs:196, src/app/main/ui/workspace/tokens/sidebar.cljs:67 -msgid "workspace.token.resolved-value" -msgstr "Resolved value: " - #: src/app/main/ui/workspace/tokens/modals/themes.cljs:208 msgid "workspace.token.save-theme" msgstr "Save theme" @@ -6573,9 +6569,9 @@ msgstr "Create new %s token" msgid "workspace.token.edit-token" msgstr "Edit token" -#: src/app/main/ui/workspace/tokens/form.cljs +#: src/app/main/ui/workspace/tokens/form.cljs, src/app/main/ui/workspace/tokens/token_pill.cljs msgid "workspace.token.resolved-value" -msgstr "Resolved value: " +msgstr "Resolved value: %s" #: src/app/main/ui/workspace/tokens/form.cljs msgid "workspace.token.token-name" @@ -6603,7 +6599,7 @@ msgstr "Add a description (optional)" #: src/app/main/ui/workspace/tokens/sidebar.cljs msgid "workspace.token.original-value" -msgstr "Original value: " +msgstr "Original value: %s" #: src/app/main/ui/workspace/tokens/sidebar.cljs msgid "workspace.token.no-themes" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 40929a6c9..963e4b524 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -6242,10 +6242,6 @@ msgstr "%s sets" msgid "workspace.token.original-value" msgstr "Valor original: " -#: src/app/main/ui/workspace/tokens/form.cljs:193, src/app/main/ui/workspace/tokens/form.cljs:196, src/app/main/ui/workspace/tokens/sidebar.cljs:67 -msgid "workspace.token.resolved-value" -msgstr "Valor resuelto: " - #: src/app/main/ui/workspace/tokens/modals/themes.cljs:208 msgid "workspace.token.save-theme" msgstr "Guardar tema" @@ -6573,9 +6569,9 @@ msgstr "Crear un token de %s" msgid "workspace.token.edit-token" msgstr "Editar token" -#: src/app/main/ui/workspace/tokens/form.cljs +#: src/app/main/ui/workspace/tokens/form.cljs ,src/app/main/ui/workspace/tokens/token_pill.cljs msgid "workspace.token.resolved-value" -msgstr "Valor resuelto: " +msgstr "Valor resuelto: %s" #: src/app/main/ui/workspace/tokens/form.cljs msgid "workspace.token.token-name" @@ -6603,7 +6599,7 @@ msgstr "Añade una Descripción (opcional)" #: src/app/main/ui/workspace/tokens/sidebar.cljs msgid "workspace.token.original-value" -msgstr "Valor original: " +msgstr "Valor original: %s" #: src/app/main/ui/workspace/tokens/sidebar.cljs msgid "workspace.token.no-themes"