mirror of
https://github.com/penpot/penpot.git
synced 2025-06-16 05:31:39 +02:00
Merge pull request #111 from tokens-studio/71-apply-token-from-the-shapes-panel-right-side
Apply border radius token from the shapes panel
This commit is contained in:
commit
23ee54b4b7
6 changed files with 98 additions and 26 deletions
|
@ -57,15 +57,34 @@
|
||||||
(->> (map (fn [attr] [attr token-id]) attributes)
|
(->> (map (fn [attr] [attr token-id]) attributes)
|
||||||
(into {})))
|
(into {})))
|
||||||
|
|
||||||
|
(defn apply-token-id-to-attributes [{:keys [shape token-id attributes]}]
|
||||||
|
(let [token (token-from-attributes token-id attributes)]
|
||||||
|
(toggle-or-apply-token shape token)))
|
||||||
|
|
||||||
|
(defn apply-token-to-shape
|
||||||
|
[{:keys [shape token attributes] :as _props}]
|
||||||
|
(let [applied-tokens (apply-token-id-to-attributes {:shape shape
|
||||||
|
:token-id (:id token)
|
||||||
|
:attributes attributes})]
|
||||||
|
(update shape :applied-tokens #(merge % applied-tokens))))
|
||||||
|
|
||||||
|
(defn maybe-apply-token-to-shape
|
||||||
|
"When the passed `:token` is non-nil apply it to the `:applied-tokens` on a shape."
|
||||||
|
[{:keys [shape token _attributes] :as props}]
|
||||||
|
(if token
|
||||||
|
(apply-token-to-shape props)
|
||||||
|
shape))
|
||||||
|
|
||||||
(defn update-token-from-attributes
|
(defn update-token-from-attributes
|
||||||
[{:keys [token-id shape-id attributes]}]
|
[{:keys [token-id shape-id attributes]}]
|
||||||
(ptk/reify ::update-token-from-attributes
|
(ptk/reify ::update-token-from-attributes
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [shape (get-shape-from-state shape-id state)
|
(let [shape (get-shape-from-state shape-id state)
|
||||||
token (token-from-attributes token-id attributes)
|
applied-tokens (apply-token-id-to-attributes {:shape shape
|
||||||
next-applied-tokens (toggle-or-apply-token shape token)]
|
:token-id token-id
|
||||||
(rx/of (update-shape shape-id {:applied-tokens next-applied-tokens}))))))
|
:attributes attributes})]
|
||||||
|
(rx/of (update-shape shape-id {:applied-tokens applied-tokens}))))))
|
||||||
|
|
||||||
(defn get-token-data-from-token-id
|
(defn get-token-data-from-token-id
|
||||||
[id]
|
[id]
|
||||||
|
|
|
@ -230,6 +230,12 @@
|
||||||
(def workspace-data
|
(def workspace-data
|
||||||
(l/derived :workspace-data st/state))
|
(l/derived :workspace-data st/state))
|
||||||
|
|
||||||
|
(def workspace-tokens
|
||||||
|
(l/derived (fn [data]
|
||||||
|
(get data :tokens []))
|
||||||
|
workspace-data
|
||||||
|
=))
|
||||||
|
|
||||||
(def workspace-file-colors
|
(def workspace-file-colors
|
||||||
(l/derived (fn [data]
|
(l/derived (fn [data]
|
||||||
(when data
|
(when data
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.common.types.shape.radius :as ctsr]
|
[app.common.types.shape.radius :as ctsr]
|
||||||
[app.main.constants :refer [size-presets]]
|
[app.main.constants :refer [size-presets]]
|
||||||
|
[app.main.data.tokens :as dt]
|
||||||
[app.main.data.workspace :as udw]
|
[app.main.data.workspace :as udw]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.workspace.changes :as dch]
|
||||||
[app.main.data.workspace.interactions :as dwi]
|
[app.main.data.workspace.interactions :as dwi]
|
||||||
|
@ -19,10 +20,12 @@
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||||
|
[app.main.ui.components.editable-select :refer [editable-select]]
|
||||||
[app.main.ui.components.numeric-input :refer [numeric-input*]]
|
[app.main.ui.components.numeric-input :refer [numeric-input*]]
|
||||||
[app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]]
|
[app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]]
|
||||||
[app.main.ui.hooks :as hooks]
|
[app.main.ui.hooks :as hooks]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
|
[app.main.ui.workspace.tokens.core :as wtc]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[clojure.set :refer [rename-keys union]]
|
[clojure.set :refer [rename-keys union]]
|
||||||
|
@ -95,6 +98,10 @@
|
||||||
selection-parents-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))
|
selection-parents-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))
|
||||||
selection-parents (mf/deref selection-parents-ref)
|
selection-parents (mf/deref selection-parents-ref)
|
||||||
|
|
||||||
|
tokens (mf/deref refs/workspace-tokens)
|
||||||
|
border-radius-tokens (mf/use-memo (mf/deps tokens) #(wtc/tokens-name-map-for-type :border-radius tokens))
|
||||||
|
border-radius-options (mf/use-memo (mf/deps border-radius-tokens) #(map (comp :name val) border-radius-tokens))
|
||||||
|
|
||||||
flex-child? (->> selection-parents (some ctl/flex-layout?))
|
flex-child? (->> selection-parents (some ctl/flex-layout?))
|
||||||
absolute? (ctl/item-absolute? shape)
|
absolute? (ctl/item-absolute? shape)
|
||||||
flex-container? (ctl/flex-layout? shape)
|
flex-container? (ctl/flex-layout? shape)
|
||||||
|
@ -255,7 +262,7 @@
|
||||||
(update-fn shape)
|
(update-fn shape)
|
||||||
shape))
|
shape))
|
||||||
{:reg-objects? true
|
{:reg-objects? true
|
||||||
:attrs [:rx :ry :r1 :r2 :r3 :r4]})))
|
:attrs [:rx :ry :r1 :r2 :r3 :r4 :applied-tokens]})))
|
||||||
|
|
||||||
on-switch-to-radius-1
|
on-switch-to-radius-1
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -282,9 +289,17 @@
|
||||||
|
|
||||||
on-radius-1-change
|
on-radius-1-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids change-radius)
|
(mf/deps ids change-radius border-radius-tokens)
|
||||||
(fn [value]
|
(fn [value]
|
||||||
(st/emit! (change-radius #(ctsr/set-radius-1 % value)))))
|
(let [token (when (symbol? value)
|
||||||
|
(get border-radius-tokens (str value)))
|
||||||
|
token-value (some-> token wtc/resolve-token-value)]
|
||||||
|
(st/emit!
|
||||||
|
(change-radius (fn [shape]
|
||||||
|
(-> (dt/maybe-apply-token-to-shape {:token token
|
||||||
|
:shape shape
|
||||||
|
:attributes (wtc/token-attributes :border-radius)})
|
||||||
|
(ctsr/set-radius-1 (or token-value value)))))))))
|
||||||
|
|
||||||
on-radius-multi-change
|
on-radius-multi-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -468,12 +483,14 @@
|
||||||
[:div {:class (stl/css :radius-1)
|
[:div {:class (stl/css :radius-1)
|
||||||
:title (tr "workspace.options.radius")}
|
:title (tr "workspace.options.radius")}
|
||||||
[:span {:class (stl/css :icon)} i/corner-radius]
|
[:span {:class (stl/css :icon)} i/corner-radius]
|
||||||
[:> numeric-input*
|
[:& editable-select
|
||||||
{:placeholder (if (= :multiple (:rx values)) (tr "settings.multiple") "--")
|
{:placeholder (if (= :multiple (:rx values)) (tr "settings.multiple") "--")
|
||||||
:ref radius-input-ref
|
:class (stl/css :token-select)
|
||||||
|
:type "number"
|
||||||
:min 0
|
:min 0
|
||||||
|
:input-class (stl/css :numeric-input)
|
||||||
:on-change on-radius-1-change
|
:on-change on-radius-1-change
|
||||||
:className (stl/css :numeric-input)
|
:options border-radius-options
|
||||||
:value (:rx values)}]]
|
:value (:rx values)}]]
|
||||||
|
|
||||||
@radius-multi?
|
@radius-multi?
|
||||||
|
|
|
@ -236,3 +236,10 @@
|
||||||
.checkbox-button {
|
.checkbox-button {
|
||||||
@extend .button-icon;
|
@extend .button-icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.token-select {
|
||||||
|
li > span {
|
||||||
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -37,6 +37,29 @@
|
||||||
int-or-double
|
int-or-double
|
||||||
(throw (ex-info (str "Implement token value resolve for " value) token))))
|
(throw (ex-info (str "Implement token value resolve for " value) token))))
|
||||||
|
|
||||||
|
(defn group-tokens-by-type
|
||||||
|
"Groups tokens by their `:type` property."
|
||||||
|
[tokens]
|
||||||
|
(->> (vals tokens)
|
||||||
|
(group-by :type)))
|
||||||
|
|
||||||
|
(defn tokens-name-map
|
||||||
|
"Convert tokens into a map with their `:name` as the key.
|
||||||
|
|
||||||
|
E.g.: {\"sm\" {:token-type :border-radius :id #uuid \"000\" ...}}"
|
||||||
|
[tokens]
|
||||||
|
(->> (map (fn [{:keys [name] :as token}] [name token]) tokens)
|
||||||
|
(into {})))
|
||||||
|
|
||||||
|
(defn tokens-name-map-for-type
|
||||||
|
"Convert tokens with `token-type` into a map with their `:name` as the key.
|
||||||
|
|
||||||
|
E.g.: {\"sm\" {:token-type :border-radius :id #uuid \"000\" ...}}"
|
||||||
|
[token-type tokens]
|
||||||
|
(-> (group-tokens-by-type tokens)
|
||||||
|
(get token-type [])
|
||||||
|
(tokens-name-map)))
|
||||||
|
|
||||||
;; Update functions ------------------------------------------------------------
|
;; Update functions ------------------------------------------------------------
|
||||||
|
|
||||||
(defn on-apply-token [{:keys [token token-type-props selected-shapes] :as _props}]
|
(defn on-apply-token [{:keys [token token-type-props selected-shapes] :as _props}]
|
||||||
|
@ -171,3 +194,6 @@
|
||||||
{:label "Paragraph Indent" :key :paragraph-indent}
|
{:label "Paragraph Indent" :key :paragraph-indent}
|
||||||
{:label "Text Decoration" :key :text-decoration}
|
{:label "Text Decoration" :key :text-decoration}
|
||||||
{:label "Text Case" :key :text-case}]}}]))
|
{:label "Text Case" :key :text-case}]}}]))
|
||||||
|
|
||||||
|
(defn token-attributes [token-type]
|
||||||
|
(get-in token-types [token-type :attributes]))
|
||||||
|
|
|
@ -7,14 +7,14 @@
|
||||||
(ns app.main.ui.workspace.tokens.sidebar
|
(ns app.main.ui.workspace.tokens.sidebar
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
|
[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.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[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.common :refer [workspace-shapes]]
|
[app.main.ui.workspace.tokens.core :as wtc]
|
||||||
[app.main.ui.workspace.tokens.core :refer [tokens-applied?] :as wtc]
|
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
i/add))
|
i/add))
|
||||||
|
|
||||||
(mf/defc token-component
|
(mf/defc token-component
|
||||||
[{:keys [type file tokens selected-shapes token-type-props]}]
|
[{:keys [type tokens selected-shapes token-type-props]}]
|
||||||
(let [open? (mf/use-state false)
|
(let [open? (mf/use-state false)
|
||||||
{:keys [modal attributes title]} token-type-props
|
{:keys [modal attributes title]} token-type-props
|
||||||
|
|
||||||
|
@ -87,8 +87,7 @@
|
||||||
:selected-shapes selected-shapes})))
|
:selected-shapes selected-shapes})))
|
||||||
tokens-count (count tokens)]
|
tokens-count (count tokens)]
|
||||||
[:div {:on-click on-toggle-open-click}
|
[:div {:on-click on-toggle-open-click}
|
||||||
[:& cmm/asset-section {:file-id (:id file)
|
[:& cmm/asset-section {:icon (mf/fnc icon-wrapper [_]
|
||||||
:icon (mf/fnc icon-wrapper [_]
|
|
||||||
[:div {:class (stl/css :section-icon)}
|
[:div {:class (stl/css :section-icon)}
|
||||||
[:& token-section-icon {:type type}]])
|
[:& token-section-icon {:type type}]])
|
||||||
|
|
||||||
|
@ -106,7 +105,7 @@
|
||||||
[:& token-pill
|
[:& token-pill
|
||||||
{:key (:id token)
|
{:key (:id token)
|
||||||
:token token
|
:token token
|
||||||
:highlighted? (tokens-applied? token selected-shapes attributes)
|
:highlighted? (wtc/tokens-applied? token selected-shapes attributes)
|
||||||
:on-click #(on-token-pill-click % token)
|
:on-click #(on-token-pill-click % token)
|
||||||
:on-context-menu #(on-context-menu % token)}])]])]]))
|
:on-context-menu #(on-context-menu % token)}])]])]]))
|
||||||
|
|
||||||
|
@ -114,13 +113,12 @@
|
||||||
"Separate token-types into groups of `:empty` or `:filled` depending if tokens exist for that type.
|
"Separate token-types into groups of `:empty` or `:filled` depending if tokens exist for that type.
|
||||||
Sort each group alphabetically (by their `:token-key`)."
|
Sort each group alphabetically (by their `:token-key`)."
|
||||||
[tokens]
|
[tokens]
|
||||||
(let [tokens-by-group (->> (vals tokens)
|
(let [tokens-by-type (wtc/group-tokens-by-type tokens)
|
||||||
(group-by :type))
|
|
||||||
{:keys [empty filled]} (->> wtc/token-types
|
{:keys [empty filled]} (->> wtc/token-types
|
||||||
(map (fn [[token-key token-type-props]]
|
(map (fn [[token-key token-type-props]]
|
||||||
{:token-key token-key
|
{:token-key token-key
|
||||||
:token-type-props token-type-props
|
:token-type-props token-type-props
|
||||||
:tokens (get tokens-by-group token-key [])}))
|
:tokens (get tokens-by-type token-key [])}))
|
||||||
(group-by (fn [{:keys [tokens]}]
|
(group-by (fn [{:keys [tokens]}]
|
||||||
(if (empty? tokens) :empty :filled))))]
|
(if (empty? tokens) :empty :filled))))]
|
||||||
{:empty (sort-by :token-key empty)
|
{:empty (sort-by :token-key empty)
|
||||||
|
@ -128,21 +126,20 @@
|
||||||
|
|
||||||
(mf/defc tokens-explorer
|
(mf/defc tokens-explorer
|
||||||
[_props]
|
[_props]
|
||||||
(let [file (mf/deref refs/workspace-file)
|
(let [objects (mf/deref refs/workspace-page-objects)
|
||||||
current-page-id (:current-page-id @st/state)
|
|
||||||
workspace-data (mf/deref refs/workspace-data)
|
selected (mf/deref refs/selected-shapes)
|
||||||
tokens (get workspace-data :tokens)
|
selected-shapes (into [] (keep (d/getf objects)) selected)
|
||||||
|
|
||||||
|
tokens (mf/deref refs/workspace-tokens)
|
||||||
token-groups (mf/with-memo [tokens]
|
token-groups (mf/with-memo [tokens]
|
||||||
(sorted-token-groups tokens))
|
(sorted-token-groups tokens))]
|
||||||
selected-shape-ids (mf/deref refs/selected-shapes)
|
|
||||||
selected-shapes (workspace-shapes workspace-data current-page-id selected-shape-ids)]
|
|
||||||
[:article
|
[:article
|
||||||
[:div.assets-bar
|
[:div.assets-bar
|
||||||
(for [{:keys [token-key token-type-props tokens]} (concat (:filled token-groups)
|
(for [{:keys [token-key token-type-props tokens]} (concat (:filled token-groups)
|
||||||
(:empty token-groups))]
|
(:empty token-groups))]
|
||||||
[:& token-component {:key token-key
|
[:& token-component {:key token-key
|
||||||
:type token-key
|
:type token-key
|
||||||
:file file
|
|
||||||
:selected-shapes selected-shapes
|
:selected-shapes selected-shapes
|
||||||
:tokens tokens
|
:tokens tokens
|
||||||
:token-type-props token-type-props}])]]))
|
:token-type-props token-type-props}])]]))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue