0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-20 05:34:23 -05:00

Implement set group toggling

This commit is contained in:
Florian Schroedl 2025-01-02 09:09:11 +01:00 committed by Andrés Moya
parent d41b4b4e51
commit 791cb7e5fe
7 changed files with 230 additions and 34 deletions

View file

@ -0,0 +1,42 @@
(ns app.common.logic.tokens
(:require
[app.common.files.changes-builder :as pcb]
[app.common.types.tokens-lib :as ctob]))
(defn generate-update-active-sets
"Copy the active sets from the currently active themes and move them to the hidden token theme and update the theme with `update-hidden-theme-fn`.
Use this for managing sets active state without having to modify a user created theme (\"no themes selected\" state in the ui)."
[changes tokens-lib update-hidden-theme-fn]
(let [prev-active-token-themes (ctob/get-active-theme-paths tokens-lib)
active-token-set-names (ctob/get-active-themes-set-names tokens-lib)
prev-hidden-token-theme (ctob/get-hidden-theme tokens-lib)
hidden-token-theme (-> (or (some-> prev-hidden-token-theme (ctob/set-sets active-token-set-names))
(ctob/make-hidden-token-theme :sets active-token-set-names))
(update-hidden-theme-fn))
changes (-> changes
(pcb/update-active-token-themes #{ctob/hidden-token-theme-path} prev-active-token-themes))
changes (if prev-hidden-token-theme
(pcb/update-token-theme changes hidden-token-theme prev-hidden-token-theme)
(pcb/add-token-theme changes hidden-token-theme))]
changes))
(defn generate-toggle-token-set
"Toggle a token set at `set-name` in `tokens-lib` without modifying a user theme."
[changes tokens-lib set-name]
(generate-update-active-sets changes tokens-lib #(ctob/toggle-set % set-name)))
(defn generate-toggle-token-set-group
"Toggle a token set group at `prefixed-set-path-str` in `tokens-lib` without modifying a user theme."
[changes tokens-lib prefixed-set-path-str]
(let [deactivate? (contains? #{:all :partial} (ctob/sets-at-path-all-active? tokens-lib prefixed-set-path-str))
sets-names (->> (ctob/get-sets-at-prefix-path tokens-lib prefixed-set-path-str)
(map :name)
(into #{}))
update-fn (if deactivate?
#(ctob/disable-sets % sets-names)
#(ctob/enable-sets % sets-names))]
(generate-update-active-sets changes tokens-lib update-fn)))

View file

@ -58,6 +58,12 @@
(validate-file! file')
file'))
(defn apply-undo-changes
[file changes]
(let [file' (ctf/update-file-data file #(cfc/process-changes % (:undo-changes changes) true))]
(validate-file! file')
file'))
;; ----- Pages
(defn sample-page

View file

@ -15,6 +15,10 @@
[app.common.types.token :as cto]
[app.common.types.tokens-lib :as ctob]))
(defn get-tokens-lib
[file]
(:tokens-lib (ctf/file-data file)))
(defn add-tokens-lib
[file]
(ctf/update-file-data file #(update % :tokens-lib ctob/ensure-tokens-lib)))
@ -87,4 +91,3 @@
(ctpl/update-page file-data
(:id page)
#(ctst/set-shape % shape'))))))

View file

@ -455,7 +455,7 @@ When `before-set-name` is nil, move set to bottom")
(get-in-set-tree [_ path] "get `path` in nested tree of all sets in the library")
(get-sets [_] "get an ordered sequence of all sets in the library")
(get-path-sets [_ path] "get an ordered sequence of sets at `path` in the library")
(get-sets-at-prefix-path [_ prefixed-path] "get an ordered sequence of sets at `prefixed-path` in the library")
(get-sets-at-prefix-path [_ prefixed-path-str] "get an ordered sequence of sets at `prefixed-path-str` in the library")
(get-sets-at-path [_ path-str] "get an ordered sequence of sets at `path` in the library")
(rename-set-group [_ from-path-str to-path-str] "renames set groups and all child set names from `from-path-str` to `to-path-str`")
(get-ordered-set-names [_] "get an ordered sequence of all sets names in the library")
@ -504,12 +504,13 @@ When `before-set-name` is nil, move set to bottom")
(def hidden-token-theme-path
(token-theme-path hidden-token-theme-group hidden-token-theme-name))
(defprotocol ITokenTheme
(set-sets [_ set-names] "set the active token sets")
(enable-set [_ set-name] "enable set in theme")
(enable-sets [_ set-names] "enable sets in theme")
(disable-set [_ set-name] "disable set in theme")
(disable-sets [_ set-names] "disable sets in theme")
(toggle-set [_ set-name] "toggle a set enabled / disabled in the theme")
(update-set-name [_ prev-set-name set-name] "update set-name from `prev-set-name` to `set-name` when it exists")
(theme-path [_] "get `token-theme-path` from theme")
(theme-matches-group-name [_ group name] "if a theme matches the given group & name")
@ -525,13 +526,22 @@ When `before-set-name` is nil, move set to bottom")
(dt/now)
set-names))
(enable-set [this set-name]
(set-sets this (conj sets set-name)))
(enable-sets [this set-names]
(set-sets this (set/union sets set-names)))
(disable-set [this set-name]
(set-sets this (disj sets set-name)))
(disable-sets [this set-names]
(set-sets this (or (set/difference sets set-names) #{})))
(toggle-set [this set-name]
(set-sets this (if (sets set-name)
(disj sets set-name)
(conj sets set-name))))
(if (sets set-name)
(disable-set this set-name)
(enable-set this set-name)))
(update-set-name [this prev-set-name set-name]
(if (get sets prev-set-name)
@ -610,6 +620,8 @@ When `before-set-name` is nil, move set to bottom")
(get-theme-tree [_] "get a nested tree of all themes in the library")
(get-themes [_] "get an ordered sequence of all themes in the library")
(get-theme [_ group name] "get one theme looking for name")
(get-hidden-theme [_] "get the theme hidden from the user ,
used for managing active sets without a user created theme.")
(get-theme-groups [_] "get a sequence of group names by order")
(get-active-theme-paths [_] "get the active theme paths")
(get-active-themes [_] "get an ordered sequence of active themes in the library")
@ -791,8 +803,8 @@ Will return a value that matches this schema:
(tree-seq d/ordered-map? vals)
(filter (partial instance? TokenSet))))
(get-sets-at-prefix-path [_ prefixed-path]
(some->> (get-in sets (split-token-set-path prefixed-path))
(get-sets-at-prefix-path [_ prefixed-path-str]
(some->> (get-in sets (split-token-set-path prefixed-path-str))
(tree-seq d/ordered-map? vals)
(filter (partial instance? TokenSet))))
@ -881,6 +893,9 @@ Will return a value that matches this schema:
(get-theme [_ group name]
(dm/get-in themes [group name]))
(get-hidden-theme [this]
(get-theme this hidden-token-theme-group hidden-token-theme-name))
(set-active-themes [_ active-themes]
(TokensLib. sets
themes
@ -946,10 +961,10 @@ Will return a value that matches this schema:
(mapcat :sets)
(get-active-themes this)))
(sets-at-path-all-active? [this prefixed-path]
(sets-at-path-all-active? [this prefixed-path-str]
(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)
(let [path-active-set-names (->> (get-sets-at-prefix-path this prefixed-path-str)
(map :name)
(into #{}))
difference (set/difference path-active-set-names active-set-names)]

View file

@ -0,0 +1,117 @@
(ns common-tests.logic.token-test
(:require
[app.common.files.changes-builder :as pcb]
[app.common.logic.tokens :as clt]
[app.common.test-helpers.files :as thf]
[app.common.test-helpers.ids-map :as thi]
[app.common.test-helpers.tokens :as tht]
[app.common.types.tokens-lib :as ctob]
[clojure.test :as t]))
(t/use-fixtures :each thi/test-fixture)
(defn- setup-file [lib-fn]
(-> (thf/sample-file :file1)
(tht/add-tokens-lib)
(tht/update-tokens-lib lib-fn)))
(t/deftest generate-toggle-token-set-test
(t/testing "toggling an active set will switch to hidden theme without user sets"
(let [file (setup-file #(-> %
(ctob/add-set (ctob/make-token-set :name "foo/bar"))
(ctob/add-theme (ctob/make-token-theme :name "theme"
:sets #{"foo/bar"}))
(ctob/set-active-themes #{"/theme"})))
changes (clt/generate-toggle-token-set (pcb/empty-changes) (tht/get-tokens-lib file) "foo/bar")
redo (thf/apply-changes file changes)
redo-lib (tht/get-tokens-lib redo)
undo (thf/apply-undo-changes redo changes)
undo-lib (tht/get-tokens-lib undo)]
(t/is (= #{ctob/hidden-token-theme-path} (ctob/get-active-theme-paths redo-lib)))
(t/is (= #{} (:sets (ctob/get-hidden-theme redo-lib))))
;; Undo
(t/is (nil? (ctob/get-hidden-theme undo-lib)))
(t/is (= #{"/theme"} (ctob/get-active-theme-paths undo-lib)))))
(t/testing "toggling an inactive set will switch to hidden theme without user sets"
(let [file (setup-file #(-> %
(ctob/add-set (ctob/make-token-set :name "foo/bar"))
(ctob/add-theme (ctob/make-token-theme :name "theme"
:sets #{"foo/bar"}))
(ctob/set-active-themes #{"/theme"})))
changes (clt/generate-toggle-token-set (pcb/empty-changes) (tht/get-tokens-lib file) "foo/bar")
redo (thf/apply-changes file changes)
redo-lib (tht/get-tokens-lib redo)
undo (thf/apply-undo-changes redo changes)
undo-lib (tht/get-tokens-lib undo)]
(t/is (= #{ctob/hidden-token-theme-path} (ctob/get-active-theme-paths redo-lib)))
(t/is (= #{} (:sets (ctob/get-hidden-theme redo-lib))))
;; Undo
(t/is (nil? (ctob/get-hidden-theme undo-lib)))
(t/is (= #{"/theme"} (ctob/get-active-theme-paths undo-lib)))))
(t/testing "toggling an set with hidden theme already active will toggle set in hidden theme"
(let [file (setup-file #(-> %
(ctob/add-set (ctob/make-token-set :name "foo/bar"))
(ctob/add-theme (ctob/make-hidden-token-theme))
(ctob/set-active-themes #{ctob/hidden-token-theme-path})))
changes (clt/generate-toggle-token-set-group (pcb/empty-changes) (tht/get-tokens-lib file) "G-foo/S-bar")
redo (thf/apply-changes file changes)
redo-lib (tht/get-tokens-lib redo)
undo (thf/apply-undo-changes redo changes)
undo-lib (tht/get-tokens-lib undo)]
(t/is (= (ctob/get-active-theme-paths redo-lib) (ctob/get-active-theme-paths undo-lib)))
(t/is (= #{"foo/bar"} (:sets (ctob/get-hidden-theme redo-lib))))
;; Undo
(t/is (some? (ctob/get-hidden-theme undo-lib))))))
(t/deftest generate-toggle-token-set-group-test
(t/testing "toggling set group with no active sets inside will activate all child sets"
(let [file (setup-file #(-> %
(ctob/add-set (ctob/make-token-set :name "foo/bar"))
(ctob/add-set (ctob/make-token-set :name "foo/bar/baz"))
(ctob/add-set (ctob/make-token-set :name "foo/bar/baz/baz-child"))
(ctob/add-theme (ctob/make-token-theme :name "theme"))
(ctob/set-active-themes #{"/theme"})))
changes (clt/generate-toggle-token-set-group (pcb/empty-changes) (tht/get-tokens-lib file) "G-foo/G-bar")
redo (thf/apply-changes file changes)
redo-lib (tht/get-tokens-lib redo)
undo (thf/apply-undo-changes redo changes)
undo-lib (tht/get-tokens-lib undo)]
(t/is (= #{ctob/hidden-token-theme-path} (ctob/get-active-theme-paths redo-lib)))
(t/is (= #{"foo/bar/baz" "foo/bar/baz/baz-child"} (:sets (ctob/get-hidden-theme redo-lib))))
;; Undo
(t/is (nil? (ctob/get-hidden-theme undo-lib)))
(t/is (= #{"/theme"} (ctob/get-active-theme-paths undo-lib)))))
(t/testing "toggling set group with partially active sets inside will deactivate all child sets"
(let [file (setup-file #(-> %
(ctob/add-set (ctob/make-token-set :name "foo/bar"))
(ctob/add-set (ctob/make-token-set :name "foo/bar/baz"))
(ctob/add-set (ctob/make-token-set :name "foo/bar/baz/baz-child"))
(ctob/add-theme (ctob/make-token-theme :name "theme"
:sets #{"foo/bar/baz"}))
(ctob/set-active-themes #{"/theme"})))
changes (clt/generate-toggle-token-set-group (pcb/empty-changes) (tht/get-tokens-lib file) "G-foo/G-bar")
redo (thf/apply-changes file changes)
redo-lib (tht/get-tokens-lib redo)
undo (thf/apply-undo-changes redo changes)
undo-lib (tht/get-tokens-lib undo)]
(t/is (= #{} (:sets (ctob/get-hidden-theme redo-lib))))
(t/is (= #{ctob/hidden-token-theme-path} (ctob/get-active-theme-paths redo-lib)))
;; Undo
(t/is (nil? (ctob/get-hidden-theme undo-lib)))
(t/is (= #{"/theme"} (ctob/get-active-theme-paths undo-lib))))))

View file

@ -9,6 +9,7 @@
[app.common.data.macros :as dm]
[app.common.files.changes-builder :as pcb]
[app.common.geom.point :as gpt]
[app.common.logic.tokens :as clt]
[app.common.types.shape :as cts]
[app.common.types.tokens-lib :as ctob]
[app.main.data.changes :as dch]
@ -158,22 +159,19 @@
(defn toggle-token-set [{:keys [token-set-name]}]
(ptk/reify ::toggle-token-set
ptk/WatchEvent
(watch [it state _]
(let [tokens-lib (get-tokens-lib state)
prev-theme (ctob/get-theme tokens-lib ctob/hidden-token-theme-group ctob/hidden-token-theme-name)
active-token-set-names (ctob/get-active-themes-set-names tokens-lib)
theme (-> (or (some-> prev-theme
(ctob/set-sets active-token-set-names))
(ctob/make-hidden-token-theme :sets active-token-set-names))
(ctob/toggle-set token-set-name))
prev-active-token-themes (ctob/get-active-theme-paths tokens-lib)
changes (-> (pcb/empty-changes it)
(pcb/update-active-token-themes #{(ctob/token-theme-path ctob/hidden-token-theme-group ctob/hidden-token-theme-name)} prev-active-token-themes))
changes' (if prev-theme
(pcb/update-token-theme changes theme prev-theme)
(pcb/add-token-theme changes theme))]
(watch [_ state _]
(let [changes (clt/generate-toggle-token-set (pcb/empty-changes) (get-tokens-lib state) token-set-name)]
(rx/of
(dch/commit-changes changes')
(dch/commit-changes changes)
(wtu/update-workspace-tokens))))))
(defn toggle-token-set-group [{:keys [prefixed-path-str]}]
(ptk/reify ::toggle-token-set-group
ptk/WatchEvent
(watch [_ state _]
(let [changes (clt/generate-toggle-token-set-group (pcb/empty-changes) (get-tokens-lib state) prefixed-path-str)]
(rx/of
(dch/commit-changes changes)
(wtu/update-workspace-tokens))))))
(defn import-tokens-lib [lib]

View file

@ -25,6 +25,9 @@
(defn on-toggle-token-set-click [token-set-name]
(st/emit! (wdt/toggle-token-set {:token-set-name token-set-name})))
(defn on-toggle-token-set-group-click [prefixed-path-str]
(st/emit! (wdt/toggle-token-set-group {:prefixed-path-str prefixed-path-str})))
(defn on-select-token-set-click [tree-path]
(st/emit! (wdt/set-selected-token-set-path tree-path)))
@ -88,7 +91,7 @@
:id (if mixed? ic/remove ic/tick)}])]))
(mf/defc sets-tree-set-group
[{:keys [label tree-depth tree-path active? selected? collapsed? editing? on-edit on-edit-reset on-edit-submit]}]
[{:keys [label tree-depth tree-path active? selected? collapsed? editing? on-toggle on-edit on-edit-reset on-edit-submit]}]
(let [editing?' (editing? tree-path)
active?' (active? tree-path)
on-context-menu
@ -102,7 +105,7 @@
(wdt/show-token-set-context-menu
{:position (dom/get-client-position event)
:prefixed-set-path tree-path})))))
on-click
on-collapse-click
(mf/use-fn
(fn [event]
(dom/stop-propagation event)
@ -111,6 +114,10 @@
(mf/use-fn
(mf/deps tree-path)
#(on-edit tree-path))
on-checkbox-click
(mf/use-fn
(mf/deps on-toggle tree-path)
#(on-toggle tree-path))
on-edit-submit'
(mf/use-fn
(mf/deps tree-path on-edit-submit)
@ -124,7 +131,7 @@
:on-context-menu on-context-menu}
[:> icon-button*
{:class (stl/css :set-item-group-collapse-button)
:on-click on-click
:on-click on-collapse-click
:aria-label (tr "labels.collapse")
:icon (if @collapsed? "arrow-right" "arrow-down")
:variant "action"}]
@ -139,7 +146,8 @@
:on-double-click on-double-click}
label]
[:& checkbox
{:checked (case active?'
{:on-click on-checkbox-click
:checked (case active?'
:all true
:partial "mixed"
:none false)
@ -172,6 +180,7 @@
(mf/deps tree-path)
#(on-edit tree-path))
on-checkbox-click (mf/use-fn
(mf/deps set-name)
(fn [event]
(dom/stop-propagation event)
(on-toggle set-name)))
@ -214,7 +223,8 @@
on-edit-submit-set
on-edit-submit-group
on-select
on-toggle
on-toggle-set
on-toggle-set-group
selected?
set-node
set-path
@ -243,7 +253,7 @@
:tree-path (or tree-path set-path)
:tree-depth tree-depth
:editing? editing?
:on-toggle on-toggle
:on-toggle on-toggle-set
:on-edit on-edit
:on-edit-reset on-edit-reset
:on-edit-submit on-edit-submit-set}]
@ -257,6 +267,7 @@
:tree-path (or tree-path set-path)
:tree-depth tree-depth
:editing? editing?
:on-toggle on-toggle-set-group
:on-edit on-edit
:on-edit-reset on-edit-reset
:on-edit-submit on-edit-submit-group}])
@ -271,7 +282,8 @@
:tree-path tree-path'
:on-select on-select
:selected? selected?
:on-toggle on-toggle
:on-toggle-set on-toggle-set
:on-toggle-set-group on-toggle-set-group
:active? active?
:group-active? group-active?
:editing? editing?
@ -289,6 +301,7 @@
token-set-group-active?
on-create-token-set
on-toggle-token-set
on-toggle-token-set-group
origin
on-select
context]
@ -310,7 +323,8 @@
:on-select on-select
:active? token-set-active?
:group-active? token-set-group-active?
:on-toggle on-toggle-token-set
:on-toggle-set on-toggle-token-set
:on-toggle-set-group on-toggle-token-set-group
:editing? editing?
:on-edit on-edit
:on-edit-reset on-reset
@ -352,6 +366,7 @@
:on-select on-select-token-set-click
:origin "set-panel"
:on-toggle-token-set on-toggle-token-set-click
:on-toggle-token-set-group on-toggle-token-set-group-click
:on-update-token-set on-update-token-set
:on-update-token-set-group on-update-token-set-group
:on-create-token-set on-create-token-set}]))