mirror of
https://github.com/penpot/penpot.git
synced 2025-06-07 19:21:39 +02:00
Merge pull request #379 from tokens-studio/florian/computed-set-checkmark
Display computed checkmark next to token set groups
This commit is contained in:
commit
15ba0746c6
5 changed files with 173 additions and 48 deletions
|
@ -625,6 +625,11 @@ When `before-set-name` is nil, move set to bottom")
|
||||||
(delete-token-from-set [_ set-name token-name] "delete a token from a set")
|
(delete-token-from-set [_ set-name token-name] "delete a token from a set")
|
||||||
(toggle-set-in-theme [_ group-name theme-name set-name] "toggle a set used / not used in a theme")
|
(toggle-set-in-theme [_ group-name theme-name set-name] "toggle a set used / not used in a theme")
|
||||||
(get-active-themes-set-names [_] "set of set names that are active in the the active themes")
|
(get-active-themes-set-names [_] "set of set names that are active in the the active themes")
|
||||||
|
(sets-at-path-all-active? [_ prefixed-path] "compute active state for child sets at `prefixed-path`.
|
||||||
|
Will return a value that matches this schema:
|
||||||
|
`:none` None of the nested sets are active
|
||||||
|
`:all` All of the nested sets are active
|
||||||
|
`:partial` Mixed active state of nested sets")
|
||||||
(get-active-themes-set-tokens [_] "set of set names that are active in the the active themes")
|
(get-active-themes-set-tokens [_] "set of set names that are active in the the active themes")
|
||||||
(encode-dtcg [_] "Encodes library to a dtcg compatible json string")
|
(encode-dtcg [_] "Encodes library to a dtcg compatible json string")
|
||||||
(decode-dtcg-json [_ parsed-json] "Decodes parsed json containing tokens and converts to library")
|
(decode-dtcg-json [_ parsed-json] "Decodes parsed json containing tokens and converts to library")
|
||||||
|
@ -870,6 +875,19 @@ When `before-set-name` is nil, move set to bottom")
|
||||||
(mapcat :sets)
|
(mapcat :sets)
|
||||||
(get-active-themes this)))
|
(get-active-themes this)))
|
||||||
|
|
||||||
|
(sets-at-path-all-active? [this prefixed-path]
|
||||||
|
(let [active-set-names (get-active-themes-set-names this)]
|
||||||
|
(if (seq active-set-names)
|
||||||
|
(let [path-active-set-names (->> (get-sets-at-prefix-path this prefixed-path)
|
||||||
|
(map :name)
|
||||||
|
(into #{}))
|
||||||
|
difference (set/difference path-active-set-names active-set-names)]
|
||||||
|
(cond
|
||||||
|
(empty? difference) :all
|
||||||
|
(seq (set/intersection path-active-set-names active-set-names)) :partial
|
||||||
|
:else :none))
|
||||||
|
:none)))
|
||||||
|
|
||||||
(get-active-themes-set-tokens [this]
|
(get-active-themes-set-tokens [this]
|
||||||
(let [sets-order (get-ordered-set-names this)
|
(let [sets-order (get-ordered-set-names this)
|
||||||
active-themes (get-active-themes this)
|
active-themes (get-active-themes this)
|
||||||
|
|
|
@ -399,8 +399,39 @@
|
||||||
expected-tokens (ctob/get-active-themes-set-tokens tokens-lib)
|
expected-tokens (ctob/get-active-themes-set-tokens tokens-lib)
|
||||||
expected-token-names (mapv key expected-tokens)]
|
expected-token-names (mapv key expected-tokens)]
|
||||||
(t/is (= '("set-a" "set-b" "inactive-set") expected-order))
|
(t/is (= '("set-a" "set-b" "inactive-set") expected-order))
|
||||||
(t/is (= ["set-a-token" "set-b-token"] expected-token-names)))))
|
(t/is (= ["set-a-token" "set-b-token"] expected-token-names))))
|
||||||
|
|
||||||
|
(t/testing "sets-at-path-active-state"
|
||||||
|
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||||
|
|
||||||
|
(ctob/add-set (ctob/make-token-set :name "foo/bar/baz"))
|
||||||
|
(ctob/add-set (ctob/make-token-set :name "foo/bar/bam"))
|
||||||
|
|
||||||
|
(ctob/add-theme (ctob/make-token-theme :name "none"))
|
||||||
|
(ctob/add-theme (ctob/make-token-theme :name "partial"
|
||||||
|
:sets #{"foo/bar/baz"}))
|
||||||
|
(ctob/add-theme (ctob/make-token-theme :name "all"
|
||||||
|
:sets #{"foo/bar/baz"
|
||||||
|
"foo/bar/bam"}))
|
||||||
|
(ctob/add-theme (ctob/make-token-theme :name "invalid"
|
||||||
|
:sets #{"foo/missing"})))
|
||||||
|
|
||||||
|
expected-none (-> tokens-lib
|
||||||
|
(ctob/set-active-themes #{"/none"})
|
||||||
|
(ctob/sets-at-path-all-active? "G-foo"))
|
||||||
|
expected-all (-> tokens-lib
|
||||||
|
(ctob/set-active-themes #{"/all"})
|
||||||
|
(ctob/sets-at-path-all-active? "G-foo"))
|
||||||
|
expected-partial (-> tokens-lib
|
||||||
|
(ctob/set-active-themes #{"/partial"})
|
||||||
|
(ctob/sets-at-path-all-active? "G-foo"))
|
||||||
|
expected-invalid-none (-> tokens-lib
|
||||||
|
(ctob/set-active-themes #{"/invalid"})
|
||||||
|
(ctob/sets-at-path-all-active? "G-foo"))]
|
||||||
|
(t/is (= :none expected-none))
|
||||||
|
(t/is (= :all expected-all))
|
||||||
|
(t/is (= :partial expected-partial))
|
||||||
|
(t/is (= :none expected-invalid-none)))))
|
||||||
|
|
||||||
(t/deftest token-theme-in-a-lib
|
(t/deftest token-theme-in-a-lib
|
||||||
(t/testing "add-token-theme"
|
(t/testing "add-token-theme"
|
||||||
|
|
|
@ -502,6 +502,14 @@
|
||||||
(def workspace-active-theme-paths
|
(def workspace-active-theme-paths
|
||||||
(l/derived (d/nilf ctob/get-active-theme-paths) tokens-lib))
|
(l/derived (d/nilf ctob/get-active-theme-paths) tokens-lib))
|
||||||
|
|
||||||
|
(defn token-sets-at-path-all-active?
|
||||||
|
[prefixed-path]
|
||||||
|
(l/derived
|
||||||
|
(fn [lib]
|
||||||
|
(when lib
|
||||||
|
(ctob/sets-at-path-all-active? lib prefixed-path)))
|
||||||
|
tokens-lib))
|
||||||
|
|
||||||
(def workspace-active-theme-paths-no-hidden
|
(def workspace-active-theme-paths-no-hidden
|
||||||
(l/derived #(disj % ctob/hidden-token-theme-path) workspace-active-theme-paths))
|
(l/derived #(disj % ctob/hidden-token-theme-path) workspace-active-theme-paths))
|
||||||
|
|
||||||
|
|
|
@ -254,41 +254,41 @@
|
||||||
[{:keys [state set-state]}]
|
[{:keys [state set-state]}]
|
||||||
(let [{:keys [theme-path]} @state
|
(let [{:keys [theme-path]} @state
|
||||||
[_ theme-group theme-name] theme-path
|
[_ theme-group theme-name] theme-path
|
||||||
|
ordered-token-sets (mf/deref refs/workspace-ordered-token-sets)
|
||||||
token-sets (mf/deref refs/workspace-token-sets-tree)
|
token-sets (mf/deref refs/workspace-token-sets-tree)
|
||||||
theme (mf/deref (refs/workspace-token-theme theme-group theme-name))
|
theme (mf/deref (refs/workspace-token-theme theme-group theme-name))
|
||||||
|
theme-state (mf/use-state theme)
|
||||||
|
lib (-> (ctob/make-tokens-lib)
|
||||||
|
(ctob/add-theme @theme-state)
|
||||||
|
(ctob/add-sets ordered-token-sets)
|
||||||
|
(ctob/activate-theme (:group @theme-state) (:name @theme-state)))
|
||||||
|
|
||||||
|
;; Form / Modal handlers
|
||||||
on-back #(set-state (constantly {:type :themes-overview}))
|
on-back #(set-state (constantly {:type :themes-overview}))
|
||||||
on-submit #(st/emit! (wdt/update-token-theme [(:group theme) (:name theme)] %))
|
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)
|
{: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)
|
disabled? (-> (:name @theme-state)
|
||||||
(str/trim)
|
(str/trim)
|
||||||
(str/empty?))
|
(str/empty?))
|
||||||
token-set-active? (mf/use-callback
|
|
||||||
(mf/deps theme-state)
|
on-change-field
|
||||||
(fn [set-name]
|
(mf/use-fn
|
||||||
(get-in @theme-state [:sets set-name])))
|
(fn [field value]
|
||||||
on-toggle-token-set (mf/use-callback
|
(swap! theme-state #(assoc % field value))))
|
||||||
(mf/deps theme-state)
|
|
||||||
(fn [set-name]
|
on-save-form
|
||||||
(swap! theme-state #(ctob/toggle-set % set-name))))
|
(mf/use-callback
|
||||||
on-click-token-set (mf/use-callback
|
(mf/deps theme-state on-submit)
|
||||||
(mf/deps on-toggle-token-set)
|
(fn [e]
|
||||||
(fn [prefixed-set-path-str]
|
(dom/prevent-default e)
|
||||||
(let [set-name (ctob/prefixed-set-path-string->set-name-string prefixed-set-path-str)]
|
(let [theme (-> @theme-state
|
||||||
(on-toggle-token-set set-name))))
|
(update :name str/trim)
|
||||||
on-change-field (fn [field value]
|
(update :group str/trim)
|
||||||
(swap! theme-state #(assoc % field value)))
|
(update :description str/trim))]
|
||||||
on-save-form (mf/use-callback
|
(when-not (str/empty? (:name theme))
|
||||||
(mf/deps theme-state on-submit)
|
(on-submit theme)))
|
||||||
(fn [e]
|
(on-back)))
|
||||||
(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
|
close-modal
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [e]
|
(fn [e]
|
||||||
|
@ -300,7 +300,33 @@
|
||||||
(mf/deps theme on-back)
|
(mf/deps theme on-back)
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (wdt/delete-token-theme (:group theme) (:name theme)))
|
(st/emit! (wdt/delete-token-theme (:group theme) (:name theme)))
|
||||||
(on-back)))]
|
(on-back)))
|
||||||
|
|
||||||
|
;; Sets tree handlers
|
||||||
|
token-set-group-active?
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps theme-state)
|
||||||
|
(fn [prefixed-path]
|
||||||
|
(ctob/sets-at-path-all-active? lib prefixed-path)))
|
||||||
|
|
||||||
|
token-set-active?
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps theme-state)
|
||||||
|
(fn [set-name]
|
||||||
|
(get-in @theme-state [:sets set-name])))
|
||||||
|
|
||||||
|
on-toggle-token-set
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps theme-state)
|
||||||
|
(fn [set-name]
|
||||||
|
(swap! theme-state #(ctob/toggle-set % set-name))))
|
||||||
|
|
||||||
|
on-click-token-set
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps on-toggle-token-set)
|
||||||
|
(fn [prefixed-set-path-str]
|
||||||
|
(let [set-name (ctob/prefixed-set-path-string->set-name-string prefixed-set-path-str)]
|
||||||
|
(on-toggle-token-set set-name))))]
|
||||||
|
|
||||||
[:div {:class (stl/css :themes-modal-wrapper)}
|
[:div {:class (stl/css :themes-modal-wrapper)}
|
||||||
[:> heading* {:level 2 :typography "headline-medium" :class (stl/css :themes-modal-title)}
|
[:> heading* {:level 2 :typography "headline-medium" :class (stl/css :themes-modal-title)}
|
||||||
|
@ -327,6 +353,7 @@
|
||||||
{:token-sets token-sets
|
{:token-sets token-sets
|
||||||
:token-set-selected? (constantly false)
|
:token-set-selected? (constantly false)
|
||||||
:token-set-active? token-set-active?
|
:token-set-active? token-set-active?
|
||||||
|
:token-set-group-active? token-set-group-active?
|
||||||
:on-select on-click-token-set
|
:on-select on-click-token-set
|
||||||
:on-toggle-token-set on-toggle-token-set
|
:on-toggle-token-set on-toggle-token-set
|
||||||
:origin "theme-modal"
|
:origin "theme-modal"
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
(ns app.main.ui.workspace.tokens.sets
|
(ns app.main.ui.workspace.tokens.sets
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[app.common.types.tokens-lib :as ctob]
|
[app.common.types.tokens-lib :as ctob]
|
||||||
[app.main.data.tokens :as wdt]
|
[app.main.data.tokens :as wdt]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
|
@ -59,9 +60,28 @@
|
||||||
:auto-focus true
|
:auto-focus true
|
||||||
:default-value default-value}]))
|
:default-value default-value}]))
|
||||||
|
|
||||||
|
(mf/defc checkbox
|
||||||
|
[{:keys [checked aria-label on-click]}]
|
||||||
|
(let [all? (true? checked)
|
||||||
|
mixed? (= checked "mixed")
|
||||||
|
checked? (or all? mixed?)]
|
||||||
|
[:div {:role "checkbox"
|
||||||
|
:aria-checked (dm/str checked)
|
||||||
|
:tabindex 0
|
||||||
|
:class (stl/css-case :checkbox-style true
|
||||||
|
:checkbox-checked-style checked?)
|
||||||
|
:on-click on-click}
|
||||||
|
(when checked?
|
||||||
|
[:> icon*
|
||||||
|
{:aria-label aria-label
|
||||||
|
:class (stl/css :check-icon)
|
||||||
|
:size "s"
|
||||||
|
:id (if mixed? ic/remove ic/tick)}])]))
|
||||||
|
|
||||||
(mf/defc sets-tree-set-group
|
(mf/defc sets-tree-set-group
|
||||||
[{:keys [label tree-depth tree-path selected? collapsed? editing? on-edit on-edit-reset _on-edit-submit]}]
|
[{:keys [label tree-depth tree-path active? selected? collapsed? editing? on-edit on-edit-reset _on-edit-submit]}]
|
||||||
(let [editing?' (editing? tree-path)
|
(let [editing?' (editing? tree-path)
|
||||||
|
active?' (active? tree-path)
|
||||||
on-context-menu
|
on-context-menu
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps editing? tree-path)
|
(mf/deps editing? tree-path)
|
||||||
|
@ -97,9 +117,16 @@
|
||||||
:on-create on-edit-reset
|
:on-create on-edit-reset
|
||||||
;; TODO Implement set group renaming
|
;; TODO Implement set group renaming
|
||||||
:on-submit (constantly nil)}]
|
:on-submit (constantly nil)}]
|
||||||
[:div {:class (stl/css :set-name)
|
[:*
|
||||||
:on-double-click #(on-edit tree-path)}
|
[:div {:class (stl/css :set-name)
|
||||||
label])]))
|
:on-double-click #(on-edit tree-path)}
|
||||||
|
label]
|
||||||
|
[:& checkbox
|
||||||
|
{:checked (case active?'
|
||||||
|
:all true
|
||||||
|
:partial "mixed"
|
||||||
|
:none false)
|
||||||
|
:arial-label (tr "workspace.token.select-set")}]])]))
|
||||||
|
|
||||||
(mf/defc sets-tree-set
|
(mf/defc sets-tree-set
|
||||||
[{:keys [set label tree-depth tree-path selected? on-select active? on-toggle editing? on-edit on-edit-reset on-edit-submit]}]
|
[{:keys [set label tree-depth tree-path selected? on-select active? on-toggle editing? on-edit on-edit-reset on-edit-submit]}]
|
||||||
|
@ -150,18 +177,25 @@
|
||||||
[:div {:class (stl/css :set-name)
|
[:div {:class (stl/css :set-name)
|
||||||
:on-double-click #(on-edit tree-path)}
|
:on-double-click #(on-edit tree-path)}
|
||||||
label]
|
label]
|
||||||
[:button {:type "button"
|
[:& checkbox
|
||||||
:on-click on-checkbox-click
|
{:on-click on-checkbox-click
|
||||||
:class (stl/css-case :checkbox-style true
|
:arial-label (tr "workspace.token.select-set")
|
||||||
:checkbox-checked-style active?')}
|
:checked active?'}]])]))
|
||||||
(when active?'
|
|
||||||
[:> icon* {:aria-label (tr "workspace.token.select-set")
|
|
||||||
:class (stl/css :check-icon)
|
|
||||||
:size "s"
|
|
||||||
:id ic/tick}])]])]))
|
|
||||||
|
|
||||||
(mf/defc sets-tree
|
(mf/defc sets-tree
|
||||||
[{:keys [set-path set-node tree-depth tree-path on-select selected? on-toggle active? editing? on-edit on-edit-reset on-edit-submit]
|
[{:keys [active?
|
||||||
|
group-active?
|
||||||
|
editing?
|
||||||
|
on-edit
|
||||||
|
on-edit-reset
|
||||||
|
on-edit-submit
|
||||||
|
on-select
|
||||||
|
on-toggle
|
||||||
|
selected?
|
||||||
|
set-node
|
||||||
|
set-path
|
||||||
|
tree-depth
|
||||||
|
tree-path]
|
||||||
:or {tree-depth 0}
|
:or {tree-depth 0}
|
||||||
:as props}]
|
:as props}]
|
||||||
(let [[set-path-prefix set-fname] (some-> set-path (ctob/split-set-str-path-prefix))
|
(let [[set-path-prefix set-fname] (some-> set-path (ctob/split-set-str-path-prefix))
|
||||||
|
@ -192,6 +226,7 @@
|
||||||
set-group?
|
set-group?
|
||||||
[:& sets-tree-set-group
|
[:& sets-tree-set-group
|
||||||
{:selected? (selected? tree-path)
|
{:selected? (selected? tree-path)
|
||||||
|
:active? group-active?
|
||||||
:on-select on-select
|
:on-select on-select
|
||||||
:label set-fname
|
:label set-fname
|
||||||
:collapsed? collapsed?
|
:collapsed? collapsed?
|
||||||
|
@ -214,6 +249,7 @@
|
||||||
:selected? selected?
|
:selected? selected?
|
||||||
:on-toggle on-toggle
|
:on-toggle on-toggle
|
||||||
:active? active?
|
:active? active?
|
||||||
|
:group-active? group-active?
|
||||||
:editing? editing?
|
:editing? editing?
|
||||||
:on-edit on-edit
|
:on-edit on-edit
|
||||||
:on-edit-reset on-edit-reset
|
:on-edit-reset on-edit-reset
|
||||||
|
@ -224,6 +260,7 @@
|
||||||
on-update-token-set
|
on-update-token-set
|
||||||
token-set-selected?
|
token-set-selected?
|
||||||
token-set-active?
|
token-set-active?
|
||||||
|
token-set-group-active?
|
||||||
on-create-token-set
|
on-create-token-set
|
||||||
on-toggle-token-set
|
on-toggle-token-set
|
||||||
origin
|
origin
|
||||||
|
@ -231,10 +268,9 @@
|
||||||
context]
|
context]
|
||||||
:as _props}]
|
:as _props}]
|
||||||
(let [{:keys [editing? new? on-edit on-reset] :as ctx} (or context (sets-context/use-context))]
|
(let [{:keys [editing? new? on-edit on-reset] :as ctx} (or context (sets-context/use-context))]
|
||||||
[:ul {:class (stl/css :sets-list)}
|
[:fieldset {:class (stl/css :sets-list)}
|
||||||
(if (and
|
(if (and (= origin "theme-modal")
|
||||||
(= origin "theme-modal")
|
(empty? token-sets))
|
||||||
(empty? token-sets))
|
|
||||||
[:> text* {:as "span" :typography "body-small" :class (stl/css :empty-state-message-sets)}
|
[:> text* {:as "span" :typography "body-small" :class (stl/css :empty-state-message-sets)}
|
||||||
(tr "workspace.token.no-sets-create")]
|
(tr "workspace.token.no-sets-create")]
|
||||||
(if (and (= origin "theme-modal")
|
(if (and (= origin "theme-modal")
|
||||||
|
@ -247,6 +283,7 @@
|
||||||
:selected? token-set-selected?
|
:selected? token-set-selected?
|
||||||
:on-select on-select
|
:on-select on-select
|
||||||
:active? token-set-active?
|
:active? token-set-active?
|
||||||
|
:group-active? token-set-group-active?
|
||||||
:on-toggle on-toggle-token-set
|
:on-toggle on-toggle-token-set
|
||||||
:editing? editing?
|
:editing? editing?
|
||||||
:on-edit on-edit
|
:on-edit on-edit
|
||||||
|
@ -276,11 +313,15 @@
|
||||||
token-set-active? (mf/use-fn
|
token-set-active? (mf/use-fn
|
||||||
(mf/deps active-token-set-names)
|
(mf/deps active-token-set-names)
|
||||||
(fn [set-name]
|
(fn [set-name]
|
||||||
(get active-token-set-names set-name)))]
|
(get active-token-set-names set-name)))
|
||||||
|
token-set-group-active? (mf/use-fn
|
||||||
|
(fn [prefixed-path]
|
||||||
|
@(refs/token-sets-at-path-all-active? prefixed-path)))]
|
||||||
[:& controlled-sets-list
|
[:& controlled-sets-list
|
||||||
{:token-sets token-sets
|
{:token-sets token-sets
|
||||||
:token-set-selected? token-set-selected?
|
:token-set-selected? token-set-selected?
|
||||||
:token-set-active? token-set-active?
|
:token-set-active? token-set-active?
|
||||||
|
:token-set-group-active? token-set-group-active?
|
||||||
:on-select on-select-token-set-click
|
:on-select on-select-token-set-click
|
||||||
:origin "set-panel"
|
:origin "set-panel"
|
||||||
:on-toggle-token-set on-toggle-token-set-click
|
:on-toggle-token-set on-toggle-token-set-click
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue