mirror of
https://github.com/penpot/penpot.git
synced 2025-08-07 14:38:33 +02:00
Merge remote-tracking branch 'origin/token-studio-develop' into token-sets-themes
This commit is contained in:
commit
2df577cba2
11 changed files with 357 additions and 41 deletions
|
@ -29,6 +29,8 @@
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.workspace.tokens.core :as wtc]
|
[app.main.ui.workspace.tokens.core :as wtc]
|
||||||
[app.main.ui.workspace.tokens.editable-select :refer [editable-select]]
|
[app.main.ui.workspace.tokens.editable-select :refer [editable-select]]
|
||||||
|
[app.main.ui.workspace.tokens.token :as wtt]
|
||||||
|
[app.main.ui.workspace.tokens.changes :as wtch]
|
||||||
[app.main.ui.workspace.tokens.token-types :as wtty]
|
[app.main.ui.workspace.tokens.token-types :as wtty]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
|
@ -985,18 +987,25 @@
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
(fn [type prop value]
|
(fn [type prop value]
|
||||||
(let [token-value (wtc/maybe-resolve-token-value value)
|
(let [token-identifier (wtt/token-identifier value)
|
||||||
val (or token-value (mth/finite value 0))]
|
val (or token-identifier (mth/finite value 0))
|
||||||
|
on-update-shape wtch/update-layout-padding]
|
||||||
(cond
|
(cond
|
||||||
(and (= type :simple) (= prop :p1))
|
(and (= type :simple) (= prop :p1))
|
||||||
(st/emit! (dwsl/update-layout ids {:layout-padding {:p1 val :p3 val}
|
(if token-identifier
|
||||||
:applied-tokens {:padding-p1 (if token-value (:id value) nil)
|
(st/emit! (wtch/apply-token {:shape-ids ids
|
||||||
:padding-p3 (if token-value (:id value) nil)}}))
|
:attributes #{:p1 :p3}
|
||||||
|
:token value
|
||||||
|
:on-update-shape on-update-shape}))
|
||||||
|
(st/emit! (on-update-shape value ids #{:p1 :p3})))
|
||||||
|
|
||||||
(and (= type :simple) (= prop :p2))
|
(and (= type :simple) (= prop :p2))
|
||||||
(st/emit! (dwsl/update-layout ids {:layout-padding {:p2 val :p4 val}
|
(if token-identifier
|
||||||
:applied-tokens {:padding-p2 (if token-value (:id value) nil)
|
(st/emit! (wtch/apply-token {:shape-ids ids
|
||||||
:padding-p4 (if token-value (:id value) nil)}}))
|
:attributes #{:p2 :p4}
|
||||||
|
:token value
|
||||||
|
:on-update-shape on-update-shape}))
|
||||||
|
(st/emit! (on-update-shape value ids #{:p2 :p4})))
|
||||||
|
|
||||||
(some? prop)
|
(some? prop)
|
||||||
(st/emit! (dwsl/update-layout ids {:layout-padding {prop val}}))))))
|
(st/emit! (dwsl/update-layout ids {:layout-padding {prop val}}))))))
|
||||||
|
|
|
@ -136,6 +136,9 @@
|
||||||
(zipmap (repeat value)))]
|
(zipmap (repeat value)))]
|
||||||
{:layout-gap layout-gap}))
|
{:layout-gap layout-gap}))
|
||||||
|
|
||||||
|
(defn update-layout-padding [value shape-ids attrs]
|
||||||
|
(dwsl/update-layout shape-ids {:layout-padding (zipmap attrs (repeat value))}))
|
||||||
|
|
||||||
(defn update-layout-spacing [value shape-ids attributes]
|
(defn update-layout-spacing [value shape-ids attributes]
|
||||||
(ptk/reify ::update-layout-spacing
|
(ptk/reify ::update-layout-spacing
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
|
@ -148,15 +151,6 @@
|
||||||
(rx/of
|
(rx/of
|
||||||
(dwsl/update-layout layout-shape-ids layout-attributes))))))
|
(dwsl/update-layout layout-shape-ids layout-attributes))))))
|
||||||
|
|
||||||
(defn update-layout-spacing-column [value shape-ids]
|
|
||||||
(ptk/reify ::update-layout-spacing-column
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ _ _]
|
|
||||||
(rx/concat
|
|
||||||
(for [shape-id shape-ids]
|
|
||||||
(let [layout-update {:layout-gap {:column-gap value :row-gap value}}]
|
|
||||||
(dwsl/update-layout [shape-id] layout-update)))))))
|
|
||||||
|
|
||||||
(defn update-shape-position [value shape-ids attributes]
|
(defn update-shape-position [value shape-ids attributes]
|
||||||
(ptk/reify ::update-shape-position
|
(ptk/reify ::update-shape-position
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
|
|
|
@ -81,8 +81,7 @@
|
||||||
(concat [all-action] single-actions)))
|
(concat [all-action] single-actions)))
|
||||||
|
|
||||||
(defn spacing-attribute-actions [{:keys [token selected-shapes] :as context-data}]
|
(defn spacing-attribute-actions [{:keys [token selected-shapes] :as context-data}]
|
||||||
(let [on-update-shape (fn [resolved-value shape-ids attrs]
|
(let [on-update-shape-padding wtch/update-layout-padding
|
||||||
(dwsl/update-layout shape-ids {:layout-padding (zipmap attrs (repeat resolved-value))}))
|
|
||||||
padding-attrs {:p1 "Top"
|
padding-attrs {:p1 "Top"
|
||||||
:p2 "Right"
|
:p2 "Right"
|
||||||
:p3 "Bottom"
|
:p3 "Bottom"
|
||||||
|
@ -105,7 +104,7 @@
|
||||||
:shape-ids shape-ids}]
|
:shape-ids shape-ids}]
|
||||||
(if all-selected?
|
(if all-selected?
|
||||||
(st/emit! (wtch/unapply-token props))
|
(st/emit! (wtch/unapply-token props))
|
||||||
(st/emit! (wtch/apply-token (assoc props :on-update-shape on-update-shape))))))}
|
(st/emit! (wtch/apply-token (assoc props :on-update-shape on-update-shape-padding))))))}
|
||||||
{:title "Horizontal"
|
{:title "Horizontal"
|
||||||
:selected? horizontal-padding-selected?
|
:selected? horizontal-padding-selected?
|
||||||
:action (fn []
|
:action (fn []
|
||||||
|
@ -116,7 +115,7 @@
|
||||||
horizontal-padding-selected? (wtch/apply-token (assoc props :attributes-to-remove horizontal-attributes))
|
horizontal-padding-selected? (wtch/apply-token (assoc props :attributes-to-remove horizontal-attributes))
|
||||||
:else (wtch/apply-token (assoc props
|
:else (wtch/apply-token (assoc props
|
||||||
:attributes horizontal-attributes
|
:attributes horizontal-attributes
|
||||||
:on-update-shape on-update-shape)))]
|
:on-update-shape on-update-shape-padding)))]
|
||||||
(st/emit! event)))}
|
(st/emit! event)))}
|
||||||
{:title "Vertical"
|
{:title "Vertical"
|
||||||
:selected? vertical-padding-selected?
|
:selected? vertical-padding-selected?
|
||||||
|
@ -128,7 +127,7 @@
|
||||||
vertical-padding-selected? (wtch/apply-token (assoc props :attributes-to-remove vertical-attributes))
|
vertical-padding-selected? (wtch/apply-token (assoc props :attributes-to-remove vertical-attributes))
|
||||||
:else (wtch/apply-token (assoc props
|
:else (wtch/apply-token (assoc props
|
||||||
:attributes vertical-attributes
|
:attributes vertical-attributes
|
||||||
:on-update-shape on-update-shape)))]
|
:on-update-shape on-update-shape-padding)))]
|
||||||
(st/emit! event)))}]
|
(st/emit! event)))}]
|
||||||
single-padding-items (->> padding-attrs
|
single-padding-items (->> padding-attrs
|
||||||
(map (fn [[attr title]]
|
(map (fn [[attr title]]
|
||||||
|
@ -149,7 +148,7 @@
|
||||||
all-selected? (-> (assoc props :attributes-to-remove all-padding-attrs)
|
all-selected? (-> (assoc props :attributes-to-remove all-padding-attrs)
|
||||||
(wtch/apply-token))
|
(wtch/apply-token))
|
||||||
selected? (wtch/unapply-token props)
|
selected? (wtch/unapply-token props)
|
||||||
:else (-> (assoc props :on-update-shape on-update-shape)
|
:else (-> (assoc props :on-update-shape on-update-shape-padding)
|
||||||
(wtch/apply-token)))]
|
(wtch/apply-token)))]
|
||||||
(st/emit! event))}))))
|
(st/emit! event))}))))
|
||||||
gap-items (all-or-sepearate-actions {:attribute-labels {:column-gap "Column Gap"
|
gap-items (all-or-sepearate-actions {:attribute-labels {:column-gap "Column Gap"
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: $s-8;
|
padding: $s-8;
|
||||||
border-radius: $br-8;
|
border-radius: $br-8;
|
||||||
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
|
|
@ -8,14 +8,15 @@
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
["lodash.debounce" :as debounce]
|
["lodash.debounce" :as debounce]
|
||||||
[app.main.ui.workspace.tokens.update :as wtu]
|
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.tokens :as dt]
|
[app.main.data.tokens :as dt]
|
||||||
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.workspace.tokens.common :as tokens.common]
|
[app.main.ui.workspace.tokens.common :as tokens.common]
|
||||||
[app.main.ui.workspace.tokens.style-dictionary :as sd]
|
[app.main.ui.workspace.tokens.style-dictionary :as sd]
|
||||||
[app.main.ui.workspace.tokens.token :as wtt]
|
[app.main.ui.workspace.tokens.token :as wtt]
|
||||||
|
[app.main.ui.workspace.tokens.update :as wtu]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[malli.core :as m]
|
[malli.core :as m]
|
||||||
|
@ -141,14 +142,15 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
(mf/defc form
|
(mf/defc form
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [token token-type] :as _args}]
|
[{:keys [token token-type] :as _args}]
|
||||||
(let [tokens (sd/use-resolved-workspace-tokens)
|
(let [tokens (mf/deref refs/workspace-tokens)
|
||||||
|
resolved-tokens (sd/use-resolved-tokens tokens)
|
||||||
token-path (mf/use-memo
|
token-path (mf/use-memo
|
||||||
(mf/deps (:name token))
|
(mf/deps (:name token))
|
||||||
#(wtt/token-name->path (:name token)))
|
#(wtt/token-name->path (:name token)))
|
||||||
tokens-tree (mf/use-memo
|
tokens-tree (mf/use-memo
|
||||||
(mf/deps token-path tokens)
|
(mf/deps token-path resolved-tokens)
|
||||||
(fn []
|
(fn []
|
||||||
(-> (wtt/token-names-tree tokens)
|
(-> (wtt/token-names-tree resolved-tokens)
|
||||||
;; Allow setting editing token to it's own path
|
;; Allow setting editing token to it's own path
|
||||||
(d/dissoc-in token-path))))
|
(d/dissoc-in token-path))))
|
||||||
|
|
||||||
|
@ -177,7 +179,7 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
|
|
||||||
;; Value
|
;; Value
|
||||||
value-ref (mf/use-var (:value token))
|
value-ref (mf/use-var (:value token))
|
||||||
token-resolve-result (mf/use-state (get-in tokens [(:id token) :resolved-value]))
|
token-resolve-result (mf/use-state (get-in resolved-tokens [(wtt/token-identifier token) :resolved-value]))
|
||||||
set-resolve-value (mf/use-callback
|
set-resolve-value (mf/use-callback
|
||||||
(fn [token-or-err]
|
(fn [token-or-err]
|
||||||
(let [v (cond
|
(let [v (cond
|
||||||
|
@ -219,7 +221,7 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
(not valid-description-field?))
|
(not valid-description-field?))
|
||||||
|
|
||||||
on-submit (mf/use-callback
|
on-submit (mf/use-callback
|
||||||
(mf/deps validate-name validate-descripion token tokens)
|
(mf/deps validate-name validate-descripion token resolved-tokens)
|
||||||
(fn [e]
|
(fn [e]
|
||||||
(dom/prevent-default e)
|
(dom/prevent-default e)
|
||||||
;; We have to re-validate the current form values before submitting
|
;; We have to re-validate the current form values before submitting
|
||||||
|
@ -236,7 +238,7 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
(validate-token-value+ {:input final-value
|
(validate-token-value+ {:input final-value
|
||||||
:name-value final-name
|
:name-value final-name
|
||||||
:token token
|
:token token
|
||||||
:tokens tokens})])
|
:tokens resolved-tokens})])
|
||||||
(p/finally (fn [result err]
|
(p/finally (fn [result err]
|
||||||
;; The result should be a vector of all resolved validations
|
;; The result should be a vector of all resolved validations
|
||||||
;; We do not handle the error case as it will be handled by the components validations
|
;; We do not handle the error case as it will be handled by the components validations
|
||||||
|
|
101
frontend/src/app/main/ui/workspace/tokens/sets.cljs
Normal file
101
frontend/src/app/main/ui/workspace/tokens/sets.cljs
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.main.ui.workspace.tokens.sets
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.icons :as i]
|
||||||
|
[app.util.dom :as dom]
|
||||||
|
[okulary.core :as l]
|
||||||
|
[potok.v2.core :as ptk]
|
||||||
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(def active-sets #{#uuid "2858b330-828e-4131-86ed-e4d1c0f4b3e3"
|
||||||
|
#uuid "d608877b-842a-473b-83ca-b5f8305caf83"})
|
||||||
|
|
||||||
|
(def sets-root-order [#uuid "2858b330-828e-4131-86ed-e4d1c0f4b3e3"
|
||||||
|
#uuid "9c5108aa-bdb4-409c-a3c8-c3dfce2f8bf8"
|
||||||
|
#uuid "0381446e-1f1d-423f-912c-ab577d61b79b"])
|
||||||
|
|
||||||
|
(def sets {#uuid "9c5108aa-bdb4-409c-a3c8-c3dfce2f8bf8" {:type :group
|
||||||
|
:name "Group A"
|
||||||
|
:children [#uuid "d1754e56-3510-493f-8287-5ef3417d4141"
|
||||||
|
#uuid "d608877b-842a-473b-83ca-b5f8305caf83"]}
|
||||||
|
#uuid "d608877b-842a-473b-83ca-b5f8305caf83" {:type :set
|
||||||
|
:name "Set A / 1"}
|
||||||
|
#uuid "d1754e56-3510-493f-8287-5ef3417d4141" {:type :group
|
||||||
|
:name "Group A / B"
|
||||||
|
:children [#uuid "f608877b-842a-473b-83ca-b5f8305caf83"
|
||||||
|
#uuid "7cc05389-9391-426e-bc0e-ba5cb8f425eb"]}
|
||||||
|
#uuid "f608877b-842a-473b-83ca-b5f8305caf83" {:type :set
|
||||||
|
:name "Set A / B / 1"}
|
||||||
|
#uuid "7cc05389-9391-426e-bc0e-ba5cb8f425eb" {:type :set
|
||||||
|
:name "Set A / B / 2"}
|
||||||
|
#uuid "2858b330-828e-4131-86ed-e4d1c0f4b3e3" {:type :set
|
||||||
|
:name "Set Root 1"}
|
||||||
|
#uuid "0381446e-1f1d-423f-912c-ab577d61b79b" {:type :set
|
||||||
|
:name "Set Root 2"}})
|
||||||
|
|
||||||
|
(def ^:private chevron-icon
|
||||||
|
(i/icon-xref :arrow (stl/css :chevron-icon)))
|
||||||
|
|
||||||
|
(defn set-selected-set
|
||||||
|
[set-id]
|
||||||
|
(dm/assert! (uuid? set-id))
|
||||||
|
(ptk/reify ::set-selected-set
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(assoc state :selected-set-id set-id))))
|
||||||
|
|
||||||
|
(mf/defc sets-tree
|
||||||
|
[{:keys [selected-set-id set-id]}]
|
||||||
|
(let [set (get sets set-id)]
|
||||||
|
(when set
|
||||||
|
(let [{:keys [type name children]} set
|
||||||
|
visible? (mf/use-state (contains? active-sets set-id))
|
||||||
|
collapsed? (mf/use-state false)
|
||||||
|
icon (if (= type :set) i/document i/group)
|
||||||
|
selected? (mf/use-state (= set-id selected-set-id))
|
||||||
|
|
||||||
|
on-click
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps type set-id)
|
||||||
|
(fn [event]
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(st/emit! (set-selected-set set-id))))]
|
||||||
|
[:div {:class (stl/css :set-item-container)
|
||||||
|
:on-click on-click}
|
||||||
|
[:div {:class (stl/css-case :set-item-group (= type :group)
|
||||||
|
:set-item-set (= type :set)
|
||||||
|
:selected-set (and (= type :set) @selected?))}
|
||||||
|
(when (= type :group)
|
||||||
|
[:span {:class (stl/css-case
|
||||||
|
:collapsabled-icon true
|
||||||
|
:collapsed @collapsed?)
|
||||||
|
:on-click #(when (= type :group) (swap! collapsed? not))}
|
||||||
|
chevron-icon])
|
||||||
|
[:span {:class (stl/css :icon)} icon]
|
||||||
|
[:div {:class (stl/css :set-name)} name]
|
||||||
|
(when (= type :set)
|
||||||
|
[:span {:class (stl/css :action-btn)
|
||||||
|
:on-click #(swap! visible? not)}
|
||||||
|
(if @visible?
|
||||||
|
i/shown
|
||||||
|
i/hide)])]
|
||||||
|
(when (and children (not @collapsed?))
|
||||||
|
[:div {:class (stl/css :set-children)}
|
||||||
|
(for [child-id children]
|
||||||
|
[:& sets-tree {:key child-id :set-id child-id :selected-set-id selected-set-id}])])]))))
|
||||||
|
|
||||||
|
(mf/defc sets-list
|
||||||
|
[{:keys [selected-set-id]}]
|
||||||
|
[:ul {:class (stl/css :sets-list)}
|
||||||
|
(for [set-id sets-root-order]
|
||||||
|
[:& sets-tree {:key set-id
|
||||||
|
:set-id set-id
|
||||||
|
:selected-set-id selected-set-id}])])
|
101
frontend/src/app/main/ui/workspace/tokens/sets.scss
Normal file
101
frontend/src/app/main/ui/workspace/tokens/sets.scss
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
@import "refactor/common-refactor.scss";
|
||||||
|
|
||||||
|
.sets-list {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: $s-12;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.set-item-container {
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--layer-row-foreground-color);
|
||||||
|
padding-left: $s-20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.set-item-set,
|
||||||
|
.set-item-group {
|
||||||
|
@include bodySmallTypography;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-height: $s-32;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--layer-row-foreground-color);
|
||||||
|
.set-name {
|
||||||
|
@include textEllipsis;
|
||||||
|
flex-grow: 1;
|
||||||
|
padding-left: $s-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: $s-20;
|
||||||
|
height: $s-20;
|
||||||
|
padding-right: $s-4;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
height: $s-20;
|
||||||
|
width: $s-20;
|
||||||
|
color: white;
|
||||||
|
fill: none;
|
||||||
|
stroke: var(--icon-foreground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.set-item-set {
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--layer-row-background-color-hover);
|
||||||
|
color: var(--layer-row-foreground-color-hover);
|
||||||
|
box-shadow: -100px 0 0 0 var(--layer-row-background-color-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-set {
|
||||||
|
background-color: var(--layer-row-background-color-selected);
|
||||||
|
color: var(--layer-row-foreground-color-selected);
|
||||||
|
box-shadow: -100px 0 0 0 var(--layer-row-background-color-selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
@extend .button-tertiary;
|
||||||
|
height: $s-28;
|
||||||
|
width: $s-28;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsabled-icon {
|
||||||
|
@include buttonStyle;
|
||||||
|
@include flexCenter;
|
||||||
|
height: $s-24;
|
||||||
|
border-radius: $br-8;
|
||||||
|
|
||||||
|
--chevron-icon-rotation: 90deg;
|
||||||
|
|
||||||
|
&.collapsed {
|
||||||
|
--chevron-icon-rotation: 0deg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
--chevron-icon-color: var(--title-foreground-color-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chevron-icon {
|
||||||
|
@extend .button-icon-small;
|
||||||
|
margin-right: $s-6;
|
||||||
|
transform: rotate(var(--chevron-icon-rotation));
|
||||||
|
stroke: var(--icon-foreground);
|
||||||
|
}
|
|
@ -13,12 +13,14 @@
|
||||||
[app.main.data.tokens :as wdt]
|
[app.main.data.tokens :as wdt]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.components.title-bar :refer [title-bar]]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.workspace.sidebar.assets.common :as cmm]
|
[app.main.ui.workspace.sidebar.assets.common :as cmm]
|
||||||
[app.main.ui.workspace.tokens.changes :as wtch]
|
[app.main.ui.workspace.tokens.changes :as wtch]
|
||||||
[app.main.ui.workspace.tokens.common :refer [labeled-input]]
|
[app.main.ui.workspace.tokens.common :refer [labeled-input]]
|
||||||
[app.main.ui.workspace.tokens.context-menu :refer [token-context-menu]]
|
[app.main.ui.workspace.tokens.context-menu :refer [token-context-menu]]
|
||||||
[app.main.ui.workspace.tokens.core :as wtc]
|
[app.main.ui.workspace.tokens.core :as wtc]
|
||||||
|
[app.main.ui.workspace.tokens.sets :refer [sets-list]]
|
||||||
[app.main.ui.workspace.tokens.style-dictionary :as sd]
|
[app.main.ui.workspace.tokens.style-dictionary :as sd]
|
||||||
[app.main.ui.workspace.tokens.token :as wtt]
|
[app.main.ui.workspace.tokens.token :as wtt]
|
||||||
[app.main.ui.workspace.tokens.token-types :as wtty]
|
[app.main.ui.workspace.tokens.token-types :as wtty]
|
||||||
|
@ -34,6 +36,9 @@
|
||||||
(def ^:private download-icon
|
(def ^:private download-icon
|
||||||
(i/icon-xref :download (stl/css :download-icon)))
|
(i/icon-xref :download (stl/css :download-icon)))
|
||||||
|
|
||||||
|
(def selected-set-id
|
||||||
|
(l/derived :selected-set-id st/state))
|
||||||
|
|
||||||
(mf/defc token-pill
|
(mf/defc token-pill
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [on-click token highlighted? on-context-menu]}]
|
[{:keys [on-click token highlighted? on-context-menu]}]
|
||||||
|
@ -260,13 +265,35 @@
|
||||||
:tokens tokens
|
:tokens tokens
|
||||||
:token-type-props token-type-props}])]]))
|
:token-type-props token-type-props}])]]))
|
||||||
|
|
||||||
|
(mf/defc sets-sidebar
|
||||||
|
[]
|
||||||
|
(let [selected-set-id (mf/deref selected-set-id)
|
||||||
|
open? (mf/use-state true)]
|
||||||
|
[:div {:class (stl/css :sets-sidebar)}
|
||||||
|
[:div {:class (stl/css :sidebar-header)}
|
||||||
|
[:& title-bar {:collapsable true
|
||||||
|
:collapsed (not @open?)
|
||||||
|
:all-clickable true
|
||||||
|
:title "SETS"
|
||||||
|
:on-collapsed #(swap! open? not)}]
|
||||||
|
[:button {:class (stl/css :add-set)
|
||||||
|
:on-click #(println "Add Set")}
|
||||||
|
i/add]]
|
||||||
|
(when @open?
|
||||||
|
[:& sets-list {:selected-set-id selected-set-id}])]))
|
||||||
|
|
||||||
(mf/defc tokens-sidebar-tab
|
(mf/defc tokens-sidebar-tab
|
||||||
{::mf/wrap [mf/memo]
|
{::mf/wrap [mf/memo]
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[_props]
|
[_props]
|
||||||
[:div {:class (stl/css :sidebar-tab-wrapper)}
|
(let [show-sets-section? false] ;; temporarily added this variable to see/hide the sets section till we have it working end to end
|
||||||
[:& tokens-explorer]
|
[:div {:class (stl/css :sidebar-tab-wrapper)}
|
||||||
[:button {:class (stl/css :download-json-button)
|
(when show-sets-section?
|
||||||
:on-click wtc/download-tokens-as-json}
|
[:div {:class (stl/css :sets-section-wrapper)}
|
||||||
download-icon
|
[:& sets-sidebar]])
|
||||||
"Export JSON"]])
|
[:div {:class (stl/css :tokens-section-wrapper)}
|
||||||
|
[:& tokens-explorer]]
|
||||||
|
[:button {:class (stl/css :download-json-button)
|
||||||
|
:on-click wtc/download-tokens-as-json}
|
||||||
|
download-icon
|
||||||
|
"Export JSON"]]))
|
||||||
|
|
|
@ -5,11 +5,57 @@
|
||||||
// Copyright (c) KALEIDOS INC
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
@import "refactor/common-refactor.scss";
|
@import "refactor/common-refactor.scss";
|
||||||
|
|
||||||
@import "./common.scss";
|
@import "./common.scss";
|
||||||
|
|
||||||
.sidebar-tab-wrapper {
|
.sidebar-tab-wrapper {
|
||||||
padding: $s-12;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sets-section-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: $s-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sets-sidebar {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-left: $s-8;
|
||||||
|
padding-top: $s-12;
|
||||||
|
color: var(--layer-row-foreground-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-set {
|
||||||
|
@extend .button-tertiary;
|
||||||
|
height: $s-32;
|
||||||
|
width: $s-28;
|
||||||
|
padding: 0;
|
||||||
|
margin-right: $s-12;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon;
|
||||||
|
stroke: var(--icon-foreground);
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tokens-section-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
padding-top: $s-12;
|
||||||
|
padding-left: $s-12;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Remove once sets are available to public
|
||||||
|
.sets-section-wrapper + .tokens-section-wrapper {
|
||||||
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.token-pills-wrapper {
|
.token-pills-wrapper {
|
||||||
|
|
|
@ -10,9 +10,8 @@
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(def StyleDictionary
|
(def StyleDictionary
|
||||||
"The global StyleDictionary instance used as an external library for now,
|
"Initiates the global StyleDictionary instance with transforms
|
||||||
as the package would need webpack to be bundled,
|
from tokens-studio used to parse and resolved token values."
|
||||||
because shadow-cljs doesn't support some of the more modern bundler features."
|
|
||||||
(do
|
(do
|
||||||
(sd-transforms/registerTransforms sd)
|
(sd-transforms/registerTransforms sd)
|
||||||
(.registerFormat sd #js {:name "custom/json"
|
(.registerFormat sd #js {:name "custom/json"
|
||||||
|
|
37
frontend/test/token_tests/style_dictionary_test.cljs
Normal file
37
frontend/test/token_tests/style_dictionary_test.cljs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
(ns token-tests.style-dictionary-test
|
||||||
|
(:require
|
||||||
|
[app.main.ui.workspace.tokens.style-dictionary :as sd]
|
||||||
|
[cljs.test :as t :include-macros true]
|
||||||
|
[promesa.core :as p]))
|
||||||
|
|
||||||
|
(def border-radius-token
|
||||||
|
{:id #uuid "8c868278-7c8d-431b-bbc9-7d8f15c8edb9"
|
||||||
|
:value "12px"
|
||||||
|
:name "borderRadius.sm"
|
||||||
|
:type :border-radius})
|
||||||
|
|
||||||
|
(def reference-border-radius-token
|
||||||
|
{:id #uuid "b9448d78-fd5b-4e3d-aa32-445904063f5b"
|
||||||
|
:value "{borderRadius.sm} * 2"
|
||||||
|
:name "borderRadius.md-with-dashes"
|
||||||
|
:type :border-radius})
|
||||||
|
|
||||||
|
(def tokens {(:id border-radius-token) border-radius-token
|
||||||
|
(:id reference-border-radius-token) reference-border-radius-token})
|
||||||
|
|
||||||
|
(t/deftest resolve-tokens-test
|
||||||
|
(t/async
|
||||||
|
done
|
||||||
|
(t/testing "resolves tokens using style-dictionary"
|
||||||
|
(-> (sd/resolve-tokens+ tokens)
|
||||||
|
(p/finally (fn [resolved-tokens]
|
||||||
|
(let [expected-tokens {"borderRadius.sm"
|
||||||
|
(assoc border-radius-token
|
||||||
|
:resolved-value 12
|
||||||
|
:resolved-unit "px")
|
||||||
|
"borderRadius.md-with-dashes"
|
||||||
|
(assoc reference-border-radius-token
|
||||||
|
:resolved-value 24
|
||||||
|
:resolved-unit "px")}]
|
||||||
|
(t/is (= expected-tokens resolved-tokens))
|
||||||
|
(done))))))))
|
Loading…
Add table
Add a link
Reference in a new issue