mirror of
https://github.com/penpot/penpot.git
synced 2026-09-08 11:54:36 -04:00
Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67bc748ebd | ||
|
|
86e5b43a5c | ||
|
|
fb3cf431c1 | ||
|
|
dcf90f9e28 | ||
|
|
b101a16c70 | ||
|
|
b3a946eaeb | ||
|
|
6a34947586 | ||
|
|
b0e1e019bb | ||
|
|
46a4a1774d | ||
|
|
6e339ba217 | ||
|
|
3e6150ab92 | ||
|
|
8d36565712 | ||
|
|
91dbb873ad | ||
|
|
4b163f94d4 | ||
|
|
0d7cf045a9 | ||
|
|
d56a460b3c | ||
|
|
12fc08d7f5 | ||
|
|
d1c3135f8d | ||
|
|
5301888083 | ||
|
|
105e97bf93 | ||
|
|
71d144f65b | ||
|
|
84507a444f | ||
|
|
c358e58e33 | ||
|
|
ca1b5541c0 | ||
|
|
37f27df9d8 | ||
|
|
ca619a4c85 |
No files matched your search
@@ -14,6 +14,7 @@
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.files.migrations :as fmg]
|
||||
[app.common.files.stats :as cfs]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.logging :as l]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.schema.desc-js-like :as-alias smdj]
|
||||
@@ -21,6 +22,7 @@
|
||||
[app.common.transit :as t]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.uri :as uri]
|
||||
[app.config :as cf]
|
||||
[app.db :as db]
|
||||
@@ -520,12 +522,20 @@
|
||||
|
||||
components-sample
|
||||
(-> (sample-assets components 4)
|
||||
(update :sample load-objects))]
|
||||
(update :sample load-objects))
|
||||
|
||||
tokens-lib (cfo/get-tokens-lib data)
|
||||
tokens-count (if (some? tokens-lib) (count (ctob/get-all-tokens tokens-lib)) 0)
|
||||
token-sets-count (if (some? tokens-lib) (count (ctob/get-sets tokens-lib)) 0)
|
||||
token-themes-count (if (some? tokens-lib) (count (ctob/get-themes-no-hidden tokens-lib)) 0)]
|
||||
|
||||
{:components components-sample
|
||||
:variants {:count (count variant-ids)}
|
||||
:colors (sample-assets (:colors data) 3)
|
||||
:typographies (sample-assets (:typographies data) 3)}))
|
||||
:typographies (sample-assets (:typographies data) 3)
|
||||
:tokens-count tokens-count
|
||||
:token-sets-count token-sets-count
|
||||
:token-themes-count token-themes-count}))
|
||||
|
||||
(def ^:private file-summary-cache-key-ttl
|
||||
(ct/duration {:days 30}))
|
||||
|
||||
@@ -106,7 +106,6 @@
|
||||
:set-token
|
||||
:set-token-set
|
||||
:set-token-theme
|
||||
:set-active-token-themes
|
||||
:rename-token-set-group
|
||||
:move-token-set
|
||||
:move-token-set-group
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.schema :as sm]
|
||||
@@ -29,6 +30,7 @@
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.common.types.typographies-list :as ctyl]
|
||||
[app.common.types.typography :as ctt]
|
||||
[app.common.types.variant :as ctv]
|
||||
@@ -398,10 +400,11 @@
|
||||
[:id ::sm/uuid]
|
||||
[:attrs [:maybe ctob/schema:token-theme-attrs]]]]
|
||||
|
||||
[:set-active-token-themes
|
||||
[:map {:title "SetActiveTokenThemes"}
|
||||
[:type [:= :set-active-token-themes]]
|
||||
[:theme-paths [:set :string]]]]
|
||||
[:set-tokens-status
|
||||
[:map {:title "SetTokensStatus"}
|
||||
[:type [:= :set-tokens-status]]
|
||||
[:theme-ids [:set ::sm/uuid]]
|
||||
[:set-ids [:set ::sm/uuid]]]]
|
||||
|
||||
[:rename-token-set-group
|
||||
[:map {:title "RenameTokenSetGroup"}
|
||||
@@ -428,7 +431,13 @@
|
||||
[:set-base-font-size
|
||||
[:map {:title "ModBaseFontSize"}
|
||||
[:type [:= :set-base-font-size]]
|
||||
[:base-font-size :string]]]])
|
||||
[:base-font-size :string]]]
|
||||
|
||||
[:set-tokens-source
|
||||
[:map {:title "SetTokensSource"}
|
||||
[:type [:= :set-tokens-source]]
|
||||
[:file-id ::sm/uuid]
|
||||
[:library-id [:maybe ::sm/uuid]]]]])
|
||||
|
||||
(def schema:changes
|
||||
[:sequential {:gen/max 5 :gen/min 1} schema:change])
|
||||
@@ -992,77 +1001,73 @@
|
||||
|
||||
(defmethod process-change :set-token
|
||||
[data {:keys [set-id token-id attrs]}]
|
||||
(update data :tokens-lib
|
||||
(fn [lib]
|
||||
(let [lib' (ctob/ensure-tokens-lib lib)]
|
||||
(cond
|
||||
(not attrs)
|
||||
(ctob/delete-token lib' set-id token-id)
|
||||
(-> (cfo/ensure-tokens-lib data)
|
||||
(cfo/update-tokens-lib
|
||||
(fn [lib']
|
||||
(cond
|
||||
(not attrs)
|
||||
(ctob/delete-token lib' set-id token-id)
|
||||
|
||||
(not (ctob/get-token lib' set-id token-id))
|
||||
(ctob/add-token lib' set-id (ctob/make-token attrs))
|
||||
(not (ctob/get-token lib' set-id token-id))
|
||||
(ctob/add-token lib' set-id (ctob/make-token attrs))
|
||||
|
||||
:else
|
||||
(ctob/update-token lib' set-id token-id
|
||||
(fn [prev-token]
|
||||
(ctob/make-token (merge prev-token attrs)))))))))
|
||||
:else
|
||||
(ctob/update-token lib' set-id token-id
|
||||
(fn [prev-token]
|
||||
(ctob/make-token (merge prev-token attrs)))))))))
|
||||
|
||||
(defmethod process-change :set-token-set
|
||||
[data {:keys [id attrs]}]
|
||||
(update data :tokens-lib
|
||||
(fn [lib]
|
||||
(let [lib' (ctob/ensure-tokens-lib lib)]
|
||||
(cond
|
||||
(not attrs)
|
||||
(ctob/delete-set lib' id)
|
||||
(-> (cfo/ensure-tokens-lib data)
|
||||
(cfo/update-tokens-lib
|
||||
(fn [lib']
|
||||
(cond
|
||||
(not attrs)
|
||||
(ctob/delete-set lib' id)
|
||||
|
||||
(not (ctob/get-set lib' id))
|
||||
(ctob/add-set lib' (ctob/make-token-set attrs))
|
||||
(not (ctob/get-set lib' id))
|
||||
(ctob/add-set lib' (ctob/make-token-set attrs))
|
||||
|
||||
:else
|
||||
(ctob/update-set lib' id (fn [_] (ctob/make-token-set attrs))))))))
|
||||
:else
|
||||
(ctob/update-set lib' id (fn [_] (ctob/make-token-set attrs))))))))
|
||||
|
||||
(defmethod process-change :set-token-theme
|
||||
[data {:keys [id attrs]}]
|
||||
(update data :tokens-lib
|
||||
(fn [lib]
|
||||
(let [lib' (ctob/ensure-tokens-lib lib)]
|
||||
(cond
|
||||
(not attrs)
|
||||
(ctob/delete-theme lib' id)
|
||||
(-> (cfo/ensure-tokens-lib data)
|
||||
(cfo/update-tokens-lib
|
||||
(fn [lib']
|
||||
(cond
|
||||
(not attrs)
|
||||
(ctob/delete-theme lib' id)
|
||||
|
||||
(not (ctob/get-theme lib' id))
|
||||
(ctob/add-theme lib' (ctob/make-token-theme attrs))
|
||||
(not (ctob/get-theme lib' id))
|
||||
(ctob/add-theme lib' (ctob/make-token-theme attrs))
|
||||
|
||||
:else
|
||||
(ctob/update-theme lib'
|
||||
id
|
||||
(fn [prev-token-theme]
|
||||
(ctob/make-token-theme (merge prev-token-theme attrs)))))))))
|
||||
:else
|
||||
(ctob/update-theme lib'
|
||||
id
|
||||
(fn [prev-token-theme]
|
||||
(ctob/make-token-theme (merge prev-token-theme attrs)))))))))
|
||||
|
||||
(defmethod process-change :set-active-token-themes
|
||||
[data {:keys [theme-paths]}]
|
||||
(update data :tokens-lib #(-> % (ctob/ensure-tokens-lib)
|
||||
(ctob/set-active-themes theme-paths))))
|
||||
(defmethod process-change :set-tokens-status
|
||||
[data {:keys [theme-ids set-ids]}]
|
||||
(-> (cfo/ensure-tokens-lib data)
|
||||
(cfo/update-tokens-status ctos/set-tokens-status theme-ids set-ids)))
|
||||
|
||||
(defmethod process-change :rename-token-set-group
|
||||
[data {:keys [set-group-path set-group-fname]}]
|
||||
(update data :tokens-lib (fn [lib]
|
||||
(-> lib
|
||||
(ctob/ensure-tokens-lib)
|
||||
(ctob/rename-set-group set-group-path set-group-fname)))))
|
||||
(-> (cfo/ensure-tokens-lib data)
|
||||
(cfo/update-tokens-lib ctob/rename-set-group set-group-path set-group-fname)))
|
||||
|
||||
(defmethod process-change :move-token-set
|
||||
[data {:keys [from-path to-path before-path before-group] :as changes}]
|
||||
(update data :tokens-lib #(-> %
|
||||
(ctob/ensure-tokens-lib)
|
||||
(ctob/move-set from-path to-path before-path before-group))))
|
||||
(-> (cfo/ensure-tokens-lib data)
|
||||
(cfo/update-tokens-lib ctob/move-set from-path to-path before-path before-group)))
|
||||
|
||||
(defmethod process-change :move-token-set-group
|
||||
[data {:keys [from-path to-path before-path before-group]}]
|
||||
(update data :tokens-lib #(-> %
|
||||
(ctob/ensure-tokens-lib)
|
||||
(ctob/move-set-group from-path to-path before-path before-group))))
|
||||
(-> (cfo/ensure-tokens-lib data)
|
||||
(cfo/update-tokens-lib ctob/move-set-group from-path to-path before-path before-group)))
|
||||
|
||||
;; === Design Tokens configuration
|
||||
|
||||
@@ -1070,10 +1075,13 @@
|
||||
[data {:keys [base-font-size]}]
|
||||
(ctf/set-base-font-size data base-font-size))
|
||||
|
||||
(defmethod process-change :set-tokens-source
|
||||
[data {:keys [library-id]}]
|
||||
(cfo/set-tokens-source data library-id))
|
||||
|
||||
;; === Operations
|
||||
|
||||
(def decode-shape-attrs
|
||||
(def decode-shape-attrs
|
||||
(sm/decoder cts/schema:shape-attrs sm/json-transformer))
|
||||
|
||||
(defmethod process-operation :assign
|
||||
@@ -1242,3 +1250,37 @@
|
||||
(defmethod frames-changed :default
|
||||
[_ _]
|
||||
nil)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Design Tokens changes detection
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(def ^:private tokens-lib-change-types
|
||||
"Set of change types that modify the tokens library."
|
||||
#{:set-tokens-lib
|
||||
:set-token
|
||||
:set-token-set
|
||||
:set-token-theme
|
||||
:rename-token-set-group
|
||||
:move-token-set
|
||||
:move-token-set-group})
|
||||
|
||||
(defn tokens-lib-changed?
|
||||
"Check if a commit contains changes that modify the tokens library."
|
||||
[changes]
|
||||
(some #(tokens-lib-change-types (:type %)) changes))
|
||||
|
||||
(def ^:private notifiable-token-change-types
|
||||
"Set of change types that modify the structure of the tokens library sets
|
||||
or themes (as opposed to `:set-token`, which only edits a token's value)."
|
||||
#{:set-token-set
|
||||
:set-token-theme
|
||||
:rename-token-set-group
|
||||
:move-token-set
|
||||
:move-token-set-group})
|
||||
|
||||
(defn notifiable-token-change-occured?
|
||||
"Check if a commit contains changes that modify the tokens library sets or
|
||||
themes structure (renamed/added/removed sets, theme set-membership, etc.)."
|
||||
[changes]
|
||||
(some #(notifiable-token-change-types (:type %)) changes))
|
||||
@@ -10,6 +10,7 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.changes :as cfc]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.rect :as grc]
|
||||
@@ -22,6 +23,7 @@
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.datafy :refer [datafy]]))
|
||||
|
||||
@@ -987,7 +989,7 @@
|
||||
[changes tokens-lib]
|
||||
(assert-library! changes)
|
||||
(let [library-data (::library-data (meta changes))
|
||||
prev-tokens-lib (get library-data :tokens-lib)]
|
||||
prev-tokens-lib (cfo/get-tokens-lib library-data)]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :set-tokens-lib :tokens-lib tokens-lib})
|
||||
(update :undo-changes conj {:type :set-tokens-lib :tokens-lib prev-tokens-lib})
|
||||
@@ -996,7 +998,7 @@
|
||||
(defn set-token [changes set-id token-id token]
|
||||
(assert-library! changes)
|
||||
(let [library-data (::library-data (meta changes))
|
||||
prev-token (some-> (get library-data :tokens-lib)
|
||||
prev-token (some-> (cfo/get-tokens-lib library-data)
|
||||
(ctob/get-token set-id token-id))]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :set-token
|
||||
@@ -1013,7 +1015,7 @@
|
||||
[changes id token-set]
|
||||
(assert-library! changes)
|
||||
(let [library-data (::library-data (meta changes))
|
||||
prev-token-set (some-> (get library-data :tokens-lib)
|
||||
prev-token-set (some-> (cfo/get-tokens-lib library-data)
|
||||
(ctob/get-set id))]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :set-token-set
|
||||
@@ -1028,7 +1030,7 @@
|
||||
[changes id new-name]
|
||||
(assert-library! changes)
|
||||
(let [library-data (::library-data (meta changes))
|
||||
prev-token-set (some-> (get library-data :tokens-lib)
|
||||
prev-token-set (some-> (cfo/get-tokens-lib library-data)
|
||||
(ctob/get-set id))]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :set-token-set
|
||||
@@ -1042,7 +1044,7 @@
|
||||
(defn set-token-theme [changes id theme]
|
||||
(assert-library! changes)
|
||||
(let [library-data (::library-data (meta changes))
|
||||
prev-theme (some-> (get library-data :tokens-lib)
|
||||
prev-theme (some-> (cfo/get-tokens-lib library-data)
|
||||
(ctob/get-theme id))]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :set-token-theme
|
||||
@@ -1053,17 +1055,21 @@
|
||||
:attrs (datafy prev-theme)})
|
||||
(apply-changes-local))))
|
||||
|
||||
(defn set-active-token-themes
|
||||
[changes active-theme-paths]
|
||||
(assert-library! changes)
|
||||
(let [library-data (::library-data (meta changes))
|
||||
prev-active-theme-paths (d/nilv (some-> (get library-data :tokens-lib)
|
||||
(ctob/get-active-theme-paths))
|
||||
#{})]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :set-active-token-themes :theme-paths active-theme-paths})
|
||||
(update :undo-changes conj {:type :set-active-token-themes :theme-paths prev-active-theme-paths})
|
||||
(apply-changes-local))))
|
||||
(defn set-tokens-status
|
||||
([changes tokens-status]
|
||||
(assert-library! changes)
|
||||
(assert (or (ctos/tokens-status? tokens-status)
|
||||
(nil? tokens-status)))
|
||||
(let [theme-ids (if tokens-status (ctos/get-active-theme-ids tokens-status) #{})
|
||||
set-ids (if tokens-status (ctos/get-active-set-ids tokens-status) #{})
|
||||
library-data (::library-data (meta changes))
|
||||
prev-tokens-status (cfo/get-tokens-status library-data)
|
||||
prev-theme-ids (if prev-tokens-status (ctos/get-active-theme-ids prev-tokens-status) #{})
|
||||
prev-set-ids (if prev-tokens-status (ctos/get-active-set-ids prev-tokens-status) #{})]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :set-tokens-status :theme-ids theme-ids :set-ids set-ids})
|
||||
(update :undo-changes conj {:type :set-tokens-status :theme-ids prev-theme-ids :set-ids prev-set-ids})
|
||||
(apply-changes-local)))))
|
||||
|
||||
(defn rename-token-set-group
|
||||
[changes set-group-path set-group-fname]
|
||||
@@ -1117,6 +1123,21 @@
|
||||
:base-font-size previous-font-size})
|
||||
(apply-changes-local))))
|
||||
|
||||
(defn set-tokens-source
|
||||
[changes library-id]
|
||||
(assert-library! changes)
|
||||
(let [library-data (::library-data (meta changes))
|
||||
file-id (:id library-data)
|
||||
prev-val (cfo/get-tokens-source library-data)]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :set-tokens-source
|
||||
:file-id file-id
|
||||
:library-id library-id})
|
||||
(update :undo-changes conj {:type :set-tokens-source
|
||||
:file-id file-id
|
||||
:library-id prev-val})
|
||||
(apply-changes-local))))
|
||||
|
||||
;; Misc changes
|
||||
|
||||
(defn reorder-children
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
[app.common.files.comp-processors :as cfcp]
|
||||
[app.common.files.defaults :as cfd]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.rect :as grc]
|
||||
@@ -1998,6 +1999,13 @@
|
||||
(update :pages-index d/update-vals update-container)
|
||||
(d/update-when :components d/update-vals update-container))))
|
||||
|
||||
(defmethod migrate-data "0027-separate-tokens-status"
|
||||
[data _]
|
||||
(if-let [tokens-lib (:tokens-lib data)]
|
||||
(assoc data :tokens-status
|
||||
(cfo/make-tokens-status-from-lib tokens-lib))
|
||||
data))
|
||||
|
||||
(def available-migrations
|
||||
(into (d/ordered-set)
|
||||
["legacy-2"
|
||||
@@ -2081,4 +2089,5 @@
|
||||
"0023-repair-token-themes-with-inexistent-sets"
|
||||
"0024b-fix-stroke-cap-placement"
|
||||
"0025-repair-empty-text-content"
|
||||
"0026-fix-svg-raw-shapes-uuids"]))
|
||||
"0026-fix-svg-raw-shapes-uuids"
|
||||
"0027-separate-tokens-status"]))
|
||||
@@ -9,6 +9,7 @@
|
||||
[app.common.data :as d]
|
||||
[app.common.files.changes-builder :as pcb]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.logging :as log]
|
||||
[app.common.path-names :as cpn]
|
||||
[app.common.types.component :as ctk]
|
||||
@@ -783,6 +784,16 @@
|
||||
(pcb/with-file-data file-data)
|
||||
(pcb/update-shapes [(:id shape)] repair-shape))))
|
||||
|
||||
(defmethod repair-error :missing-tokens-status
|
||||
[_ _ file-data _]
|
||||
(let [tokens-lib (cfo/get-tokens-lib file-data)
|
||||
tokens-status (cfo/make-tokens-status-from-lib tokens-lib)]
|
||||
(log/debug :hint "repairing shape :tokens-status-missing")
|
||||
(log/debug :hint " -> add a tokens-status generated from the library")
|
||||
(-> (pcb/empty-changes nil)
|
||||
(pcb/with-library-data file-data)
|
||||
(pcb/set-tokens-status tokens-status))))
|
||||
|
||||
(defmethod repair-error :default
|
||||
[_ error file _]
|
||||
(log/error :hint "Unknown error code, don't know how to repair" :code (:code error))
|
||||
|
||||
@@ -9,13 +9,18 @@
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.i18n :refer [tr]]
|
||||
[app.common.logging :as log]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[clojure.set :as set]
|
||||
[cuerdas.core :as str]
|
||||
[malli.core :as m]))
|
||||
|
||||
;; Change this to :info :debug or :trace to debug this module, or :warn to reset to default
|
||||
(log/set-level! :warn)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; HIGH LEVEL SCHEMAS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -165,7 +170,8 @@
|
||||
(some (fn [[token-name _]]
|
||||
(not (ctob/token-name-path-exists? token-name tokens-tree)))
|
||||
new-tokens))))]])
|
||||
(defn find-refs [value]
|
||||
|
||||
(defn- find-refs [value]
|
||||
(cond
|
||||
(string? value)
|
||||
(cto/find-token-value-references value)
|
||||
@@ -344,6 +350,8 @@
|
||||
;; HELPERS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Token
|
||||
|
||||
(def parseable-token-value-regexp
|
||||
"Regexp that can be used to parse a number value out of resolved token value.
|
||||
This regexp also trims whitespace around the value."
|
||||
@@ -415,3 +423,318 @@
|
||||
;; FIXME: this should be precalculated ?
|
||||
(defn is-reference? [token]
|
||||
(str/includes? (:value token) "{"))
|
||||
|
||||
;; Tokens lib and status in file data
|
||||
|
||||
(defn make-tokens-status-from-lib
|
||||
"Make a TokensStatus from a TokensLib, activating the themes and sets
|
||||
marked as active in the library (to migrate from legacy files)."
|
||||
[tokens-lib]
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(let [active-theme-paths (ctob/get-legacy-active-themes tokens-lib)
|
||||
active-theme-ids (into #{}
|
||||
(comp (map #(ctob/get-theme-by-path tokens-lib %))
|
||||
(remove nil?)
|
||||
(map ctob/get-id)
|
||||
(filter #(not= % ctob/hidden-theme-id)))
|
||||
active-theme-paths)
|
||||
;; Get active set names from the active themes
|
||||
active-set-names (into #{}
|
||||
(comp (filter #(and (ctob/token-theme? %)
|
||||
(contains? active-theme-paths (ctob/get-theme-path %))))
|
||||
(mapcat :sets))
|
||||
(ctob/get-themes tokens-lib))
|
||||
active-set-ids (into #{}
|
||||
(comp (map #(ctob/get-set-by-name tokens-lib %))
|
||||
(remove nil?)
|
||||
(map ctob/get-id))
|
||||
active-set-names)]
|
||||
(ctos/make-tokens-status :active-theme-ids active-theme-ids
|
||||
:active-set-ids active-set-ids)))
|
||||
|
||||
(defn ensure-tokens-lib
|
||||
"Ensure file-data has a :tokens-lib or :tokens-source, and also a :tokens-status, creating them if necessary."
|
||||
[file-data]
|
||||
(cond-> file-data
|
||||
(nil? (:tokens-source file-data))
|
||||
(update :tokens-lib #(or % (ctob/make-tokens-lib)))
|
||||
|
||||
:always
|
||||
(update :tokens-status #(or % (ctos/make-tokens-status)))))
|
||||
|
||||
(defn ensure-tokens-status
|
||||
"Ensure file-data has a :tokens-status, creating it empty if necessary."
|
||||
[file-data]
|
||||
(cond-> file-data
|
||||
(nil? (:tokens-status file-data))
|
||||
(update :tokens-status #(or % (ctos/make-tokens-status)))))
|
||||
|
||||
(defn get-tokens-source
|
||||
"Return the current value of :tokens-source attribute."
|
||||
[file-data]
|
||||
(:tokens-source file-data))
|
||||
|
||||
(defn get-effective-tokens-source
|
||||
"Return the current tokens source of the file. When there is no explicit
|
||||
:tokens-source attribute, the source is the file itself."
|
||||
[file-data]
|
||||
(or (:tokens-source file-data) (:id file-data)))
|
||||
|
||||
(defn set-tokens-source
|
||||
[file-data tokens-source]
|
||||
(assert (or (nil? tokens-source) (uuid? tokens-source)) "expected nil or valid uuid")
|
||||
(if (nil? tokens-source)
|
||||
(dissoc file-data :tokens-source)
|
||||
(assoc file-data :tokens-source tokens-source)))
|
||||
|
||||
(defn effective-tokens-source?
|
||||
"Returns true if the given id is the current tokens source of the file-data."
|
||||
[file-data id]
|
||||
(assert (uuid? id) "expected valid uuid")
|
||||
(= (get-effective-tokens-source file-data) id))
|
||||
|
||||
(defn has-own-tokens?
|
||||
"Returns true if the file-data contains a tokens-library itself and the library
|
||||
contains some tokens. Note that it still may be true even if the tokens source
|
||||
is external (in this case the own library is inactive, but still exists)."
|
||||
[file-data]
|
||||
(let [tokens-lib (:tokens-lib file-data)]
|
||||
(and (some? tokens-lib)
|
||||
(not (ctob/empty-lib? tokens-lib)))))
|
||||
|
||||
(defn tokens-provider?
|
||||
"Returns true if the file MAY become a tokens source. This is if the file has tokens and has
|
||||
not configured another tokens source."
|
||||
[file-data]
|
||||
(and (has-own-tokens? file-data)
|
||||
(effective-tokens-source? file-data (:id file-data))))
|
||||
|
||||
(defn editable-tokens?
|
||||
"Returns true if the file-data is its own tokens source."
|
||||
[file-data]
|
||||
(effective-tokens-source? file-data (:id file-data)))
|
||||
|
||||
(defn get-tokens-lib
|
||||
[file-data]
|
||||
(:tokens-lib file-data))
|
||||
|
||||
(defn get-tokens-status
|
||||
[file-data]
|
||||
(:tokens-status file-data))
|
||||
|
||||
(defn update-tokens-lib
|
||||
"Update the tokens-lib inside file-data through a callback function.
|
||||
The function will receive the tokens lib and the rest of args."
|
||||
[file-data f & args]
|
||||
(d/update-when file-data :tokens-lib #(apply f % args)))
|
||||
|
||||
(defn update-tokens-status
|
||||
"Update the tokens-status inside file-data through a callback function.
|
||||
The function will receive the tokens status and the rest of args."
|
||||
[file-data f & args]
|
||||
(d/update-when file-data :tokens-status #(apply f % args)))
|
||||
|
||||
(defn set-tokens-status
|
||||
"Replace the tokens-status inside file-data with a new one."
|
||||
[file-data tokens-status]
|
||||
(assert (or (nil? tokens-status) (ctos/tokens-status? tokens-status)) "expected valid tokens-status or nil")
|
||||
(assoc file-data :tokens-status tokens-status))
|
||||
|
||||
;; Tokens status with tokens lib
|
||||
|
||||
(defn- calculate-active-sets
|
||||
"Obtain the set-ids that needs to be active for a particular set of theme ids"
|
||||
[active-theme-ids tokens-lib]
|
||||
(let [active-themes (map #(ctob/get-theme tokens-lib %) active-theme-ids)
|
||||
active-set-names (reduce set/union #{} (map :sets active-themes))
|
||||
active-sets (map #(ctob/get-set-by-name tokens-lib %) active-set-names)
|
||||
active-set-ids (into #{} (map ctob/get-id) active-sets)]
|
||||
active-set-ids))
|
||||
|
||||
(defn get-active-themes
|
||||
"Return an ordered sequence of active themes"
|
||||
[tokens-status tokens-lib]
|
||||
(assert (ctos/tokens-status? tokens-status) "expected valid tokens-status")
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(->> (ctob/get-themes tokens-lib)
|
||||
(filter #(ctos/theme-active? tokens-status (ctob/get-id %)))))
|
||||
|
||||
(defn activate-theme
|
||||
"Activate a theme and all its sets. Deactivate any other theme in the same group."
|
||||
[tokens-status tokens-lib id]
|
||||
(assert (ctos/tokens-status? tokens-status) "expected valid tokens-status")
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(assert (uuid? id) "expected valid theme id")
|
||||
(if-not (ctos/theme-active? tokens-status id)
|
||||
(if-let [theme (ctob/get-theme tokens-lib id)]
|
||||
(let [group-themes (into #{} (ctob/get-themes-in-group tokens-lib (:group theme)))
|
||||
active-theme-ids (ctos/get-active-theme-ids tokens-status)
|
||||
active-theme-ids' (-> (set/difference active-theme-ids group-themes)
|
||||
(conj id))
|
||||
active-set-ids' (calculate-active-sets active-theme-ids' tokens-lib)]
|
||||
(ctos/set-tokens-status tokens-status active-theme-ids' active-set-ids'))
|
||||
tokens-status)
|
||||
tokens-status))
|
||||
|
||||
(defn deactivate-theme
|
||||
"Deactivate a theme and all its sets that are not in other active themes"
|
||||
[tokens-status tokens-lib id]
|
||||
(assert (ctos/tokens-status? tokens-status) "expected valid tokens-status")
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(assert (uuid? id) "expected valid theme id")
|
||||
(if (ctos/theme-active? tokens-status id)
|
||||
(let [active-theme-ids' (disj (ctos/get-active-theme-ids tokens-status) id)
|
||||
active-set-ids' (calculate-active-sets active-theme-ids' tokens-lib)]
|
||||
(ctos/set-tokens-status tokens-status active-theme-ids' active-set-ids'))
|
||||
tokens-status))
|
||||
|
||||
(defn toggle-theme-active
|
||||
"Toggle a theme's active state and update active sets accordingly."
|
||||
[tokens-status tokens-lib id]
|
||||
(if (ctos/theme-active? tokens-status id)
|
||||
(deactivate-theme tokens-status tokens-lib id)
|
||||
(activate-theme tokens-status tokens-lib id)))
|
||||
|
||||
(defn set-theme-active
|
||||
"Set a theme's active state and update active sets accordingly."
|
||||
[tokens-status tokens-lib id active?]
|
||||
(if active?
|
||||
(activate-theme tokens-status tokens-lib id)
|
||||
(deactivate-theme tokens-status tokens-lib id)))
|
||||
|
||||
(defn get-active-sets
|
||||
"Return a clojure set of the active sets, resolved from TokensStatus + TokensLib."
|
||||
[tokens-status tokens-lib]
|
||||
(assert (ctos/tokens-status? tokens-status) "expected valid tokens-status")
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(let [active-set-ids (ctos/get-active-set-ids tokens-status)]
|
||||
(into #{}
|
||||
(comp (map #(ctob/get-set tokens-lib %))
|
||||
(filter some?))
|
||||
active-set-ids)))
|
||||
|
||||
(defn set-set-active
|
||||
"Set directly a set's active state and deactivate all themes."
|
||||
[tokens-status tokens-lib id active?]
|
||||
(assert (ctos/tokens-status? tokens-status) "expected valid tokens-status")
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(assert (uuid? id) "expected valid set id")
|
||||
(if (and (ctob/get-set tokens-lib id)
|
||||
(not= active? (ctos/set-active? tokens-status id)))
|
||||
(let [active-set-ids (ctos/get-active-set-ids tokens-status)
|
||||
active-set-ids' (if active?
|
||||
(conj active-set-ids id)
|
||||
(disj active-set-ids id))]
|
||||
(ctos/set-tokens-status tokens-status #{} active-set-ids'))
|
||||
tokens-status))
|
||||
|
||||
(defn activate-set
|
||||
"Activate directly a set, and deactivate all themes."
|
||||
[tokens-status tokens-lib id]
|
||||
(set-set-active tokens-status tokens-lib id true))
|
||||
|
||||
(defn deactivate-set
|
||||
"Deactivate directly a set, and deactivate all themes."
|
||||
[tokens-status tokens-lib id]
|
||||
(set-set-active tokens-status tokens-lib id false))
|
||||
|
||||
(defn toggle-set-active
|
||||
"Toggle a set's active state and deactivate all themes."
|
||||
[tokens-status tokens-lib id]
|
||||
(set-set-active tokens-status tokens-lib id (not (ctos/set-active? tokens-status id))))
|
||||
|
||||
(defn sets-at-path-all-active?
|
||||
"Check active state of sets at a group path.
|
||||
Returns :none, :all, or :partial."
|
||||
[tokens-status tokens-lib group-path]
|
||||
(assert (ctos/tokens-status? tokens-status) "expected valid tokens-status")
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(assert (vector? group-path) "expected valid group path")
|
||||
(let [active-set-ids (ctos/get-active-set-ids tokens-status)
|
||||
path-set-ids (into #{}
|
||||
(map ctob/get-id)
|
||||
(ctob/get-sets-at-path tokens-lib group-path))]
|
||||
(if (seq active-set-ids)
|
||||
(let [difference (set/difference path-set-ids active-set-ids)]
|
||||
(cond
|
||||
(empty? difference) :all
|
||||
(seq (set/intersection path-set-ids active-set-ids)) :partial
|
||||
:else :none))
|
||||
:none)))
|
||||
|
||||
(defn toggle-set-group-active
|
||||
"Toggle the active state of all sets at a group path, and deactivate all themes.
|
||||
If all sets are active, deactivate all. If none or some are active, activate all."
|
||||
[tokens-status tokens-lib group-path]
|
||||
(let [all-active? (sets-at-path-all-active? tokens-status tokens-lib group-path)
|
||||
|
||||
sets-at-path (ctob/get-sets-at-path tokens-lib group-path)
|
||||
set-ids-at-path (into #{} (map ctob/get-id) sets-at-path)
|
||||
|
||||
active-set-ids (ctos/get-active-set-ids tokens-status)
|
||||
active-set-ids' (if (contains? #{:all :partial} all-active?)
|
||||
(set/difference active-set-ids set-ids-at-path)
|
||||
(set/union active-set-ids set-ids-at-path))]
|
||||
|
||||
(if (not= active-set-ids active-set-ids')
|
||||
(ctos/set-tokens-status tokens-status #{} active-set-ids')
|
||||
tokens-status)))
|
||||
|
||||
(defn get-tokens-in-active-sets
|
||||
"Get merged tokens from all active sets, in set order."
|
||||
[tokens-status tokens-lib]
|
||||
(assert (ctos/tokens-status? tokens-status) "expected valid tokens-status")
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(let [active-set-ids (ctos/get-active-set-ids tokens-status)
|
||||
all-set-ids (map ctob/get-id (ctob/get-sets tokens-lib))
|
||||
ordered-active (filter active-set-ids all-set-ids)]
|
||||
(reduce (fn [tokens set-id]
|
||||
(merge tokens (ctob/get-tokens tokens-lib set-id)))
|
||||
(d/ordered-map)
|
||||
ordered-active)))
|
||||
|
||||
(defn get-tokens-in-active-sets-force
|
||||
"Same as get-tokens-in-active-sets but force-including a set by id."
|
||||
[tokens-status tokens-lib force-set-id]
|
||||
(assert (ctos/tokens-status? tokens-status) "expected valid tokens-status")
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(assert (uuid? force-set-id) "expected valid set id")
|
||||
(let [active-set-ids (ctos/get-active-set-ids tokens-status)
|
||||
all-set-ids (map ctob/get-id (ctob/get-sets tokens-lib))
|
||||
ordered-active (cond-> (filter active-set-ids all-set-ids)
|
||||
(some? force-set-id)
|
||||
(conj force-set-id))]
|
||||
(reduce (fn [tokens set-id]
|
||||
(let [set (ctob/get-set tokens-lib set-id)]
|
||||
(if set
|
||||
(merge tokens (ctob/get-tokens- set))
|
||||
tokens)))
|
||||
(d/ordered-map)
|
||||
ordered-active)))
|
||||
|
||||
(defn sync-tokens-status-with-lib
|
||||
"Synchronizes tokens status with the current tokens lib:
|
||||
- Delete any theme or set that no longer exists in the lib.
|
||||
- Recalculate the list of active sets from the new themes."
|
||||
[tokens-status tokens-lib]
|
||||
(assert (ctos/tokens-status? tokens-status) "expected valid tokens-status")
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(let [active-theme-ids (ctos/get-active-theme-ids tokens-status)
|
||||
valid-theme-ids (into #{}
|
||||
(filter #(some? (ctob/get-theme tokens-lib %)))
|
||||
active-theme-ids)
|
||||
active-set-ids (ctos/get-active-set-ids tokens-status)
|
||||
valid-set-ids (if (empty? valid-theme-ids)
|
||||
(into #{}
|
||||
(filter #(some? (ctob/get-set tokens-lib %)))
|
||||
active-set-ids)
|
||||
(calculate-active-sets valid-theme-ids tokens-lib))]
|
||||
|
||||
(if (or (not= active-theme-ids valid-theme-ids)
|
||||
(not= active-set-ids valid-set-ids))
|
||||
(do
|
||||
(log/info :hint "syncing token status"
|
||||
:removed-themes (count (set/difference active-theme-ids valid-theme-ids))
|
||||
:removed-sets (count (set/difference active-set-ids valid-set-ids)))
|
||||
(ctos/set-tokens-status tokens-status valid-theme-ids valid-set-ids))
|
||||
tokens-status)))
|
||||
@@ -73,7 +73,8 @@
|
||||
:variant-main-bad-name
|
||||
:variant-main-bad-variant-name
|
||||
:variant-component-bad-name
|
||||
:variant-component-bad-id})
|
||||
:variant-component-bad-id
|
||||
:missing-tokens-status})
|
||||
|
||||
(def ^:private schema:error
|
||||
[:map {:title "ValidationError"}
|
||||
@@ -816,6 +817,17 @@
|
||||
(transient [])
|
||||
objects)))
|
||||
|
||||
(defn check-tokens
|
||||
"Check tokens in the file. The internal structure should be correct because
|
||||
of the schemas and protocol functions. But we need to check for the case that
|
||||
the tokens-status is missing due to a migration or import bug."
|
||||
[{:keys [data] :as file}]
|
||||
(when (and (some? (:tokens-lib data))
|
||||
(nil? (:tokens-status data)))
|
||||
(report-error :missing-tokens-status
|
||||
"Tokens library is present but tokens-status is missing"
|
||||
nil file nil)))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; PUBLIC API: VALIDATION FUNCTIONS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -853,6 +865,8 @@
|
||||
nil
|
||||
(:components data))
|
||||
|
||||
(check-tokens file)
|
||||
|
||||
(-> *errors* deref not-empty))))
|
||||
|
||||
(defn validate-shape
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
:token-tokenscript
|
||||
:token-import-from-library
|
||||
:token-typography-row
|
||||
:token-lib-sync
|
||||
|
||||
;; Only for developtment.
|
||||
:transit-readable-response
|
||||
|
||||
@@ -6,84 +6,31 @@
|
||||
|
||||
(ns app.common.logic.tokens
|
||||
(:require
|
||||
[app.common.files.changes :as ch]
|
||||
[app.common.files.changes-builder :as pcb]
|
||||
[app.common.types.tokens-lib :as ctob]))
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]))
|
||||
|
||||
(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-theme-fn`.
|
||||
;; Tokens source
|
||||
|
||||
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-theme-fn]
|
||||
(let [active-token-set-names (ctob/get-active-themes-set-names tokens-lib)
|
||||
|
||||
hidden-theme (ctob/get-hidden-theme tokens-lib)
|
||||
hidden-theme' (-> (some-> hidden-theme
|
||||
(ctob/set-sets active-token-set-names))
|
||||
(update-theme-fn))]
|
||||
(defn generate-set-tokens-source
|
||||
"Create changes for setting the tokens source of a file to `library`,
|
||||
copying the library's tokens status. If the library is nil, the tokens source
|
||||
is removed and the tokens status is cleared."
|
||||
[changes library]
|
||||
(let [library-id (:id library)
|
||||
library-tokens-status (if library
|
||||
(-> library ctf/file-data cfo/get-tokens-status)
|
||||
(ctos/make-tokens-status))]
|
||||
(-> changes
|
||||
(pcb/set-active-token-themes #{(ctob/get-theme-path hidden-theme')})
|
||||
(pcb/set-token-theme (ctob/get-id hidden-theme)
|
||||
hidden-theme'))))
|
||||
(pcb/set-tokens-source library-id)
|
||||
(pcb/set-tokens-status library-tokens-status))))
|
||||
|
||||
(defn generate-set-enabled-token-set
|
||||
"Enable or disable a token set at `set-name` in `tokens-lib` without modifying a user theme."
|
||||
[changes tokens-lib set-name enabled?]
|
||||
(if enabled?
|
||||
(generate-update-active-sets changes tokens-lib #(ctob/enable-set % set-name))
|
||||
(generate-update-active-sets changes tokens-lib #(ctob/disable-set % set-name))))
|
||||
;; Tokens lib
|
||||
|
||||
(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-update-active-token-theme
|
||||
"Change the active state of a theme in `tokens-lib`. If after the change there is
|
||||
any active theme other than the hidden one, deactivate the hidden theme."
|
||||
[changes tokens-lib update-fn]
|
||||
(let [active-token-themes (some-> tokens-lib
|
||||
(update-fn)
|
||||
(ctob/get-active-theme-paths))
|
||||
active-token-themes' (if (= active-token-themes #{ctob/hidden-theme-path})
|
||||
active-token-themes
|
||||
(disj active-token-themes ctob/hidden-theme-path))]
|
||||
(pcb/set-active-token-themes changes active-token-themes')))
|
||||
|
||||
(defn generate-set-active-token-theme
|
||||
"Activate or deactivate a token theme in `tokens-lib`."
|
||||
[changes tokens-lib id active?]
|
||||
(if active?
|
||||
(generate-update-active-token-theme changes tokens-lib
|
||||
#(ctob/activate-theme % id))
|
||||
(generate-update-active-token-theme changes tokens-lib
|
||||
#(ctob/deactivate-theme % id))))
|
||||
|
||||
(defn generate-toggle-token-theme
|
||||
"Toggle the active state of a token theme in `tokens-lib`."
|
||||
[changes tokens-lib id]
|
||||
(generate-update-active-token-theme changes tokens-lib
|
||||
#(ctob/toggle-theme-active % id)))
|
||||
|
||||
(defn toggle-token-set-group
|
||||
"Toggle a token set group at `group-path` in `tokens-lib` for a `tokens-lib-theme`."
|
||||
[group-path tokens-lib tokens-lib-theme]
|
||||
(let [deactivate? (contains? #{:all :partial} (ctob/sets-at-path-all-active? tokens-lib group-path))
|
||||
sets-names (->> (ctob/get-sets-at-path tokens-lib group-path)
|
||||
(map ctob/get-name)
|
||||
(into #{}))]
|
||||
(if deactivate?
|
||||
(ctob/disable-sets tokens-lib-theme sets-names)
|
||||
(ctob/enable-sets tokens-lib-theme sets-names))))
|
||||
|
||||
(defn generate-toggle-token-set-group
|
||||
"Toggle a token set group at `group-path` in `tokens-lib` without modifying a user theme."
|
||||
[changes tokens-lib group-path]
|
||||
(generate-update-active-sets changes tokens-lib #(toggle-token-set-group group-path tokens-lib %)))
|
||||
|
||||
(defn vec-starts-with? [v1 v2]
|
||||
(defn- vec-starts-with? [v1 v2]
|
||||
(= (subvec v1 0 (min (count v1) (count v2))) v2))
|
||||
|
||||
(defn- calculate-move-token-set-or-set-group
|
||||
@@ -155,27 +102,109 @@
|
||||
prev-before (assoc :prev-before-path (:path prev-before)
|
||||
:prev-before-group? (:group? prev-before))))))
|
||||
|
||||
(declare generate-sync-tokens-status-with-lib)
|
||||
|
||||
(defn generate-update-token-theme
|
||||
"Create changes for updating a token theme and regenerating the activation status
|
||||
of the sets inside it."
|
||||
[changes token-theme]
|
||||
(let [changes' (pcb/set-token-theme changes (ctob/get-id token-theme) token-theme)
|
||||
data (pcb/get-library-data changes')
|
||||
tokens-status (cfo/get-tokens-status data)
|
||||
tokens-lib' (-> data
|
||||
(ch/process-changes (:redo-changes changes'))
|
||||
(cfo/get-tokens-lib))]
|
||||
(generate-sync-tokens-status-with-lib changes'
|
||||
tokens-status
|
||||
tokens-lib')))
|
||||
|
||||
(defn generate-move-token-set
|
||||
"Create changes for dropping a token set or token set.
|
||||
Throws for impossible moves."
|
||||
[changes tokens-lib params]
|
||||
(if-let [params (calculate-move-token-set-or-set-group tokens-lib params)]
|
||||
(pcb/move-token-set changes params)
|
||||
(if tokens-lib
|
||||
(if-let [params (calculate-move-token-set-or-set-group tokens-lib params)]
|
||||
(pcb/move-token-set changes params)
|
||||
changes)
|
||||
changes))
|
||||
|
||||
(defn generate-move-token-set-group
|
||||
"Create changes for dropping a token set or token set group.
|
||||
Throws for impossible moves"
|
||||
[changes tokens-lib params]
|
||||
(if-let [params (calculate-move-token-set-or-set-group tokens-lib params)]
|
||||
(pcb/move-token-set-group changes params)
|
||||
(if tokens-lib
|
||||
(if-let [params (calculate-move-token-set-or-set-group tokens-lib params)]
|
||||
(pcb/move-token-set-group changes params)
|
||||
changes)
|
||||
changes))
|
||||
|
||||
(defn generate-delete-token-set-group
|
||||
"Create changes for deleting a token set group."
|
||||
[changes tokens-lib path]
|
||||
(let [sets (ctob/get-sets-at-path tokens-lib path)]
|
||||
(reduce (fn [changes set]
|
||||
(pcb/set-token-set changes (ctob/get-id set) nil))
|
||||
changes
|
||||
sets)))
|
||||
(if tokens-lib
|
||||
(let [sets (ctob/get-sets-at-path tokens-lib path)]
|
||||
(reduce (fn [changes set]
|
||||
(pcb/set-token-set changes (ctob/get-id set) nil))
|
||||
changes
|
||||
sets))
|
||||
changes))
|
||||
|
||||
;; Tokens Status
|
||||
|
||||
(defn- update-tokens-status
|
||||
[changes tokens-status update-fn & args]
|
||||
(if tokens-status
|
||||
(let [tokens-status' (apply update-fn tokens-status args)]
|
||||
(if (not= tokens-status tokens-status')
|
||||
(pcb/set-tokens-status changes tokens-status')
|
||||
changes))
|
||||
changes))
|
||||
|
||||
(defn generate-activate-theme
|
||||
[changes tokens-status tokens-lib id]
|
||||
(if tokens-lib
|
||||
(update-tokens-status changes tokens-status cfo/activate-theme tokens-lib id)
|
||||
changes))
|
||||
|
||||
(defn generate-deactivate-theme
|
||||
[changes tokens-status tokens-lib id]
|
||||
(if tokens-lib
|
||||
(update-tokens-status changes tokens-status cfo/deactivate-theme tokens-lib id)
|
||||
changes))
|
||||
|
||||
(defn generate-set-theme-status
|
||||
[changes tokens-status tokens-lib id active?]
|
||||
(if tokens-lib
|
||||
(update-tokens-status changes tokens-status cfo/set-theme-active tokens-lib id active?)
|
||||
changes))
|
||||
|
||||
(defn generate-toggle-theme
|
||||
[changes tokens-status tokens-lib id]
|
||||
(if tokens-lib
|
||||
(update-tokens-status changes tokens-status cfo/toggle-theme-active tokens-lib id)
|
||||
changes))
|
||||
|
||||
(defn generate-set-enabled-token-set
|
||||
[changes tokens-status tokens-lib id enabled?]
|
||||
(if tokens-lib
|
||||
(update-tokens-status changes tokens-status cfo/set-set-active tokens-lib id enabled?)
|
||||
changes))
|
||||
|
||||
(defn generate-toggle-token-set
|
||||
[changes tokens-status tokens-lib id]
|
||||
(if tokens-lib
|
||||
(update-tokens-status changes tokens-status cfo/toggle-set-active tokens-lib id)
|
||||
changes))
|
||||
|
||||
(defn generate-toggle-token-set-group
|
||||
[changes tokens-status tokens-lib group-path]
|
||||
(if tokens-lib
|
||||
(update-tokens-status changes tokens-status cfo/toggle-set-group-active tokens-lib group-path)
|
||||
changes))
|
||||
|
||||
(defn generate-sync-tokens-status-with-lib
|
||||
[changes tokens-status tokens-lib]
|
||||
(if tokens-lib
|
||||
(update-tokens-status changes tokens-status cfo/sync-tokens-status-with-lib tokens-lib)
|
||||
changes))
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
(ns app.common.test-helpers.tokens
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.test-helpers.files :as thf]
|
||||
[app.common.test-helpers.shapes :as ths]
|
||||
[app.common.types.container :as ctn]
|
||||
@@ -15,19 +16,55 @@
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.types.text :as ctt]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.tokens-lib :as ctob]))
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]))
|
||||
|
||||
(defn get-tokens-source
|
||||
[file]
|
||||
(-> file (ctf/file-data) (cfo/get-tokens-source)))
|
||||
|
||||
(defn get-tokens-lib
|
||||
[file]
|
||||
(:tokens-lib (ctf/file-data file)))
|
||||
(-> file (ctf/file-data) (cfo/get-tokens-lib)))
|
||||
|
||||
(defn get-tokens-status
|
||||
[file]
|
||||
(-> file (ctf/file-data) (cfo/get-tokens-status)))
|
||||
|
||||
(defn add-tokens-lib
|
||||
"Ensure the file has a tokens-lib and a tokens-status in its data, creating empty ones if not"
|
||||
[file]
|
||||
(ctf/update-file-data file #(update % :tokens-lib ctob/ensure-tokens-lib)))
|
||||
(ctf/update-file-data file cfo/ensure-tokens-lib))
|
||||
|
||||
(defn update-tokens-lib
|
||||
"Modify the tokens-lib of a file "
|
||||
[file f]
|
||||
(ctf/update-file-data file #(update % :tokens-lib f)))
|
||||
(ctf/update-file-data file #(cfo/update-tokens-lib % f)))
|
||||
|
||||
(defn update-tokens-status
|
||||
[file f]
|
||||
(ctf/update-file-data file #(cfo/update-tokens-status % f)))
|
||||
|
||||
(defn set-tokens-source
|
||||
[file library]
|
||||
(let [library-id (:id library)
|
||||
library-tokens-status (if library
|
||||
(-> library ctf/file-data cfo/get-tokens-status)
|
||||
(ctos/make-tokens-status))]
|
||||
(ctf/update-file-data
|
||||
file
|
||||
(fn [data]
|
||||
(-> data
|
||||
(cfo/set-tokens-source library-id)
|
||||
(cfo/set-tokens-status library-tokens-status))))))
|
||||
|
||||
(defn sample-file-with-tokens
|
||||
[& {:keys [lib-fn status-fn file-id] :as params
|
||||
:or {lib-fn identity status-fn identity file-id :file1}}]
|
||||
(-> (thf/sample-file file-id (dissoc params :lib-fn :status-fn))
|
||||
(add-tokens-lib)
|
||||
(update-tokens-lib lib-fn)
|
||||
(update-tokens-status status-fn)))
|
||||
|
||||
(defn get-token
|
||||
[file set-id token-id]
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
[:components {:optional true} schema:components]
|
||||
[:typographies {:optional true} schema:typographies]
|
||||
[:plugin-data {:optional true} schema:plugin-data]
|
||||
[:tokens-source {:optional true} ::sm/uuid] ;; Forward-compat: UUID of external library containing tokens-lib (full support in follow-up PR)
|
||||
[:tokens-source {:optional true} ::sm/uuid] ;; The tokens-lib may be in this file or in an external library
|
||||
[:tokens-lib {:optional true} ctob/schema:tokens-lib]
|
||||
[:tokens-status {:optional true} ctos/schema:tokens-status]])
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
[app.common.time :as ct]
|
||||
[app.common.transit :as t]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.core.protocols :as cp]
|
||||
[clojure.datafy :refer [datafy]]
|
||||
@@ -479,11 +480,6 @@
|
||||
[path]
|
||||
(mapv add-set-path-group-prefix path))
|
||||
|
||||
(defn- set-group-path->set-group-prefixed-path-str
|
||||
[path]
|
||||
(-> (set-group-path->set-group-prefixed-path path)
|
||||
(join-set-path)))
|
||||
|
||||
(defn add-set-group-prefix [group-path]
|
||||
(str set-group-prefix group-path))
|
||||
|
||||
@@ -547,7 +543,7 @@
|
||||
"Get an ordered sequence of all sets names in the library")
|
||||
(get-set-tree [_]
|
||||
"Get a nested tree of all sets in the library")
|
||||
(get-sets-at-path [_ path-str]
|
||||
(get-sets-at-path [_ path-vec]
|
||||
"Get an ordered sequence of sets under `path` in the library"))
|
||||
|
||||
(def ^:private schema:token-set-node
|
||||
@@ -584,8 +580,7 @@
|
||||
(disable-sets [_ set-names] "disable several 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 when it exists")
|
||||
(theme-matches-group-name [_ group name] "if a theme matches the given group & name")
|
||||
(hidden-theme? [_] "if a theme is the (from the user ui) hidden temporary theme"))
|
||||
(theme-matches-group-name [_ group name] "if a theme matches the given group & name"))
|
||||
|
||||
(def hidden-theme-id
|
||||
uuid/zero)
|
||||
@@ -659,10 +654,12 @@
|
||||
|
||||
(theme-matches-group-name [this group name]
|
||||
(and (= (:group this) group)
|
||||
(= (:name this) name)))
|
||||
(= (:name this) name))))
|
||||
|
||||
(hidden-theme? [this]
|
||||
(theme-matches-group-name this hidden-theme-group hidden-theme-name)))
|
||||
(defn hidden-theme?
|
||||
"Check if a theme is the hidden temporary theme."
|
||||
[theme]
|
||||
(theme-matches-group-name theme hidden-theme-group hidden-theme-name))
|
||||
|
||||
(defmethod pp/simple-dispatch TokenTheme
|
||||
[^TokenTheme obj]
|
||||
@@ -755,11 +752,15 @@
|
||||
|
||||
(def ^:private theme-separator "/")
|
||||
|
||||
(defn- join-theme-path [group name]
|
||||
(cpn/join-path [group name] :separator theme-separator :with-spaces? false))
|
||||
(defn- join-theme-path [group name with-spaces?]
|
||||
(let [path (if (and (str/empty? group) with-spaces?) [name] [group name])]
|
||||
(cpn/join-path path :separator theme-separator :with-spaces? with-spaces?)))
|
||||
|
||||
(defn get-theme-path [theme]
|
||||
(join-theme-path (:group theme) (:name theme)))
|
||||
(defn get-theme-path
|
||||
([theme]
|
||||
(get-theme-path theme false))
|
||||
([theme with-spaces?]
|
||||
(join-theme-path (:group theme) (:name theme) with-spaces?)))
|
||||
|
||||
(defn split-theme-path [path]
|
||||
(cpn/split-group-name path
|
||||
@@ -767,7 +768,7 @@
|
||||
:with-spaces? false))
|
||||
|
||||
(def hidden-theme-path
|
||||
(join-theme-path hidden-theme-group hidden-theme-name))
|
||||
(join-theme-path hidden-theme-group hidden-theme-name false))
|
||||
|
||||
;; === TokenThemes (collection)
|
||||
|
||||
@@ -778,18 +779,13 @@
|
||||
(delete-theme [_ id] "delete a theme in the library")
|
||||
(theme-count [_] "get the total number if themes in the library")
|
||||
(get-theme-tree [_] "get a nested tree of all themes in the library")
|
||||
(get-theme-tree-no-hidden [_] "get a nested tree of all themes in the library except the hidden theme")
|
||||
(get-themes [_] "get an ordered sequence of all themes in the library")
|
||||
(get-themes-no-hidden [_] "get an ordered sequence of all themes in the library except the hidden theme")
|
||||
(get-themes-in-group [_ group] "get an ordered sequence of the themes in the group")
|
||||
(get-theme [_ id] "get one theme looking for id")
|
||||
(get-theme-by-name [_ group name] "get one theme looking for group and name")
|
||||
(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")
|
||||
(set-active-themes [_ active-themes] "set active themes in library")
|
||||
(theme-active? [_ id] "predicate if token theme is active")
|
||||
(activate-theme [_ id] "adds theme from the active-themes")
|
||||
(deactivate-theme [_ id] "removes theme from the active-themes")
|
||||
(toggle-theme-active [_ id] "toggles theme in the active-themes")
|
||||
(get-hidden-theme [_] "get the hidden temporary theme"))
|
||||
(get-theme-groups [_] "get a sequence of group names by order"))
|
||||
|
||||
(def schema:token-themes
|
||||
[:and
|
||||
@@ -930,18 +926,10 @@
|
||||
(update-token [_ set-id token-id f] "update a token in a set")
|
||||
(delete-token [_ set-id token-id] "delete a token from a set")
|
||||
(toggle-set-in-theme [_ theme-id 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")
|
||||
(token-set-active? [_ set-name] "if a set is active in any of the active themes")
|
||||
(sets-at-path-all-active? [_ group-path] "compute active state for child sets at `group-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-tokens-in-active-sets [_] "set of set names that are active in the the active themes")
|
||||
(get-tokens-in-active-sets-force [_ force-set-id] "same as above but forcing a set to be active, even if it's not in the active themes")
|
||||
(get-all-tokens [_] "all tokens in the lib, as a sequence")
|
||||
(get-all-tokens-map [_] "all tokens in the lib, as a map name -> token")
|
||||
(get-tokens [_ set-id] "return a map of tokens in the set, indexed by token-name"))
|
||||
(get-tokens [_ set-id] "return a map of tokens in the set, indexed by token-name")
|
||||
(get-legacy-active-themes [_] "only for legacy compatibility; return active themes inside library"))
|
||||
|
||||
(declare parse-multi-set-dtcg-json)
|
||||
(declare read-multi-set-dtcg)
|
||||
@@ -1116,8 +1104,8 @@ Will return a value that matches this schema:
|
||||
(->> (tree-seq d/ordered-map? vals sets)
|
||||
(filter (partial instance? TokenSet))))
|
||||
|
||||
(get-sets-at-path [_ path]
|
||||
(some->> (map add-set-path-group-prefix path)
|
||||
(get-sets-at-path [_ path-vec]
|
||||
(some->> (map add-set-path-group-prefix path-vec)
|
||||
(get-in sets)
|
||||
(tree-seq d/ordered-map? vals)
|
||||
(filter (partial instance? TokenSet))))
|
||||
@@ -1177,7 +1165,7 @@ Will return a value that matches this schema:
|
||||
(d/dissoc-in [group name])))
|
||||
(if same-path?
|
||||
active-themes
|
||||
(disj active-themes (join-theme-path group name)))))))
|
||||
(disj active-themes (join-theme-path group name false)))))))
|
||||
this))
|
||||
|
||||
(delete-theme [this id]
|
||||
@@ -1186,12 +1174,15 @@ Will return a value that matches this schema:
|
||||
(if theme
|
||||
(TokensLib. sets
|
||||
(d/dissoc-in themes [group name])
|
||||
(disj active-themes (join-theme-path group name)))
|
||||
(disj active-themes (join-theme-path group name false)))
|
||||
this)))
|
||||
|
||||
(get-theme-tree [_]
|
||||
themes)
|
||||
|
||||
(get-theme-tree-no-hidden [_]
|
||||
(d/dissoc-in themes [hidden-theme-group hidden-theme-name]))
|
||||
|
||||
(get-theme-groups [_]
|
||||
(into [] (comp
|
||||
(map key)
|
||||
@@ -1202,6 +1193,14 @@ Will return a value that matches this schema:
|
||||
(->> (tree-seq d/ordered-map? vals themes)
|
||||
(filter (partial instance? TokenTheme))))
|
||||
|
||||
(get-themes-no-hidden [this]
|
||||
(->> (get-themes this)
|
||||
(remove #(hidden-theme? %))))
|
||||
|
||||
(get-themes-in-group [_ group]
|
||||
(->> (get themes group)
|
||||
(map (comp get-id val))))
|
||||
|
||||
(theme-count [this]
|
||||
(count (get-themes this)))
|
||||
|
||||
@@ -1212,60 +1211,12 @@ Will return a value that matches this schema:
|
||||
(get-theme-by-name [_ group name]
|
||||
(dm/get-in themes [group name]))
|
||||
|
||||
(set-active-themes [_ active-themes]
|
||||
(TokensLib. sets
|
||||
themes
|
||||
active-themes))
|
||||
|
||||
(activate-theme [this id]
|
||||
(if-let [theme (get-theme this id)]
|
||||
(let [group (:group theme)
|
||||
group-themes (->> (get themes group)
|
||||
(map (comp get-theme-path val))
|
||||
(into #{}))
|
||||
active-themes' (-> (set/difference active-themes group-themes)
|
||||
(conj (get-theme-path theme)))]
|
||||
(TokensLib. sets
|
||||
themes
|
||||
active-themes'))
|
||||
this))
|
||||
|
||||
(deactivate-theme [this id]
|
||||
(if-let [theme (get-theme this id)]
|
||||
(TokensLib. sets
|
||||
themes
|
||||
(disj active-themes (get-theme-path theme)))
|
||||
this))
|
||||
|
||||
(theme-active? [this id]
|
||||
(when-let [theme (get-theme this id)]
|
||||
(contains? active-themes (get-theme-path theme))))
|
||||
|
||||
(toggle-theme-active [this id]
|
||||
(if (theme-active? this id)
|
||||
(deactivate-theme this id)
|
||||
(activate-theme this id)))
|
||||
|
||||
(get-active-theme-paths [_]
|
||||
active-themes)
|
||||
|
||||
(get-active-themes [this]
|
||||
(into
|
||||
(list)
|
||||
(comp
|
||||
(filter (partial instance? TokenTheme))
|
||||
(filter #(theme-active? this (get-id %))))
|
||||
(tree-seq d/ordered-map? vals themes)))
|
||||
|
||||
(get-hidden-theme [this]
|
||||
(get-theme this hidden-theme-id))
|
||||
|
||||
ITokensLib
|
||||
(empty-lib? [this]
|
||||
(and (empty? sets)
|
||||
(or (empty? themes)
|
||||
(and (= (theme-count this) 1)
|
||||
(get-hidden-theme this)))))
|
||||
(get-theme this hidden-theme-id)))))
|
||||
|
||||
(set-path-exists? [_ set-path]
|
||||
(some? (get-in sets (set-full-path->set-prefixed-full-path set-path))))
|
||||
@@ -1300,58 +1251,6 @@ Will return a value that matches this schema:
|
||||
active-themes)
|
||||
this))
|
||||
|
||||
(get-active-themes-set-names [this]
|
||||
(into #{}
|
||||
(mapcat :sets)
|
||||
(get-active-themes this)))
|
||||
|
||||
(token-set-active? [this set-name]
|
||||
(let [set-names (get-active-themes-set-names this)]
|
||||
(contains? set-names set-name)))
|
||||
|
||||
(sets-at-path-all-active? [this group-path]
|
||||
(let [active-set-names (get-active-themes-set-names this)
|
||||
prefixed-path-str (set-group-path->set-group-prefixed-path-str group-path)]
|
||||
|
||||
(if (seq active-set-names)
|
||||
(let [path-active-set-names (some->> (get-in sets (split-set-name prefixed-path-str))
|
||||
(tree-seq d/ordered-map? vals)
|
||||
(filter (partial instance? TokenSet))
|
||||
(map get-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-tokens-in-active-sets [this]
|
||||
(let [theme-set-names (get-active-themes-set-names this)
|
||||
all-set-names (get-set-names this)
|
||||
active-set-names (filter theme-set-names all-set-names)
|
||||
tokens (reduce (fn [tokens set-name]
|
||||
(let [set (get-set-by-name this set-name)]
|
||||
(merge tokens (get-tokens- set))))
|
||||
(d/ordered-map)
|
||||
active-set-names)]
|
||||
tokens))
|
||||
|
||||
(get-tokens-in-active-sets-force [this force-set-id]
|
||||
(let [theme-set-names (get-active-themes-set-names this)
|
||||
all-set-names (get-set-names this)
|
||||
force-set (get-set this force-set-id)
|
||||
active-set-names (cond-> (filter theme-set-names all-set-names)
|
||||
(some? force-set)
|
||||
(conj (get-name force-set)))
|
||||
|
||||
tokens (reduce (fn [tokens set-name]
|
||||
(let [set (get-set-by-name this set-name)]
|
||||
(merge tokens (get-tokens- set))))
|
||||
(d/ordered-map)
|
||||
active-set-names)]
|
||||
tokens))
|
||||
|
||||
(get-all-tokens [this]
|
||||
(mapcat #(vals (get-tokens- %))
|
||||
(get-sets this)))
|
||||
@@ -1368,6 +1267,9 @@ Will return a value that matches this schema:
|
||||
(get-set set-id)
|
||||
(get-tokens-)))
|
||||
|
||||
(get-legacy-active-themes [_]
|
||||
active-themes)
|
||||
|
||||
IValidation
|
||||
(valid? [this]
|
||||
(valid-tokens-lib-map? (datafy this)))
|
||||
@@ -1424,6 +1326,12 @@ Will return a value that matches this schema:
|
||||
[o]
|
||||
(and (tokens-lib? o) (valid? o)))
|
||||
|
||||
(defn get-theme-by-path
|
||||
"Get a theme by its path string (e.g. \"/Theme Name\" or \"group/Theme Name\")."
|
||||
[tokens-lib path]
|
||||
(let [[group name] (split-theme-path path)]
|
||||
(get-theme-by-name tokens-lib group name)))
|
||||
|
||||
(defn- ensure-hidden-theme
|
||||
"A helper that is responsible to ensure that the hidden theme always
|
||||
exists on the themes data structure"
|
||||
@@ -1452,10 +1360,6 @@ Will return a value that matches this schema:
|
||||
(check-tokens-lib-map)
|
||||
(map->tokens-lib)))
|
||||
|
||||
(defn ensure-tokens-lib
|
||||
[tokens-lib]
|
||||
(or tokens-lib (make-tokens-lib)))
|
||||
|
||||
(def schema:tokens-lib
|
||||
(sm/type-schema
|
||||
{:type ::tokens-lib
|
||||
@@ -1924,11 +1828,22 @@ Will return a value that matches this schema:
|
||||
library
|
||||
(reduce add-theme library themes)
|
||||
|
||||
;; Activate themes by directly manipulating the internal active-themes field
|
||||
;; (since activate-theme is being removed from the protocol)
|
||||
library
|
||||
(reduce (fn [library theme-path]
|
||||
(let [[group name] (split-theme-path theme-path)
|
||||
theme (get-theme-by-name library group name)]
|
||||
(activate-theme library (get-id theme))))
|
||||
(if theme
|
||||
(let [group-themes (->> (get themes group)
|
||||
(map (comp get-theme-path val))
|
||||
(into #{}))
|
||||
active-themes' (-> (set/difference (.-active-themes ^TokensLib library) group-themes)
|
||||
(conj (get-theme-path theme)))]
|
||||
(TokensLib. (.-sets ^TokensLib library)
|
||||
(.-themes ^TokensLib library)
|
||||
active-themes'))
|
||||
library)))
|
||||
library
|
||||
active-theme-names)]
|
||||
|
||||
@@ -2033,82 +1948,183 @@ Will return a value that matches this schema:
|
||||
|
||||
(defn- dtcg-export-themes
|
||||
"Extract themes for a dtcg json export."
|
||||
[tokens-lib]
|
||||
(let [themes-xform
|
||||
(comp
|
||||
(filter #(and (instance? TokenTheme %)
|
||||
(not (hidden-theme? %))))
|
||||
(map (fn [token-theme]
|
||||
;; NOTE: this probaly can be implemented as type method
|
||||
(d/without-nils
|
||||
{"id" (:external-id token-theme)
|
||||
"name" (:name token-theme)
|
||||
"group" (:group token-theme)
|
||||
"description" (:description token-theme)
|
||||
"isSource" (:is-source token-theme)
|
||||
"selectedTokenSets" (reduce #(assoc %1 %2 "enabled") {} (:sets token-theme))}))))
|
||||
([tokens-lib]
|
||||
;; Backward-compatible version for print/serialization without tokens-status
|
||||
(let [themes-xform
|
||||
(comp
|
||||
(filter #(and (instance? TokenTheme %)
|
||||
(not (hidden-theme? %))))
|
||||
(map (fn [token-theme]
|
||||
;; NOTE: this probaly can be implemented as type method
|
||||
(d/without-nils
|
||||
{"id" (:external-id token-theme)
|
||||
"name" (:name token-theme)
|
||||
"group" (:group token-theme)
|
||||
"description" (:description token-theme)
|
||||
"isSource" (:is-source token-theme)
|
||||
"selectedTokenSets" (reduce #(assoc %1 %2 "enabled") {} (:sets token-theme))}))))
|
||||
|
||||
themes
|
||||
(->> (get-theme-tree tokens-lib)
|
||||
(tree-seq d/ordered-map? vals)
|
||||
(into [] themes-xform))
|
||||
themes
|
||||
(->> (get-theme-tree tokens-lib)
|
||||
(tree-seq d/ordered-map? vals)
|
||||
(into [] themes-xform))
|
||||
|
||||
;; Active themes without exposing hidden penpot theme
|
||||
active-themes
|
||||
(-> (get-active-theme-paths tokens-lib)
|
||||
(disj hidden-theme-path))]
|
||||
[themes active-themes]))
|
||||
;; Active themes without exposing hidden penpot theme
|
||||
active-themes
|
||||
(-> (.-active-themes ^TokensLib tokens-lib)
|
||||
(disj hidden-theme-path))]
|
||||
[themes active-themes]))
|
||||
([tokens-lib active-theme-ids]
|
||||
;; Version with explicit active-theme-ids from TokensStatus
|
||||
(let [themes-xform
|
||||
(comp
|
||||
(filter #(and (instance? TokenTheme %)
|
||||
(not (hidden-theme? %))))
|
||||
(map (fn [token-theme]
|
||||
(d/without-nils
|
||||
{"id" (:external-id token-theme)
|
||||
"name" (:name token-theme)
|
||||
"group" (:group token-theme)
|
||||
"description" (:description token-theme)
|
||||
"isSource" (:is-source token-theme)
|
||||
"selectedTokenSets" (reduce #(assoc %1 %2 "enabled") {} (:sets token-theme))}))))
|
||||
|
||||
themes
|
||||
(->> (get-theme-tree tokens-lib)
|
||||
(tree-seq d/ordered-map? vals)
|
||||
(into [] themes-xform))
|
||||
|
||||
;; Convert theme ids to theme paths, excluding hidden theme
|
||||
active-themes
|
||||
(into #{}
|
||||
(comp (map #(get-theme tokens-lib %))
|
||||
(filter some?)
|
||||
(map get-theme-path)
|
||||
(filter #(not= % hidden-theme-path)))
|
||||
active-theme-ids)]
|
||||
[themes active-themes])))
|
||||
|
||||
(defn export-dtcg-multi-file
|
||||
"Convert a TokensLib into a plain clojure map, suitable to be encoded as a multi json files each encoded in DTCG format."
|
||||
[tokens-lib]
|
||||
(let [[themes active-themes]
|
||||
(dtcg-export-themes tokens-lib)
|
||||
([tokens-lib]
|
||||
;; Backward-compatible version for print/serialization without tokens-status
|
||||
(let [[themes active-themes]
|
||||
(dtcg-export-themes tokens-lib)
|
||||
|
||||
sets
|
||||
(->> (get-sets tokens-lib)
|
||||
(map (fn [token-set]
|
||||
(let [name (get-name token-set)
|
||||
tokens (get-tokens- token-set)]
|
||||
[(str name ".json") (tokens-tree tokens :update-token-fn token->dtcg-token)])))
|
||||
(into {}))]
|
||||
sets
|
||||
(->> (get-sets tokens-lib)
|
||||
(map (fn [token-set]
|
||||
(let [name (get-name token-set)
|
||||
tokens (get-tokens- token-set)]
|
||||
[(str name ".json") (tokens-tree tokens :update-token-fn token->dtcg-token)])))
|
||||
(into {}))]
|
||||
|
||||
(-> sets
|
||||
(assoc "$themes.json" themes)
|
||||
(assoc "$metadata.json"
|
||||
{"tokenSetOrder" (get-set-names tokens-lib)
|
||||
"activeThemes" active-themes
|
||||
"activeSets" (get-active-themes-set-names tokens-lib)}))))
|
||||
(-> sets
|
||||
(assoc "$themes.json" themes)
|
||||
(assoc "$metadata.json"
|
||||
{"tokenSetOrder" (get-set-names tokens-lib)
|
||||
"activeThemes" active-themes
|
||||
;; For backward compat, use internal active-themes field
|
||||
"activeSets" (into #{}
|
||||
(comp (filter #(and (instance? TokenTheme %)
|
||||
(contains? (.-active-themes ^TokensLib tokens-lib)
|
||||
(get-theme-path %))))
|
||||
(mapcat :sets))
|
||||
(get-themes tokens-lib))}))))
|
||||
([tokens-lib tokens-status]
|
||||
;; Version with tokens-status for real exports
|
||||
(let [active-theme-ids (ctos/get-active-theme-ids tokens-status)
|
||||
[themes active-themes]
|
||||
(dtcg-export-themes tokens-lib active-theme-ids)
|
||||
|
||||
sets
|
||||
(->> (get-sets tokens-lib)
|
||||
(map (fn [token-set]
|
||||
(let [name (get-name token-set)
|
||||
tokens (get-tokens- token-set)]
|
||||
[(str name ".json") (tokens-tree tokens :update-token-fn token->dtcg-token)])))
|
||||
(into {}))
|
||||
|
||||
active-set-ids (ctos/get-active-set-ids tokens-status)
|
||||
active-set-names (into #{}
|
||||
(comp (filter #(contains? active-set-ids (get-id %)))
|
||||
(map get-name))
|
||||
(get-sets tokens-lib))]
|
||||
|
||||
(-> sets
|
||||
(assoc "$themes.json" themes)
|
||||
(assoc "$metadata.json"
|
||||
{"tokenSetOrder" (get-set-names tokens-lib)
|
||||
"activeThemes" active-themes
|
||||
"activeSets" active-set-names})))))
|
||||
|
||||
(defn export-dtcg-json
|
||||
"Convert a TokensLib into a plain clojure map, suitable to be encoded as a multi sets json string in DTCG format."
|
||||
[tokens-lib]
|
||||
(let [[themes active-themes]
|
||||
(dtcg-export-themes tokens-lib)
|
||||
([tokens-lib]
|
||||
;; Backward-compatible version for print/serialization without tokens-status
|
||||
(let [[themes active-themes]
|
||||
(dtcg-export-themes tokens-lib)
|
||||
|
||||
name-set-tuples
|
||||
(->> (get-set-tree tokens-lib)
|
||||
(tree-seq d/ordered-map? vals)
|
||||
(filter (partial instance? TokenSet))
|
||||
(map (fn [set]
|
||||
[(get-name set)
|
||||
(tokens-tree (get-tokens- set) :update-token-fn token->dtcg-token)])))
|
||||
name-set-tuples
|
||||
(->> (get-set-tree tokens-lib)
|
||||
(tree-seq d/ordered-map? vals)
|
||||
(filter (partial instance? TokenSet))
|
||||
(map (fn [set]
|
||||
[(get-name set)
|
||||
(tokens-tree (get-tokens- set) :update-token-fn token->dtcg-token)])))
|
||||
|
||||
ordered-set-names
|
||||
(mapv first name-set-tuples)
|
||||
ordered-set-names
|
||||
(mapv first name-set-tuples)
|
||||
|
||||
sets
|
||||
(into {} name-set-tuples)
|
||||
sets
|
||||
(into {} name-set-tuples)
|
||||
|
||||
active-set-names
|
||||
(get-active-themes-set-names tokens-lib)]
|
||||
;; For backward compat, use internal active-themes field
|
||||
active-set-names (into #{}
|
||||
(comp (filter #(and (instance? TokenTheme %)
|
||||
(contains? (.-active-themes ^TokensLib tokens-lib)
|
||||
(get-theme-path %))))
|
||||
(mapcat :sets))
|
||||
(get-themes tokens-lib))]
|
||||
|
||||
(when-not (empty-lib? tokens-lib)
|
||||
(-> sets
|
||||
(assoc "$themes" themes)
|
||||
(assoc "$metadata" {"tokenSetOrder" ordered-set-names
|
||||
"activeThemes" active-themes
|
||||
"activeSets" active-set-names})))))
|
||||
(when-not (empty-lib? tokens-lib)
|
||||
(-> sets
|
||||
(assoc "$themes" themes)
|
||||
(assoc "$metadata" {"tokenSetOrder" ordered-set-names
|
||||
"activeThemes" active-themes
|
||||
"activeSets" active-set-names})))))
|
||||
([tokens-lib tokens-status]
|
||||
;; Version with tokens-status for real exports
|
||||
(let [active-theme-ids (ctos/get-active-theme-ids tokens-status)
|
||||
[themes active-themes]
|
||||
(dtcg-export-themes tokens-lib active-theme-ids)
|
||||
|
||||
name-set-tuples
|
||||
(->> (get-set-tree tokens-lib)
|
||||
(tree-seq d/ordered-map? vals)
|
||||
(filter (partial instance? TokenSet))
|
||||
(map (fn [set]
|
||||
[(get-name set)
|
||||
(tokens-tree (get-tokens- set) :update-token-fn token->dtcg-token)])))
|
||||
|
||||
ordered-set-names
|
||||
(mapv first name-set-tuples)
|
||||
|
||||
sets
|
||||
(into {} name-set-tuples)
|
||||
|
||||
active-set-ids (ctos/get-active-set-ids tokens-status)
|
||||
active-set-names (into #{}
|
||||
(comp (filter #(contains? active-set-ids (get-id %)))
|
||||
(map get-name))
|
||||
(get-sets tokens-lib))]
|
||||
|
||||
(when-not (empty-lib? tokens-lib)
|
||||
(-> sets
|
||||
(assoc "$themes" themes)
|
||||
(assoc "$metadata" {"tokenSetOrder" ordered-set-names
|
||||
"activeThemes" active-themes
|
||||
"activeSets" active-set-names}))))))
|
||||
|
||||
(defn get-tokens-of-unknown-type
|
||||
"Search for all tokens in the decoded json file that have a type that is not currently
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -14,6 +14,7 @@
|
||||
[app.common.test-helpers.shapes :as ths]
|
||||
[app.common.test-helpers.tokens :as tht]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.test :as t]))
|
||||
|
||||
@@ -141,24 +142,27 @@
|
||||
|
||||
(t/deftest test-relocate-shape-out-of-layout-with-tokens
|
||||
(let [;; ==== Setup
|
||||
file (-> (thf/sample-file :file1)
|
||||
(tht/add-tokens-lib)
|
||||
(tht/update-tokens-lib #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :test-token-set)
|
||||
:name "test-token-set"))
|
||||
(ctob/add-theme (ctob/make-token-theme :name "test-theme"
|
||||
:sets #{"test-token-set"}))
|
||||
(ctob/set-active-themes #{"/test-theme"})
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-sizing)
|
||||
:name "token-sizing"
|
||||
:type :sizing
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-spacing)
|
||||
:name "token-spacing"
|
||||
:type :spacing
|
||||
:value 30))))
|
||||
file (-> (tht/sample-file-with-tokens
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :test-token-set)
|
||||
:name "test-token-set"))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :test-theme)
|
||||
:name "test-theme"
|
||||
:sets #{"test-token-set"}))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-sizing)
|
||||
:name "token-sizing"
|
||||
:type :sizing
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-spacing)
|
||||
:name "token-spacing"
|
||||
:type :spacing
|
||||
:value 30)))
|
||||
:status-fn #(-> %
|
||||
(ctos/set-tokens-status #{(thi/id :test-theme)}
|
||||
#{(thi/id :test-token-set)})))
|
||||
;; Sync tokens-status from lib's internal active-themes
|
||||
(tho/add-frame :frame-1
|
||||
:layout :flex ;; TODO: those values come from main.data.workspace.shape_layout/default-layout-params
|
||||
:layout-flex-dir :row ;; it should be good to use it directly, but first it should be moved to common.logic
|
||||
|
||||
@@ -18,75 +18,78 @@
|
||||
[app.common.types.text :as txt]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[clojure.test :as t]))
|
||||
|
||||
(t/use-fixtures :each thi/test-fixture)
|
||||
|
||||
(defn- setup-file
|
||||
[]
|
||||
(-> (thf/sample-file :file1)
|
||||
(tht/add-tokens-lib)
|
||||
(tht/update-tokens-lib #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :test-token-set)
|
||||
:name "test-token-set"))
|
||||
(ctob/add-theme (ctob/make-token-theme :name "test-theme"
|
||||
:sets #{"test-token-set"}))
|
||||
(ctob/set-active-themes #{"/test-theme"})
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-radius)
|
||||
:name "token-radius"
|
||||
:type :border-radius
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-rotation)
|
||||
:name "token-rotation"
|
||||
:type :rotation
|
||||
:value 30))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-opacity)
|
||||
:name "token-opacity"
|
||||
:type :opacity
|
||||
:value 0.7))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-stroke-width)
|
||||
:name "token-stroke-width"
|
||||
:type :stroke-width
|
||||
:value 2))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-color)
|
||||
:name "token-color"
|
||||
:type :color
|
||||
:value "#00ff00"))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-dimensions)
|
||||
:name "token-dimensions"
|
||||
:type :dimensions
|
||||
:value 100))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-font-size)
|
||||
:name "token-font-size"
|
||||
:type :font-size
|
||||
:value 24))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-letter-spacing)
|
||||
:name "token-letter-spacing"
|
||||
:type :letter-spacing
|
||||
:value 2))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-font-family)
|
||||
:name "token-font-family"
|
||||
:type :font-family
|
||||
:value ["Helvetica" "Arial" "sans-serif"]))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-sizing)
|
||||
:name "token-sizing"
|
||||
:type :sizing
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-spacing)
|
||||
:name "token-spacing"
|
||||
:type :spacing
|
||||
:value 30))))
|
||||
(-> (tht/sample-file-with-tokens
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :test-token-set)
|
||||
:name "test-token-set"))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :test-theme)
|
||||
:name "test-theme"
|
||||
:sets #{"test-token-set"}))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-radius)
|
||||
:name "token-radius"
|
||||
:type :border-radius
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-rotation)
|
||||
:name "token-rotation"
|
||||
:type :rotation
|
||||
:value 30))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-opacity)
|
||||
:name "token-opacity"
|
||||
:type :opacity
|
||||
:value 0.7))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-stroke-width)
|
||||
:name "token-stroke-width"
|
||||
:type :stroke-width
|
||||
:value 2))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-color)
|
||||
:name "token-color"
|
||||
:type :color
|
||||
:value "#00ff00"))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-dimensions)
|
||||
:name "token-dimensions"
|
||||
:type :dimensions
|
||||
:value 100))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-font-size)
|
||||
:name "token-font-size"
|
||||
:type :font-size
|
||||
:value 24))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-letter-spacing)
|
||||
:name "token-letter-spacing"
|
||||
:type :letter-spacing
|
||||
:value 2))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-font-family)
|
||||
:name "token-font-family"
|
||||
:type :font-family
|
||||
:value ["Helvetica" "Arial" "sans-serif"]))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-sizing)
|
||||
:name "token-sizing"
|
||||
:type :sizing
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :id (thi/new-id! :token-spacing)
|
||||
:name "token-spacing"
|
||||
:type :spacing
|
||||
:value 30)))
|
||||
:status-fn #(-> %
|
||||
(ctos/set-tokens-status #{(thi/id :test-theme)}
|
||||
#{(thi/id :test-token-set)})))
|
||||
(tho/add-frame :frame1
|
||||
:layout :flex ;; TODO: those values come from main.data.workspace.shape_layout/default-layout-params
|
||||
:layout-flex-dir :row ;; it should be good to use it directly, but first it should be moved to common.logic
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -11,11 +11,13 @@
|
||||
#?(:clj [app.common.test-helpers.tokens :as tht])
|
||||
#?(:clj [clojure.datafy :refer [datafy]])
|
||||
[app.common.data :as d]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.test-helpers.ids-map :as thi]
|
||||
[app.common.time :as ct]
|
||||
[app.common.transit :as tr]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.test :as t]))
|
||||
|
||||
@@ -247,6 +249,16 @@
|
||||
theme' (ctob/toggle-set theme nil)]
|
||||
(t/is (= (:sets theme') #{})))))
|
||||
|
||||
(t/deftest get-theme-path
|
||||
(let [theme1 (ctob/make-token-theme :name "theme1")
|
||||
theme2 (ctob/make-token-theme :group "group1" :name "theme2")]
|
||||
(t/is (= "/theme1" (ctob/get-theme-path theme1)))
|
||||
(t/is (= "/theme1" (ctob/get-theme-path theme1 false)))
|
||||
(t/is (= "theme1" (ctob/get-theme-path theme1 true)))
|
||||
(t/is (= "group1/theme2" (ctob/get-theme-path theme2)))
|
||||
(t/is (= "group1/theme2" (ctob/get-theme-path theme2 false)))
|
||||
(t/is (= "group1 / theme2" (ctob/get-theme-path theme2 true)))))
|
||||
|
||||
(t/deftest make-tokens-lib
|
||||
(let [tokens-lib (ctob/make-tokens-lib)]
|
||||
(t/is (= (ctob/set-count tokens-lib) 0))))
|
||||
@@ -574,208 +586,19 @@
|
||||
"token-4"
|
||||
(ctob/make-token :name "token-4"
|
||||
:type :border-radius
|
||||
:value 4000)}))
|
||||
(ctob/update-theme ctob/hidden-theme-id
|
||||
#(ctob/enable-sets % #{"set-a" "set-b"})))
|
||||
:value 4000)})))
|
||||
set-a-id (ctob/get-id (ctob/get-set-by-name tokens-lib "set-a"))
|
||||
set-b-id (ctob/get-id (ctob/get-set-by-name tokens-lib "set-b"))
|
||||
tokens-status (ctos/make-tokens-status :active-theme-ids #{}
|
||||
:active-set-ids #{set-a-id set-b-id})
|
||||
|
||||
tokens (ctob/get-tokens-in-active-sets tokens-lib)]
|
||||
tokens (cfo/get-tokens-in-active-sets tokens-status tokens-lib)]
|
||||
|
||||
(t/is (= (mapv key tokens) ["token-1" "token-2" "token-3"]))
|
||||
(t/is (= (get-in tokens ["token-1" :value]) 100))
|
||||
(t/is (= (get-in tokens ["token-2" :value]) 20))
|
||||
(t/is (= (get-in tokens ["token-3" :value]) 300))))
|
||||
|
||||
(t/deftest list-active-themes-tokens-one-theme
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "set-a"
|
||||
:tokens {"token-1"
|
||||
(ctob/make-token :name "token-1"
|
||||
:type :border-radius
|
||||
:value 10)
|
||||
"token-2"
|
||||
(ctob/make-token :name "token-2"
|
||||
:type :border-radius
|
||||
:value 20)}))
|
||||
(ctob/add-set (ctob/make-token-set :name "set-b"
|
||||
:tokens {"token-1"
|
||||
(ctob/make-token :name "token-1"
|
||||
:type :border-radius
|
||||
:value 100)
|
||||
"token-3"
|
||||
(ctob/make-token :name "token-3"
|
||||
:type :border-radius
|
||||
:value 300)}))
|
||||
(ctob/add-set (ctob/make-token-set :name "set-c"
|
||||
:tokens {"token-1"
|
||||
(ctob/make-token :name "token-1"
|
||||
:type :border-radius
|
||||
:value 1000)
|
||||
"token-2"
|
||||
(ctob/make-token :name "token-2"
|
||||
:type :border-radius
|
||||
:value 2000)
|
||||
"token-3"
|
||||
(ctob/make-token :name "token-3"
|
||||
:type :border-radius
|
||||
:value 3000)
|
||||
"token-4"
|
||||
(ctob/make-token :name "token-4"
|
||||
:type :border-radius
|
||||
:value 4000)}))
|
||||
(ctob/add-theme (ctob/make-token-theme :name "single-theme"
|
||||
:sets #{"set-b" "set-c" "set-a"}))
|
||||
(ctob/set-active-themes #{"/single-theme"}))
|
||||
|
||||
tokens (ctob/get-tokens-in-active-sets tokens-lib)]
|
||||
|
||||
;; Note that sets order inside the theme is undefined. What matters is order in that the
|
||||
;; sets have been added to the library.
|
||||
(t/is (= (mapv key tokens) ["token-1" "token-2" "token-3" "token-4"]))
|
||||
(t/is (= (get-in tokens ["token-1" :value]) 1000))
|
||||
(t/is (= (get-in tokens ["token-2" :value]) 2000))
|
||||
(t/is (= (get-in tokens ["token-3" :value]) 3000))
|
||||
(t/is (= (get-in tokens ["token-4" :value]) 4000))))
|
||||
|
||||
(t/deftest list-active-themes-tokens-two-themes
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "set-a"
|
||||
:tokens {"token-1"
|
||||
(ctob/make-token :name "token-1"
|
||||
:type :border-radius
|
||||
:value 10)
|
||||
"token-2"
|
||||
(ctob/make-token :name "token-2"
|
||||
:type :border-radius
|
||||
:value 20)}))
|
||||
(ctob/add-set (ctob/make-token-set :name "set-b"
|
||||
:tokens {"token-1"
|
||||
(ctob/make-token :name "token-1"
|
||||
:type :border-radius
|
||||
:value 100)
|
||||
"token-3"
|
||||
(ctob/make-token :name "token-3"
|
||||
:type :border-radius
|
||||
:value 300)}))
|
||||
(ctob/add-set (ctob/make-token-set :name "set-c"
|
||||
:tokens {"token-1"
|
||||
(ctob/make-token :name "token-1"
|
||||
:type :border-radius
|
||||
:value 1000)
|
||||
"token-2"
|
||||
(ctob/make-token :name "token-2"
|
||||
:type :border-radius
|
||||
:value 2000)
|
||||
"token-3"
|
||||
(ctob/make-token :name "token-3"
|
||||
:type :border-radius
|
||||
:value 3000)
|
||||
"token-4"
|
||||
(ctob/make-token :name "token-4"
|
||||
:type :border-radius
|
||||
:value 4000)}))
|
||||
(ctob/add-theme (ctob/make-token-theme :name "theme-1"
|
||||
:sets #{"set-b"}))
|
||||
(ctob/add-theme (ctob/make-token-theme :name "theme-2"
|
||||
:sets #{"set-b" "set-a"}))
|
||||
(ctob/set-active-themes #{"/theme-1" "/theme-2"}))
|
||||
|
||||
tokens (ctob/get-tokens-in-active-sets tokens-lib)]
|
||||
|
||||
;; Note that themes order is irrelevant. What matters is the union of the active sets
|
||||
;; and the order of the sets in the library.
|
||||
(t/is (= (mapv key tokens) ["token-1" "token-2" "token-3"]))
|
||||
(t/is (= (get-in tokens ["token-1" :value]) 100))
|
||||
(t/is (= (get-in tokens ["token-2" :value]) 20))
|
||||
(t/is (= (get-in tokens ["token-3" :value]) 300))))
|
||||
|
||||
(t/deftest list-active-themes-tokens-bug-taiga-10617
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "Mode/Dark"
|
||||
:tokens {"red"
|
||||
(ctob/make-token :name "red"
|
||||
:type :color
|
||||
:value "#700000")}))
|
||||
(ctob/add-set (ctob/make-token-set :name "Mode/Light"
|
||||
:tokens {"red"
|
||||
(ctob/make-token :name "red"
|
||||
:type :color
|
||||
:value "#ff0000")}))
|
||||
(ctob/add-set (ctob/make-token-set :name "Device/Desktop"
|
||||
:tokens {"border1"
|
||||
(ctob/make-token :name "border1"
|
||||
:type :border-radius
|
||||
:value 30)}))
|
||||
(ctob/add-set (ctob/make-token-set :name "Device/Mobile"
|
||||
:tokens {"border1"
|
||||
(ctob/make-token :name "border1"
|
||||
:type :border-radius
|
||||
:value 50)}))
|
||||
(ctob/add-theme (ctob/make-token-theme :group "App"
|
||||
:name "Mobile"
|
||||
:sets #{"Mode/Dark" "Device/Mobile"}))
|
||||
(ctob/add-theme (ctob/make-token-theme :group "App"
|
||||
:name "Web"
|
||||
:sets #{"Mode/Dark" "Mode/Light" "Device/Desktop"}))
|
||||
(ctob/add-theme (ctob/make-token-theme :group "Brand"
|
||||
:name "Brand A"
|
||||
:sets #{"Mode/Dark" "Mode/Light" "Device/Desktop" "Device/Mobile"}))
|
||||
(ctob/add-theme (ctob/make-token-theme :group "Brand"
|
||||
:name "Brand B"
|
||||
:sets #{}))
|
||||
(ctob/set-active-themes #{"App/Web" "Brand/Brand A"}))
|
||||
|
||||
tokens (ctob/get-tokens-in-active-sets tokens-lib)]
|
||||
|
||||
(t/is (= (mapv key tokens) ["red" "border1"]))
|
||||
(t/is (= (get-in tokens ["red" :value]) "#ff0000"))
|
||||
(t/is (= (get-in tokens ["border1" :value]) 50))))
|
||||
|
||||
(t/deftest list-active-themes-tokens-no-tokens
|
||||
(let [tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "set-a")))
|
||||
|
||||
tokens (ctob/get-tokens-in-active-sets tokens-lib)]
|
||||
|
||||
(t/is (empty? tokens))))
|
||||
|
||||
(t/deftest list-active-themes-tokens-no-sets
|
||||
(let [tokens-lib (ctob/make-tokens-lib)
|
||||
tokens (ctob/get-tokens-in-active-sets tokens-lib)]
|
||||
|
||||
(t/is (empty? tokens))))
|
||||
|
||||
(t/deftest 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? ["foo"]))
|
||||
expected-all (-> tokens-lib
|
||||
(ctob/set-active-themes #{"/all"})
|
||||
(ctob/sets-at-path-all-active? ["foo"]))
|
||||
expected-partial (-> tokens-lib
|
||||
(ctob/set-active-themes #{"/partial"})
|
||||
(ctob/sets-at-path-all-active? ["foo"]))
|
||||
expected-invalid-none (-> tokens-lib
|
||||
(ctob/set-active-themes #{"/invalid"})
|
||||
(ctob/sets-at-path-all-active? ["foo"]))]
|
||||
(t/is (= :none expected-none))
|
||||
(t/is (= :all expected-all))
|
||||
(t/is (= :partial expected-partial))
|
||||
(t/is (= :none expected-invalid-none))))
|
||||
|
||||
(t/deftest add-token-theme
|
||||
(let [theme-id (uuid/next)
|
||||
tokens-lib (ctob/make-tokens-lib)
|
||||
@@ -1283,12 +1106,12 @@
|
||||
(let [theme-1-id (uuid/next)
|
||||
theme-2-id (uuid/next)
|
||||
theme-3-id (uuid/next)
|
||||
theme-4-id (uuid/next)
|
||||
;; theme-4-id (uuid/next)
|
||||
tokens-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-theme (ctob/make-token-theme :id theme-1-id :group "" :name "token-theme-1"))
|
||||
(ctob/add-theme (ctob/make-token-theme :id theme-2-id :group "group1" :name "token-theme-2"))
|
||||
(ctob/add-theme (ctob/make-token-theme :id theme-3-id :group "group1" :name "token-theme-3"))
|
||||
#_(ctob/add-theme (ctob/make-token-theme :in-theme-4-id :group "group2" :name "token-theme-4")))
|
||||
#_(ctob/add-theme (ctob/make-token-theme :id theme-4-id :group "group2" :name "token-theme-4")))
|
||||
|
||||
tokens-lib' (-> tokens-lib
|
||||
(ctob/update-theme theme-2-id
|
||||
@@ -1612,9 +1435,9 @@
|
||||
:group "group-1"
|
||||
:external-id "test-id-01"
|
||||
:modified-at now
|
||||
:sets #{"core"}))
|
||||
(ctob/toggle-theme-active (thi/id :theme-1)))
|
||||
result (ctob/export-dtcg-json tokens-lib)
|
||||
:sets #{"core"})))
|
||||
tokens-status (cfo/toggle-theme-active (ctos/make-tokens-status) tokens-lib (thi/id :theme-1))
|
||||
result (ctob/export-dtcg-json tokens-lib tokens-status)
|
||||
expected {"$themes" [{"description" ""
|
||||
"group" "group-1"
|
||||
"isSource" false
|
||||
@@ -1665,9 +1488,9 @@
|
||||
:group "group-1"
|
||||
:external-id "test-id-01"
|
||||
:modified-at now
|
||||
:sets #{"some/set"}))
|
||||
(ctob/toggle-theme-active (thi/id :theme-1)))
|
||||
result (ctob/export-dtcg-multi-file tokens-lib)
|
||||
:sets #{"some/set"})))
|
||||
tokens-status (cfo/toggle-theme-active (ctos/make-tokens-status) tokens-lib (thi/id :theme-1))
|
||||
result (ctob/export-dtcg-multi-file tokens-lib tokens-status)
|
||||
expected {"$themes.json" [{"description" ""
|
||||
"group" "group-1"
|
||||
"isSource" false
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
(ns common-tests.types.tokens-migrations-test
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.test-helpers.ids-map :as thi]
|
||||
[app.common.time :as ct]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[clojure.datafy :refer [datafy]]
|
||||
[clojure.test :as t]))
|
||||
|
||||
@@ -79,4 +80,55 @@
|
||||
(t/is (= (ctob/get-description theme1') (ctob/get-description theme1)))
|
||||
(t/is (= (ctob/get-id theme2') (ctob/get-id theme2)))
|
||||
(t/is (= (ctob/get-name theme2') (ctob/get-name theme2)))
|
||||
(t/is (= (ctob/get-description theme2') (ctob/get-description theme2))))))
|
||||
(t/is (= (ctob/get-description theme2') (ctob/get-description theme2))))))
|
||||
|
||||
(t/deftest make-tokens-status-from-tokens-lib
|
||||
(t/testing "active themes and sets from a legacy tokens-lib should be added to the status"
|
||||
(let [base-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a)
|
||||
:name "set-a"))
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-b)
|
||||
:name "set-b"))
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-c)
|
||||
:name "set-c"))
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-d)
|
||||
:name "set-d"))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-1)
|
||||
:name "theme-1"
|
||||
:sets #{"set-a" "set-b"}))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-2)
|
||||
:name "theme-2"
|
||||
:sets #{"set-b"}))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-3)
|
||||
:name "theme-3"
|
||||
:sets #{"set-c" "set-d"})))
|
||||
;; Build a legacy tokens lib to test migration
|
||||
tokens-lib (ctob/map->tokens-lib {:sets (.-sets base-lib)
|
||||
:themes (.-themes base-lib)
|
||||
:active-themes #{"/theme-1" "/theme-2"}})
|
||||
|
||||
tokens-status (cfo/make-tokens-status-from-lib tokens-lib)]
|
||||
|
||||
(t/is (ctos/tokens-status? tokens-status))
|
||||
(t/is (ctos/check-tokens-status tokens-status))
|
||||
(t/is (= (count (ctos/get-active-theme-ids tokens-status)) 2))
|
||||
(t/is (ctos/theme-active? tokens-status (thi/id :theme-1)))
|
||||
(t/is (ctos/theme-active? tokens-status (thi/id :theme-2)))
|
||||
(t/is (= 2 (count (ctos/get-active-set-ids tokens-status))))
|
||||
(t/is (ctos/set-active? tokens-status (thi/id :set-a)))
|
||||
(t/is (ctos/set-active? tokens-status (thi/id :set-b)))))
|
||||
|
||||
(t/testing "hidden theme should be excluded from active theme ids"
|
||||
(let [tokens-lib (ctob/make-tokens-lib)
|
||||
status (cfo/make-tokens-status-from-lib tokens-lib)]
|
||||
(t/is (not (contains? (ctos/get-active-set-ids status) ctob/hidden-theme-id)))))
|
||||
|
||||
(t/testing "returns empty sets when no active themes"
|
||||
(let [base-lib (ctob/make-tokens-lib)
|
||||
tokens-lib (ctob/map->tokens-lib
|
||||
{:sets (:sets (.sets base-lib))
|
||||
:themes (:themes (.themes base-lib))
|
||||
:active-themes #{}})
|
||||
status (cfo/make-tokens-status-from-lib tokens-lib)]
|
||||
(t/is (= #{} (ctos/get-active-theme-ids status)))
|
||||
(t/is (= #{} (ctos/get-active-set-ids status))))))
|
||||
@@ -25,7 +25,6 @@
|
||||
[app.common.uuid :as uuid]
|
||||
;; Required for side effects: binds the generated enums.
|
||||
[app.wasm.enums]
|
||||
[cuerdas.core :as str]
|
||||
[promesa.core :as p]
|
||||
[shadow.esm :refer [dynamic-import]]))
|
||||
|
||||
@@ -191,22 +190,6 @@
|
||||
(aget buf 0) (aget buf 1) (aget buf 2) (aget buf 3)
|
||||
false)))))
|
||||
|
||||
(defn store-image-url!
|
||||
"Registers the public URL an image was loaded from. The SVG export emits
|
||||
linked `<image href>` from these, and falls back to Skia base64 when missing,
|
||||
so this should run for every media id the scene references (including
|
||||
already-cached images).
|
||||
|
||||
Does NOT call `mem/free`, for the same reason as `store-font-url!`."
|
||||
[image-id url]
|
||||
(when (and (some? url) (not (str/blank? url)))
|
||||
(let [bytes (js/Buffer.from url "utf-8")
|
||||
ptr (mem/alloc (.-byteLength bytes))
|
||||
quart (uuid/get-u32 image-id)]
|
||||
(mem/write-buffer ptr (mem/get-heap-u8) bytes)
|
||||
(h/call wasm/internal-module "_store_image_url"
|
||||
(aget quart 0) (aget quart 1) (aget quart 2) (aget quart 3)))))
|
||||
|
||||
(defn store-image!
|
||||
"Uploads one image's *encoded* bytes (PNG/JPEG — Skia decodes, no WebGL) into
|
||||
the WASM image store via `_store_image`. Buffer layout matches the Rust reader:
|
||||
|
||||
@@ -369,18 +369,13 @@
|
||||
"Fetches and stores every image the scene references (shape, stroke and
|
||||
text-span fills, enumerated by `app.common.types.shape.images`). Unlike fonts,
|
||||
the image store is not reset per request, so already-held images are skipped
|
||||
and repeated exports of a file reuse them.
|
||||
|
||||
Always registers a public media URL for each id so SVG export can emit linked
|
||||
`<image href>` even when the encoded bytes were already cached."
|
||||
and repeated exports of a file reuse them."
|
||||
[scene params]
|
||||
(let [all-ids (images/scene-image-ids scene)
|
||||
new-ids (remove wasm/image-cached? all-ids)]
|
||||
(l/dbg :hint "wasm render: provisioning images"
|
||||
:total (count all-ids)
|
||||
:cached (- (count all-ids) (count new-ids)))
|
||||
(doseq [image-id all-ids]
|
||||
(wasm/store-image-url! image-id (public-uri (str "assets/by-file-media-id/" image-id))))
|
||||
(->> new-ids
|
||||
(map (fn [image-id]
|
||||
(->> (fetch-file-media-bytes image-id params)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"~:revn": 11,
|
||||
"~:modified-at": "~m1778577544627",
|
||||
"~:vern": 151920609,
|
||||
"~:id": "~u1bac06a1-a942-80a6-8008-0222e1ec38d5",
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:is-shared": false,
|
||||
"~:migrations": {
|
||||
"~#ordered-set": [
|
||||
@@ -128,6 +128,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:tokens-status": {
|
||||
"~#penpot/tokens-status": {
|
||||
"~:active-theme-ids": {
|
||||
"~#set": ["~uc00d9d2e-76f9-815b-8005-e1260332abac", "~uc00d9d2e-76f9-815b-8005-e1260332abb0"]
|
||||
},
|
||||
"~:active-set-ids": {
|
||||
"~#set": [
|
||||
"~u4cdd76d8-0e6d-8168-8008-01189f0ece1d",
|
||||
"~u4cdd76d8-0e6d-8168-8008-01189f161e35",
|
||||
"~u4cdd76d8-0e6d-8168-8008-01189f101a3f",
|
||||
"~u4cdd76d8-0e6d-8168-8008-01189f0e2151",
|
||||
"~u4cdd76d8-0e6d-8168-8008-01189f0cf6d3",
|
||||
"~u4cdd76d8-0e6d-8168-8008-01189f0e7da8"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:tokens-lib": {
|
||||
"~#penpot/tokens-lib": {
|
||||
"~:sets": {
|
||||
@@ -4312,7 +4329,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:id": "~u1bac06a1-a942-80a6-8008-0222e1ec38d5",
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
|
||||
@@ -5771,6 +5771,16 @@
|
||||
},
|
||||
"~:id": "~u7b2da435-6186-815a-8007-0daa95d2f26d",
|
||||
"~:options": { "~:components-v2": true, "~:base-font-size": "16px" },
|
||||
"~:tokens-status": {
|
||||
"~#penpot/tokens-status": {
|
||||
"~:active-theme-ids": {
|
||||
"~#set": []
|
||||
},
|
||||
"~:active-set-ids": {
|
||||
"~#set": ["~u5403f14e-eb02-80be-8007-0494f09cefca"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:tokens-lib": {
|
||||
"~#penpot/tokens-lib": {
|
||||
"~:sets": {
|
||||
|
||||
@@ -134,6 +134,18 @@
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
},
|
||||
"~:tokens-status": {
|
||||
"~#penpot/tokens-status": {
|
||||
"~:active-theme-ids": {
|
||||
"~#set": []
|
||||
},
|
||||
"~:active-set-ids": {
|
||||
"~#set": [
|
||||
"~u7c1a66f7-5186-8060-8007-6ce67f8f2592"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:tokens-lib": {
|
||||
"~#penpot/tokens-lib": {
|
||||
"~:sets": {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
[
|
||||
{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"layout/grid",
|
||||
"styles/v2",
|
||||
"fdata/pointer-map",
|
||||
"fdata/objects-map",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type"
|
||||
]
|
||||
},
|
||||
"~:is-indirect": false,
|
||||
"~:name": "published component",
|
||||
"~:revn": 3,
|
||||
"~:modified-at": "~m1730103592325",
|
||||
"~:vern": 0,
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:project-id": "~u3622460c-3408-81e2-8005-2fc9059741e0",
|
||||
"~:synced-at": "~m1730103575856",
|
||||
"~:created-at": "~m1730101410834"
|
||||
}
|
||||
]
|
||||
@@ -53,6 +53,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:tokens-status": {
|
||||
"~#penpot/tokens-status": {
|
||||
"~:active-theme-ids": {
|
||||
"~#set": []
|
||||
},
|
||||
"~:active-set-ids": {
|
||||
"~#set": [
|
||||
"~uf71719b3-63a1-8157-8008-40346917de8c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:tokens-lib": {
|
||||
"~#penpot/tokens-lib": {
|
||||
"~:sets": {
|
||||
@@ -373,7 +385,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:id": "~u55608328-aed3-807a-8008-41341f2f7247",
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"~:revn": 3,
|
||||
"~:modified-at": "~m1779204621124",
|
||||
"~:vern": 0,
|
||||
"~:id": "~u9fb430ed-e1e9-81bc-8008-0b7ae978d9c4",
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:is-shared": false,
|
||||
"~:migrations": {
|
||||
"~#ordered-set": [
|
||||
@@ -130,11 +130,23 @@
|
||||
"~:name": "Page 1"
|
||||
}
|
||||
},
|
||||
"~:id": "~u9fb430ed-e1e9-81bc-8008-0b7ae978d9c4",
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
},
|
||||
"~:tokens-status": {
|
||||
"~#penpot/tokens-status": {
|
||||
"~:active-theme-ids": {
|
||||
"~#set": []
|
||||
},
|
||||
"~:active-set-ids": {
|
||||
"~#set": [
|
||||
"~u1dc5cafc-6d57-808d-8008-0b7af8180cbd"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:tokens-lib": {
|
||||
"~#penpot/tokens-lib": {
|
||||
"~:sets": {
|
||||
|
||||
@@ -42,10 +42,24 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"~:id": "~u51e13852-1a8e-8037-8005-9e9413a1f1f6",
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:options": {
|
||||
"~:components-v2": true
|
||||
},
|
||||
"~:tokens-status": {
|
||||
"~#penpot/tokens-status": {
|
||||
"~:active-theme-ids": {
|
||||
"~#set": ["~u66697432-c33d-8055-8006-2c62de27d738"]
|
||||
},
|
||||
"~:active-set-ids": {
|
||||
"~#set": [
|
||||
"~u66697432-c33d-8055-8006-2c62de27d709",
|
||||
"~u51e13852-1a8e-8037-8005-9e9413a1f1f6",
|
||||
"~u66697432-c33d-8055-8006-2c62de27d731"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:tokens-lib": {
|
||||
"~#penpot/tokens-lib": {
|
||||
"~:sets": {
|
||||
|
||||
@@ -54,6 +54,19 @@
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
},
|
||||
"~:tokens-status": {
|
||||
"~#penpot/tokens-status": {
|
||||
"~:active-theme-ids": {
|
||||
"~#set": []
|
||||
},
|
||||
"~:active-set-ids": {
|
||||
"~#set": [
|
||||
"~u7239ff52-c1d9-8014-8006-ae7ad49690e3",
|
||||
"~u97915939-ccca-808f-8006-aeb3c391e0f4"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:tokens-lib": {
|
||||
"~#penpot/tokens-lib": {
|
||||
"~:sets": {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"fdata/path-data",
|
||||
"plugins/runtime",
|
||||
"design-tokens/v1",
|
||||
"variants/v1",
|
||||
"layout/grid",
|
||||
"styles/v2",
|
||||
"fdata/objects-map",
|
||||
"tokens/numeric-input",
|
||||
"render-wasm/v1",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type"
|
||||
]
|
||||
},
|
||||
"~:team-id": "~u5519794a-7293-802b-8008-16c227930902",
|
||||
"~:permissions": {
|
||||
"~:type": "~:membership",
|
||||
"~:is-owner": true,
|
||||
"~:is-admin": true,
|
||||
"~:can-edit": true,
|
||||
"~:can-read": true,
|
||||
"~:is-logged": true
|
||||
},
|
||||
"~:has-media-trimmed": false,
|
||||
"~:comment-thread-seqn": 0,
|
||||
"~:name": "File with attached lib",
|
||||
"~:revn": 3,
|
||||
"~:modified-at": "~m1787664703168",
|
||||
"~:vern": 0,
|
||||
"~:id": "~ua604eafd-4265-803c-8008-898ba4b3c8d2",
|
||||
"~:is-shared": false,
|
||||
"~:version": 67,
|
||||
"~:project-id": "~ua604eafd-4265-803c-8008-898b8b680ab4",
|
||||
"~:created-at": "~m1787664674511",
|
||||
"~:backend": "db",
|
||||
"~:data": {
|
||||
"~:pages": [
|
||||
"~ua604eafd-4265-803c-8008-898ba4b3c8d3"
|
||||
],
|
||||
"~:pages-index": {
|
||||
"~ua604eafd-4265-803c-8008-898ba4b3c8d3": {
|
||||
"~:objects": {
|
||||
"~#penpot/objects-map/v2": {
|
||||
"~u00000000-0000-0000-0000-000000000000": "[\"~#shape\",[\"^ \",\"~:y\",0,\"~:hide-fill-on-export\",false,\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:name\",\"Root Frame\",\"~:width\",0.01,\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",0.0,\"~:y\",0.0]],[\"^:\",[\"^ \",\"~:x\",0.01,\"~:y\",0.0]],[\"^:\",[\"^ \",\"~:x\",0.01,\"~:y\",0.01]],[\"^:\",[\"^ \",\"~:x\",0.0,\"~:y\",0.01]]],\"~:r2\",0,\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^3\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",0,\"~:proportion\",1.0,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",0,\"~:y\",0,\"^6\",0.01,\"~:height\",0.01,\"~:x1\",0,\"~:y1\",0,\"~:x2\",0.01,\"~:y2\",0.01]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^H\",0.01,\"~:flip-y\",null,\"~:shapes\",[\"~ud9574b23-9bcc-80d2-8008-898baf40c2e8\"]]]",
|
||||
"~ud9574b23-9bcc-80d2-8008-898baf40c2e8": "[\"~#shape\",[\"^ \",\"~:y\",100,\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:grow-type\",\"~:fixed\",\"~:hide-in-viewer\",false,\"~:name\",\"Rectangle\",\"~:width\",199.9999966621399,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",100,\"~:y\",100]],[\"^<\",[\"^ \",\"~:x\",299.9999966621399,\"~:y\",100]],[\"^<\",[\"^ \",\"~:x\",299.9999966621399,\"~:y\",199.99999511241913]],[\"^<\",[\"^ \",\"~:x\",100,\"~:y\",199.99999511241913]]],\"~:r2\",0,\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^2\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~ud9574b23-9bcc-80d2-8008-898baf40c2e8\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",100,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",100,\"~:y\",100,\"^8\",199.9999966621399,\"~:height\",99.99999511241913,\"~:x1\",100,\"~:y1\",100,\"~:x2\",299.9999966621399,\"~:y2\",199.99999511241913]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^J\",99.99999511241913,\"~:flip-y\",null]]"
|
||||
}
|
||||
},
|
||||
"~:id": "~ua604eafd-4265-803c-8008-898ba4b3c8d3",
|
||||
"~:name": "Page 1"
|
||||
}
|
||||
},
|
||||
"~:id": "~ua604eafd-4265-803c-8008-898ba4b3c8d2",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@
|
||||
"~:revn": 36,
|
||||
"~:modified-at": "~m1776760054954",
|
||||
"~:vern": 0,
|
||||
"~:id": "~u1062e0a0-8fe0-80ae-8007-e70b4993f5ef",
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:is-shared": false,
|
||||
"~:migrations": {
|
||||
"~#ordered-set": [
|
||||
@@ -423,7 +423,7 @@
|
||||
"~:key": "wgjr6b27pa",
|
||||
"~:font-size": "16",
|
||||
"~:font-weight": "400",
|
||||
"~:typography-ref-file": "~u1062e0a0-8fe0-80ae-8007-e70b4993f5ef",
|
||||
"~:typography-ref-file": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:modified-at": "~m1776759448186",
|
||||
"~:font-variant-id": "regular",
|
||||
"~:text-decoration": "none",
|
||||
@@ -445,7 +445,7 @@
|
||||
"~:key": "1dpjnycmsmq",
|
||||
"~:font-size": "16",
|
||||
"~:font-weight": "400",
|
||||
"~:typography-ref-file": "~u1062e0a0-8fe0-80ae-8007-e70b4993f5ef",
|
||||
"~:typography-ref-file": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:text-direction": "ltr",
|
||||
"~:type": "paragraph",
|
||||
"~:modified-at": "~m1776759448186",
|
||||
@@ -1079,7 +1079,7 @@
|
||||
"~:key": "wgjr6b27pa",
|
||||
"~:font-size": "18",
|
||||
"~:font-weight": "700",
|
||||
"~:typography-ref-file": "~u1062e0a0-8fe0-80ae-8007-e70b4993f5ef",
|
||||
"~:typography-ref-file": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:modified-at": "~m1776759420985",
|
||||
"~:font-variant-id": "700",
|
||||
"~:text-decoration": "none",
|
||||
@@ -1101,7 +1101,7 @@
|
||||
"~:key": "1dpjnycmsmq",
|
||||
"~:font-size": "18",
|
||||
"~:font-weight": "700",
|
||||
"~:typography-ref-file": "~u1062e0a0-8fe0-80ae-8007-e70b4993f5ef",
|
||||
"~:typography-ref-file": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:text-direction": "ltr",
|
||||
"~:type": "paragraph",
|
||||
"~:modified-at": "~m1776759420985",
|
||||
@@ -1517,7 +1517,7 @@
|
||||
"~:name": "Page 1"
|
||||
}
|
||||
},
|
||||
"~:id": "~u1062e0a0-8fe0-80ae-8007-e70b4993f5ef",
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
@@ -1554,6 +1554,18 @@
|
||||
"~:font-family": "IM Fell French Canon SC"
|
||||
}
|
||||
},
|
||||
"~:tokens-status": {
|
||||
"~#penpot/tokens-status": {
|
||||
"~:active-theme-ids": {
|
||||
"~#set": []
|
||||
},
|
||||
"~:active-set-ids": {
|
||||
"~#set": [
|
||||
"~u12f7a4ff-ddae-80ff-8007-e70bba7e2db2"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"~:tokens-lib": {
|
||||
"~#penpot/tokens-lib": {
|
||||
"~:sets": {
|
||||
|
||||
@@ -554,11 +554,14 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||
await expect(this.toolbarOptions).toHaveCSS("opacity", "0");
|
||||
}
|
||||
|
||||
async clickLayers(clickOptions = {}) {
|
||||
await this.sidebar.getByText("Layers").click(clickOptions);
|
||||
}
|
||||
async clickAssets(clickOptions = {}) {
|
||||
await this.sidebar.getByText("Assets").click(clickOptions);
|
||||
}
|
||||
async clickLayers(clickOptions = {}) {
|
||||
await this.sidebar.getByText("Layers").click(clickOptions);
|
||||
async clickTokens(clickOptions = {}) {
|
||||
await this.sidebar.getByText("Tokens").click(clickOptions);
|
||||
}
|
||||
|
||||
async openLibrariesModal(clickOptions = {}) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { WasmWorkspacePage } from "../pages/WasmWorkspacePage";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await WasmWorkspacePage.init(page);
|
||||
await WasmWorkspacePage.mockConfigFlags(page, ["enable-token-lib-sync"]);
|
||||
});
|
||||
|
||||
test("User adds a library and its automatically selected in the color palette", async ({
|
||||
@@ -31,6 +32,7 @@ test("User adds a library and its automatically selected in the color palette",
|
||||
// Now the get-file call should return a library
|
||||
await workspacePage.mockRPC(/get\-file\?/, "workspace/get-file-library.json");
|
||||
await workspacePage.openLibrariesModal();
|
||||
await workspacePage.librariesModal.getByRole("tab", { name: "Libraries" }).click();
|
||||
await workspacePage.clickLibrary("Testing library 1");
|
||||
await workspacePage.closeLibrariesModal();
|
||||
|
||||
@@ -40,6 +42,7 @@ test("User adds a library and its automatically selected in the color palette",
|
||||
|
||||
// Remove Testing library 1
|
||||
await workspacePage.openLibrariesModal();
|
||||
await workspacePage.librariesModal.getByRole("tab", { name: "This file" }).click();
|
||||
await workspacePage.clickLibrary("Testing library 1");
|
||||
await workspacePage.closeLibrariesModal();
|
||||
|
||||
|
||||
@@ -152,6 +152,7 @@ test("[Taiga #10630] [INSPECT] Style assets not being displayed on info tab", as
|
||||
await workspacePage.clickAssets();
|
||||
await workspacePage.mockRPC(/get\-file\?/, "workspace/get-file-library.json");
|
||||
await workspacePage.openLibrariesModal();
|
||||
await workspacePage.librariesModal.getByRole("tab", { name: "Libraries" }).click();
|
||||
await workspacePage.clickLibrary("Testing library 1");
|
||||
await workspacePage.closeLibrariesModal();
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ test("Multiselection of text and typographies", async ({ page }) => {
|
||||
);
|
||||
|
||||
await workspacePage.goToWorkspace({
|
||||
fileId: "1062e0a0-8fe0-80ae-8007-e70b4993f5ef",
|
||||
fileId: "c7ce0794-0992-8105-8004-38f280443849",
|
||||
pageId: "1062e0a0-8fe0-80ae-8007-e70b4993f5f0",
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { WasmWorkspacePage } from "../../pages/WasmWorkspacePage";
|
||||
import {
|
||||
setupEmptyTokensFileRender,
|
||||
createToken,
|
||||
unfoldTokenType,
|
||||
} from "./helpers";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await WasmWorkspacePage.init(page);
|
||||
});
|
||||
|
||||
test("File with tokens is its own tokens source", async ({ page }) => {
|
||||
await WasmWorkspacePage.mockConfigFlags(page, ["enable-token-lib-sync"]);
|
||||
const workspacePage = new WasmWorkspacePage(page);
|
||||
|
||||
await workspacePage.setupEmptyFile(page);
|
||||
|
||||
await workspacePage.mockRPC(
|
||||
"get-team-shared-files?team-id=*",
|
||||
"workspace/get-team-shared-libraries-non-empty.json",
|
||||
);
|
||||
|
||||
await workspacePage.goToWorkspace();
|
||||
|
||||
// A file without tokens is not tokens source
|
||||
await workspacePage.clickAssets();
|
||||
await workspacePage.openLibrariesModal();
|
||||
await workspacePage.librariesModal
|
||||
.getByRole("tab", { name: "This file" })
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
workspacePage.librariesModal.getByText("Tokens source"),
|
||||
).not.toBeVisible();
|
||||
|
||||
await workspacePage.closeLibrariesModal();
|
||||
|
||||
// Create a token in the file
|
||||
await workspacePage.clickTokens();
|
||||
await createToken(
|
||||
page,
|
||||
"Color",
|
||||
"color.primary",
|
||||
"Value",
|
||||
"textbox",
|
||||
"#ff0000",
|
||||
);
|
||||
|
||||
// Now it is a tokens source
|
||||
await workspacePage.clickAssets();
|
||||
await workspacePage.openLibrariesModal();
|
||||
await workspacePage.librariesModal
|
||||
.getByRole("tab", { name: "This file" })
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
workspacePage.librariesModal.getByText("Tokens source"),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("User sets a library as tokens source and then they can use the tokens in it", async ({
|
||||
page,
|
||||
}) => {
|
||||
await WasmWorkspacePage.mockConfigFlags(page, ["enable-token-lib-sync"]);
|
||||
|
||||
// Set up a file linked to a library with tokens
|
||||
|
||||
const { workspacePage, tokenThemesSetsSidebar, tokenContextMenuForSet } =
|
||||
await setupEmptyTokensFileRender(page);
|
||||
|
||||
await workspacePage.mockGetFile("workspace/get-file-with-lib.json");
|
||||
|
||||
await workspacePage.mockRPC(
|
||||
"get-file-libraries?file-id=*",
|
||||
"workspace/get-file-libraries-tokens.json",
|
||||
);
|
||||
|
||||
await workspacePage.mockRPC(
|
||||
/get\-file\?id=c7ce0794-0992-8105-8004-38f280443849/,
|
||||
"workspace/get-file-tokens.json",
|
||||
);
|
||||
|
||||
await workspacePage.mockRPC(
|
||||
"get-team-shared-files?team-id=*",
|
||||
"workspace/get-team-shared-libraries-non-empty.json",
|
||||
);
|
||||
|
||||
await workspacePage.goToWorkspace();
|
||||
|
||||
// Set the external library as the tokens source
|
||||
|
||||
await workspacePage.clickAssets();
|
||||
await workspacePage.openLibrariesModal();
|
||||
await workspacePage.librariesModal
|
||||
.getByRole("tab", { name: "This file" })
|
||||
.click();
|
||||
await workspacePage.librariesModal
|
||||
.getByRole("button", { name: "Set as tokens source" })
|
||||
.click();
|
||||
await workspacePage.closeLibrariesModal();
|
||||
|
||||
// Check that we can apply a token from the library to a shape
|
||||
|
||||
await workspacePage.sidebar.getByRole("tab", { name: "Tokens" }).click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Select the first shape in the file
|
||||
await page.keyboard.press("v");
|
||||
await workspacePage.clickAt(200, 150);
|
||||
|
||||
// Apply a color token from the library as the shape fill
|
||||
await workspacePage.sidebar.getByRole("tab", { name: "Tokens" }).click();
|
||||
await unfoldTokenType(workspacePage.tokensSidebar, "Color");
|
||||
|
||||
const colorTokenName = "colors.red.600";
|
||||
await workspacePage.tokensSidebar
|
||||
.getByRole("button", { name: colorTokenName })
|
||||
.click({ button: "right" });
|
||||
await workspacePage.tokenContextMenuForToken.getByText("Fill").click();
|
||||
|
||||
// Check that the token has been correctly applied in the right sidebar
|
||||
const fillSection = workspacePage.rightSidebar.getByRole("region", {
|
||||
name: "Fill section",
|
||||
});
|
||||
await expect(fillSection).toBeVisible();
|
||||
|
||||
const fillTokenPill = fillSection.getByLabel(colorTokenName, {
|
||||
exact: true,
|
||||
});
|
||||
await expect(fillTokenPill).toBeVisible();
|
||||
|
||||
// Go back to the libraries modal and set the current file as tokens source
|
||||
await workspacePage.clickAssets();
|
||||
await workspacePage.openLibrariesModal();
|
||||
await workspacePage.librariesModal
|
||||
.getByRole("tab", { name: "This file" })
|
||||
.click();
|
||||
await workspacePage.librariesModal
|
||||
.getByRole("button", { name: "Set as tokens source" })
|
||||
.click();
|
||||
await workspacePage.closeLibrariesModal();
|
||||
|
||||
// Check that the applied token now looks broken
|
||||
await expect(fillSection).toBeVisible();
|
||||
const brokenTokenPill = fillSection.getByLabel(colorTokenName, {
|
||||
exact: true,
|
||||
});
|
||||
await expect(brokenTokenPill).toBeVisible();
|
||||
await brokenTokenPill.hover();
|
||||
|
||||
const brokenTokenTooltip = page.getByRole("tooltip", {
|
||||
name: colorTokenName,
|
||||
});
|
||||
await expect(brokenTokenTooltip).toBeVisible();
|
||||
await expect(brokenTokenTooltip).toHaveText(
|
||||
`{${colorTokenName}} token does not exist or has been deleted.`,
|
||||
);
|
||||
});
|
||||
@@ -89,6 +89,12 @@ test.describe("Tokens Themes", () => {
|
||||
tokenThemeUpdateCreateModal.getByText("Changed" + "4 active sets"),
|
||||
).toBeVisible();
|
||||
|
||||
await tokenThemeUpdateCreateModal
|
||||
.getByRole("switch", {
|
||||
name: "Changed",
|
||||
})
|
||||
.click();
|
||||
|
||||
await tokenThemeUpdateCreateModal
|
||||
.getByRole("button")
|
||||
.getByText("close")
|
||||
|
||||
@@ -143,6 +143,10 @@ test("BUG 14214 - Updates tab refreshes after syncing a freshly linked library",
|
||||
// Open the library modal
|
||||
await workspace.clickAssets();
|
||||
await workspace.openLibrariesModal();
|
||||
|
||||
// Switch to the Libraries tab
|
||||
await workspace.librariesModal.getByRole("tab", { name: "Libraries" }).click();
|
||||
|
||||
await workspace.librariesModal
|
||||
.getByRole("button", { name: "Connect library" })
|
||||
.click();
|
||||
|
||||
@@ -25,7 +25,7 @@ import { WasmWorkspacePage } from "../pages/WasmWorkspacePage";
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const FILE_A = {
|
||||
id: "1062e0a0-8fe0-80ae-8007-e70b4993f5ef",
|
||||
id: "c7ce0794-0992-8105-8004-38f280443849",
|
||||
pageId: "1062e0a0-8fe0-80ae-8007-e70b4993f5f0",
|
||||
// "Text with typography asset one" carries a ref to in-file typography whose
|
||||
// font-family is "IM Fell French Canon SC" (multiselection-typography.json).
|
||||
|
||||
@@ -315,6 +315,7 @@ test("User adds a library and its automatically selected in the color palette",
|
||||
// Now the get-file call should return a library
|
||||
await workspacePage.mockRPC(/get\-file\?/, "workspace/get-file-library.json");
|
||||
await workspacePage.openLibrariesModal();
|
||||
await workspacePage.librariesModal.getByRole("tab", { name: "Libraries" }).click();
|
||||
await workspacePage.clickLibrary("Testing library 1");
|
||||
await workspacePage.closeLibrariesModal();
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
@@ -37,6 +38,23 @@
|
||||
([state file-id]
|
||||
(dm/get-in state [:files file-id :data])))
|
||||
|
||||
;; TODOstatus perhaps this is not necessary, lookup-tokens-lib should be enough
|
||||
(defn lookup-tokens-source-data
|
||||
[state]
|
||||
(let [current-file-data (lookup-file-data state)
|
||||
tokens-source-id (cfo/get-effective-tokens-source current-file-data)]
|
||||
(lookup-file-data state tokens-source-id)))
|
||||
|
||||
(defn lookup-tokens-lib
|
||||
[state]
|
||||
(let [tokens-source-data (lookup-tokens-source-data state)]
|
||||
(cfo/get-tokens-lib tokens-source-data)))
|
||||
|
||||
(defn lookup-tokens-status
|
||||
[state]
|
||||
(let [current-file-data (lookup-file-data state)] ;; Tokens status is always in the current file
|
||||
(cfo/get-tokens-status current-file-data)))
|
||||
|
||||
(defn get-page
|
||||
[fdata page-id]
|
||||
(dm/get-in fdata [:pages-index page-id]))
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
[app.common.logging :as log]
|
||||
[app.common.logic.libraries :as cll]
|
||||
[app.common.logic.shapes :as cls]
|
||||
[app.common.logic.tokens :as clo]
|
||||
[app.common.logic.variants :as clv]
|
||||
[app.common.path-names :as cpn]
|
||||
[app.common.time :as ct]
|
||||
@@ -46,6 +47,7 @@
|
||||
[app.main.data.workspace.specialized-panel :as dwsp]
|
||||
[app.main.data.workspace.thumbnails :as dwt]
|
||||
[app.main.data.workspace.thumbnails-wasm :as dwt.wasm]
|
||||
[app.main.data.workspace.tokens.propagation :as dwtp]
|
||||
[app.main.data.workspace.transforms :as dwtr]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.data.workspace.wasm-text :as dwwt]
|
||||
@@ -654,6 +656,7 @@
|
||||
(merge (meta it))))
|
||||
(dwu/start-undo-transaction undo-id)
|
||||
(dch/commit-changes changes)
|
||||
(dwtp/propagate-workspace-tokens) ;; Make the new instance get the token values from the current file, not from the component's library
|
||||
(ptk/data-event :layout/update {:ids [(:id new-shape)]})
|
||||
(dws/select-shapes (d/ordered-set (:id new-shape)))
|
||||
(when start-move?
|
||||
@@ -837,7 +840,11 @@
|
||||
(rx/merge
|
||||
(->> (rx/of library-id)
|
||||
(rx/delay 5000)
|
||||
(rx/map fetch-library-thumbnails)))
|
||||
(rx/map fetch-library-thumbnails))
|
||||
(when (ch/tokens-lib-changed? changes)
|
||||
(rx/of (dwtp/propagate-workspace-tokens)))
|
||||
(when (ch/notifiable-token-change-occured? changes)
|
||||
(rx/of (ntf/info (tr "workspace.tokens.notifications.source-sets-or-themes-updated")))))
|
||||
|
||||
(rx/take-until stopper-s))))))
|
||||
|
||||
@@ -1096,6 +1103,7 @@
|
||||
(rx/of
|
||||
(dwu/start-undo-transaction undo-id)
|
||||
(dch/commit-changes changes)
|
||||
(dwtp/propagate-workspace-tokens) ;; Make the new instance get the token values from the current file, not from the component's library
|
||||
(when (and (features/active-feature? state "render-wasm/v1")
|
||||
(seq new-text-ids))
|
||||
(dwwt/resize-wasm-text-all new-text-ids))
|
||||
@@ -1345,6 +1353,9 @@
|
||||
#(do (apply st/emit! (map (fn [library]
|
||||
(sync-file file-id (:id library)))
|
||||
libraries-with-changes))
|
||||
;; Launch a local tokens propagation, so that the copies have the token values
|
||||
;; with the local tokens status, not the one coming from the external library.
|
||||
(st/emit! (dwtp/propagate-workspace-tokens))
|
||||
(st/emit! (ntf/hide)))
|
||||
|
||||
do-dismiss
|
||||
@@ -1397,8 +1408,8 @@
|
||||
(launch-component-sync component-id file-id undo-group)))))
|
||||
|
||||
(defn watch-component-changes
|
||||
"Watch the state for changes that affect to any main instance. If a change is detected will throw
|
||||
an update-component-sync, so changes are immediately propagated to the component and copies."
|
||||
"Watch the state for changes that affect to any main instance. If a change is detected will call
|
||||
component-changed, so changes are immediately propagated to the component and copies."
|
||||
[]
|
||||
(ptk/reify ::watch-component-changes
|
||||
ptk/WatchEvent
|
||||
@@ -1530,6 +1541,47 @@
|
||||
|
||||
(rx/take-until stopper-s)))))))
|
||||
|
||||
(defn sync-tokens-status-with-lib
|
||||
[]
|
||||
(ptk/reify ::sync-tokens-status-with-lib
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [tokens-lib (dsh/lookup-tokens-lib state)
|
||||
tokens-status (dsh/lookup-tokens-status state)]
|
||||
(when (and tokens-lib tokens-status)
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
changes (-> (pcb/empty-changes)
|
||||
(pcb/with-library-data data)
|
||||
(clo/generate-sync-tokens-status-with-lib tokens-status tokens-lib))]
|
||||
(rx/of (dch/commit-changes changes))))))))
|
||||
|
||||
(defn watch-token-changes
|
||||
"Watch the state for changes that affect the tokens library. If a change is detected,
|
||||
launches a sync-tokens-status event so the tokens-status is kept in sync with the library."
|
||||
[]
|
||||
(ptk/reify ::watch-token-changes
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
(let [stopper-s
|
||||
(->> stream
|
||||
(rx/map ptk/type)
|
||||
(rx/filter (fn [event-type]
|
||||
(or (= ::dwpg/finalize-page event-type)
|
||||
(= ::watch-token-changes event-type)))))
|
||||
|
||||
changes-s
|
||||
(->> stream
|
||||
(rx/filter dch/commit?)
|
||||
(rx/map deref)
|
||||
(rx/filter #(= :local (:source %)))
|
||||
(rx/observe-on :async))]
|
||||
|
||||
(->> changes-s
|
||||
(rx/filter (comp ch/tokens-lib-changed? :changes))
|
||||
(rx/debounce 5000)
|
||||
(rx/map (fn [_] (sync-tokens-status-with-lib)))
|
||||
(rx/take-until stopper-s))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Backend interactions
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -1575,6 +1627,7 @@
|
||||
(map #(assoc % :library-of file-id))
|
||||
(d/index-by :id))))))
|
||||
|
||||
|
||||
(defn- load-library-file
|
||||
[file-id library-id]
|
||||
(ptk/reify ::load-library-file
|
||||
@@ -1584,8 +1637,9 @@
|
||||
(rx/merge
|
||||
(->> (rp/cmd! :get-file {:id library-id :features features})
|
||||
(rx/merge-map fpmap/resolve-file)
|
||||
(rx/map (fn [file]
|
||||
(libraries-fetched file-id [file]))))
|
||||
(rx/mapcat (fn [file]
|
||||
(rx/of
|
||||
(libraries-fetched file-id [file])))))
|
||||
(->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id :tag "component"})
|
||||
(rx/map (fn [thumbnails]
|
||||
(fn [state]
|
||||
@@ -1594,10 +1648,10 @@
|
||||
|
||||
(defn link-file-to-library
|
||||
[file-id library-id]
|
||||
(ptk/reify ::attach-library
|
||||
(ptk/reify ::link-file-to-library
|
||||
ev/Event
|
||||
(-data [_]
|
||||
{::ev/name "attach-library"
|
||||
{::ev/name "link-file-to-library"
|
||||
:file-id file-id
|
||||
:library-id library-id})
|
||||
|
||||
@@ -1614,23 +1668,22 @@
|
||||
(map first)
|
||||
set)]
|
||||
(rx/concat
|
||||
(rx/merge
|
||||
(->> (rp/cmd! :link-file-to-library {:file-id file-id :library-id library-id})
|
||||
(rx/merge-map (fn [libraries-to-load]
|
||||
(as-> libraries-to-load $
|
||||
(remove loaded-libraries $)
|
||||
(conj $ library-id)
|
||||
(map #(load-library-file file-id %) $))))
|
||||
(rx/catch (fn [cause]
|
||||
(let [error (ex-data cause)]
|
||||
(if (= (:code error) :circular-library-reference)
|
||||
(rx/of (ntf/error (tr "errors.circular-library-reference")))
|
||||
(rx/throw cause)))))))
|
||||
(rx/of (ptk/reify ::attach-library-finished))
|
||||
(->> (rp/cmd! :link-file-to-library {:file-id file-id :library-id library-id})
|
||||
(rx/merge-map (fn [libraries-to-load]
|
||||
(as-> libraries-to-load $
|
||||
(remove loaded-libraries $)
|
||||
(conj $ library-id)
|
||||
(map #(load-library-file file-id %) $))))
|
||||
(rx/catch (fn [cause]
|
||||
(let [error (ex-data cause)]
|
||||
(if (= (:code error) :circular-library-reference)
|
||||
(rx/of (ntf/error (tr "errors.circular-library-reference")))
|
||||
(rx/throw cause))))))
|
||||
(rx/of (ptk/reify ::link-file-to-library-finished))
|
||||
(when (pos? variants-count)
|
||||
(->> (rp/cmd! :get-library-usage {:file-id library-id})
|
||||
(rx/map (fn [library-usage]
|
||||
(ev/event {::ev/name "attach-library-variants"
|
||||
(ev/event {::ev/name "link-file-to-library-variants"
|
||||
:file-id file-id
|
||||
:library-id library-id
|
||||
:variants-count variants-count
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
(rx/of (dwth/watch-state-changes file-id page-id)))
|
||||
|
||||
(rx/of (dwl/watch-component-changes))
|
||||
(rx/of (dwl/watch-token-changes))
|
||||
|
||||
(let [profile (:profile state)
|
||||
props (get profile :props)]
|
||||
|
||||
@@ -22,11 +22,9 @@
|
||||
[app.common.types.text :as txt]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.changes :as dch]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.workspace :as-alias dw]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.modifiers :as dwm]
|
||||
[app.main.data.workspace.pages :as-alias dwpg]
|
||||
[app.main.data.workspace.reflow :as wrf]
|
||||
@@ -1168,66 +1166,6 @@
|
||||
(let [{:keys [name]} (fonts/get-font-data font-id)]
|
||||
(assoc typography :name (str name " " (str/title font-variant-id)))))
|
||||
|
||||
(defn add-typography
|
||||
"A higher level version of dwl/add-typography, and has mainly two
|
||||
responsabilities: add the typography to the library and apply it to
|
||||
the currently selected text shapes (being aware of the open text
|
||||
editors.
|
||||
Optionally accepts a group-path to place the new typography inside
|
||||
a specific group."
|
||||
([file-id] (add-typography file-id nil))
|
||||
([file-id group-path]
|
||||
(ptk/reify ::add-typography
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [selected (dsh/lookup-selected state)
|
||||
objects (dsh/lookup-page-objects state)
|
||||
|
||||
xform (comp (keep (d/getf objects))
|
||||
(filter cfh/text-shape?))
|
||||
shapes (into [] xform selected)
|
||||
shape (first shapes)
|
||||
|
||||
values (current-text-values
|
||||
{:editor-state (dm/get-in state [:workspace-editor-state (:id shape)])
|
||||
:shape shape
|
||||
:attrs txt/text-node-attrs})
|
||||
|
||||
multiple? (or (> 1 (count shapes))
|
||||
(d/seek (partial = :multiple)
|
||||
(vals values)))
|
||||
|
||||
values (-> (d/without-nils values)
|
||||
(select-keys
|
||||
(d/concat-vec txt/text-font-attrs
|
||||
txt/text-spacing-attrs
|
||||
txt/text-transform-attrs)))
|
||||
values (cond-> values
|
||||
(number? (:line-height values))
|
||||
(update :line-height #(str (mth/precision % 2)))
|
||||
|
||||
(number? (:letter-spacing values))
|
||||
(update :letter-spacing #(str (mth/precision % 2))))
|
||||
|
||||
typ-id (uuid/next)
|
||||
typ (-> (if multiple?
|
||||
txt/default-typography
|
||||
(merge txt/default-typography values))
|
||||
(generate-typography-name)
|
||||
(assoc :id typ-id)
|
||||
(cond-> (string? group-path)
|
||||
(update :name #(str group-path " / " %))))]
|
||||
|
||||
(rx/concat
|
||||
(rx/of (dwl/add-typography typ)
|
||||
(ev/event {::ev/name "add-asset-to-library"
|
||||
:asset-type "typography"}))
|
||||
|
||||
(when (not multiple?)
|
||||
(rx/of (update-attrs (:id shape)
|
||||
{:typography-ref-id typ-id
|
||||
:typography-ref-file file-id})))))))))
|
||||
|
||||
;; -- Text Editor v2
|
||||
|
||||
(defn v2-update-text-editor-styles
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
;; 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 SUBSIDIARY SL
|
||||
|
||||
(ns app.main.data.workspace.texts-events
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.types.text :as txt]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.workspace :as-alias dw]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.pages :as-alias dwpg]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
;; This function must be separated from app.main.data.workspace.texts to avoid a circular
|
||||
;; dependency due main.data.workspace.libraries eventually calling app.main.data.workspace.texts.
|
||||
|
||||
(defn add-typography
|
||||
"A higher level version of dwl/add-typography, and has mainly two
|
||||
responsabilities: add the typography to the library and apply it to
|
||||
the currently selected text shapes (being aware of the open text
|
||||
editors.
|
||||
Optionally accepts a group-path to place the new typography inside
|
||||
a specific group."
|
||||
([file-id] (add-typography file-id nil))
|
||||
([file-id group-path]
|
||||
(ptk/reify ::add-typography
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [selected (dsh/lookup-selected state)
|
||||
objects (dsh/lookup-page-objects state)
|
||||
|
||||
xform (comp (keep (d/getf objects))
|
||||
(filter cfh/text-shape?))
|
||||
shapes (into [] xform selected)
|
||||
shape (first shapes)
|
||||
|
||||
values (dwt/current-text-values
|
||||
{:editor-state (dm/get-in state [:workspace-editor-state (:id shape)])
|
||||
:shape shape
|
||||
:attrs txt/text-node-attrs})
|
||||
|
||||
multiple? (or (> 1 (count shapes))
|
||||
(d/seek (partial = :multiple)
|
||||
(vals values)))
|
||||
|
||||
values (-> (d/without-nils values)
|
||||
(select-keys
|
||||
(d/concat-vec txt/text-font-attrs
|
||||
txt/text-spacing-attrs
|
||||
txt/text-transform-attrs)))
|
||||
values (cond-> values
|
||||
(number? (:line-height values))
|
||||
(update :line-height #(str (mth/precision % 2)))
|
||||
|
||||
(number? (:letter-spacing values))
|
||||
(update :letter-spacing #(str (mth/precision % 2))))
|
||||
|
||||
typ-id (uuid/next)
|
||||
typ (-> (if multiple?
|
||||
txt/default-typography
|
||||
(merge txt/default-typography values))
|
||||
(dwt/generate-typography-name)
|
||||
(assoc :id typ-id)
|
||||
(cond-> (string? group-path)
|
||||
(update :name #(str group-path " / " %))))]
|
||||
|
||||
(rx/concat
|
||||
(rx/of (dwl/add-typography typ)
|
||||
(ev/event {::ev/name "add-asset-to-library"
|
||||
:asset-type "typography"}))
|
||||
|
||||
(when (not multiple?)
|
||||
(rx/of (dwt/update-attrs (:id shape)
|
||||
{:typography-ref-id typ-id
|
||||
:typography-ref-file file-id})))))))))
|
||||
@@ -25,7 +25,6 @@
|
||||
[app.main.data.style-dictionary :as sd]
|
||||
[app.main.data.tinycolor :as tinycolor]
|
||||
[app.main.data.tokenscript :as ts]
|
||||
[app.main.data.workspace :as udw]
|
||||
[app.main.data.workspace.colors :as wdc]
|
||||
[app.main.data.workspace.shape-layout :as dwsl]
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
@@ -95,11 +94,11 @@
|
||||
(watch [_ _ _]
|
||||
(when (number? value)
|
||||
(rx/of
|
||||
(udw/trigger-bounding-box-cloaking shape-ids)
|
||||
(udw/increase-rotation shape-ids value nil
|
||||
{:page-id page-id
|
||||
:ignore-touched true
|
||||
:no-wasm? true})))))))
|
||||
(dwtr/trigger-bounding-box-cloaking shape-ids)
|
||||
(dwtr/increase-rotation shape-ids value nil
|
||||
{:page-id page-id
|
||||
:ignore-touched true
|
||||
:no-wasm? true})))))))
|
||||
|
||||
(defn update-stroke-width
|
||||
([value shape-ids attributes] (update-stroke-width value shape-ids attributes nil))
|
||||
@@ -675,9 +674,10 @@
|
||||
(ctt/typography-token-keys (:type token)) (set/union attributes-to-remove ctt/typography-keys)
|
||||
(ctt/typography-keys (:type token)) (set/union attributes-to-remove ctt/typography-token-keys)
|
||||
:else attributes-to-remove)]
|
||||
(when-let [tokens (some-> (dsh/lookup-file-data state)
|
||||
(get :tokens-lib)
|
||||
(ctob/get-tokens-in-active-sets))]
|
||||
(when-let [tokens (let [tokens-lib (dsh/lookup-tokens-lib state)
|
||||
tokens-status (dsh/lookup-tokens-status state)]
|
||||
(when (and tokens-lib tokens-status)
|
||||
(cfo/get-tokens-in-active-sets tokens-status tokens-lib)))]
|
||||
(->> (if (contains? cf/flags :tokenscript)
|
||||
(rx/of (ts/resolve-tokens tokens))
|
||||
(sd/resolve-tokens tokens))
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.changes-builder :as pcb]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.logic.tokens :as clt]
|
||||
[app.common.logic.tokens :as clo]
|
||||
[app.common.path-names :as cpn]
|
||||
[app.common.test-helpers.ids-map :as cthi]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.changes :as dch]
|
||||
[app.main.data.event :as ev]
|
||||
@@ -34,19 +36,12 @@
|
||||
;; TOKENS Getters
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; FIXME: lookup rename
|
||||
|
||||
(defn get-tokens-lib
|
||||
[state]
|
||||
(-> (dsh/lookup-file-data state)
|
||||
(get :tokens-lib)))
|
||||
|
||||
(defn lookup-token-set
|
||||
([state]
|
||||
(when-let [selected (dm/get-in state [:workspace-tokens :selected-token-set-id])]
|
||||
(lookup-token-set state selected)))
|
||||
([state id]
|
||||
(some-> (get-tokens-lib state)
|
||||
(some-> (dsh/lookup-tokens-lib state)
|
||||
(ctob/get-set id))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -231,8 +226,7 @@
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tokens-lib (get data :tokens-lib)]
|
||||
|
||||
tokens-lib (dsh/lookup-tokens-lib state)]
|
||||
(if (and tokens-lib (ctob/get-theme tokens-lib (ctob/get-id token-theme)))
|
||||
(rx/of (ntf/show {:content (tr "errors.token-theme-already-exists")
|
||||
:type :toast
|
||||
@@ -249,8 +243,8 @@
|
||||
(ptk/reify ::update-token-theme
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tokens-lib (get data :tokens-lib)]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tokens-lib (dsh/lookup-tokens-lib state)]
|
||||
(if (and (not= id (ctob/get-id token-theme))
|
||||
(ctob/get-theme tokens-lib (ctob/get-id token-theme)))
|
||||
(rx/of (ntf/show {:content (tr "errors.token-theme-already-exists")
|
||||
@@ -259,7 +253,7 @@
|
||||
:timeout 9000}))
|
||||
(let [changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(pcb/set-token-theme (ctob/get-id token-theme) token-theme))]
|
||||
(clo/generate-update-token-theme token-theme))]
|
||||
(rx/of (dch/commit-changes changes))))))))
|
||||
|
||||
(defn set-token-theme-active
|
||||
@@ -269,31 +263,35 @@
|
||||
(ptk/reify ::set-token-theme-active
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tokens-lib (get-tokens-lib state)
|
||||
changes (-> (pcb/empty-changes)
|
||||
(pcb/with-library-data data)
|
||||
(clt/generate-set-active-token-theme tokens-lib id active?))]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tokens-status (dsh/lookup-tokens-status state)
|
||||
tokens-lib (dsh/lookup-tokens-lib state)
|
||||
changes (-> (pcb/empty-changes)
|
||||
(pcb/with-library-data data)
|
||||
(clo/generate-set-theme-status tokens-status tokens-lib id active?))]
|
||||
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(dwtp/propagate-workspace-tokens))))))
|
||||
|
||||
(defn toggle-token-theme-active
|
||||
[id]
|
||||
(assert (uuid? id) "expected a uuid for `id`")
|
||||
(ptk/reify ::toggle-token-theme-active
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tokens-lib (get-tokens-lib state)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(clt/generate-toggle-token-theme tokens-lib id))]
|
||||
(let [data (dsh/lookup-tokens-source-data state)
|
||||
tokens-status (dsh/lookup-tokens-status state)
|
||||
tokens-lib (dsh/lookup-tokens-lib state)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(clo/generate-toggle-theme tokens-status tokens-lib id))]
|
||||
(rx/of
|
||||
(dch/commit-changes changes)
|
||||
(dwtp/propagate-workspace-tokens))))))
|
||||
|
||||
(defn delete-token-theme
|
||||
[id]
|
||||
(assert (uuid? id) "expected a uuid for `id`")
|
||||
(ptk/reify ::delete-token-theme
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
@@ -350,10 +348,11 @@
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tokens-lib (get data :tokens-lib)
|
||||
tokens-lib (dsh/lookup-tokens-lib state)
|
||||
suffix (tr "workspace.tokens.duplicate-suffix")]
|
||||
|
||||
(when-let [token-set (ctob/duplicate-set id tokens-lib {:suffix suffix})]
|
||||
(when-let [token-set (when tokens-lib
|
||||
(ctob/duplicate-set id tokens-lib {:suffix suffix}))]
|
||||
(when id-ref (reset! id-ref (ctob/get-id token-set)))
|
||||
(let [changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
@@ -362,32 +361,34 @@
|
||||
(dch/commit-changes changes)))))))))
|
||||
|
||||
(defn set-enabled-token-set
|
||||
[name enabled?]
|
||||
(assert (string? name) "expected a string for `name`")
|
||||
[id enabled?]
|
||||
(assert (uuid? id) "expected a uuid for `id`")
|
||||
(assert (boolean? enabled?) "expected a boolean for `enabled?`")
|
||||
(ptk/reify ::set-enabled-token-set
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tlib (get-tokens-lib state)
|
||||
changes (-> (pcb/empty-changes)
|
||||
(pcb/with-library-data data)
|
||||
(clt/generate-set-enabled-token-set tlib name enabled?))]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tokens-lib (dsh/lookup-tokens-lib state)
|
||||
tokens-status (dsh/lookup-tokens-status state)
|
||||
changes (-> (pcb/empty-changes)
|
||||
(pcb/with-library-data data)
|
||||
(clo/generate-set-enabled-token-set tokens-status tokens-lib id enabled?))]
|
||||
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(dwtp/propagate-workspace-tokens))))))
|
||||
|
||||
(defn toggle-token-set
|
||||
[name]
|
||||
(assert (string? name) "expected a string for `name`")
|
||||
[id]
|
||||
(assert (uuid? id) "expected a uuid for `id`")
|
||||
(ptk/reify ::toggle-token-set
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tlib (get-tokens-lib state)
|
||||
changes (-> (pcb/empty-changes)
|
||||
(pcb/with-library-data data)
|
||||
(clt/generate-toggle-token-set tlib name))]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tokens-lib (dsh/lookup-tokens-lib state)
|
||||
tokens-status (dsh/lookup-tokens-status state)
|
||||
changes (-> (pcb/empty-changes)
|
||||
(pcb/with-library-data data)
|
||||
(clo/generate-toggle-token-set tokens-status tokens-lib id))]
|
||||
|
||||
(rx/of
|
||||
(dch/commit-changes changes)
|
||||
@@ -398,10 +399,12 @@
|
||||
(ptk/reify ::toggle-token-set-group
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
changes (-> (pcb/empty-changes)
|
||||
(pcb/with-library-data data)
|
||||
(clt/generate-toggle-token-set-group (get-tokens-lib state) group-path))]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tokens-lib (dsh/lookup-tokens-lib state)
|
||||
tokens-status (dsh/lookup-tokens-status state)
|
||||
changes (-> (pcb/empty-changes)
|
||||
(pcb/with-library-data data)
|
||||
(clo/generate-toggle-token-set-group tokens-status tokens-lib group-path))]
|
||||
|
||||
(rx/of
|
||||
(dch/commit-changes changes)
|
||||
@@ -413,12 +416,27 @@
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
status (cfo/make-tokens-status-from-lib lib)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(pcb/set-tokens-lib lib))]
|
||||
(pcb/set-tokens-lib lib)
|
||||
(pcb/set-tokens-status status))]
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(dwtp/propagate-workspace-tokens))))))
|
||||
|
||||
(defn set-tokens-source
|
||||
[library-id]
|
||||
(ptk/reify ::set-tokens-source
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
library (dsh/lookup-file state library-id)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(clo/generate-set-tokens-source library)
|
||||
(pcb/set-tokens-source library-id))]
|
||||
(rx/of (dch/commit-changes changes))))))
|
||||
|
||||
(defn delete-token-set
|
||||
[id]
|
||||
(ptk/reify ::delete-token-set
|
||||
@@ -439,7 +457,7 @@
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(clt/generate-delete-token-set-group (get-tokens-lib state) path))]
|
||||
(clo/generate-delete-token-set-group (dsh/lookup-tokens-lib state) path))]
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(dwtp/propagate-workspace-tokens))))))
|
||||
|
||||
@@ -467,7 +485,7 @@
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(try
|
||||
(when-let [changes (clt/generate-move-token-set-group (pcb/empty-changes it) (get-tokens-lib state) drop-opts)]
|
||||
(when-let [changes (clo/generate-move-token-set-group (pcb/empty-changes it) (dsh/lookup-tokens-lib state) drop-opts)]
|
||||
(rx/of
|
||||
(dch/commit-changes changes)
|
||||
(dwtp/propagate-workspace-tokens)))
|
||||
@@ -483,9 +501,9 @@
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(try
|
||||
(let [tokens-lib (get-tokens-lib state)
|
||||
(let [tokens-lib (dsh/lookup-tokens-lib state)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(clt/generate-move-token-set tokens-lib params))]
|
||||
(clo/generate-move-token-set tokens-lib params))]
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(dwtp/propagate-workspace-tokens)))
|
||||
(catch :default cause
|
||||
@@ -506,11 +524,13 @@
|
||||
token-set
|
||||
(ctob/make-token-set :name set-name)
|
||||
|
||||
hidden-theme
|
||||
(ctob/make-hidden-theme)
|
||||
hidden-theme ;; For legacy compatibility only
|
||||
(-> (ctob/make-hidden-theme)
|
||||
(ctob/enable-set set-name))
|
||||
|
||||
hidden-theme-with-set
|
||||
(ctob/enable-set hidden-theme set-name)
|
||||
token-status
|
||||
(ctos/make-tokens-status :active-theme-ids #{}
|
||||
:active-set-ids #{(ctob/get-id token-set)})
|
||||
|
||||
changes
|
||||
(-> (pcb/empty-changes)
|
||||
@@ -518,8 +538,9 @@
|
||||
(pcb/set-token-set (ctob/get-id token-set) token-set)
|
||||
(pcb/set-token (ctob/get-id token-set) (:id token) token)
|
||||
(pcb/set-token-theme (ctob/get-id hidden-theme)
|
||||
hidden-theme-with-set)
|
||||
(pcb/set-active-token-themes #{ctob/hidden-theme-path}))]
|
||||
hidden-theme)
|
||||
(pcb/set-tokens-status token-status))]
|
||||
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(set-selected-token-set-id (ctob/get-id token-set)))))))
|
||||
|
||||
@@ -559,7 +580,7 @@
|
||||
(let [token-set (lookup-token-set state set-id)
|
||||
data (dsh/lookup-file-data state)
|
||||
changes (reduce (fn [changes token-id]
|
||||
(let [token (-> (get-tokens-lib state)
|
||||
(let [token (-> (dsh/lookup-tokens-lib state)
|
||||
(ctob/get-token (ctob/get-id token-set) token-id))
|
||||
new-name (->
|
||||
(cpn/split-path (:name token) :separator ".")
|
||||
@@ -589,21 +610,22 @@
|
||||
(lookup-token-set state set-id)
|
||||
(lookup-token-set state))
|
||||
data (dsh/lookup-file-data state)
|
||||
token (-> (get-tokens-lib state)
|
||||
(ctob/get-token (ctob/get-id token-set) id))
|
||||
token' (->> (merge token params)
|
||||
(into {})
|
||||
(ctob/make-token))
|
||||
token-type (:type token)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(pcb/set-token (ctob/get-id token-set)
|
||||
id
|
||||
token'))]
|
||||
(toggle-token-path (str (name token-type) "." (:name token)))
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(ev/event (-> {::ev/name "edit-token" :type token-type}
|
||||
(merge (meta it))))))))))
|
||||
tokens-lib (dsh/lookup-tokens-lib state)]
|
||||
(when (and tokens-lib token-set)
|
||||
(let [token (ctob/get-token tokens-lib (ctob/get-id token-set) id)
|
||||
token' (->> (merge token params)
|
||||
(into {})
|
||||
(ctob/make-token))
|
||||
token-type (:type token)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(pcb/set-token (ctob/get-id token-set)
|
||||
id
|
||||
token'))]
|
||||
(toggle-token-path (str (name token-type) "." (:name token)))
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(ev/event (-> {::ev/name "edit-token" :type token-type}
|
||||
(merge (meta it))))))))))))
|
||||
|
||||
(defn bulk-update-tokens
|
||||
[set-id token-ids type old-path new-path & {:keys [undo-group]}]
|
||||
@@ -617,7 +639,7 @@
|
||||
(lookup-token-set state))
|
||||
data (dsh/lookup-file-data state)
|
||||
changes (reduce (fn [changes token-id]
|
||||
(let [token (-> (get-tokens-lib state)
|
||||
(let [token (-> (dsh/lookup-tokens-lib state)
|
||||
(ctob/get-token (ctob/get-id token-set) token-id))
|
||||
new-name (str/replace (:name token) old-path new-path)
|
||||
token' (->> (merge token {:name new-name})
|
||||
@@ -643,19 +665,20 @@
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
tokens-lib (dsh/lookup-tokens-lib state)
|
||||
token-set (if set-id
|
||||
(lookup-token-set state set-id)
|
||||
(lookup-token-set state))
|
||||
token (-> (get-tokens-lib state)
|
||||
(ctob/get-token (ctob/get-id token-set) token-id))
|
||||
token-type (:type token)
|
||||
(lookup-token-set state))]
|
||||
(when (and tokens-lib token-set)
|
||||
(let [token (ctob/get-token tokens-lib (ctob/get-id token-set) token-id)
|
||||
token-type (:type token)
|
||||
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(pcb/set-token set-id token-id nil))]
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(ev/event (-> {::ev/name "delete-token" :type token-type}
|
||||
(merge (meta it)))))))))
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(pcb/set-token set-id token-id nil))]
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(ev/event (-> {::ev/name "delete-token" :type token-type}
|
||||
(merge (meta it)))))))))))
|
||||
|
||||
(defn bulk-delete-tokens
|
||||
[set-id token-ids]
|
||||
@@ -680,7 +703,7 @@
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(when-let [token-set (lookup-token-set state)]
|
||||
(when-let [tokens-lib (get-tokens-lib state)]
|
||||
(when-let [tokens-lib (dsh/lookup-tokens-lib state)]
|
||||
(when-let [token (ctob/get-token tokens-lib
|
||||
(ctob/get-id token-set)
|
||||
token-id)]
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.logging :as l]
|
||||
[app.common.time :as ct]
|
||||
[app.common.types.token :as ctt]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.config :as cf]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.style-dictionary :as sd]
|
||||
@@ -188,27 +188,28 @@
|
||||
(ptk/reify ::propagate-workspace-tokens
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(when-let [tokens-tree (-> (dsh/lookup-file-data state)
|
||||
(get :tokens-lib)
|
||||
(ctob/get-tokens-in-active-sets))]
|
||||
(->> (if (contains? cf/flags :tokenscript)
|
||||
(rx/of (-> (ts/resolve-tokens tokens-tree)
|
||||
(d/update-vals #(update % :resolved-value ts/tokenscript-symbols->penpot-unit))))
|
||||
(sd/resolve-tokens tokens-tree))
|
||||
(rx/mapcat
|
||||
(fn [sd-tokens]
|
||||
(let [undo-id (js/Symbol)]
|
||||
(rx/concat
|
||||
(rx/of (dwu/start-undo-transaction undo-id :timeout false))
|
||||
(let [tokens-lib (dsh/lookup-tokens-lib state)
|
||||
tokens-status (dsh/lookup-tokens-status state)]
|
||||
(when (and tokens-lib tokens-status)
|
||||
(when-let [tokens-tree (cfo/get-tokens-in-active-sets tokens-status tokens-lib)]
|
||||
(->> (if (contains? cf/flags :tokenscript)
|
||||
(rx/of (-> (ts/resolve-tokens tokens-tree)
|
||||
(d/update-vals #(update % :resolved-value ts/tokenscript-symbols->penpot-unit))))
|
||||
(sd/resolve-tokens tokens-tree))
|
||||
(rx/mapcat
|
||||
(fn [sd-tokens]
|
||||
(let [undo-id (js/Symbol)]
|
||||
(rx/concat
|
||||
(rx/of (dwu/start-undo-transaction undo-id :timeout false))
|
||||
|
||||
;; FIXME: now the tokens propagations is done by accumulating the update-shapes
|
||||
;; into a single commit-changes. This is not really the best way, the token application
|
||||
;; should be done with a changes_builder and sending only one `commit-changes` instead
|
||||
;; of creating lots of `update-shapes`.
|
||||
(rx/of (dwsh/update-shapes-buffer-start))
|
||||
(->> (propagate-tokens state sd-tokens)
|
||||
(rx/catch #(rx/concat
|
||||
(rx/of (dwsh/update-shapes-buffer-stop))
|
||||
(rx/throw %))))
|
||||
(rx/of (dwsh/update-shapes-buffer-stop))
|
||||
(rx/of (dwu/commit-undo-transaction undo-id)))))))))))
|
||||
;; FIXME: now the tokens propagations is done by accumulating the update-shapes
|
||||
;; into a single commit-changes. This is not really the best way, the token application
|
||||
;; should be done with a changes_builder and sending only one `commit-changes` instead
|
||||
;; of creating lots of `update-shapes`.
|
||||
(rx/of (dwsh/update-shapes-buffer-start))
|
||||
(->> (propagate-tokens state sd-tokens)
|
||||
(rx/catch #(rx/concat
|
||||
(rx/of (dwsh/update-shapes-buffer-stop))
|
||||
(rx/throw %))))
|
||||
(rx/of (dwsh/update-shapes-buffer-stop))
|
||||
(rx/of (dwu/commit-undo-transaction undo-id)))))))))))))
|
||||
@@ -13,26 +13,22 @@
|
||||
|
||||
(defn- get-selected-token-set-id [state]
|
||||
(or (get-in state [:workspace-tokens :selected-token-set-id])
|
||||
(some-> (dsh/lookup-file-data state)
|
||||
(get :tokens-lib)
|
||||
(some-> (dsh/lookup-tokens-lib state)
|
||||
(ctob/get-sets)
|
||||
(first)
|
||||
(ctob/get-id))))
|
||||
|
||||
(defn get-selected-token-set [state]
|
||||
(when-let [set-id (get-selected-token-set-id state)]
|
||||
(some-> (dsh/lookup-file-data state)
|
||||
(get :tokens-lib)
|
||||
(some-> (dsh/lookup-tokens-lib state)
|
||||
(ctob/get-set set-id))))
|
||||
|
||||
(defn get-token-in-selected-set [state token-id]
|
||||
(when-let [set-id (get-selected-token-set-id state)]
|
||||
(some-> (dsh/lookup-file-data state)
|
||||
(get :tokens-lib)
|
||||
(some-> (dsh/lookup-tokens-lib state)
|
||||
(ctob/get-token set-id token-id))))
|
||||
|
||||
(defn get-all-tokens-in-selected-set [state]
|
||||
(when-let [set-id (get-selected-token-set-id state)]
|
||||
(some-> (dsh/lookup-file-data state)
|
||||
(get :tokens-lib)
|
||||
(some-> (dsh/lookup-tokens-lib state)
|
||||
(ctob/get-tokens set-id))))
|
||||
@@ -10,9 +10,11 @@
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cph]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.types.shape-tree :as ctt]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.config :as cf]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.workspace.tokens.selected-set :as dwts]
|
||||
@@ -464,7 +466,10 @@
|
||||
;; ---- Token refs
|
||||
|
||||
(def tokens-lib
|
||||
(l/derived :tokens-lib workspace-data))
|
||||
(l/derived dsh/lookup-tokens-lib st/state))
|
||||
|
||||
(def tokens-status
|
||||
(l/derived dsh/lookup-tokens-status st/state))
|
||||
|
||||
(def workspace-token-theme-groups
|
||||
(l/derived (d/nilf ctob/get-theme-groups) tokens-lib))
|
||||
@@ -501,26 +506,28 @@
|
||||
(def workspace-token-sets-tree
|
||||
(l/derived (d/nilf ctob/get-set-tree) tokens-lib))
|
||||
|
||||
(def workspace-active-theme-paths
|
||||
(l/derived (d/nilf ctob/get-active-theme-paths) tokens-lib))
|
||||
(def workspace-active-theme-ids
|
||||
(l/derived (d/nilf ctos/get-active-theme-ids) tokens-status))
|
||||
|
||||
(def workspace-all-tokens-map
|
||||
(l/derived (d/nilf ctob/get-all-tokens-map) tokens-lib))
|
||||
|
||||
;; TODOstatus ver una forma eficiente de hacer un derived de lib y status a la vez
|
||||
(defn token-sets-at-path-all-active
|
||||
[group-path]
|
||||
(l/derived
|
||||
(fn [lib]
|
||||
(when lib
|
||||
(ctob/sets-at-path-all-active? lib group-path)))
|
||||
tokens-lib))
|
||||
|
||||
(def workspace-active-theme-paths-no-hidden
|
||||
(l/derived #(disj % ctob/hidden-theme-path) workspace-active-theme-paths))
|
||||
(fn [status]
|
||||
(when status
|
||||
(cfo/sets-at-path-all-active? status @(l/derived identity tokens-lib) group-path)))
|
||||
tokens-status))
|
||||
|
||||
;; FIXME: deprecated, it should not be implemented with ref (still used in form)
|
||||
(def workspace-active-theme-sets-tokens
|
||||
(l/derived #(or (some-> % ctob/get-tokens-in-active-sets) {}) tokens-lib))
|
||||
(l/derived (fn [[status lib]]
|
||||
(if (and status lib)
|
||||
(cfo/get-tokens-in-active-sets status lib)
|
||||
{}))
|
||||
[tokens-status tokens-lib]))
|
||||
|
||||
(def workspace-token-in-selected-set
|
||||
(fn [token-id]
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
|
||||
.icon {
|
||||
color: var(--arrow-icon-color);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.title-wrapper {
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
(def libraries (mf/create-context nil))
|
||||
(def design-tokens (mf/create-context nil))
|
||||
(def token-inputs (mf/create-context nil))
|
||||
(def tokens-lib (mf/create-context nil))
|
||||
(def tokens-status (mf/create-context nil))
|
||||
|
||||
(def current-scroll (mf/create-context nil))
|
||||
(def current-zoom (mf/create-context nil))
|
||||
@@ -45,6 +47,7 @@
|
||||
|
||||
(def permissions (mf/create-context nil))
|
||||
(def can-edit? (mf/create-context nil))
|
||||
(def can-edit-tokens? (mf/create-context nil))
|
||||
|
||||
(def active-tokens-by-type
|
||||
"Active tokens by type, used mainly for provide tokens data to the
|
||||
|
||||
@@ -313,7 +313,8 @@
|
||||
"A collection of all icons"
|
||||
(collect-icons))
|
||||
|
||||
(def ^:private ^:const icon-size-l 32)
|
||||
(def ^:private ^:const icon-size-xl 32)
|
||||
(def ^:private ^:const icon-size-l 24)
|
||||
(def ^:private ^:const icon-size-m 16)
|
||||
(def ^:private ^:const icon-size-s 12)
|
||||
|
||||
@@ -322,12 +323,13 @@
|
||||
[:class {:optional true} [:maybe :string]]
|
||||
[:icon-id [:and :string [:fn #(contains? icon-list %)]]]
|
||||
[:size {:optional true}
|
||||
[:maybe [:enum "s" "m" "l"]]]])
|
||||
[:maybe [:enum "s" "m" "l" "xl"]]]])
|
||||
|
||||
(mf/defc icon*
|
||||
{::mf/schema schema:icon}
|
||||
[{:keys [icon-id size class] :rest props}]
|
||||
(let [size-px (cond (= size "l") icon-size-l
|
||||
(let [size-px (cond (= size "xl") icon-size-xl
|
||||
(= size "l") icon-size-l
|
||||
(= size "s") icon-size-s
|
||||
:else icon-size-m)
|
||||
offset (if (or (= size "s") (= size "m"))
|
||||
|
||||
@@ -25,6 +25,6 @@
|
||||
(when icon
|
||||
[:div {:class (stl/css :icon-wrapper)}
|
||||
[:> icon* {:icon-id icon
|
||||
:size "l"
|
||||
:size "xl"
|
||||
:class (stl/css :icon)}]])
|
||||
[:div {:class (stl/css :text)} text]]))
|
||||
@@ -9,6 +9,7 @@
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.types.component :as ctc]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
@@ -111,11 +112,17 @@
|
||||
panels (type->panel-group shape-type)
|
||||
|
||||
tokens-lib (mf/deref refs/tokens-lib)
|
||||
active-themes (mf/deref refs/workspace-active-theme-paths-no-hidden)
|
||||
active-sets (mf/with-memo [tokens-lib]
|
||||
(some-> tokens-lib (ctob/get-active-themes-set-names)))
|
||||
active-tokens (mf/with-memo [tokens-lib]
|
||||
(some-> tokens-lib (ctob/get-tokens-in-active-sets)))
|
||||
tokens-status (mf/deref refs/tokens-status)
|
||||
active-theme-ids (mf/deref refs/workspace-active-theme-ids)
|
||||
active-themes (mf/with-memo [active-theme-ids tokens-lib]
|
||||
(when tokens-lib
|
||||
(keep #(some-> (ctob/get-theme tokens-lib %) ctob/get-name) active-theme-ids)))
|
||||
active-sets (mf/with-memo [tokens-status tokens-lib]
|
||||
(when (and tokens-status tokens-lib)
|
||||
(cfo/get-active-sets tokens-status tokens-lib)))
|
||||
active-tokens (mf/with-memo [tokens-status tokens-lib]
|
||||
(when (and tokens-status tokens-lib)
|
||||
(cfo/get-tokens-in-active-sets tokens-status tokens-lib)))
|
||||
resolved-active-tokens (sd/use-resolved-tokens* active-tokens)
|
||||
has-visibility-props? (mf/use-fn
|
||||
(fn [shape]
|
||||
@@ -152,7 +159,7 @@
|
||||
(when (or (seq active-themes) (seq active-sets))
|
||||
[:li
|
||||
[:> style-box* {:panel :token}
|
||||
[:> tokens-panel* {:theme-paths active-themes :set-names active-sets}]]])
|
||||
[:> tokens-panel* {:theme-names active-themes :set-names (map ctob/get-name active-sets)}]]])
|
||||
(for [panel panels]
|
||||
[:li {:key (d/name panel)}
|
||||
(case panel
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc tokens-panel*
|
||||
[{:keys [theme-paths set-names]}]
|
||||
[{:keys [theme-names set-names]}]
|
||||
[:div {:class (stl/css :tokens-panel)}
|
||||
(when (seq theme-paths)
|
||||
(let [theme-list (str/join ", " theme-paths)]
|
||||
(when (seq theme-names)
|
||||
(let [theme-list (str/join ", " theme-names)]
|
||||
[:> properties-row* {:class (stl/css :token-theme)
|
||||
:term (tr "inspect.tabs.styles.active-themes")
|
||||
:detail theme-list}]))
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.types.color :as cc]
|
||||
@@ -759,10 +760,15 @@
|
||||
tokens-lib
|
||||
(mf/deref refs/tokens-lib)
|
||||
|
||||
tokens-status
|
||||
(mf/deref refs/tokens-status)
|
||||
|
||||
active-sets-names
|
||||
(mf/with-memo [tokens-lib]
|
||||
(some-> tokens-lib
|
||||
(ctob/get-active-themes-set-names)))
|
||||
(mf/with-memo [tokens-status tokens-lib]
|
||||
(when (and tokens-status tokens-lib)
|
||||
(into #{}
|
||||
(map ctob/get-name)
|
||||
(cfo/get-active-sets tokens-status tokens-lib))))
|
||||
|
||||
active-tokens (if (delay? active-tokens)
|
||||
@active-tokens
|
||||
@@ -782,7 +788,7 @@
|
||||
(filter-active-sets active-sets-names)
|
||||
(filter-non-empty-sets)
|
||||
(group-sets)
|
||||
(combine-groups-with-resolved color-tokens)))]
|
||||
(combine-groups-with-resolved color-tokens)))]
|
||||
|
||||
(mf/with-effect []
|
||||
(st/emit! (st/emit! (dsc/push-shortcuts ::colorpicker sc/shortcuts :workspace)))
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.files.variant :as cfv]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.file :as ctf]
|
||||
@@ -24,6 +25,7 @@
|
||||
[app.main.data.team :as dtm]
|
||||
[app.main.data.workspace.colors :as mdc]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.render :refer [component-svg]]
|
||||
[app.main.store :as st]
|
||||
@@ -34,7 +36,8 @@
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]]
|
||||
[app.main.ui.ds.foundations.typography.text :refer [text*]]
|
||||
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
|
||||
[app.main.ui.ds.product.empty-state :refer [empty-state*]]
|
||||
[app.main.ui.hooks :as h]
|
||||
@@ -56,16 +59,27 @@
|
||||
typographies (count (:typographies data))
|
||||
components (count (->> (ctkl/components-seq data)
|
||||
(remove #(cfv/is-secondary-variant? % data))))
|
||||
tokens-lib (cfo/get-tokens-lib data)
|
||||
tokens (if (some? tokens-lib) (count (ctob/get-all-tokens tokens-lib)) 0)
|
||||
token-sets (if (some? tokens-lib) (count (ctob/get-sets tokens-lib)) 0)
|
||||
token-themes (if (some? tokens-lib) (count (ctob/get-themes-no-hidden tokens-lib)) 0)
|
||||
|
||||
empty? (and (zero? components)
|
||||
(zero? graphics)
|
||||
(zero? colors)
|
||||
(zero? typographies))]
|
||||
(zero? typographies)
|
||||
(zero? tokens)
|
||||
(zero? token-sets)
|
||||
(zero? token-themes))]
|
||||
|
||||
{:is-empty empty?
|
||||
:colors colors
|
||||
:graphics graphics
|
||||
:typographies typographies
|
||||
:components components}))
|
||||
:components components
|
||||
:tokens tokens
|
||||
:token-sets token-sets
|
||||
:token-themes token-themes}))
|
||||
|
||||
(defn- adapt-backend-summary
|
||||
[summary]
|
||||
@@ -73,16 +87,25 @@
|
||||
graphics (or (-> summary :media :count) 0)
|
||||
typographies (or (-> summary :typographies :count) 0)
|
||||
colors (or (-> summary :colors :count) 0)
|
||||
tokens (or (-> summary :tokens-count) 0)
|
||||
token-sets (or (-> summary :token-sets-count) 0)
|
||||
token-themes (or (-> summary :token-themes-count) 0)
|
||||
|
||||
empty? (and (zero? components)
|
||||
(zero? graphics)
|
||||
(zero? colors)
|
||||
(zero? typographies))]
|
||||
{:is-empty empty?
|
||||
:components components
|
||||
:graphics graphics
|
||||
(zero? typographies)
|
||||
(zero? tokens)
|
||||
(zero? token-sets)
|
||||
(zero? token-themes))]
|
||||
{:is-empty empty?
|
||||
:components components
|
||||
:graphics graphics
|
||||
:typographies typographies
|
||||
:colors colors}))
|
||||
:colors colors
|
||||
:tokens tokens
|
||||
:token-sets token-sets
|
||||
:token-themes token-themes}))
|
||||
|
||||
(defn- describe-library
|
||||
[components-count graphics-count colors-count typography-count]
|
||||
@@ -108,28 +131,88 @@
|
||||
|
||||
(mf/defc library-description*
|
||||
{::mf/private true}
|
||||
[{:keys [summary]}]
|
||||
(let [components-count (get summary :components)
|
||||
graphics-count (get summary :graphics)
|
||||
typography-count (get summary :typographies)
|
||||
colors-count (get summary :colors)]
|
||||
[{:keys [summary hint-name]}]
|
||||
(let [components-count (get summary :components)
|
||||
graphics-count (get summary :graphics)
|
||||
typography-count (get summary :typographies)
|
||||
colors-count (get summary :colors)
|
||||
tokens-count (get summary :tokens)
|
||||
token-sets-count (get summary :token-sets)
|
||||
token-themes-count (get summary :token-themes)
|
||||
|
||||
[:*
|
||||
(when (pos? components-count)
|
||||
[:li {:class (stl/css :element-count)}
|
||||
(tr "workspace.libraries.components" (c components-count))])
|
||||
token-lib-sync? (contains? cf/flags :token-lib-sync)
|
||||
|
||||
(when (pos? graphics-count)
|
||||
[:li {:class (stl/css :element-count)}
|
||||
(tr "workspace.libraries.graphics" (c graphics-count))])
|
||||
elements-line
|
||||
(str/join " · "
|
||||
(cond-> []
|
||||
(pos? components-count)
|
||||
(conj (tr "workspace.libraries.components" (c components-count)))
|
||||
|
||||
(when (pos? colors-count)
|
||||
[:li {:class (stl/css :element-count)}
|
||||
(tr "workspace.libraries.colors" (c colors-count))])
|
||||
(pos? graphics-count)
|
||||
(conj (tr "workspace.libraries.graphics" (c graphics-count)))
|
||||
|
||||
(when (pos? typography-count)
|
||||
[:li {:class (stl/css :element-count)}
|
||||
(tr "workspace.libraries.typography" (c typography-count))])]))
|
||||
(pos? colors-count)
|
||||
(conj (tr "workspace.libraries.colors" (c colors-count)))
|
||||
|
||||
(pos? typography-count)
|
||||
(conj (tr "workspace.libraries.typography" (c typography-count)))))
|
||||
|
||||
tokens-line
|
||||
(str/join " · "
|
||||
(cond-> []
|
||||
(pos? tokens-count)
|
||||
(conj (tr "workspace.libraries.tokens" (c tokens-count)))
|
||||
|
||||
(pos? token-sets-count)
|
||||
(conj (tr "workspace.libraries.token-sets" (c token-sets-count)))
|
||||
|
||||
(pos? token-themes-count)
|
||||
(conj (tr "workspace.libraries.token-themes" (c token-themes-count)))))]
|
||||
|
||||
(if token-lib-sync?
|
||||
;; New format: show elements and tokens in separate lines
|
||||
[:*
|
||||
(when-not (str/empty? elements-line)
|
||||
[:li {:class (stl/css :element-count-line)} elements-line])
|
||||
|
||||
(when-not (str/empty? tokens-line)
|
||||
[:li {:class (stl/css :element-count-line)} tokens-line])
|
||||
|
||||
(when hint-name
|
||||
[:li {:class (stl/css :hint-line)}
|
||||
"(" (tr "workspace.libraries.connected-through") " "
|
||||
[:span {:class (stl/css :hint-library-name)} hint-name]
|
||||
")"])]
|
||||
|
||||
;; Old format: show each item individually
|
||||
[:*
|
||||
(when (pos? components-count)
|
||||
[:li {:class (stl/css :element-count-legacy)}
|
||||
(tr "workspace.libraries.components" (c components-count))])
|
||||
|
||||
(when (pos? graphics-count)
|
||||
[:li {:class (stl/css :element-count-legacy)}
|
||||
(tr "workspace.libraries.graphics" (c graphics-count))])
|
||||
|
||||
(when (pos? colors-count)
|
||||
[:li {:class (stl/css :element-count-legacy)}
|
||||
(tr "workspace.libraries.colors" (c colors-count))])
|
||||
|
||||
(when (pos? typography-count)
|
||||
[:li {:class (stl/css :element-count-legacy)}
|
||||
(tr "workspace.libraries.typography" (c typography-count))])
|
||||
|
||||
(when (pos? tokens-count)
|
||||
[:li {:class (stl/css :element-count-legacy)}
|
||||
(tr "workspace.libraries.tokens" (c tokens-count))])
|
||||
|
||||
(when (pos? token-sets-count)
|
||||
[:li {:class (stl/css :element-count-legacy)}
|
||||
(tr "workspace.libraries.token-sets" (c token-sets-count))])
|
||||
|
||||
(when (pos? token-themes-count)
|
||||
[:li {:class (stl/css :element-count-legacy)}
|
||||
(tr "workspace.libraries.token-themes" (c token-themes-count))])])))
|
||||
|
||||
(mf/defc sample-library-entry*
|
||||
{::mf/private true}
|
||||
@@ -182,7 +265,7 @@
|
||||
(when-let [tokens-lib (get data :tokens-lib)]
|
||||
(not (ctob/empty-lib? tokens-lib))))
|
||||
|
||||
(mf/defc libraries-tab*
|
||||
(mf/defc libraries-tab-legacy*
|
||||
{::mf/private true}
|
||||
[{:keys [is-shared linked-libraries shared-libraries]}]
|
||||
(let [file-id (mf/use-ctx ctx/current-file-id)
|
||||
@@ -262,7 +345,7 @@
|
||||
|
||||
unlink-library
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
(mf/deps file-id local-library)
|
||||
(fn [event]
|
||||
(let [library-id (some-> (dom/get-current-target event)
|
||||
(dom/get-data "library-id")
|
||||
@@ -270,7 +353,11 @@
|
||||
(when (= library-id @selected)
|
||||
(reset! selected :file))
|
||||
(st/emit! (dwl/unlink-file-from-library file-id library-id)
|
||||
(dwl/sync-file file-id library-id)))))
|
||||
(dwl/sync-file file-id library-id))
|
||||
;; When the unlinked library is the current tokens source,
|
||||
;; we must reset it to the local library.
|
||||
(when (cfo/effective-tokens-source? local-library library-id)
|
||||
(st/emit! (dwtl/set-tokens-source (:id local-library)))))))
|
||||
|
||||
import-tokens
|
||||
(mf/use-fn
|
||||
@@ -283,6 +370,7 @@
|
||||
:tokens/import-from-library {:file-id file-id
|
||||
:library-id library-id})))))
|
||||
|
||||
|
||||
on-delete-accept
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
@@ -324,7 +412,7 @@
|
||||
:on-cancel on-delete-cancel
|
||||
:count-libraries 1}))))]
|
||||
|
||||
[:div {:class (stl/css :libraries-content)}
|
||||
[:div {:class (stl/css :libraries-content-legacy)}
|
||||
[:div {:class (stl/css :lib-section)}
|
||||
[:> title-bar* {:collapsable false
|
||||
:title (tr "workspace.libraries.in-this-file")
|
||||
@@ -334,7 +422,7 @@
|
||||
[:div {:class (stl/css :section-list-publish)}
|
||||
[:div {:class (stl/css :item-content)}
|
||||
[:div {:class (stl/css :item-title)} (tr "workspace.libraries.file-library")]
|
||||
[:ul {:class (stl/css :item-contents)}
|
||||
[:ul {:class (stl/css :item-contents-legacy)}
|
||||
[:> library-description* {:summary summary}]]]
|
||||
|
||||
(if ^boolean is-shared
|
||||
@@ -352,21 +440,21 @@
|
||||
(let [disabled? (some #(contains? linked-libraries-ids %) connected-to)
|
||||
has-tokens? (and (has-tokens? library)
|
||||
(contains? cf/flags :token-import-from-library))]
|
||||
[:div {:class (stl/css :section-list-item)
|
||||
[:div {:class (stl/css :section-list-item-legacy)
|
||||
:key (dm/str id)
|
||||
:data-testid "library-item"}
|
||||
[:div {:class (stl/css :item-content)}
|
||||
[:div {:class (stl/css-case :item-name true
|
||||
:item-name-short has-tokens?)} name]
|
||||
[:ul {:class (stl/css :item-contents)}
|
||||
[:div {:class (stl/css :item-name)} name]
|
||||
[:ul {:class (stl/css :item-contents-legacy)}
|
||||
(let [summary (get-library-summary data)]
|
||||
[:*
|
||||
[:> library-description* {:summary summary}]
|
||||
(when (seq connected-to)
|
||||
[:div {:class (stl/css :connected-to-wrapper)}
|
||||
[:div {:class (stl/css :connected-to-wrapper-legacy)}
|
||||
[:span "(" (tr "workspace.libraries.connected-to") " "]
|
||||
[:span {:class (stl/css :connected-to-values)} (str/join ", " connected-to-names)]
|
||||
[:span ")"]])])]]
|
||||
|
||||
[:div {:class (stl/css :library-actions)}
|
||||
(when ^boolean has-tokens?
|
||||
[:> icon-button*
|
||||
@@ -397,12 +485,12 @@
|
||||
(if (seq shared-libraries)
|
||||
[:div {:class (stl/css :section-list-shared)}
|
||||
(for [{:keys [id name] :as library} shared-libraries]
|
||||
[:div {:class (stl/css :section-list-item)
|
||||
[:div {:class (stl/css :section-list-item-legacy)
|
||||
:key (dm/str id)
|
||||
:data-testid "library-item"}
|
||||
[:div {:class (stl/css :item-content)}
|
||||
[:div {:class (stl/css :item-name)} name]
|
||||
[:ul {:class (stl/css :item-contents)}
|
||||
[:ul {:class (stl/css :item-contents-legacy)}
|
||||
(let [summary (-> (:library-summary library)
|
||||
(adapt-backend-summary))]
|
||||
[:> library-description* {:summary summary}])]]
|
||||
@@ -439,6 +527,372 @@
|
||||
:else
|
||||
(tr "workspace.libraries.no-matches-for" search-term))]))]]))
|
||||
|
||||
(mf/defc libraries-tab*
|
||||
{::mf/private true}
|
||||
[{:keys [linked-libraries shared-libraries]}]
|
||||
(let [file-id (mf/use-ctx ctx/current-file-id)
|
||||
search-term* (mf/use-state "")
|
||||
search-term (deref search-term*)
|
||||
|
||||
|
||||
selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent)
|
||||
dependencies (mf/with-memo [shared-libraries]
|
||||
(into {} (map (juxt :id :library-file-ids) (vals shared-libraries))))
|
||||
|
||||
library-names (mf/with-memo [shared-libraries]
|
||||
(into {} (map (fn [{:keys [id name]}]
|
||||
[id name])
|
||||
(vals shared-libraries))))
|
||||
|
||||
find-connected-to
|
||||
(mf/use-fn
|
||||
(mf/deps dependencies)
|
||||
(fn [library-id]
|
||||
(->> dependencies
|
||||
(keep (fn [[k v]] (when (contains? v library-id) k))))))
|
||||
|
||||
shared-libraries
|
||||
(mf/with-memo [shared-libraries linked-libraries file-id search-term]
|
||||
(when shared-libraries
|
||||
(->> (vals shared-libraries)
|
||||
(remove #(= (:id %) file-id))
|
||||
(filter #(matches-search (:name %) search-term))
|
||||
(map #(assoc % :connected-to (find-connected-to (:id %))))
|
||||
(map #(assoc % :connected-to-names (->> (:connected-to %)
|
||||
(keep library-names))))
|
||||
(map #(assoc % :linked? (contains? linked-libraries (:id %))))
|
||||
(sort-by (comp str/lower :name)))))
|
||||
|
||||
|
||||
importing*
|
||||
(mf/use-state nil)
|
||||
|
||||
sample-libraries
|
||||
(mf/with-memo []
|
||||
[{:id "penpot-design-system", :name "Design system example"}
|
||||
{:id "wireframing-kit", :name "Wireframe library"}
|
||||
{:id "whiteboarding-kit", :name "Whiteboarding Kit"}])
|
||||
|
||||
|
||||
change-search-term
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(reset! search-term* event)))
|
||||
|
||||
link-library
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
(fn [event]
|
||||
(let [library-id (some-> (dom/get-current-target event)
|
||||
(dom/get-data "library-id")
|
||||
(uuid/parse))]
|
||||
(reset! selected library-id)
|
||||
(st/emit! (dwl/link-file-to-library file-id library-id)))))]
|
||||
|
||||
[:div {:class (stl/css :libraries-content)}
|
||||
[:div {:class (stl/css :shared-section)}
|
||||
[:> title-bar* {:collapsable false
|
||||
:title (tr "workspace.libraries.shared-libraries")
|
||||
:class (stl/css :title-spacing-lib)}]
|
||||
[:> search-bar* {:on-change change-search-term
|
||||
:value search-term
|
||||
:placeholder (tr "workspace.libraries.search-shared-libraries")
|
||||
:icon-id i/search}]
|
||||
|
||||
(if (seq shared-libraries)
|
||||
[:div {:class (stl/css :section-list-shared)}
|
||||
(for [{:keys [id name linked?] :as library} shared-libraries]
|
||||
[:div {:class (stl/css :section-list-item)
|
||||
:key (dm/str id)
|
||||
:data-testid "library-item"}
|
||||
[:div {:class (stl/css :item-content)}
|
||||
[:div {:class (stl/css :item-name)} name]
|
||||
[:ul {:class (stl/css :item-contents)}
|
||||
(let [summary (-> (:library-summary library)
|
||||
(adapt-backend-summary))]
|
||||
[:> library-description* {:summary summary}])]]
|
||||
|
||||
(if ^boolean linked?
|
||||
[:> text* {:class (stl/css :shared-library-added)
|
||||
:as "span"
|
||||
:typography "body-medium"}
|
||||
[:> icon* {:icon-id i/tick
|
||||
:class (stl/css :shared-library-added-icon)}]
|
||||
(tr "workspace.libraries.shared-library-added")]
|
||||
[:> icon-button* {:class (stl/css :item-button-shared)
|
||||
:variant "secondary"
|
||||
:data-library-id (dm/str id)
|
||||
:icon "add"
|
||||
:aria-label (tr "workspace.libraries.shared-library-btn")
|
||||
:on-click link-library}])])]
|
||||
|
||||
(when (empty? shared-libraries)
|
||||
[:div {:class (stl/css :section-list-empty)}
|
||||
(cond
|
||||
(nil? shared-libraries)
|
||||
(tr "workspace.libraries.loading")
|
||||
|
||||
(str/empty? search-term)
|
||||
[:*
|
||||
[:div {:class (stl/css :sample-libraries-info)}
|
||||
(tr "workspace.libraries.empty.no-libraries")
|
||||
[:a {:target "_blank"
|
||||
:class (stl/css :sample-libraries-link)
|
||||
:href "https://penpot.app/libraries-templates"}
|
||||
(tr "workspace.libraries.empty.some-templates")]]
|
||||
[:div {:class (stl/css :sample-libraries-container)}
|
||||
(tr "workspace.libraries.empty.add-some")
|
||||
(for [library sample-libraries]
|
||||
[:> sample-library-entry*
|
||||
{:library library
|
||||
:key (dm/str (:id library))
|
||||
:importing importing*}])]]
|
||||
|
||||
:else
|
||||
(tr "workspace.libraries.no-matches-for" search-term))]))]]))
|
||||
|
||||
(mf/defc file-tab*
|
||||
{::mf/private true}
|
||||
[{:keys [is-shared linked-libraries shared-libraries on-change-tab]}]
|
||||
(let [file-id (mf/use-ctx ctx/current-file-id)
|
||||
|
||||
;; The summary of the current/local library
|
||||
;; NOTE: we only need a snapshot of current library
|
||||
local-library (deref refs/workspace-data)
|
||||
summary (get-library-summary local-library)
|
||||
empty-library? (empty-library? summary)
|
||||
|
||||
selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent)
|
||||
dependencies (mf/with-memo [shared-libraries]
|
||||
(into {} (map (juxt :id :library-file-ids) (vals shared-libraries))))
|
||||
|
||||
library-names (mf/with-memo [shared-libraries]
|
||||
(into {} (map (fn [{:keys [id name]}]
|
||||
[id name])
|
||||
(vals shared-libraries))))
|
||||
|
||||
find-connected-to
|
||||
(mf/use-fn
|
||||
(mf/deps dependencies)
|
||||
(fn [library-id]
|
||||
(->> dependencies
|
||||
(keep (fn [[k v]] (when (contains? v library-id) k))))))
|
||||
|
||||
linked-libraries
|
||||
(mf/with-memo [linked-libraries find-connected-to library-names]
|
||||
(let [libs
|
||||
(->> (vals linked-libraries)
|
||||
(map #(assoc % :connected-to (find-connected-to (:id %)))))
|
||||
|
||||
linked-ids
|
||||
(into #{} (map :id) libs)
|
||||
|
||||
sort-by-name
|
||||
(partial sort-by (comp str/lower :name))
|
||||
|
||||
parent-id
|
||||
(fn [{:keys [connected-to]}]
|
||||
(first (filter linked-ids connected-to)))
|
||||
|
||||
nested-by-parent
|
||||
(->> libs
|
||||
(filter parent-id)
|
||||
(map #(assoc %
|
||||
:nested? true
|
||||
:parent-name (library-names (parent-id %))))
|
||||
(group-by parent-id)
|
||||
(d/mapm (fn [_ v] (sort-by-name v))))]
|
||||
|
||||
(->> libs
|
||||
(remove parent-id)
|
||||
(map #(assoc % :nested? false))
|
||||
(sort-by-name)
|
||||
(mapcat (fn [{:keys [id] :as library}]
|
||||
(cons library (get nested-by-parent id [])))))))
|
||||
|
||||
linked-libraries-ids
|
||||
(mf/with-memo [linked-libraries]
|
||||
(into #{} d/xf:map-id linked-libraries))
|
||||
|
||||
unlink-library
|
||||
(mf/use-fn
|
||||
(mf/deps file-id local-library)
|
||||
(fn [event]
|
||||
(let [library-id (some-> (dom/get-current-target event)
|
||||
(dom/get-data "library-id")
|
||||
(uuid/parse))]
|
||||
(when (= library-id @selected)
|
||||
(reset! selected :file))
|
||||
(st/emit! (dwl/unlink-file-from-library file-id library-id)
|
||||
(dwl/sync-file file-id library-id))
|
||||
;; When the unlinked library is the current tokens source,
|
||||
;; we must reset it to the local library.
|
||||
(when (cfo/effective-tokens-source? local-library library-id)
|
||||
(st/emit! (dwtl/set-tokens-source (:id local-library)))))))
|
||||
|
||||
import-tokens
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
(fn [event]
|
||||
(let [library-id (some-> (dom/get-current-target event)
|
||||
(dom/get-data "library-id")
|
||||
(uuid/parse))]
|
||||
(st/emit! (modal/show
|
||||
:tokens/import-from-library {:file-id file-id
|
||||
:library-id library-id})))))
|
||||
|
||||
set-as-tokens-source
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [library-id (some-> (dom/get-current-target event)
|
||||
(dom/get-data "library-id")
|
||||
(uuid/parse))]
|
||||
(st/emit! (dwtl/set-tokens-source library-id)))))
|
||||
|
||||
on-delete-accept
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
#(st/emit! (dwl/set-file-shared file-id false)
|
||||
(modal/show :libraries-dialog {:file-id file-id})))
|
||||
|
||||
on-delete-cancel
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
#(st/emit! (modal/show :libraries-dialog {:file-id file-id})))
|
||||
|
||||
publish
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
(fn [event]
|
||||
(let [input-node (dom/get-target event)
|
||||
publish-library #(st/emit! (dwl/set-file-shared file-id true))
|
||||
cancel-publish #(st/emit! (modal/show :libraries-dialog {:file-id file-id}))]
|
||||
(if empty-library?
|
||||
(st/emit! (modal/show
|
||||
{:type :confirm
|
||||
:title (tr "modals.publish-empty-library.title")
|
||||
:message (tr "modals.publish-empty-library.message")
|
||||
:accept-label (tr "modals.publish-empty-library.accept")
|
||||
:on-accept publish-library
|
||||
:on-cancel cancel-publish}))
|
||||
(publish-library))
|
||||
(dom/blur! input-node))))
|
||||
|
||||
unpublish
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
(fn [_]
|
||||
(st/emit! (modal/show
|
||||
{:type :delete-shared-libraries
|
||||
:ids #{file-id}
|
||||
:origin :unpublish
|
||||
:on-accept on-delete-accept
|
||||
:on-cancel on-delete-cancel
|
||||
:count-libraries 1}))))
|
||||
|
||||
go-to-shared
|
||||
(mf/use-fn
|
||||
(mf/deps on-change-tab)
|
||||
(fn [_]
|
||||
(on-change-tab "libraries")))]
|
||||
|
||||
[:div {:class (stl/css :lib-section)}
|
||||
[:> title-bar* {:collapsable false
|
||||
:title "ASSETS IN THIS FILE"
|
||||
:class (stl/css :title-spacing-lib)}]
|
||||
[:div {:class (stl/css :section-list)}
|
||||
[:div {:class (stl/css :section-list-publish)}
|
||||
[:div {:class (stl/css :item-content)}
|
||||
[:div {:class (stl/css :item-title)} (tr "workspace.libraries.file-library")]
|
||||
[:ul {:class (stl/css :item-contents)}
|
||||
[:> library-description* {:summary summary}]]]
|
||||
(when (and (contains? cf/flags :token-lib-sync)
|
||||
(cfo/effective-tokens-source? local-library (:id local-library))
|
||||
(cfo/has-own-tokens? local-library))
|
||||
[:> text* {:class (stl/css :tokens-source-label)
|
||||
:as "span"
|
||||
:typography "body-medium"}
|
||||
(tr "workspace.libraries.tokens-source")])
|
||||
(when (and (contains? cf/flags :token-lib-sync)
|
||||
(not (cfo/effective-tokens-source? local-library (:id local-library))))
|
||||
[:> button* {:variant "secondary"
|
||||
:type "button"
|
||||
:data-library-id (dm/str (:id local-library))
|
||||
:on-click set-as-tokens-source}
|
||||
(tr "workspace.libraries.set-as-tokens-source")])
|
||||
|
||||
(if ^boolean is-shared
|
||||
[:> button* {:variant "secondary"
|
||||
:type "button"
|
||||
:on-click unpublish}
|
||||
(tr "common.unpublish")]
|
||||
|
||||
[:> button* {:variant "primary"
|
||||
:type "button"
|
||||
:on-click publish}
|
||||
(tr "common.publish")])]
|
||||
|
||||
[:div {:class (stl/css :section-list-linked)}
|
||||
[:> title-bar* {:collapsable false
|
||||
:title (tr "workspace.libraries.connected-libraries")
|
||||
:class (stl/css :title-spacing-lib)
|
||||
:title-class (stl/css :connected-libraries-title)}]
|
||||
(if (seq linked-libraries)
|
||||
(for [{:keys [id name data connected-to nested? parent-name] :as library} linked-libraries]
|
||||
(let [disabled? (some #(contains? linked-libraries-ids %) connected-to)
|
||||
has-tokens? (and (has-tokens? library)
|
||||
(contains? cf/flags :token-import-from-library))]
|
||||
[:div {:class (stl/css-case :section-list-item true
|
||||
:section-list-item-nested nested?)
|
||||
:key (dm/str id)
|
||||
:data-testid "library-item"}
|
||||
[:div {:class (stl/css :item-content)}
|
||||
[:div {:class (stl/css :item-name)} name]
|
||||
[:ul {:class (stl/css :item-contents)}
|
||||
(let [summary (get-library-summary data)]
|
||||
[:> library-description* {:summary summary :hint-name parent-name}])]]
|
||||
|
||||
[:div {:class (stl/css :library-actions)}
|
||||
(when (and (contains? cf/flags :token-lib-sync)
|
||||
(cfo/effective-tokens-source? local-library id))
|
||||
[:> text* {:class (stl/css :tokens-source-label)
|
||||
:as "span"
|
||||
:typography "body-medium"}
|
||||
(tr "workspace.libraries.tokens-source")])
|
||||
(if (contains? cf/flags :token-lib-sync)
|
||||
(when (and (cfo/tokens-provider? (:data library))
|
||||
(not (cfo/effective-tokens-source? local-library id)))
|
||||
[:> button* {:variant "secondary"
|
||||
:type "button"
|
||||
:data-library-id (dm/str id)
|
||||
:on-click set-as-tokens-source}
|
||||
(tr "workspace.libraries.set-as-tokens-source")])
|
||||
(when ^boolean has-tokens?
|
||||
[:> icon-button*
|
||||
{:type "button"
|
||||
:aria-label (tr "workspace.tokens.import-tokens")
|
||||
:icon i/import-export
|
||||
:data-library-id (dm/str id)
|
||||
:variant "secondary"
|
||||
:on-click import-tokens}]))
|
||||
|
||||
[:> icon-button* {:type "button"
|
||||
:aria-label (tr "workspace.libraries.unlink-library-btn")
|
||||
:icon i/detach
|
||||
:data-library-id (dm/str id)
|
||||
:variant "secondary"
|
||||
:disabled disabled?
|
||||
:on-click unlink-library}]]]))
|
||||
[:div {:class (stl/css :shared-libraries-empty)}
|
||||
[:> text* {:class (stl/css :empty-libraries-text)
|
||||
:as "span"
|
||||
:typography "body-small"}
|
||||
(tr "workspace.libraries.empty.no-connected-libraries")]
|
||||
[:button {:class (stl/css :go-to-shared-button)
|
||||
:on-click go-to-shared}
|
||||
"Add a shared library"]])]]]))
|
||||
|
||||
|
||||
(defn- extract-assets
|
||||
[file-data library summary?]
|
||||
(let [exceeded (volatile! {:components false
|
||||
@@ -534,7 +988,7 @@
|
||||
[:div {:class (stl/css :section-list-item)
|
||||
:key (dm/str id)}
|
||||
[:div {:class (stl/css :item-content)}
|
||||
[:div {:class (stl/css :item-name-long)} name]
|
||||
[:div {:class (stl/css :item-name)} name]
|
||||
[:ul {:class (stl/css :item-contents)} (describe-library
|
||||
(count components)
|
||||
0
|
||||
@@ -655,8 +1109,10 @@
|
||||
(fn [_]
|
||||
(modal/hide!)))
|
||||
|
||||
token-lib-sync? (contains? cf/flags :token-lib-sync)
|
||||
|
||||
selected-tab*
|
||||
(mf/use-state #(d/nilv starting-tab "libraries"))
|
||||
(mf/use-state #(d/nilv starting-tab (if token-lib-sync? "file" "libraries")))
|
||||
|
||||
selected-tab
|
||||
(deref selected-tab*)
|
||||
@@ -665,11 +1121,18 @@
|
||||
(mf/use-fn #(reset! selected-tab* %))
|
||||
|
||||
tabs
|
||||
(mf/with-memo []
|
||||
[{:label (tr "workspace.libraries.libraries")
|
||||
:id "libraries"}
|
||||
{:label (tr "workspace.libraries.updates")
|
||||
:id "updates"}])]
|
||||
(mf/with-memo [token-lib-sync?]
|
||||
(if token-lib-sync?
|
||||
[{:label "This file"
|
||||
:id "file"}
|
||||
{:label (tr "workspace.libraries.libraries")
|
||||
:id "libraries"}
|
||||
{:label (tr "workspace.libraries.updates")
|
||||
:id "updates"}]
|
||||
[{:label (tr "workspace.libraries.libraries")
|
||||
:id "libraries"}
|
||||
{:label (tr "workspace.libraries.updates")
|
||||
:id "updates"}]))]
|
||||
|
||||
(mf/with-effect []
|
||||
(st/emit! (dtm/fetch-shared-files)))
|
||||
@@ -690,11 +1153,21 @@
|
||||
:selected selected-tab
|
||||
:on-change on-change-tab}
|
||||
(case selected-tab
|
||||
"file"
|
||||
(when token-lib-sync?
|
||||
[:> file-tab* {:is-shared shared?
|
||||
:on-change-tab on-change-tab
|
||||
:linked-libraries linked-libraries
|
||||
:shared-libraries shared-libraries}])
|
||||
"libraries"
|
||||
[:> libraries-tab*
|
||||
{:is-shared shared?
|
||||
:linked-libraries linked-libraries
|
||||
:shared-libraries shared-libraries}]
|
||||
(if token-lib-sync?
|
||||
[:> libraries-tab*
|
||||
{:linked-libraries linked-libraries
|
||||
:shared-libraries shared-libraries}]
|
||||
[:> libraries-tab-legacy*
|
||||
{:is-shared shared?
|
||||
:linked-libraries linked-libraries
|
||||
:shared-libraries shared-libraries}])
|
||||
|
||||
"updates"
|
||||
[:> updates-tab*
|
||||
|
||||
@@ -49,7 +49,14 @@
|
||||
}
|
||||
|
||||
// Tabs content
|
||||
.libraries-content,
|
||||
.libraries-content {
|
||||
display: grid;
|
||||
gap: var(--sp-xxxl);
|
||||
max-height: $sz-400;
|
||||
padding-block-start: var(--sp-l);
|
||||
}
|
||||
|
||||
.libraries-content-legacy,
|
||||
.updates-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
@@ -75,6 +82,10 @@
|
||||
margin: 0 0 0 calc(-1 * var(--sp-s));
|
||||
}
|
||||
|
||||
.connected-libraries-title {
|
||||
@include t.use-typography("headline-small");
|
||||
}
|
||||
|
||||
.section-list,
|
||||
.section-list-shared {
|
||||
display: grid;
|
||||
@@ -86,7 +97,8 @@
|
||||
|
||||
%section-list-item-placeholder {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: var(--sp-s);
|
||||
border: $b-1 solid var(--color-background-quaternary);
|
||||
padding: var(--sp-s) var(--sp-s) var(--sp-m) var(--sp-m);
|
||||
@@ -96,21 +108,33 @@
|
||||
.section-list-publish {
|
||||
@extend %section-list-item-placeholder;
|
||||
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.section-list-item-legacy {
|
||||
@extend %section-list-item-placeholder;
|
||||
}
|
||||
|
||||
.section-list-item {
|
||||
@extend %section-list-item-placeholder;
|
||||
|
||||
padding: var(--sp-m);
|
||||
}
|
||||
|
||||
.section-list-item-nested {
|
||||
margin-inline-start: var(--sp-l);
|
||||
}
|
||||
|
||||
.section-list-item-double-icon {
|
||||
@extend %section-list-item-placeholder;
|
||||
|
||||
grid-template-columns: 1fr auto auto;
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
height: fit-content;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
@@ -130,6 +154,13 @@
|
||||
color: var(--title-foreground-color);
|
||||
}
|
||||
|
||||
.section-list-linked {
|
||||
display: grid;
|
||||
grid-auto-rows: min-content;
|
||||
gap: var(--sp-s);
|
||||
max-height: px2rem(320);
|
||||
}
|
||||
|
||||
// empty state
|
||||
.section-list-empty {
|
||||
display: grid;
|
||||
@@ -141,6 +172,23 @@
|
||||
margin-block: var(--sp-l);
|
||||
}
|
||||
|
||||
.shared-libraries-empty {
|
||||
border: $b-1 solid var(--color-background-quaternary);
|
||||
padding: px2rem(40) var(--sp-s);
|
||||
border-radius: $br-8;
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
justify-items: center;
|
||||
gap: var(--sp-m);
|
||||
text-align: center;
|
||||
height: fit-content;
|
||||
margin-block: var(--sp-l);
|
||||
}
|
||||
|
||||
.empty-libraries-text {
|
||||
color: var(--color-foreground-secondary);
|
||||
}
|
||||
|
||||
// Update library tab
|
||||
.libraries-updates-see-all {
|
||||
background: unset;
|
||||
@@ -206,7 +254,6 @@
|
||||
@include text-ellipsis;
|
||||
|
||||
margin: 0;
|
||||
max-width: px2rem(236);
|
||||
color: var(--library-name-foreground-color);
|
||||
}
|
||||
|
||||
@@ -214,16 +261,6 @@
|
||||
@extend %item-name;
|
||||
}
|
||||
|
||||
.item-name-short {
|
||||
max-width: px2rem(206);
|
||||
}
|
||||
|
||||
.item-name-long {
|
||||
@extend %item-name;
|
||||
|
||||
max-width: px2rem(450);
|
||||
}
|
||||
|
||||
.item-title {
|
||||
@include t.use-typography("body-large");
|
||||
|
||||
@@ -241,7 +278,7 @@
|
||||
border-radius: $br-8;
|
||||
}
|
||||
|
||||
.item-contents {
|
||||
.item-contents-legacy {
|
||||
@include t.use-typography("body-small");
|
||||
|
||||
color: var(--library-content-foreground-color);
|
||||
@@ -250,12 +287,22 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.item-contents {
|
||||
@include t.use-typography("body-small");
|
||||
|
||||
color: var(--library-content-foreground-color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.library-actions {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
gap: var(--sp-xs);
|
||||
}
|
||||
|
||||
.element-count {
|
||||
.element-count-legacy {
|
||||
white-space: nowrap;
|
||||
|
||||
&:not(:last-child)::after {
|
||||
@@ -264,14 +311,42 @@
|
||||
}
|
||||
}
|
||||
|
||||
.connected-to-wrapper {
|
||||
.element-count-line {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: var(--sp-xs);
|
||||
|
||||
&::before {
|
||||
content: "•";
|
||||
}
|
||||
}
|
||||
|
||||
.connected-to-wrapper-legacy {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.connected-to-values {
|
||||
.connected-to-values-legacy {
|
||||
color: var(--color-foreground-primary);
|
||||
}
|
||||
|
||||
.hint-line {
|
||||
color: var(--color-foreground-secondary);
|
||||
}
|
||||
|
||||
.hint-library-name {
|
||||
color: var(--color-foreground-primary);
|
||||
}
|
||||
|
||||
.shared-library-added {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: var(--color-accent-tertiary);
|
||||
block-size: fit-content;
|
||||
border: $b-1 solid var(--color-accent-select);
|
||||
border-radius: $br-8;
|
||||
}
|
||||
|
||||
// Modal Component v2 update
|
||||
.modal-v2-info {
|
||||
width: px2rem(664);
|
||||
@@ -364,6 +439,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
.go-to-shared-button {
|
||||
@include t.use-typography("body-small");
|
||||
|
||||
color: var(--color-accent-primary);
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.sample-libraries-container {
|
||||
@include t.use-typography("body-small");
|
||||
|
||||
@@ -403,3 +491,15 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.tokens-source-label {
|
||||
block-size: $sz-32;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: var(--sp-s) var(--sp-xl);
|
||||
background: var(--color-background-primary);
|
||||
border: $b-1 solid var(--color-accent-select);
|
||||
color: var(--color-accent-tertiary);
|
||||
border-radius: $br-8;
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.config :as cf]
|
||||
[app.main.constants :refer [left-sidebar-default-max-width
|
||||
@@ -22,7 +23,7 @@
|
||||
[app.main.features :as features]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.context :as muc]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
|
||||
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
|
||||
@@ -116,7 +117,7 @@
|
||||
|
||||
(mf/defc left-sidebar*
|
||||
{::mf/memo true}
|
||||
[{:keys [layout file tokens-lib active-tokens resolved-active-tokens]}]
|
||||
[{:keys [layout file tokens-lib tokens-status active-tokens resolved-active-tokens]}]
|
||||
(let [options-mode (mf/deref refs/options-mode-global)
|
||||
project (mf/deref refs/project)
|
||||
file-id (get file :id)
|
||||
@@ -173,7 +174,7 @@
|
||||
(mf/with-memo []
|
||||
(mf/html [:> collapse-button* {}]))]
|
||||
|
||||
[:> (mf/provider muc/sidebar) {:value :left}
|
||||
[:> (mf/provider ctx/sidebar) {:value :left}
|
||||
[:aside {:ref parent-ref
|
||||
:id "left-sidebar-aside"
|
||||
:data-testid "left-sidebar"
|
||||
@@ -215,9 +216,11 @@
|
||||
:file-id file-id}]
|
||||
|
||||
:tokens
|
||||
[:> tokens-sidebar-tab* {:tokens-lib tokens-lib
|
||||
:active-tokens active-tokens
|
||||
:resolved-active-tokens resolved-active-tokens}]
|
||||
[:> tokens-sidebar-tab*
|
||||
{:tokens-lib tokens-lib
|
||||
:tokens-status tokens-status
|
||||
:active-tokens active-tokens
|
||||
:resolved-active-tokens resolved-active-tokens}]
|
||||
|
||||
:layers
|
||||
[:> layers-content* {:layout layout
|
||||
@@ -313,8 +316,8 @@
|
||||
(mf/with-memo [active-tokens]
|
||||
(delay (ctob/group-by-type active-tokens)))]
|
||||
|
||||
[:> (mf/provider muc/sidebar) {:value :right}
|
||||
[:> (mf/provider muc/active-tokens-by-type) {:value active-tokens-by-type}
|
||||
[:> (mf/provider ctx/sidebar) {:value :right}
|
||||
[:> (mf/provider ctx/active-tokens-by-type) {:value active-tokens-by-type}
|
||||
[:aside
|
||||
{:class (stl/css-case :right-sidebar true
|
||||
:not-expand (not can-be-expanded?)
|
||||
@@ -358,19 +361,22 @@
|
||||
(let [tokens-lib
|
||||
(mf/deref refs/tokens-lib)
|
||||
|
||||
tokens-status
|
||||
(mf/deref refs/tokens-status)
|
||||
|
||||
active-tokens
|
||||
(mf/with-memo [tokens-lib]
|
||||
(if tokens-lib
|
||||
(ctob/get-tokens-in-active-sets tokens-lib)
|
||||
(mf/with-memo [tokens-status tokens-lib]
|
||||
(if (and tokens-status tokens-lib)
|
||||
(cfo/get-tokens-in-active-sets tokens-status tokens-lib)
|
||||
{}))
|
||||
|
||||
selected-token-set-id
|
||||
(mf/deref refs/selected-token-set-id)
|
||||
|
||||
active-tokens-force-set
|
||||
(mf/with-memo [tokens-lib selected-token-set-id]
|
||||
(if (and tokens-lib selected-token-set-id)
|
||||
(ctob/get-tokens-in-active-sets-force tokens-lib selected-token-set-id)
|
||||
(mf/with-memo [tokens-status tokens-lib selected-token-set-id]
|
||||
(if (and tokens-status tokens-lib selected-token-set-id)
|
||||
(cfo/get-tokens-in-active-sets-force tokens-status tokens-lib selected-token-set-id)
|
||||
{}))
|
||||
|
||||
tokenscript? (contains? cf/flags :tokenscript)
|
||||
@@ -389,25 +395,27 @@
|
||||
resolved-active-tokens-force-set
|
||||
(sd/use-resolved-tokens* active-tokens-force-set)]
|
||||
|
||||
[:*
|
||||
(if (:collapse-left-sidebar layout)
|
||||
[:> collapsed-button*]
|
||||
[:> left-sidebar* {:layout layout
|
||||
[:> (mf/provider ctx/tokens-lib) {:value tokens-lib}
|
||||
[:> (mf/provider ctx/tokens-status) {:value tokens-status}
|
||||
(if (:collapse-left-sidebar layout)
|
||||
[:> collapsed-button*]
|
||||
[:> left-sidebar* {:layout layout
|
||||
:file file
|
||||
:page-id page-id
|
||||
:tokens-lib tokens-lib
|
||||
:tokens-status tokens-status
|
||||
:active-tokens active-tokens-force-set
|
||||
:resolved-active-tokens (if tokenscript?
|
||||
tokenscript-resolved-active-tokens-force-set
|
||||
resolved-active-tokens-force-set)}])
|
||||
[:> right-sidebar* {:section section
|
||||
:selected selected
|
||||
:drawing-tool drawing-tool
|
||||
:layout layout
|
||||
:file file
|
||||
:file-id file-id
|
||||
:page-id page-id
|
||||
:tokens-lib tokens-lib
|
||||
:active-tokens active-tokens-force-set
|
||||
:resolved-active-tokens (if tokenscript?
|
||||
tokenscript-resolved-active-tokens-force-set
|
||||
resolved-active-tokens-force-set)}])
|
||||
[:> right-sidebar* {:section section
|
||||
:selected selected
|
||||
:drawing-tool drawing-tool
|
||||
:layout layout
|
||||
:file file
|
||||
:file-id file-id
|
||||
:page-id page-id
|
||||
:tokens-lib tokens-lib
|
||||
:active-tokens (if tokenscript?
|
||||
tokenscript-resolved-active-tokens
|
||||
resolved-active-tokens)}]]))
|
||||
:active-tokens (if tokenscript?
|
||||
tokenscript-resolved-active-tokens
|
||||
resolved-active-tokens)}]]]))
|
||||
@@ -8,6 +8,7 @@
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.workspace :as dw]
|
||||
@@ -33,6 +34,12 @@
|
||||
[{:keys [filters]}]
|
||||
(let [file-id (mf/use-ctx ctx/current-file-id)
|
||||
files (mf/deref refs/files)
|
||||
current-file-data
|
||||
(mf/deref refs/workspace-data)
|
||||
tokens-source
|
||||
(mf/with-memo [current-file-data]
|
||||
(cfo/get-effective-tokens-source current-file-data))
|
||||
|
||||
libraries (mf/with-memo [files file-id]
|
||||
(->> (refs/select-libraries files file-id)
|
||||
(vals)
|
||||
@@ -46,6 +53,7 @@
|
||||
{:key (dm/str (:id file))
|
||||
:file file
|
||||
:is-local false
|
||||
:is-tokens-source (= (:id file) tokens-source)
|
||||
:is-default-open false
|
||||
:filters filters}])))
|
||||
|
||||
@@ -57,11 +65,16 @@
|
||||
(mf/defc assets-local-library*
|
||||
{::mf/private true}
|
||||
[{:keys [filters]}]
|
||||
(let [file (mf/deref ref:local-library)]
|
||||
(let [file (mf/deref ref:local-library)
|
||||
|
||||
is-tokens-source
|
||||
(mf/with-memo [file]
|
||||
(cfo/effective-tokens-source? (:data file) (:id file)))]
|
||||
[:> file-library*
|
||||
{:file file
|
||||
:is-local true
|
||||
:is-default-open true
|
||||
:is-tokens-source is-tokens-source
|
||||
:filters filters}]))
|
||||
|
||||
(defn- toggle-values
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.title-bar :refer [title-bar*]]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]]
|
||||
[app.main.ui.ds.tooltip :refer [tooltip*]]
|
||||
[app.main.ui.workspace.sidebar.assets.colors :refer [colors-section*]]
|
||||
[app.main.ui.workspace.sidebar.assets.common :as cmm]
|
||||
[app.main.ui.workspace.sidebar.assets.components :refer [components-section*]]
|
||||
@@ -76,7 +77,7 @@
|
||||
|
||||
(mf/defc file-library-title*
|
||||
{::mf/private true}
|
||||
[{:keys [is-open is-local file-id page-id file-name]}]
|
||||
[{:keys [is-open is-local file-id page-id file-name is-tokens-source]}]
|
||||
(let [router (mf/deref refs/router)
|
||||
team-id (mf/use-ctx ctx/current-team-id)
|
||||
url (rt/resolve router :workspace
|
||||
@@ -93,7 +94,15 @@
|
||||
(mf/use-fn
|
||||
(fn [ev]
|
||||
(dom/stop-propagation ev)
|
||||
(st/emit! (ev/event {::ev/name "navigate-to-library-file"}))))]
|
||||
(st/emit! (ev/event {::ev/name "navigate-to-library-file"}))))
|
||||
|
||||
tokens-source-icon
|
||||
(when is-tokens-source
|
||||
(mf/html [:> tooltip* {:content (tr "workspace.tokens.current-tokens-source-tooltip")}
|
||||
[:span {:class (stl/css :tokens-source-icon-wrapper)}
|
||||
[:> icon* {:icon-id i/tokens
|
||||
:size "m"
|
||||
:class (stl/css :tokens-source-icon)}]]]))]
|
||||
|
||||
[:div {:class (stl/css-case
|
||||
:library-title true
|
||||
@@ -103,17 +112,24 @@
|
||||
:on-collapsed toggle-open
|
||||
:title (if is-local
|
||||
(mf/html [:div {:class (stl/css :special-title)}
|
||||
(tr "workspace.assets.local-library")])
|
||||
[:span {:class (stl/css :special-title-text)}
|
||||
(tr "workspace.assets.local-library")]
|
||||
tokens-source-icon])
|
||||
;; Do we need to add shared info here?
|
||||
(mf/html [:div {:class (stl/css :special-title)}
|
||||
file-name]))}
|
||||
[:span {:class (stl/css :special-title-text)}
|
||||
file-name]
|
||||
tokens-source-icon]))}
|
||||
(when-not ^boolean is-local
|
||||
[:span {:title (tr "workspace.assets.open-library")}
|
||||
[:a {:class (stl/css :file-link)
|
||||
:href (str "#" url)
|
||||
:target "_blank"
|
||||
:on-click on-click}
|
||||
deprecated-icon/open-link]])]]))
|
||||
[:> icon* {:icon-id i/open-link
|
||||
:size "m"
|
||||
:class (stl/css :file-link-icon)}]]])]]))
|
||||
|
||||
|
||||
(defn- extend-selected
|
||||
[selected type asset-groups asset-id file-id]
|
||||
@@ -299,13 +315,15 @@
|
||||
(not ^boolean show-colors?)
|
||||
(not ^boolean show-typography?))
|
||||
[:div {:class (stl/css :asset-title)}
|
||||
[:span {:class (stl/css :no-found-icon)}
|
||||
deprecated-icon/search]
|
||||
[:span {:class (stl/css :no-found-icon-wrapper)}
|
||||
[:> icon* {:icon-id i/search
|
||||
:size "l"
|
||||
:class (stl/css :no-found-icon)}]]
|
||||
[:span {:class (stl/css :no-found-text)}
|
||||
(tr "workspace.assets.not-found")]])])]))
|
||||
|
||||
(mf/defc file-library*
|
||||
[{:keys [file is-local is-default-open filters]}]
|
||||
[{:keys [file is-local is-default-open filters is-tokens-source]}]
|
||||
(let [file-id (:id file)
|
||||
file-name (:name file)
|
||||
page-id (dm/get-in file [:data :pages 0])
|
||||
@@ -381,7 +399,8 @@
|
||||
:page-id page-id
|
||||
:file-name file-name
|
||||
:is-open open?
|
||||
:is-local is-local}]
|
||||
:is-local is-local
|
||||
:is-tokens-source is-tokens-source}]
|
||||
|
||||
(when ^boolean open?
|
||||
[:> file-library-content*
|
||||
|
||||
@@ -4,95 +4,131 @@
|
||||
//
|
||||
// Copyright (c) KALEIDOS SUBSIDIARY SL
|
||||
|
||||
@use "ds/typography.scss" as t;
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
@use "ds/_borders.scss" as *;
|
||||
@use "ds/_sizes.scss" as *;
|
||||
@use "ds/_utils.scss" as *;
|
||||
@use "ds/typography.scss" as *;
|
||||
|
||||
.tool-window {
|
||||
padding: 0 0 deprecated.$s-24 deprecated.$s-12;
|
||||
padding-inline-start: var(--sp-m);
|
||||
padding-block-end: var(--sp-xxl);
|
||||
display: grid;
|
||||
grid-auto-rows: max-content;
|
||||
gap: deprecated.$s-4;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
@include t.use-typography("body-small");
|
||||
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-grow: 100;
|
||||
height: 100%;
|
||||
gap: var(--sp-xs);
|
||||
block-size: 100%;
|
||||
}
|
||||
|
||||
.loading {
|
||||
@include t.use-typography("body-small");
|
||||
@include use-typography("body-small");
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
height: deprecated.$s-32;
|
||||
padding-left: calc(deprecated.$s-12 + deprecated.$s-2);
|
||||
block-size: $sz-32;
|
||||
padding-inline-start: calc(var(--sp-m) + var(--sp-xxs));
|
||||
color: var(--color-foreground-secondary);
|
||||
}
|
||||
|
||||
.special-title {
|
||||
@include deprecated.text-ellipsis;
|
||||
|
||||
color: var(--title-foreground-color-hover);
|
||||
margin-left: deprecated.$s-2;
|
||||
box-sizing: border-box;
|
||||
inline-size: 100%;
|
||||
min-inline-size: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--sp-xs);
|
||||
color: var(--color-foreground-primary);
|
||||
padding-inline-start: var(--sp-xxs);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.special-title-text {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tokens-source-icon-wrapper {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
border: $b-1 solid var(--color-accent-select);
|
||||
border-radius: $br-4;
|
||||
padding: var(--sp-xxs);
|
||||
}
|
||||
|
||||
.tokens-source-icon {
|
||||
flex-shrink: 0;
|
||||
color: var(--color-accent-tertiary);
|
||||
}
|
||||
|
||||
.file-link {
|
||||
@extend %button-tertiary;
|
||||
--file-link-background-color: transparent;
|
||||
--file-link-border-color: transparent;
|
||||
--file-link-foreground-color: var(--color-foreground-secondary);
|
||||
|
||||
height: deprecated.$s-32;
|
||||
width: deprecated.$s-28;
|
||||
border-radius: deprecated.$br-8;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
block-size: $sz-32;
|
||||
inline-size: $sz-28;
|
||||
border: $b-2 solid var(--file-link-border-color);
|
||||
border-radius: $br-8;
|
||||
background-color: var(--file-link-background-color);
|
||||
color: var(--file-link-foreground-color);
|
||||
cursor: pointer;
|
||||
|
||||
svg {
|
||||
@extend %button-icon;
|
||||
&:hover {
|
||||
--file-link-background-color: var(--color-background-quaternary);
|
||||
--file-link-border-color: var(--color-background-quaternary);
|
||||
--file-link-foreground-color: var(--color-accent-primary);
|
||||
}
|
||||
|
||||
stroke: var(--icon-foreground);
|
||||
fill: var(--title-foreground-color-hover);
|
||||
&:active {
|
||||
--file-link-background-color: var(--color-background-secondary);
|
||||
--file-link-border-color: transparent;
|
||||
--file-link-foreground-color: var(--color-accent-primary);
|
||||
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
--file-link-background-color: var(--color-background-tertiary);
|
||||
--file-link-foreground-color: var(--color-foreground-primary);
|
||||
|
||||
outline: none;
|
||||
border: $b-1 solid var(--color-accent-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.library-content {
|
||||
width: 100%;
|
||||
inline-size: 100%;
|
||||
display: grid;
|
||||
grid-auto-rows: max-content;
|
||||
gap: deprecated.$s-4;
|
||||
gap: var(--sp-xs);
|
||||
}
|
||||
|
||||
.asset-title {
|
||||
margin-left: deprecated.$s-28;
|
||||
margin-inline-start: px2rem(28);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: deprecated.$s-8;
|
||||
gap: var(--sp-s);
|
||||
}
|
||||
|
||||
.no-found-icon {
|
||||
@include deprecated.flex-center;
|
||||
|
||||
background-color: var(--not-found-background-color);
|
||||
border-radius: deprecated.$br-circle;
|
||||
height: deprecated.$s-48;
|
||||
width: deprecated.$s-48;
|
||||
|
||||
svg {
|
||||
@extend %button-icon;
|
||||
|
||||
height: deprecated.$s-24;
|
||||
width: deprecated.$s-24;
|
||||
stroke: var(--not-found-foreground-color);
|
||||
}
|
||||
.no-found-icon-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--color-background-tertiary);
|
||||
border-radius: $br-circle;
|
||||
block-size: $sz-48;
|
||||
inline-size: $sz-48;
|
||||
color: var(--color-foreground-secondary);
|
||||
}
|
||||
|
||||
.no-found-text {
|
||||
@include deprecated.body-small-typography;
|
||||
@include use-typography("body-small");
|
||||
|
||||
color: var(--not-found-foreground-color);
|
||||
color: var(--color-foreground-secondary);
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.data.workspace.texts-events :as dwte]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
@@ -170,7 +171,7 @@
|
||||
(mf/deps file-id prefix)
|
||||
(fn [_]
|
||||
(st/emit! (dw/set-assets-section-open file-id :typographies true)
|
||||
(dwt/add-typography file-id prefix))))]
|
||||
(dwte/add-typography file-id prefix))))]
|
||||
|
||||
[:div {:class (stl/css :typographies-group)
|
||||
:on-drag-enter on-drag-enter
|
||||
@@ -278,7 +279,7 @@
|
||||
(mf/deps file-id)
|
||||
(fn [_]
|
||||
(st/emit! (dw/set-assets-section-open file-id :typographies true))
|
||||
(st/emit! (dwt/add-typography file-id))))
|
||||
(st/emit! (dwte/add-typography file-id))))
|
||||
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
[app.common.path-names :as cpn]
|
||||
[app.common.types.shape.layout :as ctsl]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
[app.main.data.helpers :as dh]
|
||||
@@ -49,21 +50,18 @@
|
||||
|
||||
(mf/defc selected-set-info*
|
||||
{::mf/private true}
|
||||
[{:keys [tokens-lib selected-token-set-id]}]
|
||||
[{:keys [tokens-lib tokens-status selected-token-set-id]}]
|
||||
(let [selected-token-set
|
||||
(mf/with-memo [tokens-lib selected-token-set-id]
|
||||
(when selected-token-set-id
|
||||
(some-> tokens-lib (ctob/get-set selected-token-set-id))))
|
||||
|
||||
active-token-sets-names
|
||||
(mf/with-memo [tokens-lib]
|
||||
(some-> tokens-lib (ctob/get-active-themes-set-names)))
|
||||
|
||||
token-set-active?
|
||||
(mf/use-fn
|
||||
(mf/deps active-token-sets-names)
|
||||
(fn [name]
|
||||
(contains? active-token-sets-names name)))]
|
||||
(mf/deps tokens-status)
|
||||
(fn [id]
|
||||
(ctos/set-active? tokens-status id)))]
|
||||
|
||||
[:div {:class (stl/css :sets-header-container)}
|
||||
[:> text* {:as "span"
|
||||
:typography "headline-small"
|
||||
@@ -71,7 +69,7 @@
|
||||
:data-testid "active-token-set-title"}
|
||||
(tr "workspace.tokens.tokens-section-title" (ctob/get-name selected-token-set))]
|
||||
(when (and (some? selected-token-set-id)
|
||||
(not (token-set-active? (ctob/get-name selected-token-set))))
|
||||
(not (token-set-active? selected-token-set-id)))
|
||||
[:div {:class (stl/css :sets-header-status) :title (tr "workspace.tokens.inactive-set-description")}
|
||||
;; NOTE: when no set in tokens-lib, the selected-token-set-id
|
||||
;; will be `nil`, so for properly hide the inactive message we
|
||||
@@ -84,7 +82,7 @@
|
||||
|
||||
(mf/defc tokens-section*
|
||||
{::mf/private true}
|
||||
[{:keys [tokens-lib active-tokens resolved-active-tokens]}]
|
||||
[{:keys [tokens-lib tokens-status active-tokens resolved-active-tokens]}]
|
||||
(let [objects (mf/deref refs/workspace-page-objects)
|
||||
selected (mf/deref refs/selected-shapes)
|
||||
|
||||
@@ -305,6 +303,7 @@
|
||||
:on-delete-node delete-node}]
|
||||
|
||||
[:> selected-set-info* {:tokens-lib tokens-lib
|
||||
:tokens-status tokens-status
|
||||
:selected-token-set-id selected-token-set-id}]
|
||||
|
||||
(for [type filled-group]
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.util.clipboard :as clipboard]
|
||||
@@ -346,31 +347,39 @@
|
||||
(defn default-actions
|
||||
[{:keys [token selected-token-set-id on-delete-token errors]}]
|
||||
(let [{:keys [modal]} (dwta/get-token-properties token)
|
||||
|
||||
can-edit-tokens?
|
||||
(mf/use-ctx ctx/can-edit-tokens?)
|
||||
|
||||
on-copy-name #(clipboard/to-clipboard (:name token))
|
||||
on-duplicate-token #(st/emit! (dwtl/duplicate-token (:id token)))]
|
||||
[{:title (tr "workspace.tokens.edit")
|
||||
:no-selectable true
|
||||
:action (fn [event]
|
||||
(let [{:keys [key fields]} modal]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dwtl/assign-token-context-menu nil)
|
||||
(modal/show key {:x (.-clientX ^js event)
|
||||
:y (.-clientY ^js event)
|
||||
:position :right
|
||||
:fields fields
|
||||
:initial-errors errors
|
||||
:action "edit"
|
||||
:selected-token-set-id selected-token-set-id
|
||||
:token token}))))}
|
||||
{:title (tr "workspace.tokens.duplicate")
|
||||
:no-selectable true
|
||||
:action on-duplicate-token}
|
||||
{:title (tr "workspace.tokens.copy-name")
|
||||
:no-selectable true
|
||||
:action on-copy-name}
|
||||
{:title (tr "workspace.tokens.delete")
|
||||
:no-selectable true
|
||||
:action #(on-delete-token token)}]))
|
||||
(concat
|
||||
[]
|
||||
(when can-edit-tokens?
|
||||
[{:title (tr "workspace.tokens.edit")
|
||||
:no-selectable true
|
||||
:action (fn [event]
|
||||
(let [{:keys [key fields]} modal]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dwtl/assign-token-context-menu nil)
|
||||
(modal/show key {:x (.-clientX ^js event)
|
||||
:y (.-clientY ^js event)
|
||||
:position :right
|
||||
:fields fields
|
||||
:initial-errors errors
|
||||
:action "edit"
|
||||
:selected-token-set-id selected-token-set-id
|
||||
:token token}))))}
|
||||
{:title (tr "workspace.tokens.duplicate")
|
||||
:no-selectable true
|
||||
:action on-duplicate-token}])
|
||||
[{:title (tr "workspace.tokens.copy-name")
|
||||
:no-selectable true
|
||||
:action on-copy-name}]
|
||||
(when can-edit-tokens?
|
||||
[{:title (tr "workspace.tokens.delete")
|
||||
:no-selectable true
|
||||
:action #(on-delete-token token)}]))))
|
||||
|
||||
(defn- allowed-shape-attributes
|
||||
[shapes]
|
||||
|
||||
@@ -92,8 +92,8 @@
|
||||
(not (and (some? edition)
|
||||
(= :text (:type (get objects edition))))))
|
||||
|
||||
can-edit?
|
||||
(mf/use-ctx ctx/can-edit?)
|
||||
can-edit-tokens?
|
||||
(mf/use-ctx ctx/can-edit-tokens?)
|
||||
|
||||
is-selected-inside-layout (d/nilv is-selected-inside-layout false)
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
:aria-controls (dm/str "token-tree-" (name type))
|
||||
:on-toggle-expand on-toggle-open-click
|
||||
:icon (token-section-icon type)}
|
||||
(when can-edit?
|
||||
(when can-edit-tokens?
|
||||
[:> icon-button* {:id (str "add-token-button-" title)
|
||||
:icon "add"
|
||||
:aria-label (tr "workspace.tokens.add-token" title)
|
||||
|
||||
@@ -140,14 +140,17 @@
|
||||
on-pill-context-menu
|
||||
on-node-context-menu]}]
|
||||
(let [separator "."
|
||||
raw-tree (mf/with-memo [tokens]
|
||||
(cpn/build-tree-root tokens separator))
|
||||
permissions (mf/use-ctx ctx/permissions)
|
||||
can-edit? (:can-edit permissions)
|
||||
raw-tree
|
||||
(mf/with-memo [tokens]
|
||||
(cpn/build-tree-root tokens separator))
|
||||
|
||||
can-edit-file?
|
||||
(mf/use-ctx ctx/can-edit?)
|
||||
|
||||
on-node-context-menu (mf/use-fn
|
||||
(mf/deps can-edit? on-node-context-menu)
|
||||
(mf/deps can-edit-file? on-node-context-menu)
|
||||
(fn [event node]
|
||||
(when can-edit?
|
||||
(when can-edit-file?
|
||||
(on-node-context-menu event node))))
|
||||
|
||||
ordered-nodes (mf/with-memo [raw-tree]
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
(ns app.main.ui.workspace.tokens.sets
|
||||
(:require
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
@@ -19,27 +20,32 @@
|
||||
(st/emit! (dwtl/clear-tokens-paths)
|
||||
(dwtl/set-selected-token-set-id id)))
|
||||
|
||||
(defn- on-toggle-token-set-click [name]
|
||||
(st/emit! (dwtl/toggle-token-set name)))
|
||||
(defn- on-toggle-token-set-click [id]
|
||||
(st/emit! (dwtl/toggle-token-set id)))
|
||||
|
||||
(defn- on-toggle-token-set-group-click [path]
|
||||
(st/emit! (dwtl/toggle-token-set-group path)))
|
||||
|
||||
(mf/defc sets-list*
|
||||
[{:keys [tokens-lib selected new-path edition-id]}]
|
||||
[{:keys [selected new-path edition-id]}]
|
||||
|
||||
(let [token-sets
|
||||
(let [tokens-lib
|
||||
(mf/use-ctx ctx/tokens-lib)
|
||||
|
||||
tokens-status
|
||||
(mf/use-ctx ctx/tokens-status)
|
||||
|
||||
token-sets
|
||||
(some-> tokens-lib (ctob/get-set-tree))
|
||||
|
||||
can-edit?
|
||||
(mf/use-ctx ctx/can-edit?)
|
||||
can-edit-tokens?
|
||||
(mf/use-ctx ctx/can-edit-tokens?)
|
||||
|
||||
token-set-active?
|
||||
(mf/use-fn
|
||||
(mf/deps tokens-lib)
|
||||
(fn [name]
|
||||
(when tokens-lib
|
||||
(ctob/token-set-active? tokens-lib name))))
|
||||
(mf/deps tokens-status)
|
||||
(fn [set-id]
|
||||
(ctos/set-active? tokens-status set-id)))
|
||||
|
||||
token-set-group-active?
|
||||
(mf/use-fn
|
||||
@@ -49,17 +55,17 @@
|
||||
|
||||
on-reset-edition
|
||||
(mf/use-fn
|
||||
(mf/deps can-edit?)
|
||||
(mf/deps can-edit-tokens?)
|
||||
(fn [_]
|
||||
(when can-edit?
|
||||
(when can-edit-tokens?
|
||||
(st/emit! (dwtl/clear-token-set-edition)
|
||||
(dwtl/clear-token-set-creation)))))
|
||||
|
||||
on-start-edition
|
||||
(mf/use-fn
|
||||
(mf/deps can-edit?)
|
||||
(mf/deps can-edit-tokens?)
|
||||
(fn [id]
|
||||
(when can-edit?
|
||||
(when can-edit-tokens?
|
||||
(st/emit! (dwtl/start-token-set-edition id)))))]
|
||||
|
||||
[:> controlled-sets-list*
|
||||
@@ -75,7 +81,6 @@
|
||||
:edition-id edition-id
|
||||
|
||||
:origin "set-panel"
|
||||
:can-edit can-edit?
|
||||
:on-start-edition on-start-edition
|
||||
:on-reset-edition on-reset-edition
|
||||
|
||||
|
||||
@@ -86,8 +86,8 @@
|
||||
|
||||
(mf/defc inline-add-button*
|
||||
[]
|
||||
(let [can-edit? (mf/use-ctx ctx/can-edit?)]
|
||||
(if can-edit?
|
||||
(let [can-edit-tokens? (mf/use-ctx ctx/can-edit-tokens?)]
|
||||
(if can-edit-tokens?
|
||||
[:div {:class (stl/css :empty-sets-wrapper)}
|
||||
[:> text* {:as "span" :typography "body-small" :class (stl/css :empty-state-message)}
|
||||
(tr "workspace.tokens.no-sets-yet")]
|
||||
@@ -110,7 +110,10 @@
|
||||
[{:keys [id label is-editing is-active is-selected is-draggable is-collapsed path depth index
|
||||
on-toggle on-drop on-start-edition on-reset-edition on-edit-submit on-toggle-collapse]}]
|
||||
|
||||
(let [can-edit?
|
||||
(let [can-edit-tokens?
|
||||
(mf/use-ctx ctx/can-edit-tokens?)
|
||||
|
||||
can-edit-file?
|
||||
(mf/use-ctx ctx/can-edit?)
|
||||
|
||||
label-id
|
||||
@@ -118,11 +121,11 @@
|
||||
|
||||
on-context-menu
|
||||
(mf/use-fn
|
||||
(mf/deps is-editing id path can-edit?)
|
||||
(mf/deps is-editing id path can-edit-tokens?)
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(when (and can-edit? (not is-editing))
|
||||
(when (and can-edit-tokens? (not is-editing))
|
||||
(st/emit! (dwtl/assign-token-set-context-menu
|
||||
{:position (dom/get-client-position event)
|
||||
:is-group true
|
||||
@@ -141,12 +144,12 @@
|
||||
|
||||
on-checkbox-click
|
||||
(mf/use-fn
|
||||
(mf/deps on-toggle path can-edit?)
|
||||
(mf/deps on-toggle path can-edit-file?)
|
||||
#(on-toggle path))
|
||||
|
||||
on-edit-submit'
|
||||
(mf/use-fn
|
||||
(mf/deps path on-edit-submit can-edit?)
|
||||
(mf/deps path on-edit-submit can-edit-tokens?)
|
||||
#(on-edit-submit path %))
|
||||
|
||||
on-drop
|
||||
@@ -196,7 +199,7 @@
|
||||
label]
|
||||
[:> checkbox*
|
||||
{:on-click on-checkbox-click
|
||||
:disabled (not can-edit?)
|
||||
:disabled (not can-edit-file?)
|
||||
:checked (case is-active
|
||||
:all true
|
||||
:partial "mixed"
|
||||
@@ -207,7 +210,11 @@
|
||||
[{:keys [id set label is-editing is-active is-selected is-draggable is-new path depth index
|
||||
on-select on-toggle on-drop on-start-edition on-reset-edition on-edit-submit]}]
|
||||
|
||||
(let [can-edit? (mf/use-ctx ctx/can-edit?)
|
||||
(let [can-edit-tokens?
|
||||
(mf/use-ctx ctx/can-edit-tokens?)
|
||||
|
||||
can-edit-file?
|
||||
(mf/use-ctx ctx/can-edit?)
|
||||
|
||||
on-click
|
||||
(mf/use-fn
|
||||
@@ -220,11 +227,11 @@
|
||||
|
||||
on-context-menu
|
||||
(mf/use-fn
|
||||
(mf/deps is-editing id path can-edit?)
|
||||
(mf/deps is-editing id path can-edit-tokens?)
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(when (and can-edit? (not is-editing))
|
||||
(when (and can-edit-tokens? (not is-editing))
|
||||
(st/emit! (dwtl/assign-token-set-context-menu
|
||||
{:position (dom/get-client-position event)
|
||||
:is-group false
|
||||
@@ -244,7 +251,7 @@
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(when (fn? on-toggle)
|
||||
(on-toggle (ctob/get-name set)))))
|
||||
(on-toggle (ctob/get-id set)))))
|
||||
|
||||
on-edit-submit'
|
||||
(mf/use-fn
|
||||
@@ -305,15 +312,15 @@
|
||||
label]
|
||||
[:> checkbox*
|
||||
{:on-click on-checkbox-click
|
||||
:disabled (not can-edit?)
|
||||
:disabled (not can-edit-file?)
|
||||
:arial-label (tr "workspace.tokens.select-set")
|
||||
:checked is-active}]])]))
|
||||
|
||||
(mf/defc token-sets-tree*
|
||||
[{:keys [is-draggable
|
||||
selected
|
||||
is-token-set-group-active
|
||||
is-token-set-active
|
||||
is-token-set-group-active
|
||||
on-start-edition
|
||||
on-reset-edition
|
||||
on-edit-submit-set
|
||||
@@ -418,7 +425,7 @@
|
||||
:set token-set
|
||||
:label (peek path)
|
||||
:is-editing (= edition-id id)
|
||||
:is-active (is-token-set-active (ctob/get-name token-set))
|
||||
:is-active (is-token-set-active id)
|
||||
:is-selected (= selected id)
|
||||
:is-draggable is-draggable
|
||||
:is-new false
|
||||
@@ -452,15 +459,15 @@
|
||||
new-path
|
||||
edition-id]}]
|
||||
|
||||
(assert (fn? is-token-set-group-active) "expected a function for `is-token-set-group-active` prop")
|
||||
(assert (fn? is-token-set-active) "expected a function for `is-token-set-active` prop")
|
||||
(assert (fn? is-token-set-group-active) "expected a function for `is-token-set-group-active` prop")
|
||||
|
||||
(let [theme-modal? (= origin "theme-modal")
|
||||
can-edit? (mf/use-ctx ctx/can-edit?)
|
||||
draggable? (and (not theme-modal?) can-edit?)
|
||||
empty-state? (and theme-modal?
|
||||
(empty? token-sets)
|
||||
(not new-path))
|
||||
(let [theme-modal? (= origin "theme-modal")
|
||||
can-edit-tokens? (mf/use-ctx ctx/can-edit-tokens?)
|
||||
draggable? (and (not theme-modal?) can-edit-tokens?)
|
||||
empty-state? (and theme-modal?
|
||||
(empty? token-sets)
|
||||
(not new-path))
|
||||
|
||||
;; NOTE: on-reset-edition and on-start-edition function can
|
||||
;; come as nil, in this case we need to provide a safe
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
(ns app.main.ui.workspace.tokens.sidebar
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.config :as cf]
|
||||
[app.main.data.modal :as modal]
|
||||
@@ -25,6 +26,7 @@
|
||||
[app.main.ui.workspace.tokens.sets.context-menu :refer [token-set-context-menu*]]
|
||||
[app.main.ui.workspace.tokens.sets.lists :as tsetslist]
|
||||
[app.main.ui.workspace.tokens.themes :refer [themes-header*]]
|
||||
[app.main.ui.workspace.tokens.tokens-source :refer [tokens-source-info*]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[rumext.v2 :as mf]
|
||||
@@ -34,8 +36,11 @@
|
||||
|
||||
(mf/defc token-sets-list*
|
||||
{::mf/private true}
|
||||
[{:keys [tokens-lib]}]
|
||||
(let [token-sets
|
||||
[]
|
||||
(let [tokens-lib
|
||||
(mf/use-ctx ctx/tokens-lib)
|
||||
|
||||
token-sets
|
||||
(some-> tokens-lib (ctob/get-set-tree))
|
||||
|
||||
selected-token-set-id
|
||||
@@ -60,20 +65,25 @@
|
||||
|
||||
(mf/defc token-management-section*
|
||||
{::mf/private true}
|
||||
[{:keys [resize-height] :as props}]
|
||||
[{:keys [resize-height current-file-data] :as props}]
|
||||
|
||||
(let [can-edit?
|
||||
(mf/use-ctx ctx/can-edit?)]
|
||||
(let [can-edit-tokens?
|
||||
(mf/use-ctx ctx/can-edit-tokens?)
|
||||
|
||||
tokens-source
|
||||
(mf/with-memo [current-file-data]
|
||||
(cfo/get-effective-tokens-source current-file-data))]
|
||||
[:*
|
||||
[:> token-set-context-menu*]
|
||||
[:section {:data-testid "token-management-sidebar"
|
||||
:class (stl/css :token-management-section-wrapper)
|
||||
:style {"--resize-height" (str resize-height "px")}}
|
||||
[:> themes-header*]
|
||||
(when (not= tokens-source (:id current-file-data))
|
||||
[:> tokens-source-info* {:tokens-source tokens-source}])
|
||||
[:> themes-header* {:tokens-source tokens-source}]
|
||||
[:div {:class (stl/css :sidebar-header)}
|
||||
[:> title-bar* {:title (tr "labels.sets")}
|
||||
(when can-edit?
|
||||
(when can-edit-tokens?
|
||||
[:> tsetslist/add-button*])]]
|
||||
|
||||
[:> token-sets-list* props]]]))
|
||||
@@ -83,8 +93,8 @@
|
||||
(let [show-menu* (mf/use-state false)
|
||||
show-menu? (deref show-menu*)
|
||||
|
||||
can-edit?
|
||||
(mf/use-ctx ctx/can-edit?)
|
||||
can-edit-tokens?
|
||||
(mf/use-ctx ctx/can-edit-tokens?)
|
||||
|
||||
open-menu
|
||||
(mf/use-fn
|
||||
@@ -124,7 +134,7 @@
|
||||
:on-close close-menu
|
||||
:id "tokens-menu"
|
||||
:class (stl/css :import-export-menu)}
|
||||
(when can-edit?
|
||||
(when can-edit-tokens?
|
||||
[:> dropdown-menu-item* {:class (stl/css :import-export-menu-item)
|
||||
:on-click on-modal-show}
|
||||
[:div {:class (stl/css :import-menu-item)}
|
||||
@@ -133,31 +143,42 @@
|
||||
:on-click on-export}
|
||||
(tr "labels.export")]]
|
||||
|
||||
|
||||
(when (and can-edit? (contains? cf/flags :token-base-font-size))
|
||||
(when (and can-edit-tokens? (contains? cf/flags :token-base-font-size))
|
||||
[:> icon-button* {:variant "secondary"
|
||||
:icon i/settings
|
||||
:aria-label "Settings"
|
||||
:on-click open-settings-modal}])]))
|
||||
|
||||
(mf/defc tokens-sidebar-tab*
|
||||
[{:keys [tokens-lib] :as props}]
|
||||
[{:keys [] :as props}]
|
||||
(let [{on-pointer-down-pages :on-pointer-down
|
||||
on-lost-pointer-capture-pages :on-lost-pointer-capture
|
||||
on-pointer-move-pages :on-pointer-move
|
||||
size-pages-opened :size}
|
||||
(use-resize-hook :tokens 200 38 "0.6" :y false nil)]
|
||||
(use-resize-hook :tokens 200 38 "0.6" :y false nil)
|
||||
|
||||
[:div {:class (stl/css :sidebar-wrapper)}
|
||||
[:> token-management-section*
|
||||
{:resize-height size-pages-opened
|
||||
:tokens-lib tokens-lib}]
|
||||
[:article {:class (stl/css :tokens-section-wrapper)
|
||||
:data-testid "tokens-sidebar"}
|
||||
[:div {:class (stl/css :resize-area-horiz)
|
||||
:on-pointer-down on-pointer-down-pages
|
||||
:on-lost-pointer-capture on-lost-pointer-capture-pages
|
||||
:on-pointer-move on-pointer-move-pages}
|
||||
[:div {:class (stl/css :resize-handle-horiz)}]]
|
||||
[:> tokens-section* props]]
|
||||
[:> import-export-button*]]))
|
||||
current-file-data
|
||||
(mf/deref refs/workspace-data)
|
||||
|
||||
can-edit-file?
|
||||
(mf/use-ctx ctx/can-edit?)
|
||||
|
||||
can-edit-tokens?
|
||||
(mf/with-memo [can-edit-file? current-file-data]
|
||||
(and can-edit-file?
|
||||
(cfo/editable-tokens? current-file-data)))]
|
||||
|
||||
[:> (mf/provider ctx/can-edit-tokens?) {:value can-edit-tokens?}
|
||||
[:div {:class (stl/css :sidebar-wrapper)}
|
||||
[:> token-management-section*
|
||||
{:resize-height size-pages-opened
|
||||
:current-file-data current-file-data}]
|
||||
[:article {:class (stl/css :tokens-section-wrapper)
|
||||
:data-testid "tokens-sidebar"}
|
||||
[:div {:class (stl/css :resize-area-horiz)
|
||||
:on-pointer-down on-pointer-down-pages
|
||||
:on-lost-pointer-capture on-lost-pointer-capture-pages
|
||||
:on-pointer-move on-pointer-move-pages}
|
||||
[:div {:class (stl/css :resize-handle-horiz)}]]
|
||||
[:> tokens-section* props]]
|
||||
[:> import-export-button*]]]))
|
||||
@@ -26,7 +26,7 @@
|
||||
overflow-y: auto;
|
||||
scrollbar-gutter: stable;
|
||||
position: relative;
|
||||
padding-block-end: var(--sp-l);
|
||||
padding-block: var(--sp-m) var(--sp-l);
|
||||
}
|
||||
|
||||
.tokens-section-wrapper {
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
|
||||
(mf/defc themes-header*
|
||||
{::mf/private true}
|
||||
[]
|
||||
[{:keys [tokens-source]}]
|
||||
(let [ordered-themes
|
||||
(mf/deref refs/workspace-token-themes-no-hidden)
|
||||
|
||||
can-edit?
|
||||
(mf/use-ctx ctx/can-edit?)
|
||||
can-edit-tokens?
|
||||
(mf/use-ctx ctx/can-edit-tokens?)
|
||||
|
||||
open-modal
|
||||
(mf/use-fn
|
||||
@@ -38,18 +38,18 @@
|
||||
[:div {:class (stl/css :empty-theme-wrapper)}
|
||||
[:> text* {:as "span" :typography "body-small" :class (stl/css :empty-state-message)}
|
||||
(tr "workspace.tokens.no-themes")]
|
||||
(when can-edit?
|
||||
(when can-edit-tokens?
|
||||
[:button {:on-click open-modal
|
||||
:class (stl/css :create-theme-button)}
|
||||
(tr "workspace.tokens.create-one")])]
|
||||
(if can-edit?
|
||||
(if can-edit-tokens?
|
||||
[:div {:class (stl/css :theme-selector-wrapper)}
|
||||
[:> theme-selector*]
|
||||
[:> theme-selector* {:tokens-source tokens-source}]
|
||||
[:> button* {:variant "secondary"
|
||||
:type "button"
|
||||
:class (stl/css :edit-theme-button)
|
||||
:on-click open-modal}
|
||||
(tr "labels.edit")]]
|
||||
[:div {:title (when-not can-edit?
|
||||
[:div {:title (when-not can-edit-tokens?
|
||||
(tr "workspace.tokens.no-permission-themes"))}
|
||||
[:> theme-selector*]]))]))
|
||||
[:> theme-selector* {:tokens-source tokens-source}]]))]))
|
||||
@@ -9,7 +9,7 @@
|
||||
@use "ds/spacing.scss" as *;
|
||||
|
||||
.themes-wrapper {
|
||||
padding: var(--sp-m) 0 0 var(--sp-m);
|
||||
padding: 0 0 0 var(--sp-m);
|
||||
}
|
||||
|
||||
.themes-header {
|
||||
|
||||
@@ -10,15 +10,16 @@
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.logic.tokens :as clt]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.main.constants :refer [max-input-length]]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.controls.combobox :refer [combobox*]]
|
||||
@@ -66,7 +67,7 @@
|
||||
|
||||
(mf/defc themes-overview
|
||||
[{:keys [change-view]}]
|
||||
(let [active-theme-paths (mf/deref refs/workspace-active-theme-paths)
|
||||
(let [active-theme-ids (mf/deref refs/workspace-active-theme-ids)
|
||||
themes-groups (mf/deref refs/workspace-token-theme-tree-no-hidden)
|
||||
|
||||
create-theme
|
||||
@@ -95,7 +96,7 @@
|
||||
[:ul {:class (stl/css :theme-group-rows-wrapper)}
|
||||
(for [[_ {:keys [id name] :as theme}] themes
|
||||
:let [theme-path (ctob/get-theme-path theme)
|
||||
selected? (some? (get active-theme-paths theme-path))
|
||||
selected? (some? (get active-theme-ids (ctob/get-id theme)))
|
||||
delete-theme
|
||||
(fn [e]
|
||||
(dom/prevent-default e)
|
||||
@@ -249,10 +250,15 @@
|
||||
|
||||
(defn- make-lib-with-theme
|
||||
[theme sets]
|
||||
(let [tlib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-theme theme))
|
||||
tlib (reduce ctob/add-set tlib sets)]
|
||||
(ctob/activate-theme tlib (ctob/get-id theme))))
|
||||
(as-> (ctob/make-tokens-lib) $
|
||||
(ctob/add-theme $ theme)
|
||||
(reduce ctob/add-set $ sets)))
|
||||
|
||||
(defn- make-status-with-theme
|
||||
[tokens-lib theme]
|
||||
(let [sets (map #(ctob/get-set-by-name tokens-lib %) (:sets theme))]
|
||||
(ctos/make-tokens-status :active-theme-ids #{(:id theme)}
|
||||
:active-set-ids (into #{} (map ctob/get-id sets)))))
|
||||
|
||||
(mf/defc edit-create-theme*
|
||||
[{:keys [change-view theme on-save is-editing has-prev-view]}]
|
||||
@@ -262,7 +268,8 @@
|
||||
|
||||
current-theme* (mf/use-state theme)
|
||||
current-theme (deref current-theme*)
|
||||
lib (make-lib-with-theme current-theme ordered-token-sets)
|
||||
lib-with-theme (make-lib-with-theme current-theme ordered-token-sets)
|
||||
status-with-theme (make-status-with-theme lib-with-theme current-theme)
|
||||
|
||||
;; Form / Modal handlers
|
||||
on-back (mf/use-fn
|
||||
@@ -306,35 +313,44 @@
|
||||
;; Sets tree handlers
|
||||
token-set-group-active?
|
||||
(mf/use-fn
|
||||
(mf/deps current-theme)
|
||||
(mf/deps status-with-theme lib-with-theme)
|
||||
(fn [group-path]
|
||||
(ctob/sets-at-path-all-active? lib group-path)))
|
||||
(cfo/sets-at-path-all-active? status-with-theme lib-with-theme group-path)))
|
||||
|
||||
token-set-active?
|
||||
(mf/use-fn
|
||||
(mf/deps current-theme)
|
||||
(fn [name]
|
||||
(contains? (:sets current-theme) name)))
|
||||
(mf/deps status-with-theme)
|
||||
(fn [id]
|
||||
(ctos/set-active? status-with-theme id)))
|
||||
|
||||
on-toggle-token-set
|
||||
(mf/use-fn
|
||||
(mf/deps current-theme)
|
||||
(fn [set-name]
|
||||
(swap! current-theme* #(ctob/toggle-set % set-name))))
|
||||
(mf/deps current-theme tokens-lib)
|
||||
(fn [set-id]
|
||||
(let [set (ctob/get-set tokens-lib set-id)]
|
||||
(swap! current-theme* #(ctob/toggle-set % (ctob/get-name set))))))
|
||||
|
||||
on-toggle-token-set-group
|
||||
(mf/use-fn
|
||||
(mf/deps current-theme ordered-token-sets)
|
||||
(fn [group-path]
|
||||
(swap! current-theme* (fn [theme']
|
||||
(let [lib' (make-lib-with-theme theme' ordered-token-sets)]
|
||||
(clt/toggle-token-set-group group-path lib' theme'))))))
|
||||
; TODOstatus ver si se puede añadir una función en files.tokens o types.tokens
|
||||
; según si necesitamos al final el status o no (que creo que no)
|
||||
(let [lib' (make-lib-with-theme theme' ordered-token-sets)
|
||||
status' (make-status-with-theme lib' theme')
|
||||
active? (cfo/sets-at-path-all-active? status' lib' group-path)
|
||||
sets-at-path (ctob/get-sets-at-path lib' group-path)
|
||||
set-names (into #{} (map ctob/get-name) sets-at-path)]
|
||||
(if (contains? #{:all :partial} active?)
|
||||
(ctob/disable-sets theme' set-names)
|
||||
(ctob/enable-sets theme' set-names)))))))
|
||||
|
||||
on-click-token-set
|
||||
(mf/use-fn
|
||||
(mf/deps on-toggle-token-set)
|
||||
(fn [set-id]
|
||||
(let [set (ctob/get-set lib set-id)]
|
||||
(let [set (ctob/get-set lib-with-theme set-id)]
|
||||
(on-toggle-token-set (ctob/get-name set)))))]
|
||||
|
||||
[:div {:class (stl/css :themes-modal-wrapper)}
|
||||
@@ -450,12 +466,14 @@
|
||||
::mf/register modal/components
|
||||
::mf/register-as :tokens/themes}
|
||||
[]
|
||||
[:div {:class (stl/css :modal-overlay)}
|
||||
[:div {:class (stl/css :modal-dialog)
|
||||
:data-testid "token-theme-update-create-modal"}
|
||||
[:> icon-button* {:class (stl/css :close-btn)
|
||||
:on-click modal/hide!
|
||||
:aria-label (tr "labels.close")
|
||||
:variant "action"
|
||||
:icon i/close}]
|
||||
[:> themes-modal-body*]]])
|
||||
(let [tokens-status (mf/deref refs/tokens-status)]
|
||||
[:> (mf/provider ctx/tokens-status) {:value tokens-status}
|
||||
[:div {:class (stl/css :modal-overlay)}
|
||||
[:div {:class (stl/css :modal-dialog)
|
||||
:data-testid "token-theme-update-create-modal"}
|
||||
[:> icon-button* {:class (stl/css :close-btn)
|
||||
:on-click modal/hide!
|
||||
:aria-label (tr "labels.close")
|
||||
:variant "action"
|
||||
:icon i/close}]
|
||||
[:> themes-modal-body*]]]]))
|
||||
@@ -8,13 +8,16 @@
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
|
||||
[app.main.ui.ds.foundations.typography.text :refer [text*]]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
@@ -24,17 +27,16 @@
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc themes-list*
|
||||
[{:keys [themes active-theme-paths on-close is-grouped]}]
|
||||
[{:keys [themes tokens-status on-close is-grouped]}]
|
||||
(when (seq themes)
|
||||
[:ul {:class (stl/css :theme-options)}
|
||||
(for [[_ {:keys [id name] :as theme}] themes
|
||||
:let [theme-id (ctob/get-theme-path theme)
|
||||
selected? (get active-theme-paths theme-id)
|
||||
:let [selected? (ctos/theme-active? tokens-status id)
|
||||
select-theme (fn [e]
|
||||
(dom/stop-propagation e)
|
||||
(st/emit! (dwtl/toggle-token-theme-active id))
|
||||
(on-close))]]
|
||||
[:li {:key theme-id
|
||||
[:li {:key (str "theme-" id)
|
||||
:role "option"
|
||||
:aria-selected selected?
|
||||
:class (stl/css-case
|
||||
@@ -48,47 +50,68 @@
|
||||
:class (stl/css-case :check-icon true
|
||||
:check-icon-visible selected?)}]])]))
|
||||
|
||||
(defn- open-tokens-theme-modal
|
||||
[]
|
||||
(modal/show! :tokens/themes {}))
|
||||
|
||||
(mf/defc theme-options*
|
||||
[{:keys [active-theme-paths themes on-close]}]
|
||||
[:ul {:class (stl/css :theme-options :custom-select-dropdown)
|
||||
:role "listbox"}
|
||||
(for [[group themes] themes]
|
||||
[:li {:key group
|
||||
:aria-labelledby (dm/str group "-label")
|
||||
:role "group"}
|
||||
(when (seq group)
|
||||
[:> text* {:as "span" :typography "headline-small" :class (stl/css :group) :id (dm/str (str/kebab group) "-label") :title group} group])
|
||||
[:> themes-list* {:themes themes
|
||||
:active-theme-paths active-theme-paths
|
||||
:on-close on-close
|
||||
:is-grouped true}]])
|
||||
[:li {:class (stl/css :separator)
|
||||
:aria-hidden true}]
|
||||
[:li {:class (stl/css-case :checked-element true
|
||||
:checked-element-button true)
|
||||
:role "option"
|
||||
:on-click open-tokens-theme-modal}
|
||||
[:> text* {:as "span" :typography "body-small"} (tr "workspace.tokens.edit-themes")]
|
||||
[:> icon* {:icon-id i/arrow-right :aria-hidden true}]]])
|
||||
[{:keys [tokens-lib tokens-status tokens-source can-edit-tokens team-id on-close]}]
|
||||
(let [themes
|
||||
(mf/with-memo [tokens-lib]
|
||||
(ctob/get-theme-tree-no-hidden tokens-lib))
|
||||
|
||||
edit-token-themes
|
||||
(fn []
|
||||
(if can-edit-tokens
|
||||
(modal/show! :tokens/themes {})
|
||||
(st/emit! (rt/nav :workspace
|
||||
{:team-id team-id
|
||||
:file-id tokens-source
|
||||
:layout :tokens}
|
||||
::rt/new-window true))))]
|
||||
|
||||
[:ul {:class (stl/css :theme-options :custom-select-dropdown)
|
||||
:role "listbox"}
|
||||
(for [[group themes] themes]
|
||||
[:li {:key group
|
||||
:aria-labelledby (dm/str group "-label")
|
||||
:role "group"}
|
||||
(when (seq group)
|
||||
[:> text* {:as "span" :typography "headline-small" :class (stl/css :group) :id (dm/str (str/kebab group) "-label") :title group} group])
|
||||
[:> themes-list* {:themes themes
|
||||
:tokens-status tokens-status
|
||||
:on-close on-close
|
||||
:is-grouped true}]])
|
||||
[:li {:class (stl/css :separator)
|
||||
:aria-hidden true}]
|
||||
[:li {:class (stl/css-case :checked-element true
|
||||
:checked-element-button true)
|
||||
:role "option"
|
||||
:on-click edit-token-themes}
|
||||
[:> text* {:as "span" :typography "body-small"} (tr "workspace.tokens.edit-themes")]
|
||||
[:> icon* {:icon-id (if can-edit-tokens
|
||||
i/arrow-right
|
||||
i/open-link)
|
||||
:aria-hidden true}]]]))
|
||||
|
||||
(mf/defc theme-selector*
|
||||
[{:keys []}]
|
||||
[{:keys [tokens-source]}]
|
||||
(let [;; Store
|
||||
active-theme-paths (mf/deref refs/workspace-active-theme-paths-no-hidden)
|
||||
active-themes-count (count active-theme-paths)
|
||||
themes (mf/deref refs/workspace-token-theme-tree-no-hidden)
|
||||
can-edit? (:can-edit (deref refs/permissions))
|
||||
tokens-lib (mf/use-ctx ctx/tokens-lib)
|
||||
tokens-status (mf/use-ctx ctx/tokens-status)
|
||||
can-edit-file? (mf/use-ctx ctx/can-edit?)
|
||||
can-edit-tokens (mf/use-ctx ctx/can-edit-tokens?)
|
||||
team-id (mf/use-ctx ctx/current-team-id)
|
||||
|
||||
active-themes
|
||||
(mf/with-memo [tokens-lib tokens-status]
|
||||
(cfo/get-active-themes tokens-status tokens-lib))
|
||||
|
||||
active-themes-count
|
||||
(mf/with-memo [active-themes]
|
||||
(count active-themes))
|
||||
|
||||
;; Data
|
||||
current-label (cond
|
||||
(> active-themes-count 1) (tr "workspace.tokens.active-themes" active-themes-count)
|
||||
(= active-themes-count 1) (some->> (first active-theme-paths)
|
||||
(ctob/split-theme-path)
|
||||
(remove empty?)
|
||||
(str/join " / "))
|
||||
(= active-themes-count 1) (-> (first active-themes)
|
||||
(ctob/get-theme-path true))
|
||||
:else (tr "workspace.tokens.no-active-theme"))
|
||||
|
||||
;; State
|
||||
@@ -105,9 +128,9 @@
|
||||
|
||||
on-open-dropdown
|
||||
(mf/use-fn
|
||||
(mf/deps can-edit?)
|
||||
(mf/deps can-edit-file?)
|
||||
(fn [event]
|
||||
(when can-edit?
|
||||
(when can-edit-file?
|
||||
(when-let [node (dom/get-current-target event)]
|
||||
(let [rect (dom/get-bounding-rect node)]
|
||||
(swap! state* assoc
|
||||
@@ -117,14 +140,14 @@
|
||||
container (hooks/use-portal-container :popup)]
|
||||
|
||||
[:div {:on-click on-open-dropdown
|
||||
:disabled (not can-edit?)
|
||||
:disabled (not can-edit-file?)
|
||||
:aria-expanded is-open?
|
||||
:aria-haspopup "listbox"
|
||||
:tab-index "0"
|
||||
:role "combobox"
|
||||
:data-testid "theme-select"
|
||||
:class (stl/css-case :custom-select true
|
||||
:disabled-select (not can-edit?))}
|
||||
:disabled-select (not can-edit-file?))}
|
||||
[:> text* {:as "span" :typography "body-small" :class (stl/css :current-label)}
|
||||
current-label]
|
||||
[:> icon* {:icon-id i/arrow-down :class (stl/css :dropdown-button) :aria-hidden true}]
|
||||
@@ -140,7 +163,10 @@
|
||||
|
||||
[:& dropdown {:show is-open?
|
||||
:on-close on-close-dropdown}
|
||||
[:> theme-options* {:active-theme-paths active-theme-paths
|
||||
:themes themes
|
||||
[:> theme-options* {:tokens-lib tokens-lib
|
||||
:tokens-status tokens-status
|
||||
:tokens-source tokens-source
|
||||
:can-edit-tokens can-edit-tokens
|
||||
:team-id team-id
|
||||
:on-close on-close-dropdown}]]])
|
||||
container))]))
|
||||
@@ -0,0 +1,52 @@
|
||||
;; 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 Sucursal en España SL
|
||||
|
||||
(ns app.main.ui.workspace.tokens.tokens-source
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.main.refs :as refs]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.foundations.typography.text :refer [text*]]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc tokens-source-info*
|
||||
{::mf/private true}
|
||||
[{:keys [tokens-source] :as props}]
|
||||
|
||||
(let [files (mf/deref refs/files)
|
||||
tokens-source-file (get files tokens-source)
|
||||
|
||||
team-id
|
||||
(mf/use-ctx ctx/current-team-id)
|
||||
|
||||
open-library-new-window
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (rt/nav :workspace
|
||||
{:team-id team-id
|
||||
:file-id tokens-source
|
||||
:layout :tokens}
|
||||
::rt/new-window true))))]
|
||||
|
||||
[:div {:class (stl/css :tokens-source-wrapper)}
|
||||
[:div {:class (stl/css :tokens-source-header)}
|
||||
[:> text* {:as "span"
|
||||
:typography "headline-small"
|
||||
:class (stl/css :tokens-source-title)}
|
||||
(:name tokens-source-file)]
|
||||
[:> text* {:as "span"
|
||||
:typography "body-medium"
|
||||
:class (stl/css :tokens-source-description)}
|
||||
(tr "workspace.tokens.connected-library")]]
|
||||
[:> icon-button*
|
||||
{:variant "ghost"
|
||||
:aria-label (tr "workspace.tokens.open-connected-library")
|
||||
:on-click open-library-new-window
|
||||
:icon "open-link"}]]))
|
||||
@@ -0,0 +1,40 @@
|
||||
// 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 Sucursal en España SL
|
||||
|
||||
@use "ds/typography.scss" as *;
|
||||
@use "ds/_sizes" as *;
|
||||
@use "ds/_borders.scss" as *;
|
||||
@use "ds/spacing.scss" as *;
|
||||
@use "ds/_utils.scss" as *;
|
||||
|
||||
.tokens-source-wrapper {
|
||||
display: flex;
|
||||
padding: 0 0 0 var(--sp-m);
|
||||
}
|
||||
|
||||
.tokens-source-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--sp-s);
|
||||
flex-grow: 1;
|
||||
padding: var(--sp-s);
|
||||
}
|
||||
|
||||
.tokens-source-title {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
color: var(--color-foreground-primary);
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.tokens-source-description {
|
||||
flex-shrink: 0;
|
||||
color: var(--color-foreground-secondary);
|
||||
border: $b-1 solid var(--color-foreground-secondary);
|
||||
padding: var(--sp-xxs) px2rem(6);
|
||||
border-radius: $br-6;
|
||||
}
|
||||
@@ -1177,7 +1177,7 @@
|
||||
(let [file-id (:current-file-id @st/state)
|
||||
library-id (uuid/parse library-id)]
|
||||
(->> st/stream
|
||||
(rx/filter (ptk/type? ::dwl/attach-library-finished))
|
||||
(rx/filter (ptk/type? ::dwl/link-file-to-library-finished))
|
||||
(rx/take 1)
|
||||
(rx/subs! #(resolve (library-proxy plugin-id library-id)) reject))
|
||||
(st/emit! (-> (dwl/link-file-to-library file-id library-id)
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.json :as json]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.tokenscript :as ts]
|
||||
[app.main.data.workspace.tokens.application :as dwta]
|
||||
@@ -204,6 +206,7 @@
|
||||
(ctob/get-tokens set-id)))
|
||||
:set
|
||||
(fn [_ value]
|
||||
(u/check-editable-tokens file-id)
|
||||
(st/emit! (-> (dwtl/update-token set-id id {:name value})
|
||||
(se/add-event plugin-id))))}
|
||||
|
||||
@@ -230,6 +233,7 @@
|
||||
base))
|
||||
:set
|
||||
(fn [_ value]
|
||||
(u/check-editable-tokens file-id)
|
||||
(let [token (u/locate-token file-id set-id id)
|
||||
value (cond-> value
|
||||
(= :font-family (:type token))
|
||||
@@ -243,7 +247,8 @@
|
||||
(fn [_]
|
||||
(let [token (u/locate-token file-id set-id id)
|
||||
tokens-lib (u/locate-tokens-lib file-id)
|
||||
tokens-tree (ctob/get-tokens-in-active-sets tokens-lib)]
|
||||
tokens-status (u/locate-tokens-status file-id)
|
||||
tokens-tree (cfo/get-tokens-in-active-sets tokens-status tokens-lib)]
|
||||
(get-resolved-value token tokens-tree)))}
|
||||
|
||||
:resolvedValueString
|
||||
@@ -253,7 +258,8 @@
|
||||
(fn [_]
|
||||
(let [token (u/locate-token file-id set-id id)
|
||||
tokens-lib (u/locate-tokens-lib file-id)
|
||||
tokens-tree (ctob/get-tokens-in-active-sets tokens-lib)]
|
||||
tokens-status (u/locate-tokens-status file-id)
|
||||
tokens-tree (cfo/get-tokens-in-active-sets tokens-status tokens-lib)]
|
||||
(str (get-resolved-value token tokens-tree))))}
|
||||
|
||||
:description
|
||||
@@ -265,6 +271,7 @@
|
||||
:schema cfo/schema:token-description
|
||||
:set
|
||||
(fn [_ value]
|
||||
(u/check-editable-tokens file-id)
|
||||
(st/emit! (-> (dwtl/update-token set-id id {:description value})
|
||||
(se/add-event :plugin-id))))}
|
||||
|
||||
@@ -275,6 +282,7 @@
|
||||
;; - use this function in dwtl/duplicate-token
|
||||
;; - return the new token proxy using the locally forced id
|
||||
;; - do the same with sets and themes
|
||||
(u/check-editable-tokens file-id)
|
||||
(let [token (u/locate-token file-id set-id id)
|
||||
token' (ctob/make-token (-> (datafy token)
|
||||
(dissoc :id
|
||||
@@ -285,6 +293,7 @@
|
||||
|
||||
:remove
|
||||
(fn []
|
||||
(u/check-editable-tokens file-id)
|
||||
(st/emit! (-> (dwtl/delete-token set-id id)
|
||||
(se/add-event plugin-id))))
|
||||
|
||||
@@ -337,6 +346,7 @@
|
||||
id)
|
||||
:set
|
||||
(fn [_ name]
|
||||
(u/check-editable-tokens file-id)
|
||||
(let [set (u/locate-token-set file-id id)]
|
||||
(st/emit! (dwtl/rename-token-set set name))))}
|
||||
|
||||
@@ -345,19 +355,16 @@
|
||||
:enumerable false
|
||||
:get
|
||||
(fn [_]
|
||||
(let [tokens-lib (u/locate-tokens-lib file-id)
|
||||
set (u/locate-token-set file-id id)]
|
||||
(ctob/token-set-active? tokens-lib (ctob/get-name set))))
|
||||
(let [tokens-status (u/locate-tokens-status file-id)]
|
||||
(ctos/set-active? tokens-status id)))
|
||||
:schema ::sm/boolean
|
||||
:set
|
||||
(fn [_ value]
|
||||
(let [set (u/locate-token-set file-id id)]
|
||||
(st/emit! (dwtl/set-enabled-token-set (ctob/get-name set) value))))}
|
||||
(st/emit! (dwtl/set-enabled-token-set id value)))} ;; This can be done even with tokens in an external library
|
||||
|
||||
:toggleActive
|
||||
(fn [_]
|
||||
(let [set (u/locate-token-set file-id id)]
|
||||
(st/emit! (dwtl/toggle-token-set (ctob/get-name set)))))
|
||||
(st/emit! (dwtl/toggle-token-set id)))
|
||||
|
||||
:tokens
|
||||
{:this true
|
||||
@@ -416,6 +423,7 @@
|
||||
(sm/update-properties assoc :decode/json cfo/convert-dtcg-token))]))
|
||||
:decode/options {:key-fn identity}
|
||||
:fn (fn [attrs]
|
||||
(u/check-editable-tokens file-id)
|
||||
(let [tokens-lib (u/locate-tokens-lib file-id)
|
||||
token (ctob/make-token attrs)
|
||||
;; Resolve against all tokens in the library (including those
|
||||
@@ -441,6 +449,7 @@
|
||||
|
||||
:duplicate
|
||||
(fn []
|
||||
(u/check-editable-tokens file-id)
|
||||
(let [id-ref (atom nil)]
|
||||
(st/emit! (dwtl/duplicate-token-set id {:id-ref id-ref}))
|
||||
(when (some? @id-ref)
|
||||
@@ -448,6 +457,7 @@
|
||||
|
||||
:remove
|
||||
(fn []
|
||||
(u/check-editable-tokens file-id)
|
||||
(st/emit! (dwtl/delete-token-set id))))))
|
||||
|
||||
(defn token-theme-proxy? [p]
|
||||
@@ -501,6 +511,7 @@
|
||||
(:id theme)))
|
||||
:set
|
||||
(fn [_ group]
|
||||
(u/check-editable-tokens file-id)
|
||||
(let [theme (u/locate-token-theme file-id id)]
|
||||
(st/emit! (dwtl/update-token-theme id (assoc theme :group group)))))}
|
||||
|
||||
@@ -517,6 +528,7 @@
|
||||
(:group theme)))
|
||||
:set
|
||||
(fn [_ name]
|
||||
(u/check-editable-tokens file-id)
|
||||
(let [theme (u/locate-token-theme file-id id)]
|
||||
(when name
|
||||
(st/emit! (dwtl/update-token-theme id (assoc theme :name name))))))}
|
||||
@@ -526,8 +538,8 @@
|
||||
:enumerable false
|
||||
:get
|
||||
(fn [_]
|
||||
(let [tokens-lib (u/locate-tokens-lib file-id)]
|
||||
(ctob/theme-active? tokens-lib id)))
|
||||
(let [tokens-status (u/locate-tokens-status file-id)]
|
||||
(ctos/theme-active? tokens-status id)))
|
||||
:schema ::sm/boolean
|
||||
:set
|
||||
(fn [_ value]
|
||||
@@ -554,6 +566,7 @@
|
||||
{:enumerable false
|
||||
:schema [:tuple [:or [:fn token-set-proxy?] ::sm/uuid]]
|
||||
:fn (fn [set-arg]
|
||||
(u/check-editable-tokens file-id)
|
||||
(let [set-name (token-set-name (resolve-token-set file-id set-arg))
|
||||
theme (u/locate-token-theme file-id id)]
|
||||
(when (and set-name theme)
|
||||
@@ -563,6 +576,7 @@
|
||||
{:enumerable false
|
||||
:schema [:tuple [:or [:fn token-set-proxy?] ::sm/uuid]]
|
||||
:fn (fn [set-arg]
|
||||
(u/check-editable-tokens file-id)
|
||||
(let [set-name (token-set-name (resolve-token-set file-id set-arg))
|
||||
theme (u/locate-token-theme file-id id)]
|
||||
(when (and set-name theme)
|
||||
@@ -570,6 +584,7 @@
|
||||
|
||||
:duplicate
|
||||
(fn []
|
||||
(u/check-editable-tokens file-id)
|
||||
(let [theme (u/locate-token-theme file-id id)
|
||||
theme' (ctob/make-token-theme (-> (datafy theme)
|
||||
(dissoc :id
|
||||
@@ -579,6 +594,7 @@
|
||||
|
||||
:remove
|
||||
(fn []
|
||||
(u/check-editable-tokens file-id)
|
||||
(st/emit! (dwtl/delete-token-theme id)))))
|
||||
|
||||
(defn tokens-catalog
|
||||
@@ -588,6 +604,14 @@
|
||||
:$plugin {:enumerable false :get (constantly plugin-id)}
|
||||
:$id {:enumerable false :get (constantly file-id)}
|
||||
|
||||
:isEditableTokens
|
||||
{:this false
|
||||
:enumerable false
|
||||
:get
|
||||
(fn []
|
||||
(let [file (u/locate-file file-id)]
|
||||
(cfo/editable-tokens? (ctf/file-data file))))}
|
||||
|
||||
:themes
|
||||
{:this true
|
||||
:enumerable false
|
||||
@@ -619,6 +643,7 @@
|
||||
nil)
|
||||
(sm/dissoc-key :id))]) ;; We don't allow plugins to set the id
|
||||
:fn (fn [attrs]
|
||||
(u/check-editable-tokens file-id)
|
||||
(let [theme (ctob/make-token-theme attrs)]
|
||||
(st/emit! (dwtl/create-token-theme theme))
|
||||
(token-theme-proxy plugin-id file-id (:id theme))))}
|
||||
@@ -638,6 +663,7 @@
|
||||
(sm/merge [:map [:active {:optional true} ::sm/boolean]]))]
|
||||
|
||||
:fn (fn [attrs]
|
||||
(u/check-editable-tokens file-id)
|
||||
(let [active? (boolean (:active attrs))
|
||||
attrs (-> attrs
|
||||
(dissoc :active)
|
||||
@@ -648,7 +674,7 @@
|
||||
;; requested. Enabling only adds the set name to the hidden theme,
|
||||
;; so it does not depend on the create event having propagated yet.
|
||||
(when active?
|
||||
(st/emit! (dwtl/set-enabled-token-set (ctob/get-name set) true)))
|
||||
(st/emit! (dwtl/set-enabled-token-set (ctob/get-id set) true)))
|
||||
;; Pass the set name as `initial-name` so the proxy can resolve
|
||||
;; it immediately, before the async `st/emit!` above propagates
|
||||
;; the new set into `@st/state`.
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.i18n :as i18n :refer [tr]]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.schema.messages :as csm]
|
||||
@@ -67,8 +68,18 @@
|
||||
|
||||
(defn locate-tokens-lib
|
||||
[file-id]
|
||||
(let [file (locate-file file-id)]
|
||||
(->> file :data :tokens-lib)))
|
||||
(let [file (locate-file file-id)
|
||||
file-data (ctf/file-data file)
|
||||
tokens-source-id (cfo/get-effective-tokens-source file-data)
|
||||
tokens-file (locate-file tokens-source-id)
|
||||
tokens-file-data (ctf/file-data tokens-file)]
|
||||
(cfo/get-tokens-lib tokens-file-data)))
|
||||
|
||||
(defn locate-tokens-status
|
||||
[file-id]
|
||||
(let [file (locate-file file-id)
|
||||
file-data (ctf/file-data file)]
|
||||
(cfo/get-tokens-status file-data)))
|
||||
|
||||
(defn locate-token-theme
|
||||
[file-id id]
|
||||
@@ -266,6 +277,12 @@
|
||||
(boolean
|
||||
(dm/get-in @st/state [:plugins :flags plugin-id :natural-child-ordering])))
|
||||
|
||||
(defn check-editable-tokens
|
||||
[file-id]
|
||||
(let [file (locate-file file-id)]
|
||||
(when-not (cfo/editable-tokens? (ctf/file-data file))
|
||||
(throw (js/Error. (dm/str "[PENPOT PLUGIN] Cannot modify tokens in an external library"))))))
|
||||
|
||||
(defn throw-validation-errors?
|
||||
[plugin-id]
|
||||
(boolean
|
||||
|
||||
@@ -880,25 +880,6 @@
|
||||
(h/call wasm/internal-module "_store_image")
|
||||
true)))))
|
||||
|
||||
(defn- store-image-url!
|
||||
"Registers the public URL an image was loaded from so SVG export can emit a
|
||||
linked `<image href>` instead of a Skia base64 embed."
|
||||
[image-id url]
|
||||
(when (and (wasm/live?) (some? url) (not (str/blank? url)))
|
||||
(let [buffer (uuid/get-u32 image-id)
|
||||
encoder (js/TextEncoder.)
|
||||
encoded (.encode encoder url)
|
||||
size (.-byteLength encoded)
|
||||
offset (mem/alloc size)
|
||||
heap (mem/get-heap-u8)]
|
||||
(.set heap encoded offset)
|
||||
(h/call wasm/internal-module "_store_image_url"
|
||||
(aget buffer 0)
|
||||
(aget buffer 1)
|
||||
(aget buffer 2)
|
||||
(aget buffer 3))
|
||||
true)))
|
||||
|
||||
(defn- store-image-texture
|
||||
"Creates a WebGL texture from a decoded image and passes the texture ID to
|
||||
WASM. This avoids decoding the image twice (once in browser, once in WASM)."
|
||||
@@ -941,7 +922,6 @@
|
||||
so Skia rasterizes them."
|
||||
[shape-id image-id thumbnail?]
|
||||
(let [url (cf/resolve-file-media {:id image-id} thumbnail?)]
|
||||
(store-image-url! image-id url)
|
||||
{:key url
|
||||
:thumbnail? thumbnail?
|
||||
:callback
|
||||
@@ -979,8 +959,6 @@
|
||||
(aget buffer 2)
|
||||
(aget buffer 3)
|
||||
thumbnail?)]
|
||||
;; Always register the URL (SVG export needs it even when bytes are cached).
|
||||
(store-image-url! id (cf/resolve-file-media {:id id} thumbnail?))
|
||||
(when (zero? cached-image?)
|
||||
(fetch-image shape-id id thumbnail?)))))
|
||||
|
||||
@@ -1015,7 +993,6 @@
|
||||
(aget buffer 2)
|
||||
(aget buffer 3)
|
||||
thumbnail?)]
|
||||
(store-image-url! id (cf/resolve-file-media {:id id} thumbnail?))
|
||||
(when (zero? cached-image?)
|
||||
(fetch-image shape-id id thumbnail?))))
|
||||
(types.fills/get-image-ids fills))))))
|
||||
@@ -1044,7 +1021,6 @@
|
||||
(aget buffer 2)
|
||||
(aget buffer 3)
|
||||
thumbnail?)]
|
||||
(store-image-url! image-id (cf/resolve-file-media {:id image-id} thumbnail?))
|
||||
(when (zero? cached-image?)
|
||||
(fetch-image shape-id image-id thumbnail?))))
|
||||
image-ids))))
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
[app.common.types.text :as txt]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.data.workspace.texts-events :as dwte]
|
||||
[app.main.ui.workspace.shapes.text.viewport-texts-html :as vth]
|
||||
[cljs.test :as t :include-macros true]
|
||||
[frontend-tests.helpers.state :as ths]))
|
||||
@@ -312,7 +313,7 @@
|
||||
store (ths/setup-store file)
|
||||
events [;; Pre-select the text shape so add-typography can find it
|
||||
(fn [state] (assoc-in state [:workspace-local :selected] #{shape-id}))
|
||||
(dwt/add-typography file-id)]]
|
||||
(dwte/add-typography file-id)]]
|
||||
|
||||
(ths/run-store
|
||||
store done events
|
||||
@@ -339,7 +340,7 @@
|
||||
file-id (:id file)
|
||||
store (ths/setup-store file)
|
||||
events [(fn [state] (assoc-in state [:workspace-local :selected] #{shape-id}))
|
||||
(dwt/add-typography file-id)]]
|
||||
(dwte/add-typography file-id)]]
|
||||
|
||||
(ths/run-store
|
||||
store done events
|
||||
@@ -366,7 +367,7 @@
|
||||
file-id (:id file)
|
||||
store (ths/setup-store file)
|
||||
events [(fn [state] (assoc-in state [:workspace-local :selected] #{shape-id}))
|
||||
(dwt/add-typography file-id)]]
|
||||
(dwte/add-typography file-id)]]
|
||||
|
||||
(ths/run-store
|
||||
store done events
|
||||
|
||||
@@ -6,9 +6,11 @@
|
||||
|
||||
(ns frontend-tests.helpers.state
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.pprint :refer [pprint]]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.test-helpers.files :as cthf]
|
||||
[app.common.test-helpers.tokens :as ctht]
|
||||
[app.main.data.workspace.layout :as layout]
|
||||
[app.main.features :as features]
|
||||
[beicon.v2.core :as rx]
|
||||
@@ -34,12 +36,21 @@
|
||||
|
||||
(defn setup-store
|
||||
([file] (setup-store file nil))
|
||||
([file {:keys [renderer] :as _opts}]
|
||||
(let [state (-> initial-state
|
||||
([file {:keys [renderer libraries tokens-source-library] :as _opts
|
||||
:or {libraries [] tokens-source-library nil}}]
|
||||
(let [file (cond-> file
|
||||
(some? tokens-source-library)
|
||||
(ctht/set-tokens-source tokens-source-library))
|
||||
libraries (map #(assoc %
|
||||
:library-of (:id file)
|
||||
:is-shared true)
|
||||
libraries)
|
||||
files (d/index-by :id (cons file libraries))
|
||||
state (-> initial-state
|
||||
(assoc :current-file-id (:id file)
|
||||
:current-page-id (cthf/current-page-id file)
|
||||
:permissions {:can-edit true}
|
||||
:files {(:id file) file})
|
||||
:files files)
|
||||
(cond-> (some? renderer)
|
||||
(assoc-in [:profile :props :renderer] renderer)))
|
||||
store (ptk/store {:state state :on-error on-error})]
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
[app.common.math :as mth]
|
||||
[app.common.test-helpers.components :as cthc]
|
||||
[app.common.test-helpers.compositions :as ctho]
|
||||
[app.common.test-helpers.files :as cthf]
|
||||
[app.common.test-helpers.ids-map :as cthi]
|
||||
[app.common.test-helpers.shapes :as cths]
|
||||
[app.common.test-helpers.tokens :as ctht]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
@@ -35,29 +35,31 @@
|
||||
|
||||
(defn- setup-base-file
|
||||
[]
|
||||
(-> (cthf/sample-file :file1)
|
||||
(ctht/add-tokens-lib)
|
||||
(ctht/update-tokens-lib #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :test-token-set)
|
||||
:name "test-token-set"))
|
||||
(ctob/add-theme (ctob/make-token-theme :name "test-theme"
|
||||
:sets #{"test-token-set"}))
|
||||
(ctob/set-active-themes #{"/test-theme"})
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :test-token-1)
|
||||
:name "test-token-1"
|
||||
:type :border-radius
|
||||
:value 25))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :test-token-2)
|
||||
:name "test-token-2"
|
||||
:type :border-radius
|
||||
:value 50))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :test-token-3)
|
||||
:name "test-token-3"
|
||||
:type :border-radius
|
||||
:value 75))))
|
||||
(-> (ctht/sample-file-with-tokens
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :test-token-set)
|
||||
:name "test-token-set"))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (cthi/new-id! :test-theme)
|
||||
:name "test-theme"
|
||||
:sets #{"test-token-set"}))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :test-token-1)
|
||||
:name "test-token-1"
|
||||
:type :border-radius
|
||||
:value 25))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :test-token-2)
|
||||
:name "test-token-2"
|
||||
:type :border-radius
|
||||
:value 50))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :test-token-3)
|
||||
:name "test-token-3"
|
||||
:type :border-radius
|
||||
:value 75)))
|
||||
:status-fn #(-> %
|
||||
(ctos/set-tokens-status #{(cthi/id :test-theme)}
|
||||
#{(cthi/id :test-token-set)})))
|
||||
(ctho/add-frame :frame1)
|
||||
(ctht/apply-token-to-shape :frame1 "test-token-1" [:r1 :r2 :r3 :r4] [:r1 :r2 :r3 :r4] 25)))
|
||||
|
||||
@@ -323,44 +325,44 @@
|
||||
(t/async
|
||||
done
|
||||
(let [;; ==== Setup
|
||||
file (-> (cthf/sample-file :file1)
|
||||
(ctht/add-tokens-lib)
|
||||
(ctht/update-tokens-lib #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :test-token-set)
|
||||
:name "test-token-set"))
|
||||
(ctob/add-theme (ctob/make-token-theme :name "test-theme"
|
||||
:sets #{"test-token-set"}))
|
||||
(ctob/set-active-themes #{"/test-theme"})
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :token-radius)
|
||||
:name "token-radius"
|
||||
:type :border-radius
|
||||
:value 10))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :token-rotation)
|
||||
:name "token-rotation"
|
||||
:type :rotation
|
||||
:value 30))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :token-opacity)
|
||||
:name "token-opacity"
|
||||
:type :opacity
|
||||
:value 0.7))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :token-stroke-width)
|
||||
:name "token-stroke-width"
|
||||
:type :stroke-width
|
||||
:value 2))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :token-color)
|
||||
:name "token-color"
|
||||
:type :color
|
||||
:value "#00ff00"))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :token-dimensions)
|
||||
:name "token-dimensions"
|
||||
:type :dimensions
|
||||
:value 100))))
|
||||
file (-> (ctht/sample-file-with-tokens
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :test-token-set)
|
||||
:name "test-token-set"))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (cthi/new-id! :test-theme)
|
||||
:name "test-theme"
|
||||
:sets #{"test-token-set"}))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :token-radius)
|
||||
:name "token-radius"
|
||||
:type :border-radius
|
||||
:value 10))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :token-rotation)
|
||||
:name "token-rotation"
|
||||
:type :rotation
|
||||
:value 30))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :token-opacity)
|
||||
:name "token-opacity"
|
||||
:type :opacity
|
||||
:value 0.7))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :token-stroke-width)
|
||||
:name "token-stroke-width"
|
||||
:type :stroke-width
|
||||
:value 2))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :token-color)
|
||||
:name "token-color"
|
||||
:type :color
|
||||
:value "#00ff00"))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :token-dimensions)
|
||||
:name "token-dimensions"
|
||||
:type :dimensions
|
||||
:value 100)))
|
||||
:status-fn #(ctos/set-tokens-status % #{(cthi/id :test-theme)} #{(cthi/id :test-token-set)}))
|
||||
(ctho/add-frame :frame1)
|
||||
(ctht/apply-token-to-shape :frame1 "token-radius" [:r1 :r2 :r3 :r4] [:r1 :r2 :r3 :r4] 10)
|
||||
(ctht/apply-token-to-shape :frame1 "token-rotation" [:rotation] [:rotation] 30)
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
|
||||
(ns frontend-tests.plugins.tokens-test
|
||||
(:require
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.test-helpers.compositions :as ctho]
|
||||
[app.common.test-helpers.files :as cthf]
|
||||
[app.common.test-helpers.ids-map :as cthi]
|
||||
[app.common.test-helpers.tokens :as ctht]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.tokenscript :as ts]
|
||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||
@@ -107,24 +109,25 @@
|
||||
done
|
||||
(let [set-id (cthi/new-id! :token-set)
|
||||
token-id (cthi/new-id! :spacing-token)
|
||||
file (-> (cthf/sample-file :file1 :page-label :page1)
|
||||
(ctho/add-frame :frame1 {:layout :flex})
|
||||
(ctht/add-tokens-lib)
|
||||
(ctht/update-tokens-lib
|
||||
#(-> %
|
||||
(ctob/add-set
|
||||
(ctob/make-token-set :id set-id
|
||||
:name "spacing"))
|
||||
(ctob/add-theme
|
||||
(ctob/make-token-theme :name "theme"
|
||||
:sets #{"spacing"}))
|
||||
(ctob/set-active-themes #{"/theme"})
|
||||
(ctob/add-token
|
||||
set-id
|
||||
(ctob/make-token :id token-id
|
||||
:name "spacing.medium"
|
||||
:type :spacing
|
||||
:value 16)))))
|
||||
theme-id (cthi/new-id! :theme)
|
||||
file (-> (ctht/sample-file-with-tokens
|
||||
:file-id :file1
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set
|
||||
(ctob/make-token-set :id set-id
|
||||
:name "spacing"))
|
||||
(ctob/add-theme
|
||||
(ctob/make-token-theme :id theme-id
|
||||
:name "theme"
|
||||
:sets #{"spacing"}))
|
||||
(ctob/add-token
|
||||
set-id
|
||||
(ctob/make-token :id token-id
|
||||
:name "spacing.medium"
|
||||
:type :spacing
|
||||
:value 16)))
|
||||
:status-fn #(ctos/set-tokens-status % #{theme-id} #{set-id}))
|
||||
(ctho/add-frame :frame1 {:layout :flex}))
|
||||
store (ths/setup-store file)
|
||||
_ (set! st/state store)
|
||||
_ (set! st/stream (ptk/input-stream store))
|
||||
@@ -191,10 +194,11 @@
|
||||
;; Demonstrates the bug: resolving the new token against active sets
|
||||
;; only leaves the reference unresolved.
|
||||
(let [tokens-lib (inactive-set-library)
|
||||
tokens-status (cfo/make-tokens-status-from-lib tokens-lib)
|
||||
token (ctob/make-token {:name "color.bg.default"
|
||||
:value "{color.gray.50}"
|
||||
:type :color})
|
||||
tokens-tree (-> (ctob/get-tokens-in-active-sets tokens-lib)
|
||||
tokens-tree (-> (cfo/get-tokens-in-active-sets tokens-status tokens-lib)
|
||||
(assoc (:name token) token))
|
||||
resolved (ts/resolve-tokens tokens-tree)
|
||||
{:keys [errors resolved-value]} (get resolved (:name token))]
|
||||
@@ -234,15 +238,17 @@
|
||||
(t/deftest token-set-duplicate-returns-the-duplicated-set
|
||||
(let [file-id (cthi/new-id! :file)
|
||||
set-id (cthi/new-id! :set)
|
||||
dup-id (cthi/new-id! :dup)
|
||||
proxy (ptok/token-set-proxy "plugin-id" file-id set-id)]
|
||||
(with-redefs [dwtl/duplicate-token-set
|
||||
dup-id (cthi/new-id! :dup)]
|
||||
(with-redefs [u/locate-tokens-lib (constantly nil)
|
||||
u/check-editable-tokens (constantly nil)
|
||||
dwtl/duplicate-token-set
|
||||
(mock/stub (fn [id {:keys [id-ref]}]
|
||||
(t/is (= set-id id))
|
||||
(reset! id-ref dup-id)
|
||||
:duplicate-token-set))
|
||||
st/emit! mock/noop]
|
||||
(let [dup (.duplicate proxy)]
|
||||
(let [proxy (ptok/token-set-proxy "plugin-id" file-id set-id)
|
||||
dup (.duplicate proxy)]
|
||||
(t/is (ptok/token-set-proxy? dup))
|
||||
(t/is (= (str dup-id) (.-id dup)))))))
|
||||
|
||||
@@ -250,10 +256,10 @@
|
||||
(let [file-id (cthi/new-id! :file)
|
||||
theme-id (cthi/new-id! :theme)
|
||||
set-id (cthi/new-id! :set)
|
||||
set (ptok/token-set-proxy "plugin-id" file-id set-id "Primitives")
|
||||
theme (ptok/token-theme-proxy "plugin-id" file-id theme-id)
|
||||
captured (atom [])]
|
||||
(with-redefs [u/locate-token-theme
|
||||
(with-redefs [u/locate-tokens-lib (constantly nil)
|
||||
u/check-editable-tokens (constantly nil)
|
||||
u/locate-token-theme
|
||||
(fn [_file _theme]
|
||||
(ctob/make-token-theme :id theme-id
|
||||
:name "Theme"
|
||||
@@ -263,18 +269,22 @@
|
||||
(swap! captured conj {:id id :theme theme})
|
||||
:update-token-theme)
|
||||
st/emit! mock/noop]
|
||||
(.addSet theme set)
|
||||
(.removeSet theme set)
|
||||
(t/is (= [theme-id theme-id] (mapv :id @captured)))
|
||||
(t/is (contains? (-> @captured first :theme :sets) "Primitives"))
|
||||
(t/is (not (contains? (-> @captured second :theme :sets) "Primitives"))))))
|
||||
(let [set (ptok/token-set-proxy "plugin-id" file-id set-id "Primitives")
|
||||
theme (ptok/token-theme-proxy "plugin-id" file-id theme-id)]
|
||||
(.addSet theme set)
|
||||
(.removeSet theme set)
|
||||
(t/is (= [theme-id theme-id] (mapv :id @captured)))
|
||||
(t/is (contains? (-> @captured first :theme :sets) "Primitives"))
|
||||
(t/is (not (contains? (-> @captured second :theme :sets) "Primitives")))))))
|
||||
|
||||
(t/deftest font-family-token-value-accepts-a-string
|
||||
(let [file-id (cthi/new-id! :file)
|
||||
set-id (cthi/new-id! :set)
|
||||
token-id (cthi/new-id! :token)
|
||||
captured (atom nil)]
|
||||
(with-redefs [u/locate-token (constantly {:id token-id
|
||||
(with-redefs [u/locate-tokens-lib (constantly nil)
|
||||
u/check-editable-tokens (constantly nil)
|
||||
u/locate-token (constantly {:id token-id
|
||||
:name "font.primary"
|
||||
:type :font-family
|
||||
:value ["Inter"]})
|
||||
@@ -347,12 +357,14 @@
|
||||
theme (ctob/make-token-theme :id theme-id :group "mode" :name "Light")
|
||||
emitted (atom [])
|
||||
invalid (atom [])]
|
||||
(with-redefs [u/locate-token-set (fn [_ id] (when (= id set-id) token-set))
|
||||
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
||||
u/not-valid (fn [_ code value] (swap! invalid conj [code value]))
|
||||
(with-redefs [u/locate-tokens-lib (constantly nil)
|
||||
u/locate-token-set (fn [_ id] (when (= id set-id) token-set))
|
||||
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
||||
u/check-editable-tokens (constantly nil)
|
||||
u/not-valid (fn [_ code value] (swap! invalid conj [code value]))
|
||||
dwtl/update-token-theme (fn [id theme] {:id id :theme theme})
|
||||
st/emit! (fn ([event] (swap! emitted conj event) nil)
|
||||
([event & _] (swap! emitted conj event) nil))]
|
||||
st/emit! (fn ([event] (swap! emitted conj event) nil)
|
||||
([event & _] (swap! emitted conj event) nil))]
|
||||
(let [theme-proxy (ptok/token-theme-proxy plugin-id file-id theme-id)]
|
||||
(.addSet theme-proxy (str set-id))
|
||||
(t/is (= #{"Core"} (-> @emitted first :theme :sets)))
|
||||
@@ -367,12 +379,14 @@
|
||||
theme (ctob/make-token-theme :id theme-id :group "mode" :name "Light")
|
||||
emitted (atom [])
|
||||
invalid (atom [])]
|
||||
(with-redefs [u/locate-token-set (fn [_ id] (when (= id set-id) token-set))
|
||||
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
||||
u/not-valid (fn [_ code value] (swap! invalid conj [code value]))
|
||||
(with-redefs [u/locate-tokens-lib (constantly nil)
|
||||
u/locate-token-set (fn [_ id] (when (= id set-id) token-set))
|
||||
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
||||
u/check-editable-tokens (constantly nil)
|
||||
u/not-valid (fn [_ code value] (swap! invalid conj [code value]))
|
||||
dwtl/update-token-theme (fn [id theme] {:id id :theme theme})
|
||||
st/emit! (fn ([event] (swap! emitted conj event) nil)
|
||||
([event & _] (swap! emitted conj event) nil))]
|
||||
st/emit! (fn ([event] (swap! emitted conj event) nil)
|
||||
([event & _] (swap! emitted conj event) nil))]
|
||||
(let [theme-proxy (ptok/token-theme-proxy plugin-id file-id theme-id)
|
||||
set-proxy (ptok/token-set-proxy plugin-id file-id set-id "Core")]
|
||||
(.addSet theme-proxy set-proxy)
|
||||
@@ -385,18 +399,22 @@
|
||||
theme-id (uuid/next)
|
||||
theme (ctob/make-token-theme :id theme-id :group "mode" :name "Light")
|
||||
emitted (atom [])
|
||||
errors (atom [])]
|
||||
(with-redefs [u/locate-token-set (constantly nil)
|
||||
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
||||
invalid (atom [])]
|
||||
(with-redefs [u/locate-tokens-lib (constantly nil)
|
||||
u/locate-token-set (constantly nil)
|
||||
u/throw-validation-errors? (constantly true)
|
||||
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
||||
u/check-editable-tokens (constantly nil)
|
||||
u/handle-error (fn [plugin-id]
|
||||
(fn [cause]
|
||||
(u/not-valid plugin-id :error (str cause))))
|
||||
dwtl/update-token-theme (fn [id theme] {:id id :theme theme})
|
||||
st/emit! (fn ([event] (swap! emitted conj event) nil)
|
||||
([event & _] (swap! emitted conj event) nil))]
|
||||
(let [theme-proxy (ptok/token-theme-proxy plugin-id file-id theme-id)]
|
||||
;; Non-id, non-proxy arguments are rejected by the schema coercer.
|
||||
(try (.addSet theme-proxy 42) (catch :default e (swap! errors conj e)))
|
||||
(try (.removeSet theme-proxy nil) (catch :default e (swap! errors conj e)))
|
||||
(try (.addSet theme-proxy 42) (catch :default e (swap! invalid conj e)))
|
||||
(try (.removeSet theme-proxy nil) (catch :default e (swap! invalid conj e)))
|
||||
(t/is (empty? @emitted))
|
||||
(t/is (= 2 (count @errors)))
|
||||
(t/is (every? #(instance? js/Error %) @errors))))))
|
||||
(t/is (= 2 (count @invalid)))
|
||||
(t/is (every? #(instance? js/Error %) @invalid))))))
|
||||
|
||||
@@ -72,7 +72,9 @@
|
||||
[frontend-tests.tokens.import-export-test]
|
||||
[frontend-tests.tokens.logic.token-actions-test]
|
||||
[frontend-tests.tokens.logic.token-data-test]
|
||||
[frontend-tests.tokens.logic.token-libraries-test]
|
||||
[frontend-tests.tokens.logic.token-remapping-test]
|
||||
[frontend-tests.tokens.logic.tokens-status-test]
|
||||
[frontend-tests.tokens.style-dictionary-test]
|
||||
[frontend-tests.tokens.token-errors-test]
|
||||
[frontend-tests.tokens.workspace-tokens-remap-test]
|
||||
@@ -110,98 +112,102 @@
|
||||
(.exit js/process 1)))
|
||||
|
||||
(def test-namespaces
|
||||
['frontend-tests.basic-shapes-test
|
||||
'frontend-tests.code-gen-style-test
|
||||
'frontend-tests.composable-tests.comp.sync-test
|
||||
'frontend-tests.copy-as-svg-test
|
||||
'frontend-tests.data.dashboard-test
|
||||
'frontend-tests.data.nitrate-test
|
||||
'frontend-tests.data.profile-test
|
||||
'frontend-tests.data.repo-test
|
||||
'frontend-tests.data.store-test
|
||||
'frontend-tests.data.exports-assets-test
|
||||
'frontend-tests.data.uploads-test
|
||||
'frontend-tests.data.viewer-test
|
||||
'frontend-tests.data.workspace-colors-test
|
||||
'frontend-tests.data.workspace-comments-test
|
||||
'frontend-tests.data.workspace-interactions-test
|
||||
'frontend-tests.data.workspace-mcp-test
|
||||
'frontend-tests.data.workspace-media-test
|
||||
'frontend-tests.data.workspace-pages-test
|
||||
'frontend-tests.data.workspace-path-edition-test
|
||||
'frontend-tests.data.workspace-reflow-test
|
||||
'frontend-tests.data.workspace-shortcuts-test
|
||||
'frontend-tests.data.workspace-texts-test
|
||||
'frontend-tests.data.workspace-thumbnails-test
|
||||
'frontend-tests.errors-test
|
||||
'frontend-tests.fonts-test
|
||||
'frontend-tests.helpers-shapes-test
|
||||
'frontend-tests.logic.comp-remove-swap-slots-test
|
||||
'frontend-tests.logic.components-and-tokens
|
||||
'frontend-tests.logic.copying-and-duplicating-test
|
||||
'frontend-tests.logic.frame-guides-test
|
||||
'frontend-tests.logic.groups-test
|
||||
'frontend-tests.logic.nudge-selected-shapes-test
|
||||
'frontend-tests.logic.path-actions-test
|
||||
'frontend-tests.logic.path-clipboard-test
|
||||
'frontend-tests.logic.path-helpers-test
|
||||
'frontend-tests.logic.path-lifecycle-test
|
||||
'frontend-tests.logic.path-tools-test
|
||||
'frontend-tests.logic.pasting-in-containers-test
|
||||
'frontend-tests.main-errors-test
|
||||
'frontend-tests.logic.sidebar-transform-coalescing-test
|
||||
'frontend-tests.logic.update-position-test
|
||||
'frontend-tests.logic.wasm-modifiers-nil-id-test
|
||||
'frontend-tests.plugins.comments-test
|
||||
'frontend-tests.plugins.context-shapes-test
|
||||
'frontend-tests.plugins.file-test
|
||||
'frontend-tests.plugins.format-test
|
||||
'frontend-tests.plugins.grid-test
|
||||
'frontend-tests.plugins.interactions-test
|
||||
'frontend-tests.plugins.library-test
|
||||
'frontend-tests.plugins.local-storage-test
|
||||
'frontend-tests.plugins.page-active-validation-test
|
||||
'frontend-tests.plugins.page-test
|
||||
'frontend-tests.plugins.parser-test
|
||||
'frontend-tests.plugins.shape-bugfixes-test
|
||||
'frontend-tests.plugins.text-test
|
||||
'frontend-tests.plugins.tokens-test
|
||||
'frontend-tests.plugins.utils-test
|
||||
'frontend-tests.plugins.value-objects-test
|
||||
'frontend-tests.render-wasm.process-objects-test
|
||||
'frontend-tests.render-wasm.text-editor-apply-styles-test
|
||||
'frontend-tests.render-wasm.text-editor-caret-color-test
|
||||
'frontend-tests.svg-fills-test
|
||||
'frontend-tests.tokens.copy-paste-props-test
|
||||
'frontend-tests.tokens.import-export-test
|
||||
'frontend-tests.tokens.logic.token-actions-test
|
||||
'frontend-tests.tokens.logic.token-data-test
|
||||
'frontend-tests.tokens.logic.token-remapping-test
|
||||
'frontend-tests.tokens.style-dictionary-test
|
||||
'frontend-tests.tokens.token-errors-test
|
||||
'frontend-tests.tokens.workspace-tokens-remap-test
|
||||
'frontend-tests.ui.check-updates-test
|
||||
'frontend-tests.ui.colorpicker-token-set-order-test
|
||||
'frontend-tests.ui.comments-clustering-test
|
||||
'frontend-tests.ui.comments-position-modifier-test
|
||||
'frontend-tests.ui.ds-controls-numeric-input-test
|
||||
'frontend-tests.ui.gradient-handlers-test
|
||||
'frontend-tests.ui.layout-container-multiple-test
|
||||
'frontend-tests.ui.measures-menu-props-test
|
||||
'frontend-tests.ui.routes-test
|
||||
'frontend-tests.render-dimensions-test
|
||||
'frontend-tests.text-editor-paste-guard-test
|
||||
'frontend-tests.ui.settings-password-schema-test
|
||||
'frontend-tests.ui.settings-shortcuts-test
|
||||
'frontend-tests.util-clipboard-test
|
||||
'frontend-tests.util-object-test
|
||||
'frontend-tests.util-range-tree-test
|
||||
'frontend-tests.util-simple-math-test
|
||||
'frontend-tests.util-text-editor-test
|
||||
'frontend-tests.util-webapi-test
|
||||
'frontend-tests.util.dom.dnd-test
|
||||
'frontend-tests.util-zip-test
|
||||
'frontend-tests.worker-snap-test])
|
||||
[
|
||||
;; 'frontend-tests.basic-shapes-test
|
||||
;; 'frontend-tests.code-gen-style-test
|
||||
;; 'frontend-tests.composable-tests.comp.sync-test
|
||||
;; 'frontend-tests.copy-as-svg-test
|
||||
;; 'frontend-tests.data.dashboard-test
|
||||
;; 'frontend-tests.data.nitrate-test
|
||||
;; 'frontend-tests.data.profile-test
|
||||
;; 'frontend-tests.data.repo-test
|
||||
;; 'frontend-tests.data.store-test
|
||||
;; 'frontend-tests.data.exports-assets-test
|
||||
;; 'frontend-tests.data.uploads-test
|
||||
;; 'frontend-tests.data.viewer-test
|
||||
;; 'frontend-tests.data.workspace-colors-test
|
||||
;; 'frontend-tests.data.workspace-comments-test
|
||||
;; 'frontend-tests.data.workspace-interactions-test
|
||||
;; 'frontend-tests.data.workspace-mcp-test
|
||||
;; 'frontend-tests.data.workspace-media-test
|
||||
;; 'frontend-tests.data.workspace-pages-test
|
||||
;; 'frontend-tests.data.workspace-path-edition-test
|
||||
;; 'frontend-tests.data.workspace-reflow-test
|
||||
;; 'frontend-tests.data.workspace-shortcuts-test
|
||||
;; 'frontend-tests.data.workspace-texts-test
|
||||
;; 'frontend-tests.data.workspace-thumbnails-test
|
||||
;; 'frontend-tests.errors-test
|
||||
;; 'frontend-tests.fonts-test
|
||||
;; 'frontend-tests.helpers-shapes-test
|
||||
;; 'frontend-tests.logic.comp-remove-swap-slots-test
|
||||
;; 'frontend-tests.logic.components-and-tokens
|
||||
;; 'frontend-tests.logic.copying-and-duplicating-test
|
||||
;; 'frontend-tests.logic.frame-guides-test
|
||||
;; 'frontend-tests.logic.groups-test
|
||||
;; 'frontend-tests.logic.nudge-selected-shapes-test
|
||||
;; 'frontend-tests.logic.path-actions-test
|
||||
;; 'frontend-tests.logic.path-clipboard-test
|
||||
;; 'frontend-tests.logic.path-helpers-test
|
||||
;; 'frontend-tests.logic.path-lifecycle-test
|
||||
;; 'frontend-tests.logic.path-tools-test
|
||||
;; 'frontend-tests.logic.pasting-in-containers-test
|
||||
;; 'frontend-tests.main-errors-test
|
||||
;; 'frontend-tests.logic.sidebar-transform-coalescing-test
|
||||
;; 'frontend-tests.logic.update-position-test
|
||||
;; 'frontend-tests.logic.wasm-modifiers-nil-id-test
|
||||
;; 'frontend-tests.plugins.comments-test
|
||||
;; 'frontend-tests.plugins.context-shapes-test
|
||||
;; 'frontend-tests.plugins.file-test
|
||||
;; 'frontend-tests.plugins.format-test
|
||||
;; 'frontend-tests.plugins.grid-test
|
||||
;; 'frontend-tests.plugins.interactions-test
|
||||
;; 'frontend-tests.plugins.library-test
|
||||
;; 'frontend-tests.plugins.local-storage-test
|
||||
;; 'frontend-tests.plugins.page-active-validation-test
|
||||
;; 'frontend-tests.plugins.page-test
|
||||
;; 'frontend-tests.plugins.parser-test
|
||||
;; 'frontend-tests.plugins.shape-bugfixes-test
|
||||
;; 'frontend-tests.plugins.text-test
|
||||
;; 'frontend-tests.plugins.tokens-test
|
||||
;; 'frontend-tests.plugins.utils-test
|
||||
;; 'frontend-tests.plugins.value-objects-test
|
||||
;; 'frontend-tests.render-wasm.process-objects-test
|
||||
;; 'frontend-tests.render-wasm.text-editor-apply-styles-test
|
||||
;; 'frontend-tests.render-wasm.text-editor-caret-color-test
|
||||
;; 'frontend-tests.svg-fills-test
|
||||
;; 'frontend-tests.tokens.copy-paste-props-test
|
||||
;; 'frontend-tests.tokens.import-export-test
|
||||
;; 'frontend-tests.tokens.logic.token-actions-test
|
||||
;; 'frontend-tests.tokens.logic.token-data-test
|
||||
'frontend-tests.tokens.logic.token-libraries-test
|
||||
;; 'frontend-tests.tokens.logic.token-remapping-test
|
||||
;; 'frontend-tests.tokens.style-dictionary-test
|
||||
;; 'frontend-tests.tokens.token-errors-test
|
||||
;; 'frontend-tests.tokens.logic.tokens-status-test
|
||||
;; 'frontend-tests.tokens.workspace-tokens-remap-test
|
||||
;; 'frontend-tests.ui.check-updates-test
|
||||
;; 'frontend-tests.ui.colorpicker-token-set-order-test
|
||||
;; 'frontend-tests.ui.comments-clustering-test
|
||||
;; 'frontend-tests.ui.comments-position-modifier-test
|
||||
;; 'frontend-tests.ui.ds-controls-numeric-input-test
|
||||
;; 'frontend-tests.ui.gradient-handlers-test
|
||||
;; 'frontend-tests.ui.layout-container-multiple-test
|
||||
;; 'frontend-tests.ui.measures-menu-props-test
|
||||
;; 'frontend-tests.ui.routes-test
|
||||
;; 'frontend-tests.render-dimensions-test
|
||||
;; 'frontend-tests.text-editor-paste-guard-test
|
||||
;; 'frontend-tests.ui.settings-password-schema-test
|
||||
;; 'frontend-tests.ui.settings-shortcuts-test
|
||||
;; 'frontend-tests.util-clipboard-test
|
||||
;; 'frontend-tests.util-object-test
|
||||
;; 'frontend-tests.util-range-tree-test
|
||||
;; 'frontend-tests.util-simple-math-test
|
||||
;; 'frontend-tests.util-text-editor-test
|
||||
;; 'frontend-tests.util-webapi-test
|
||||
;; 'frontend-tests.util.dom.dnd-test
|
||||
;; 'frontend-tests.util-zip-test
|
||||
;; 'frontend-tests.worker-snap-test
|
||||
])
|
||||
|
||||
(assert (every? find-ns-obj test-namespaces)
|
||||
"test-namespaces contains a namespace that isn't required in runner.cljs")
|
||||
|
||||
@@ -6,49 +6,51 @@
|
||||
[app.common.test-helpers.shapes :as ths]
|
||||
[app.common.test-helpers.tokens :as tht]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.main.ui.workspace.tokens.management.context-menu :as wtcm]
|
||||
[clojure.test :as t]))
|
||||
|
||||
(defn setup-file []
|
||||
(-> (thf/sample-file :file-1)
|
||||
(tht/add-tokens-lib)
|
||||
(tht/update-tokens-lib #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :name "test-token-set"))
|
||||
(ctob/add-theme (ctob/make-token-theme :name "test-theme"
|
||||
:sets #{"test-token-set"}))
|
||||
(ctob/set-active-themes #{"/test-theme"})
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-radius"
|
||||
:type :border-radius
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-color"
|
||||
:type :color
|
||||
:value "red"))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-spacing"
|
||||
:type :spacing
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-sizing"
|
||||
:type :sizing
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-rotation"
|
||||
:type :rotation
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-opacity"
|
||||
:type :opacity
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-dimensions"
|
||||
:type :dimensions
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-number"
|
||||
:type :number
|
||||
:value 10))))
|
||||
(-> (tht/sample-file-with-tokens
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :test-token-set)
|
||||
:name "test-token-set"))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :test-theme)
|
||||
:name "test-theme"
|
||||
:sets #{"test-token-set"}))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-radius"
|
||||
:type :border-radius
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-color"
|
||||
:type :color
|
||||
:value "red"))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-spacing"
|
||||
:type :spacing
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-sizing"
|
||||
:type :sizing
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-rotation"
|
||||
:type :rotation
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-opacity"
|
||||
:type :opacity
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-dimensions"
|
||||
:type :dimensions
|
||||
:value 10))
|
||||
(ctob/add-token (thi/id :test-token-set)
|
||||
(ctob/make-token :name "token-number"
|
||||
:type :number
|
||||
:value 10)))
|
||||
:status-fn #(ctos/set-tokens-status % #{(thi/id :test-theme)} #{(thi/id :test-token-set)}))
|
||||
;; app.main.data.workspace.tokens.application/generic-attributes
|
||||
(tho/add-group :group1)
|
||||
;; app.main.data.workspace.tokens.application/rect-attributes
|
||||
|
||||
@@ -6,9 +6,12 @@
|
||||
|
||||
(ns frontend-tests.tokens.helpers.state
|
||||
(:require
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.main.data.changes :as dch]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.style-dictionary :as sd]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
@@ -29,11 +32,13 @@
|
||||
(ptk/reify ::end+
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [data (dsh/lookup-file-data state)]
|
||||
(->> (get data :tokens-lib)
|
||||
(ctob/get-tokens-in-active-sets)
|
||||
(sd/resolve-tokens)
|
||||
(rx/mapcat #(rx/of (end))))))))
|
||||
(let [tokens-status (dsh/lookup-tokens-status state)
|
||||
tokens-lib (dsh/lookup-tokens-lib state)]
|
||||
(if (and tokens-status tokens-lib)
|
||||
(->> (cfo/get-tokens-in-active-sets tokens-status tokens-lib)
|
||||
(sd/resolve-tokens)
|
||||
(rx/mapcat #(rx/of (end))))
|
||||
(rx/of (end)))))))
|
||||
|
||||
(defn stop-on
|
||||
"Helper function to be used with async version of run-store.
|
||||
@@ -51,6 +56,31 @@
|
||||
"Stops on `send-update-indices` function being called, which should be the last function of an event chain."
|
||||
(stop-on ::end))
|
||||
|
||||
(defn watch-undo-stack
|
||||
"Maintain the workspace undo stack by watching for commit events.
|
||||
Must be emitted before the events under test so undo entries are populated."
|
||||
[]
|
||||
(ptk/reify ::watch-undo-stack
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ stream]
|
||||
(let [stopper-s (->> stream (rx/filter (ptk/type? ::watch-undo-stack)))]
|
||||
(->> stream
|
||||
(rx/filter dch/commit?)
|
||||
(rx/map deref)
|
||||
(rx/filter #(= :local (:source %)))
|
||||
(rx/mapcat
|
||||
(fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo? selected-before]}]
|
||||
(if (and save-undo? (seq undo-changes))
|
||||
(rx/of (dwu/append-undo
|
||||
{:undo-changes undo-changes
|
||||
:redo-changes redo-changes
|
||||
:undo-group undo-group
|
||||
:tags tags
|
||||
:selected-before selected-before}
|
||||
stack-undo?))
|
||||
(rx/empty))))
|
||||
(rx/take-until stopper-s))))))
|
||||
|
||||
;; Support for async events in tests
|
||||
;; https://chat.kaleidos.net/penpot-partners/pl/tz1yoes3w3fr9qanxqpuhoz3ch
|
||||
(defn run-store
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
[app.common.types.tokens-lib :as ctob]))
|
||||
|
||||
(defn get-token [file name]
|
||||
(some-> (get-in file [:data :tokens-lib])
|
||||
(ctob/get-tokens-in-active-sets)
|
||||
(get name)))
|
||||
(let [data (get-in file [:data])
|
||||
tokens-status (cfo/get-tokens-status data)
|
||||
tokens-lib (cfo/get-tokens-lib data)]
|
||||
(some-> (cfo/get-tokens-in-active-sets tokens-status tokens-lib)
|
||||
(get name))))
|
||||
|
||||
(defn apply-token-to-shape
|
||||
[file shape-label token-label attributes]
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
[app.common.test-helpers.files :as cthf]
|
||||
[app.common.test-helpers.ids-map :as cthi]
|
||||
[app.common.test-helpers.shapes :as cths]
|
||||
[app.common.test-helpers.tokens :as ctht]
|
||||
[app.common.types.text :as txt]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.main.data.workspace.tokens.application :as dwta]
|
||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||
[app.main.data.workspace.wasm-text :as dwwt]
|
||||
@@ -44,21 +46,22 @@
|
||||
|
||||
(defn setup-file-with-tokens
|
||||
[& {:keys [rect-1 rect-2 rect-3]}]
|
||||
(-> (setup-file)
|
||||
(ctho/add-rect :rect-1 rect-1)
|
||||
(ctho/add-rect :rect-2 rect-2)
|
||||
(ctho/add-rect :rect-3 rect-3)
|
||||
(ctho/add-text :text-1 "Hello World!")
|
||||
(assoc-in [:data :tokens-lib]
|
||||
(-> (ctob/make-tokens-lib)
|
||||
(ctob/add-theme (ctob/make-token-theme :name "Theme A" :sets #{"Set A"}))
|
||||
(ctob/set-active-themes #{"/Theme A"})
|
||||
(-> (ctht/sample-file-with-tokens
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-a)
|
||||
:name "Set A"))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (cthi/new-id! :theme-a)
|
||||
:name "Theme A"
|
||||
:sets #{"Set A"}))
|
||||
(ctob/add-token (cthi/id :set-a)
|
||||
(ctob/make-token border-radius-token))
|
||||
(ctob/add-token (cthi/id :set-a)
|
||||
(ctob/make-token reference-border-radius-token))))))
|
||||
(ctob/make-token reference-border-radius-token)))
|
||||
:status-fn #(ctos/set-tokens-status % #{(cthi/id :theme-a)} #{(cthi/id :set-a)}))
|
||||
(ctho/add-rect :rect-1 rect-1)
|
||||
(ctho/add-rect :rect-2 rect-2)
|
||||
(ctho/add-rect :rect-3 rect-3)
|
||||
(ctho/add-text :text-1 "Hello World!")))
|
||||
|
||||
(def debounce-text-stop
|
||||
(tohs/stop-on ::dwwt/resize-wasm-text-debounce-commit))
|
||||
@@ -83,15 +86,16 @@
|
||||
done
|
||||
(let [file (setup-file-with-empty-lib)
|
||||
store (ths/setup-store file)
|
||||
set (ctob/make-token-set :name "primitives")
|
||||
set (ctob/make-token-set :id (cthi/new-id! :set1) :name "primitives")
|
||||
events [(dwtl/create-token-set set)]]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
lib (get-in file' [:data :tokens-lib])]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
lib (ctht/get-tokens-lib file')
|
||||
status (ctht/get-tokens-status file')]
|
||||
(t/is (some? (ctob/get-set lib (ctob/get-id set))))
|
||||
(t/is (false? (ctob/token-set-active? lib "primitives"))))))))))
|
||||
(t/is (false? (ctos/set-active? status (cthi/id :set1)))))))))))
|
||||
|
||||
(t/deftest test-create-then-enable-token-set
|
||||
(t/testing "create followed by set-enabled (as the plugin addSet does) yields an active set"
|
||||
@@ -99,16 +103,17 @@
|
||||
done
|
||||
(let [file (setup-file-with-empty-lib)
|
||||
store (ths/setup-store file)
|
||||
set (ctob/make-token-set :name "primitives")
|
||||
set (ctob/make-token-set :id (cthi/new-id! :set1) :name "primitives")
|
||||
events [(dwtl/create-token-set set)
|
||||
(dwtl/set-enabled-token-set "primitives" true)]]
|
||||
(dwtl/set-enabled-token-set (cthi/id :set1) true)]]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
lib (get-in file' [:data :tokens-lib])]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
lib (ctht/get-tokens-lib file')
|
||||
status (ctht/get-tokens-status file')]
|
||||
(t/is (some? (ctob/get-set lib (ctob/get-id set))))
|
||||
(t/is (true? (ctob/token-set-active? lib "primitives"))))))))))
|
||||
(t/is (true? (ctos/set-active? status (cthi/id :set1)))))))))))
|
||||
|
||||
(t/deftest test-apply-token
|
||||
(t/testing "applies token to shape and updates shape attributes to resolved value"
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
(:require
|
||||
[app.common.test-helpers.files :as cthf]
|
||||
[app.common.test-helpers.ids-map :as cthi]
|
||||
[app.common.test-helpers.tokens :as ctho]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[cljs.test :as t :include-macros true]
|
||||
[frontend-tests.helpers.pages :as thp]
|
||||
[frontend-tests.helpers.state :as ths]
|
||||
@@ -25,11 +28,40 @@
|
||||
|
||||
(defn setup-file-with-token-lib
|
||||
[]
|
||||
(-> (setup-file)
|
||||
(assoc-in [:data :tokens-lib]
|
||||
(-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :test-token-set)
|
||||
:name "Set A"))))))
|
||||
(ctho/sample-file-with-tokens
|
||||
:file-id :file-1
|
||||
:page-label :page-1
|
||||
:lib-fn #(ctob/add-set % (ctob/make-token-set :id (cthi/new-id! :test-token-set)
|
||||
:name "Set A"))
|
||||
:status-fn #(ctos/set-tokens-status % #{} #{(cthi/id :test-token-set)})))
|
||||
|
||||
(defn setup-file-with-token-lib-and-theme
|
||||
[theme-id]
|
||||
(ctho/sample-file-with-tokens
|
||||
:file-id :file-1
|
||||
:page-label :page-1
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :test-token-set)
|
||||
:name "Set A"))
|
||||
(ctob/add-theme (ctob/make-token-theme :id theme-id
|
||||
:name "Theme A"
|
||||
:group "default")))
|
||||
:status-fn #(ctos/set-tokens-status % #{theme-id} #{(cthi/id :test-token-set)})))
|
||||
|
||||
(defn setup-file-with-token-lib-and-token
|
||||
[]
|
||||
(ctho/sample-file-with-tokens
|
||||
:file-id :file-1
|
||||
:page-label :page-1
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :test-token-set)
|
||||
:name "Set A"))
|
||||
(ctob/add-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id (cthi/new-id! :color.primary)
|
||||
:name "color.primary"
|
||||
:type :color
|
||||
:value "#000000")))
|
||||
:status-fn #(ctos/set-tokens-status % #{} #{(cthi/id :test-token-set)})))
|
||||
|
||||
(t/deftest add-set
|
||||
(t/async
|
||||
@@ -50,6 +82,20 @@
|
||||
(t/is (= (count sets') 2))
|
||||
(t/is (some? set-b')))))))))
|
||||
|
||||
(t/deftest add-set-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/create-token-set (ctob/make-token-set :name "Set A"))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest rename-set
|
||||
(t/async
|
||||
done
|
||||
@@ -71,6 +117,21 @@
|
||||
(t/is (= (count sets') 1))
|
||||
(t/is (some? set-a')))))))))
|
||||
|
||||
(t/deftest rename-set-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
set-a (ctob/make-token-set :name "Set A")
|
||||
events [(dwtl/rename-token-set set-a "Set A updated")]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest duplicate-set
|
||||
(t/async
|
||||
done
|
||||
@@ -103,21 +164,734 @@
|
||||
sets (ctob/get-sets token-lib)]
|
||||
|
||||
(t/testing "Token lib contains one set"
|
||||
(t/is (= (count sets) 1))))))))
|
||||
(t/is (= (count sets) 1)))))))))
|
||||
|
||||
(t/deftest delete-set
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file-with-token-lib)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/delete-token-set (cthi/id :test-token-set))]]
|
||||
(t/deftest duplicate-set-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/duplicate-token-set (uuid/next))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')
|
||||
sets' (ctob/get-sets tokens-lib')]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/testing "Set has been deleted"
|
||||
(t/is (= (count sets') 0))))))))))
|
||||
(t/deftest delete-set
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file-with-token-lib)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/delete-token-set (cthi/id :test-token-set))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')
|
||||
sets' (ctob/get-sets tokens-lib')]
|
||||
|
||||
(t/testing "Set has been deleted"
|
||||
(t/is (= (count sets') 0)))))))))
|
||||
|
||||
(t/deftest delete-set-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/delete-token-set (uuid/next))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest set-tokens-source
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file-with-token-lib)
|
||||
store (ths/setup-store file)
|
||||
library-id (uuid/next)]
|
||||
|
||||
;; Phase 1: set tokens-source with undo watcher active
|
||||
(tohs/run-store
|
||||
store identity
|
||||
[(tohs/watch-undo-stack)
|
||||
(dwtl/set-tokens-source library-id)]
|
||||
(fn [new-state]
|
||||
(let [file-data' (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "tokens-source is set to the library id"
|
||||
(t/is (= library-id (:tokens-source file-data'))))))
|
||||
(tohs/stop-on ::dwtl/set-tokens-source))
|
||||
|
||||
;; Phase 2: undo and verify restoration
|
||||
(tohs/run-store
|
||||
store done
|
||||
[dwu/undo]
|
||||
(fn [undone-state]
|
||||
(let [file-data'' (-> (ths/get-file-from-state undone-state) :data)]
|
||||
(t/testing "tokens-source is restored to nil"
|
||||
(t/is (nil? (:tokens-source file-data''))))))
|
||||
(tohs/stop-on ::dwu/undo)))))
|
||||
|
||||
(t/deftest set-tokens-source-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
library-id (uuid/next)]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done
|
||||
[(dwtl/set-tokens-source library-id)]
|
||||
(fn [new-state]
|
||||
(let [file-data' (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "tokens-source is set even without tokens-lib"
|
||||
(t/is (= library-id (:tokens-source file-data'))))))))))
|
||||
|
||||
;; ==========================================================================
|
||||
;; Token Themes
|
||||
;; ==========================================================================
|
||||
|
||||
(t/deftest create-token-theme
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file-with-token-lib)
|
||||
store (ths/setup-store file)
|
||||
theme-id (uuid/next)
|
||||
events [(dwtl/create-token-theme (ctob/make-token-theme :id theme-id
|
||||
:name "Theme B"
|
||||
:group "default"))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')
|
||||
theme' (ctob/get-theme tokens-lib' theme-id)]
|
||||
|
||||
(t/testing "Theme has been created"
|
||||
(t/is (some? theme'))
|
||||
(t/is (= "Theme B" (:name theme'))))))))))
|
||||
|
||||
(t/deftest create-token-theme-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
theme-id (uuid/next)
|
||||
events [(dwtl/create-token-theme (ctob/make-token-theme :id theme-id
|
||||
:name "Theme A"
|
||||
:group "default"))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest update-token-theme
|
||||
(t/async
|
||||
done
|
||||
(let [theme-id (uuid/next)
|
||||
file (setup-file-with-token-lib-and-theme theme-id)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/update-token-theme theme-id
|
||||
(ctob/make-token-theme :id theme-id
|
||||
:name "Theme A renamed"
|
||||
:group "default"))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')
|
||||
theme' (ctob/get-theme tokens-lib' theme-id)]
|
||||
|
||||
(t/testing "Theme has been renamed"
|
||||
(t/is (= "Theme A renamed" (:name theme'))))))))))
|
||||
|
||||
(t/deftest update-token-theme-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
theme-id (uuid/next)
|
||||
events [(dwtl/update-token-theme theme-id
|
||||
(ctob/make-token-theme :id theme-id
|
||||
:name "Theme A"
|
||||
:group "default"))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest set-token-theme-active
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file-with-token-lib)
|
||||
store (ths/setup-store file)
|
||||
theme-id (uuid/next)
|
||||
events [(dwtl/create-token-theme (ctob/make-token-theme :id theme-id
|
||||
:name "Theme B"
|
||||
:group "default"))
|
||||
(dwtl/set-token-theme-active theme-id true)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-status (ctho/get-tokens-status file')]
|
||||
|
||||
(t/testing "Theme has been activated"
|
||||
(t/is (ctos/theme-active? tokens-status theme-id)))))))))
|
||||
|
||||
(t/deftest set-token-theme-active-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
theme-id (uuid/next)
|
||||
events [(dwtl/set-token-theme-active theme-id true)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest toggle-token-theme-active
|
||||
(t/async
|
||||
done
|
||||
(let [theme-id (uuid/next)
|
||||
file (setup-file-with-token-lib-and-theme theme-id)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/toggle-token-theme-active theme-id)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-status (ctho/get-tokens-status file')]
|
||||
|
||||
(t/testing "Theme has been deactivated"
|
||||
(t/is (not (ctos/theme-active? tokens-status theme-id))))))))))
|
||||
|
||||
(t/deftest toggle-token-theme-active-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
theme-id (uuid/next)
|
||||
events [(dwtl/toggle-token-theme-active theme-id)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest delete-token-theme
|
||||
(t/async
|
||||
done
|
||||
(let [theme-id (uuid/next)
|
||||
file (setup-file-with-token-lib-and-theme theme-id)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/delete-token-theme theme-id)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')
|
||||
theme' (ctob/get-theme tokens-lib' theme-id)]
|
||||
|
||||
(t/testing "Theme has been deleted"
|
||||
(t/is (nil? theme')))))))))
|
||||
|
||||
(t/deftest delete-token-theme-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
theme-id (uuid/next)
|
||||
events [(dwtl/delete-token-theme theme-id)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
;; ==========================================================================
|
||||
;; Token Set Operations
|
||||
;; ==========================================================================
|
||||
|
||||
(t/deftest set-enabled-token-set
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file-with-token-lib)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/set-enabled-token-set (cthi/id :test-token-set) true)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-status (ctho/get-tokens-status file')]
|
||||
|
||||
(t/testing "Set has been enabled"
|
||||
(t/is (ctos/set-active? tokens-status (cthi/id :test-token-set))))))))))
|
||||
|
||||
(t/deftest set-enabled-token-set-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/set-enabled-token-set (uuid/next) true)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest toggle-token-set
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file-with-token-lib)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/toggle-token-set (cthi/id :test-token-set))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-status (ctho/get-tokens-status file')]
|
||||
|
||||
(t/testing "Set has been toggled (deactivated)"
|
||||
(t/is (not (ctos/set-active? tokens-status (cthi/id :test-token-set)))))))))))
|
||||
|
||||
(t/deftest toggle-token-set-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/toggle-token-set (uuid/next))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest toggle-token-set-group
|
||||
(t/async
|
||||
done
|
||||
(let [file (ctho/sample-file-with-tokens
|
||||
:file-id :file-1
|
||||
:page-label :page-1
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-a)
|
||||
:name "group/set-a"))
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-b)
|
||||
:name "group/set-b")))
|
||||
:status-fn #(ctos/set-tokens-status % #{} #{}))
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/toggle-token-set-group ["group"])]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-status (ctho/get-tokens-status file')]
|
||||
|
||||
(t/testing "Set group has been toggled (activated)"
|
||||
(t/is (ctos/set-active? tokens-status (cthi/id :set-a)))
|
||||
(t/is (ctos/set-active? tokens-status (cthi/id :set-b))))))))))
|
||||
|
||||
(t/deftest toggle-token-set-group-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/toggle-token-set-group ["group"])]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest delete-token-set-group
|
||||
(t/async
|
||||
done
|
||||
(let [file (ctho/sample-file-with-tokens
|
||||
:file-id :file-1
|
||||
:page-label :page-1
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-a)
|
||||
:name "group/set-a"))
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-b)
|
||||
:name "group/set-b"))
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-c)
|
||||
:name "other/set-c"))))
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/delete-token-set-group ["group"])]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')]
|
||||
|
||||
(t/testing "Group sets deleted, other set remains"
|
||||
(t/is (nil? (ctob/get-set-by-name tokens-lib' "group/set-a")))
|
||||
(t/is (nil? (ctob/get-set-by-name tokens-lib' "group/set-b")))
|
||||
(t/is (some? (ctob/get-set-by-name tokens-lib' "other/set-c"))))))))))
|
||||
|
||||
(t/deftest delete-token-set-group-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/delete-token-set-group ["group"])]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest rename-token-set-group
|
||||
(t/async
|
||||
done
|
||||
(let [file (ctho/sample-file-with-tokens
|
||||
:file-id :file-1
|
||||
:page-label :page-1
|
||||
:lib-fn #(ctob/add-set % (ctob/make-token-set :id (cthi/new-id! :set-a)
|
||||
:name "old-group/set-a")))
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/rename-token-set-group ["old-group"] "new-group")]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')]
|
||||
|
||||
(t/testing "Set group has been renamed"
|
||||
(t/is (some? (ctob/get-set-by-name tokens-lib' "new-group/set-a")))
|
||||
(t/is (nil? (ctob/get-set-by-name tokens-lib' "old-group/set-a"))))))))))
|
||||
|
||||
(t/deftest rename-token-set-group-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/rename-token-set-group ["old-group"] "new-group")]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
;; ==========================================================================
|
||||
;; Drop Operations
|
||||
;; ==========================================================================
|
||||
|
||||
(t/deftest drop-token-set-group
|
||||
(t/async
|
||||
done
|
||||
(let [file (ctho/sample-file-with-tokens
|
||||
:file-id :file-1
|
||||
:page-label :page-1
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-a)
|
||||
:name "foo/foo"))
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-b)
|
||||
:name "bar/bar"))
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-c)
|
||||
:name "baz/baz"))))
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/drop-token-set-group {:from-index 2
|
||||
:to-index 0
|
||||
:position :top})]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')
|
||||
sets' (ctob/get-set-names tokens-lib')]
|
||||
|
||||
(t/testing "Set groups have been reordered"
|
||||
(t/is (= ["bar/bar" "foo/foo" "baz/baz"] (vec sets'))))))))))
|
||||
|
||||
(t/deftest drop-token-set-group-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/drop-token-set-group {:from-index 0
|
||||
:to-index 1
|
||||
:position :top})]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest drop-token-set
|
||||
(t/async
|
||||
done
|
||||
(let [file (ctho/sample-file-with-tokens
|
||||
:file-id :file-1
|
||||
:page-label :page-1
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-a)
|
||||
:name "foo"))
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-b)
|
||||
:name "bar"))
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-c)
|
||||
:name "baz"))))
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/drop-token-set {:from-index 0
|
||||
:to-index 2
|
||||
:position :bot})]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')
|
||||
sets' (ctob/get-set-names tokens-lib')]
|
||||
|
||||
(t/testing "Token sets have been reordered"
|
||||
(t/is (= ["bar" "baz" "foo"] (vec sets'))))))))))
|
||||
|
||||
(t/deftest drop-token-set-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/drop-token-set {:from-index 0
|
||||
:to-index 1
|
||||
:position :top})]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
;; ==========================================================================
|
||||
;; Token CRUD
|
||||
;; ==========================================================================
|
||||
|
||||
(t/deftest create-token-in-set
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file-with-token-lib)
|
||||
store (ths/setup-store file)
|
||||
token-id (cthi/new-id! :color.primary)
|
||||
events [(dwtl/create-token (cthi/id :test-token-set)
|
||||
(ctob/make-token :id token-id
|
||||
:name "color.primary"
|
||||
:type :color
|
||||
:value "#000000"))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')
|
||||
token (ctob/get-token tokens-lib' (cthi/id :test-token-set)
|
||||
(cthi/id :color.primary))]
|
||||
|
||||
(t/testing "Token has been created in set"
|
||||
(t/is (some? token)))))))))
|
||||
|
||||
(t/deftest create-token-no-set
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
token-id (cthi/new-id! :color.primary)
|
||||
events [(dwtl/create-token (ctob/make-token :id token-id
|
||||
:name "color.primary"
|
||||
:type :color
|
||||
:value "#000000"))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')]
|
||||
|
||||
(t/testing "Global set has been created with the token"
|
||||
(t/is (some? tokens-lib'))
|
||||
(t/is (some? (ctob/get-set-by-name tokens-lib' "Global"))))))))))
|
||||
|
||||
(t/deftest update-token
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file-with-token-lib-and-token)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/update-token (cthi/id :test-token-set)
|
||||
(cthi/id :color.primary)
|
||||
{:value "#ffffff"
|
||||
:name "color.primary.updated"})]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')
|
||||
token' (ctob/get-token tokens-lib' (cthi/id :test-token-set)
|
||||
(cthi/id :color.primary))]
|
||||
|
||||
(t/testing "Token has been updated"
|
||||
(t/is (= "color.primary.updated" (:name token')))
|
||||
(t/is (= "#ffffff" (:value token'))))))))))
|
||||
|
||||
(t/deftest update-token-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/update-token (uuid/next) (uuid/next) {:value "#ffffff"})]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest delete-token
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file-with-token-lib-and-token)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/delete-token (cthi/id :test-token-set)
|
||||
(cthi/id :color.primary))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')
|
||||
token' (ctob/get-token tokens-lib' (cthi/id :test-token-set)
|
||||
(cthi/id :color.primary))]
|
||||
|
||||
(t/testing "Token has been deleted"
|
||||
(t/is (nil? token')))))))))
|
||||
|
||||
(t/deftest delete-token-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/delete-token (uuid/next) (uuid/next))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
(t/deftest duplicate-token
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file-with-token-lib-and-token)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/set-selected-token-set-id (cthi/id :test-token-set))
|
||||
(dwtl/duplicate-token (cthi/id :color.primary))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')
|
||||
tokens (ctob/get-tokens tokens-lib' (cthi/id :test-token-set))]
|
||||
|
||||
(t/testing "Token has been duplicated"
|
||||
(t/is (= 2 (count tokens))))))))))
|
||||
|
||||
(t/deftest duplicate-token-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
events [(dwtl/duplicate-token (uuid/next))]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file-data (-> (ths/get-file-from-state new-state) :data)]
|
||||
(t/testing "No crash when file has no tokens-lib"
|
||||
(t/is (some? file-data)))))))))
|
||||
|
||||
;; ==========================================================================
|
||||
;; Import Tokens Lib
|
||||
;; ==========================================================================
|
||||
|
||||
(t/deftest import-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
new-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "Imported Set")))
|
||||
events [(dwtl/import-tokens-lib new-lib)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')]
|
||||
|
||||
(t/testing "Tokens lib has been imported"
|
||||
(t/is (some? tokens-lib'))
|
||||
(t/is (some? (ctob/get-set-by-name tokens-lib' "Imported Set"))))))))))
|
||||
|
||||
(t/deftest import-tokens-lib-no-tokens-lib
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
new-lib (-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :name "Imported Set")))
|
||||
events [(dwtl/import-tokens-lib new-lib)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
tokens-lib' (toht/get-tokens-lib file')]
|
||||
(t/testing "Tokens lib has been imported into file without existing lib"
|
||||
(t/is (some? tokens-lib'))
|
||||
(t/is (some? (ctob/get-set-by-name tokens-lib' "Imported Set"))))))))))
|
||||
@@ -0,0 +1,100 @@
|
||||
;; 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 SUBSIDIARY SL
|
||||
|
||||
(ns frontend-tests.tokens.logic.token-libraries-test
|
||||
(:require
|
||||
[app.common.test-helpers.files :as cthf]
|
||||
[app.common.test-helpers.ids-map :as cthi]
|
||||
[app.common.test-helpers.shapes :as cths]
|
||||
[app.common.test-helpers.tokens :as ctht]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.main.data.workspace.tokens.application :as dwta]
|
||||
[cljs.test :as t :include-macros true]
|
||||
[frontend-tests.helpers.pages :as thp]
|
||||
[frontend-tests.helpers.state :as ths]
|
||||
[frontend-tests.helpers.wasm :as thw]
|
||||
[frontend-tests.tokens.helpers.state :as tohs]
|
||||
[frontend-tests.tokens.helpers.tokens :as toht]))
|
||||
|
||||
(t/use-fixtures :each
|
||||
{:before (fn []
|
||||
(thp/reset-idmap!)
|
||||
(thw/setup-wasm-mocks!))
|
||||
:after thw/teardown-wasm-mocks!})
|
||||
|
||||
(defn setup-file []
|
||||
(-> (cthf/sample-file :file-1 :page-label :page-1)
|
||||
(cths/add-sample-shape :rect-1
|
||||
:type :rect
|
||||
:r1 0 :r2 0 :r3 0 :r4 0)))
|
||||
|
||||
(defn setup-file-with-tokens
|
||||
[]
|
||||
(-> (ctht/sample-file-with-tokens
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-a)
|
||||
:name "Set A"))
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-b)
|
||||
:name "Set B"))
|
||||
(ctob/add-token (cthi/id :set-a)
|
||||
(ctob/make-token {:name "borderRadius.sm"
|
||||
:value "12"
|
||||
:type :border-radius}))
|
||||
(ctob/add-token (cthi/id :set-b)
|
||||
(ctob/make-token {:name "borderRadius.sm"
|
||||
:value "24"
|
||||
:type :border-radius})))
|
||||
:status-fn #(ctos/set-tokens-status % #{} #{(cthi/id :set-a)}))))
|
||||
|
||||
(t/deftest test-apply-token-from-lib
|
||||
(t/testing "applies token from library to local shape updates shape attributes to resolved value"
|
||||
(t/async
|
||||
done
|
||||
(let [library (setup-file-with-tokens)
|
||||
file (setup-file)
|
||||
store (ths/setup-store file {:libraries [library]
|
||||
:tokens-source-library library})
|
||||
rect-1 (cths/get-shape file :rect-1)
|
||||
token (toht/get-token library "borderRadius.sm")
|
||||
events [(dwta/apply-token {:shape-ids [(:id rect-1)]
|
||||
:attributes #{:r1 :r2 :r3 :r4}
|
||||
:token token
|
||||
:on-update-shape dwta/update-shape-radius})]]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
rect-1' (cths/get-shape file' :rect-1)]
|
||||
|
||||
(t/testing "shape `:applied-tokens` got updated"
|
||||
(t/is (some? (:applied-tokens rect-1')))
|
||||
(t/is (= (:r1 (:applied-tokens rect-1')) (:name token))))
|
||||
|
||||
(t/testing "shape radius got update to the resolved token value."
|
||||
(t/is (= (:r1 rect-1') 12)))))))))
|
||||
|
||||
(t/testing "applies token using active set-b when the file's active token set changes"
|
||||
(t/async
|
||||
done
|
||||
(let [library (setup-file-with-tokens)
|
||||
file (-> (setup-file)
|
||||
(ctht/set-tokens-source library)
|
||||
(ctht/update-tokens-status #(ctos/set-tokens-status % #{} #{(cthi/id :set-b)})))
|
||||
store (ths/setup-store file {:libraries [library]})
|
||||
rect-1 (cths/get-shape file :rect-1)
|
||||
token (toht/get-token library "borderRadius.sm")
|
||||
events [(dwta/apply-token {:shape-ids [(:id rect-1)]
|
||||
:attributes #{:r1 :r2 :r3 :r4}
|
||||
:token token
|
||||
:on-update-shape dwta/update-shape-radius})]]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
rect-1' (cths/get-shape file' :rect-1)]
|
||||
(t/testing "shape radius uses the value from the active set-b"
|
||||
(t/is (= (:r1 rect-1') 24))))))))))
|
||||
@@ -13,6 +13,7 @@
|
||||
[app.common.test-helpers.tokens :as ctht]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.main.data.workspace.tokens.remapping :as dwtr]
|
||||
[cljs.test :as t :include-macros true]))
|
||||
|
||||
@@ -27,19 +28,20 @@
|
||||
:name "color.secondary"
|
||||
:value "{color.primary}"
|
||||
:type :color}]
|
||||
(-> (cthf/sample-file :file-1 :page-label :page-1)
|
||||
(ctho/add-rect :rect-1)
|
||||
(ctho/add-rect :rect-2)
|
||||
(assoc-in [:data :tokens-lib]
|
||||
(-> (ctob/make-tokens-lib)
|
||||
(ctob/add-theme (ctob/make-token-theme :name "Theme A" :sets #{"Set A"}))
|
||||
(ctob/set-active-themes #{"/Theme A"})
|
||||
(-> (ctht/sample-file-with-tokens
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-a)
|
||||
:name "Set A"))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (cthi/new-id! :theme-a)
|
||||
:name "Theme A"
|
||||
:sets #{"Set A"}))
|
||||
(ctob/add-token (cthi/id :set-a)
|
||||
(ctob/make-token color-token))
|
||||
(ctob/add-token (cthi/id :set-a)
|
||||
(ctob/make-token alias-token))))
|
||||
(ctob/make-token alias-token)))
|
||||
:status-fn #(ctos/set-tokens-status % #{(cthi/id :theme-a)} #{(cthi/id :set-a)}))
|
||||
(ctho/add-rect :rect-1)
|
||||
(ctho/add-rect :rect-2)
|
||||
;; Apply the token to rect-1
|
||||
(ctht/apply-token-to-shape :rect-1 "color.primary" [:fill] [:fill] "#FF0000"))))
|
||||
|
||||
@@ -132,22 +134,23 @@
|
||||
:name "color.secondary"
|
||||
:value "#00FF00"
|
||||
:type :color}]
|
||||
(-> (cthf/sample-file :file-1 :page-label :page-1)
|
||||
(-> (ctht/sample-file-with-tokens
|
||||
:lib-fn #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-a)
|
||||
:name "Set A"))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (cthi/new-id! :theme-a)
|
||||
:name "Theme A"
|
||||
:sets #{"Set A"}))
|
||||
(ctob/add-token (cthi/id :set-a)
|
||||
(ctob/make-token color-primary))
|
||||
(ctob/add-token (cthi/id :set-a)
|
||||
(ctob/make-token color-secondary)))
|
||||
:status-fn #(ctos/set-tokens-status % #{(cthi/id :theme-a)} #{(cthi/id :set-a)}))
|
||||
(ctho/add-simple-component-with-copy :component1
|
||||
:main-root
|
||||
:main-child
|
||||
:copy-root
|
||||
:copy-root-params {:children-labels [:copy-child]})
|
||||
(assoc-in [:data :tokens-lib]
|
||||
(-> (ctob/make-tokens-lib)
|
||||
(ctob/add-theme (ctob/make-token-theme :name "Theme A" :sets #{"Set A"}))
|
||||
(ctob/set-active-themes #{"/Theme A"})
|
||||
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-a)
|
||||
:name "Set A"))
|
||||
(ctob/add-token (cthi/id :set-a)
|
||||
(ctob/make-token color-primary))
|
||||
(ctob/add-token (cthi/id :set-a)
|
||||
(ctob/make-token color-secondary))))
|
||||
(ctht/apply-token-to-shape :main-child "color.primary" [:fill] [:fill] "#FF0000")
|
||||
(ctht/apply-token-to-shape :copy-child "color.primary" [:fill] [:fill] "#FF0000"))))
|
||||
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
(ns frontend-tests.tokens.logic.tokens-status-test
|
||||
(:require
|
||||
[app.common.test-helpers.ids-map :as thi]
|
||||
[app.common.test-helpers.tokens :as tho]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||
[cljs.test :as t :include-macros true]
|
||||
[frontend-tests.helpers.pages :as thp]
|
||||
[frontend-tests.helpers.state :as ths]
|
||||
[frontend-tests.tokens.helpers.state :as tohs]))
|
||||
|
||||
(t/use-fixtures :each
|
||||
{:before thp/reset-idmap!})
|
||||
|
||||
(defn- setup-file
|
||||
"Create a file with several token themes and token sets, some active and
|
||||
some inactive. Returns the file map with :tokens-lib and :tokens-status
|
||||
in its :data."
|
||||
[]
|
||||
(-> (tho/sample-file-with-tokens
|
||||
:lib-fn #(-> %
|
||||
;; Add token sets
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-active)
|
||||
:name "set-active"))
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-inactive)
|
||||
:name "set-inactive"))
|
||||
;; Add themes
|
||||
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-active)
|
||||
:name "theme-active"
|
||||
:group "group-1"
|
||||
:sets #{"set-active"}))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-inactive)
|
||||
:name "theme-inactive"
|
||||
:group "group-1"
|
||||
:sets #{"set-inactive"})))
|
||||
:status-fn #(-> %
|
||||
(ctos/set-tokens-status #{(thi/id :theme-active)}
|
||||
#{(thi/id :set-active)})))))
|
||||
|
||||
(defn- get-tokens-status [file]
|
||||
(get-in file [:data :tokens-status]))
|
||||
|
||||
(t/deftest test-set-token-theme-active-deactivate
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
theme-id (thi/id :theme-active)
|
||||
set-id (thi/id :set-active)
|
||||
events [(dwtl/set-token-theme-active theme-id false)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
status (get-tokens-status file')]
|
||||
(t/is (not (ctos/theme-active? status theme-id))
|
||||
"theme should be inactive after deactivation")
|
||||
(t/is (not (ctos/set-active? status set-id))
|
||||
"set should be inactive when its theme is deactivated")))))))
|
||||
|
||||
(t/deftest test-set-token-theme-active-activate
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
theme-id (thi/id :theme-inactive)
|
||||
set-id (thi/id :set-inactive)
|
||||
events [(dwtl/set-token-theme-active theme-id true)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
status (get-tokens-status file')]
|
||||
(t/is (ctos/theme-active? status theme-id)
|
||||
"theme should be active after activation")
|
||||
(t/is (ctos/set-active? status set-id)
|
||||
"set should be active when its theme is activated")))))))
|
||||
|
||||
(t/deftest test-toggle-token-theme-active-deactivate
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
theme-id (thi/id :theme-active)
|
||||
set-id (thi/id :set-active)
|
||||
events [(dwtl/toggle-token-theme-active theme-id)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
status (get-tokens-status file')]
|
||||
(t/is (not (ctos/theme-active? status theme-id))
|
||||
"active theme should become inactive after toggle")
|
||||
(t/is (not (ctos/set-active? status set-id))
|
||||
"set should be inactive when its theme is toggled off")))))))
|
||||
|
||||
(t/deftest test-toggle-token-theme-active-activate
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
theme-id (thi/id :theme-inactive)
|
||||
set-id (thi/id :set-inactive)
|
||||
events [(dwtl/toggle-token-theme-active theme-id)]]
|
||||
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-state new-state)
|
||||
status (get-tokens-status file')]
|
||||
(t/is (ctos/theme-active? status theme-id)
|
||||
"inactive theme should become active after toggle")
|
||||
(t/is (ctos/set-active? status set-id)
|
||||
"set should be active when its theme is toggled on")))))))
|
||||
@@ -10,8 +10,10 @@
|
||||
[app.common.test-helpers.files :as cthf]
|
||||
[app.common.test-helpers.ids-map :as cthi]
|
||||
[app.common.test-helpers.shapes :as cths]
|
||||
[app.common.test-helpers.tokens :as ctht]
|
||||
[app.common.types.text :as txt]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.types.tokens-status :as ctos]
|
||||
[app.main.data.workspace.tokens.remapping :as remap]
|
||||
[cljs.test :as t :include-macros true]
|
||||
[frontend-tests.helpers.state :as ths]
|
||||
@@ -31,17 +33,22 @@
|
||||
|
||||
(defn- attach-token-set [file tokens]
|
||||
(let [set-id (cthi/new-id! :token-set)
|
||||
tokens-lib (reduce
|
||||
(fn [lib token]
|
||||
(ctob/add-token lib set-id (ctob/make-token token)))
|
||||
(-> (ctob/make-tokens-lib)
|
||||
(ctob/add-set (ctob/make-token-set :id set-id
|
||||
:name token-set-name))
|
||||
(ctob/add-theme (ctob/make-token-theme :name token-theme-name
|
||||
:sets #{token-set-name}))
|
||||
(ctob/set-active-themes #{(str "/" token-theme-name)}))
|
||||
tokens)]
|
||||
(assoc-in file [:data :tokens-lib] tokens-lib)))
|
||||
theme-id (cthi/new-id! :theme)]
|
||||
(-> file
|
||||
(ctht/add-tokens-lib)
|
||||
(ctht/update-tokens-lib
|
||||
#(reduce
|
||||
(fn [lib token]
|
||||
(ctob/add-token lib set-id (ctob/make-token token)))
|
||||
(-> %
|
||||
(ctob/add-set (ctob/make-token-set :id set-id
|
||||
:name token-set-name))
|
||||
(ctob/add-theme (ctob/make-token-theme :id theme-id
|
||||
:name token-theme-name
|
||||
:sets #{token-set-name})))
|
||||
tokens))
|
||||
(ctht/update-tokens-status
|
||||
#(ctos/set-tokens-status % #{theme-id} #{set-id})))))
|
||||
|
||||
(defn- tokens-lib [file]
|
||||
(get-in file [:data :tokens-lib]))
|
||||
|
||||
@@ -7394,14 +7394,22 @@ msgid_plural "workspace.libraries.components"
|
||||
msgstr[0] "1 component"
|
||||
msgstr[1] "%s components"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:367
|
||||
msgid "workspace.libraries.connected-to"
|
||||
msgstr "Connected to"
|
||||
#: src/app/main/ui/workspace/libraries.cljs:541
|
||||
msgid "workspace.libraries.connected-libraries"
|
||||
msgstr "Connected library"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:550
|
||||
msgid "workspace.libraries.connected-through"
|
||||
msgstr "Connected through"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:432
|
||||
msgid "workspace.libraries.empty.add-some"
|
||||
msgstr "Or add some of these to try:"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:600
|
||||
msgid "workspace.libraries.empty.no-connected-libraries"
|
||||
msgstr "No connected libraries yet."
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:426
|
||||
msgid "workspace.libraries.empty.no-libraries"
|
||||
msgstr "There are no Shared Libraries at your team, you can look for"
|
||||
@@ -7414,6 +7422,14 @@ msgstr "some templates in here"
|
||||
msgid "workspace.libraries.file-library"
|
||||
msgstr "File library"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:336
|
||||
msgid "workspace.libraries.tokens-source"
|
||||
msgstr "Tokens source"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:336
|
||||
msgid "workspace.libraries.set-as-tokens-source"
|
||||
msgstr "Set as tokens source"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:100, src/app/main/ui/workspace/libraries.cljs:124
|
||||
msgid "workspace.libraries.graphics"
|
||||
msgid_plural "workspace.libraries.graphics"
|
||||
@@ -7462,6 +7478,10 @@ msgstr "Search shared libraries"
|
||||
msgid "workspace.libraries.shared-libraries"
|
||||
msgstr "SHARED LIBRARIES"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:311
|
||||
msgid "workspace.libraries.shared-library-added"
|
||||
msgstr "Added"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:414
|
||||
msgid "workspace.libraries.shared-library-btn"
|
||||
msgstr "Connect library"
|
||||
@@ -7507,6 +7527,24 @@ msgid_plural "workspace.libraries.typography"
|
||||
msgstr[0] "1 typography"
|
||||
msgstr[1] "%s typographies"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:106, src/app/main/ui/workspace/libraries.cljs:150
|
||||
msgid "workspace.libraries.tokens"
|
||||
msgid_plural "workspace.libraries.tokens"
|
||||
msgstr[0] "1 token"
|
||||
msgstr[1] "%s tokens"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:106, src/app/main/ui/workspace/libraries.cljs:150
|
||||
msgid "workspace.libraries.token-sets"
|
||||
msgid_plural "workspace.libraries.token-sets"
|
||||
msgstr[0] "1 set"
|
||||
msgstr[1] "%s sets"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:106, src/app/main/ui/workspace/libraries.cljs:150
|
||||
msgid "workspace.libraries.token-themes"
|
||||
msgid_plural "workspace.libraries.token-themes"
|
||||
msgstr[0] "1 theme"
|
||||
msgstr[1] "%s themes"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:381
|
||||
msgid "workspace.libraries.unlink-library-btn"
|
||||
msgstr "Disconnect library"
|
||||
@@ -10109,6 +10147,22 @@ msgstr "Use a reference"
|
||||
msgid "workspace.tokens.value-not-valid"
|
||||
msgstr "The value is not valid"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/tokens_source.cljs:24
|
||||
msgid "workspace.tokens.connected-library"
|
||||
msgstr "connected library"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/assets/file_library.cljs:102
|
||||
msgid "workspace.tokens.current-tokens-source-tooltip"
|
||||
msgstr "This is the current Tokens source"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/tokens_source.cljs:25
|
||||
msgid "workspace.tokens.open-connected-library"
|
||||
msgstr "Open connected library"
|
||||
|
||||
#: src/app/main/data/workspace/libraries.cljs:847
|
||||
msgid "workspace.tokens.notifications.source-sets-or-themes-updated"
|
||||
msgstr "Tokens source sets or themes have been modified"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/forms/generic_form.cljs
|
||||
#, unused
|
||||
msgid "workspace.tokens.warning-name-change"
|
||||
|
||||
@@ -7223,10 +7223,22 @@ msgid_plural "workspace.libraries.components"
|
||||
msgstr[0] "1 componente"
|
||||
msgstr[1] "%s componentes"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:541
|
||||
msgid "workspace.libraries.connected-libraries"
|
||||
msgstr "Biblioteca conectada"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:550
|
||||
msgid "workspace.libraries.connected-through"
|
||||
msgstr "Conectada mediante"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:367
|
||||
msgid "workspace.libraries.connected-to"
|
||||
msgstr "Conectada con"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:600
|
||||
msgid "workspace.libraries.empty.no-connected-libraries"
|
||||
msgstr "Aun no hay bibliotecas conectadas."
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:432
|
||||
msgid "workspace.libraries.empty.add-some"
|
||||
msgstr "O añadir algunas de éstas para probar:"
|
||||
@@ -7243,6 +7255,14 @@ msgstr "algunas plantillas aquí"
|
||||
msgid "workspace.libraries.file-library"
|
||||
msgstr "Biblioteca del archivo"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:336
|
||||
msgid "workspace.libraries.tokens-source"
|
||||
msgstr "Fuente de tokens"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:336
|
||||
msgid "workspace.libraries.set-as-tokens-source"
|
||||
msgstr "Activar fuente de tokens"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:100, src/app/main/ui/workspace/libraries.cljs:124
|
||||
msgid "workspace.libraries.graphics"
|
||||
msgid_plural "workspace.libraries.graphics"
|
||||
@@ -7291,6 +7311,10 @@ msgstr "Buscar bibliotecas compartidas"
|
||||
msgid "workspace.libraries.shared-libraries"
|
||||
msgstr "BIBLIOTECAS COMPARTIDAS"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:311
|
||||
msgid "workspace.libraries.shared-library-added"
|
||||
msgstr "Añadido"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:414
|
||||
msgid "workspace.libraries.shared-library-btn"
|
||||
msgstr "Conectar biblioteca"
|
||||
@@ -7331,6 +7355,24 @@ msgid_plural "workspace.libraries.typography"
|
||||
msgstr[0] "1 tipografía"
|
||||
msgstr[1] "%s tipografías"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:106, src/app/main/ui/workspace/libraries.cljs:150
|
||||
msgid "workspace.libraries.tokens"
|
||||
msgid_plural "workspace.libraries.tokens"
|
||||
msgstr[0] "1 token"
|
||||
msgstr[1] "%s tokens"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:106, src/app/main/ui/workspace/libraries.cljs:150
|
||||
msgid "workspace.libraries.token-sets"
|
||||
msgid_plural "workspace.libraries.token-sets"
|
||||
msgstr[0] "1 token set"
|
||||
msgstr[1] "%s token sets"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:106, src/app/main/ui/workspace/libraries.cljs:150
|
||||
msgid "workspace.libraries.token-themes"
|
||||
msgid_plural "workspace.libraries.token-themes"
|
||||
msgstr[0] "1 token theme"
|
||||
msgstr[1] "%s token themes"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:381
|
||||
msgid "workspace.libraries.unlink-library-btn"
|
||||
msgstr "Desconectar biblioteca"
|
||||
@@ -9762,6 +9804,22 @@ msgstr "Usa una referencia"
|
||||
msgid "workspace.tokens.value-not-valid"
|
||||
msgstr "El valor no es válido"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/tokens_source.cljs:24
|
||||
msgid "workspace.tokens.connected-library"
|
||||
msgstr "librería conectada"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/assets/file_library.cljs:102
|
||||
msgid "workspace.tokens.current-tokens-source-tooltip"
|
||||
msgstr "Esta es la actual fuente de Tokens"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/tokens_source.cljs:25
|
||||
msgid "workspace.tokens.open-connected-library"
|
||||
msgstr "Abrir librería conectada"
|
||||
|
||||
#: src/app/main/data/workspace/libraries.cljs:847
|
||||
msgid "workspace.tokens.notifications.source-sets-or-themes-updated"
|
||||
msgstr "Los sets o temas de la fuente de tokens se han modificado"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/forms/generic_form.cljs
|
||||
#, unused
|
||||
msgid "workspace.tokens.warning-name-change"
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
- **plugins-runtime**: `Library.createComponent()` now rejects invalid input (an empty shape list, or a shape inside a component copy) with a validation error instead of returning a component proxy pointing at nothing.
|
||||
- **plugins-runtime**: Setting an individual padding/margin side (`leftPadding`, `topMargin`, …) now re-derives the padding/margin type, switching to `multiple` when the four sides stop being symmetric (so the value is actually painted) and back to `simple` once top/bottom and left/right are mirrored again.
|
||||
- **plugins-runtime**: Removed the premature deep-hardening of the host plugin context, which froze shared host functions (including `Function.prototype`) before SES override taming, causing `TypeError: Cannot assign to read only property 'toString'` on later host-side function extension. Related to #11001.
|
||||
|
||||
## 1.5.0 (2026-07-08)
|
||||
|
||||
|
||||
@@ -6,13 +6,15 @@
|
||||
<div class="panel">
|
||||
<div class="panel-heading">
|
||||
<p class="headline-m">THEMES</p>
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="addTheme()"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
@if (isEditableTokens) {
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="addTheme()"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<ul data-handler="themes-list">
|
||||
@@ -24,20 +26,22 @@
|
||||
}
|
||||
{{ theme.name }}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="renameTheme(theme.id, theme.name)"
|
||||
>
|
||||
🖊️
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="deleteTheme(theme.id)"
|
||||
>
|
||||
❌
|
||||
</button>
|
||||
@if (isEditableTokens) {
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="renameTheme(theme.id, theme.name)"
|
||||
>
|
||||
🖊️
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="deleteTheme(theme.id)"
|
||||
>
|
||||
❌
|
||||
</button>
|
||||
}
|
||||
<div class="checkbox-container">
|
||||
<input
|
||||
class="checkbox-input"
|
||||
@@ -55,9 +59,15 @@
|
||||
<div class="panel">
|
||||
<div class="panel-heading">
|
||||
<p class="headline-m">SETS</p>
|
||||
<button type="button" data-appearance="secondary" (click)="addSet()">
|
||||
+
|
||||
</button>
|
||||
@if (isEditableTokens) {
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="addSet()"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<ul data-handler="sets-list">
|
||||
@@ -69,20 +79,22 @@
|
||||
<span (click)="loadTokens(set.id)">
|
||||
{{ set.name }}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="renameSet(set.id, set.name)"
|
||||
>
|
||||
🖊️
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="deleteSet(set.id)"
|
||||
>
|
||||
❌
|
||||
</button>
|
||||
@if (isEditableTokens) {
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="renameSet(set.id, set.name)"
|
||||
>
|
||||
🖊️
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="deleteSet(set.id)"
|
||||
>
|
||||
❌
|
||||
</button>
|
||||
}
|
||||
<div class="checkbox-container">
|
||||
<input
|
||||
class="checkbox-input"
|
||||
@@ -105,13 +117,15 @@
|
||||
@for (group of tokenGroups; track group[0]) {
|
||||
<li class="body-m token-group">
|
||||
<span>{{ group[0] }}</span>
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="addToken(group[0])"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
@if (isEditableTokens) {
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="addToken(group[0])"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
}
|
||||
</li>
|
||||
@for (token of group[1]; track token.id) {
|
||||
<li
|
||||
@@ -125,20 +139,22 @@
|
||||
>
|
||||
{{ token.name }}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="renameToken(token.id, token.name)"
|
||||
>
|
||||
🖊️
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="deleteToken(token.id)"
|
||||
>
|
||||
❌
|
||||
</button>
|
||||
@if (isEditableTokens) {
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="renameToken(token.id, token.name)"
|
||||
>
|
||||
🖊️
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-appearance="secondary"
|
||||
(click)="deleteToken(token.id)"
|
||||
>
|
||||
❌
|
||||
</button>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
}
|
||||
|
||||
Loaded 100 of 125 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user