mirror of
https://github.com/penpot/penpot.git
synced 2025-06-07 09:11:41 +02:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
076d64df8f
31 changed files with 339 additions and 141 deletions
|
@ -55,8 +55,12 @@
|
||||||
- Fix problem with constraints when creating group [Taiga #10455](https://tree.taiga.io/project/penpot/issue/10455)
|
- Fix problem with constraints when creating group [Taiga #10455](https://tree.taiga.io/project/penpot/issue/10455)
|
||||||
- Fix opening pen with shortcut multiple times breaks toolbar [Taiga #10566](https://tree.taiga.io/project/penpot/issue/10566)
|
- Fix opening pen with shortcut multiple times breaks toolbar [Taiga #10566](https://tree.taiga.io/project/penpot/issue/10566)
|
||||||
- Fix actions when workspace is visited first time [Taiga #10548](https://tree.taiga.io/project/penpot/issue/10548)
|
- Fix actions when workspace is visited first time [Taiga #10548](https://tree.taiga.io/project/penpot/issue/10548)
|
||||||
|
- Chat icon overlaps "Show" button in carrousel section [Taiga #10542](https://tree.taiga.io/project/penpot/issue/10542)
|
||||||
|
- Fix assets name on inspect tab [Taiga #10630](https://tree.taiga.io/project/penpot/issue/10630)
|
||||||
- Fix chat icon overlaps "Show" button in carrousel section [Taiga #10542](https://tree.taiga.io/project/penpot/issue/10542)
|
- Fix chat icon overlaps "Show" button in carrousel section [Taiga #10542](https://tree.taiga.io/project/penpot/issue/10542)
|
||||||
- Fix incorrect handling of background task result (now task rows are properly marked as completed)
|
- Fix incorrect handling of background task result (now task rows are properly marked as completed)
|
||||||
|
- Fix available size of resize handler [Taiga #10639](https://tree.taiga.io/project/penpot/issue/10639)
|
||||||
|
- Internal error when install a plugin by penpothub - Try plugin [Taiga #10542](https://tree.taiga.io/project/penpot/issue/10542)
|
||||||
|
|
||||||
|
|
||||||
## 2.5.4
|
## 2.5.4
|
||||||
|
@ -73,7 +77,6 @@
|
||||||
methods (add missing team-id prop)
|
methods (add missing team-id prop)
|
||||||
- Fix problem with viewer role and inspect mode [Taiga #9751](https://tree.taiga.io/project/penpot/issue/9751)
|
- Fix problem with viewer role and inspect mode [Taiga #9751](https://tree.taiga.io/project/penpot/issue/9751)
|
||||||
- Fix error when clicking on a comment at the viewer's sidebar [Taiga #10465](https://tree.taiga.io/project/penpot/issue/10465)
|
- Fix error when clicking on a comment at the viewer's sidebar [Taiga #10465](https://tree.taiga.io/project/penpot/issue/10465)
|
||||||
- Internal error when install a plugin by penpothub - Try plugin [Taiga #10542](https://tree.taiga.io/project/penpot/issue/10542)
|
|
||||||
|
|
||||||
## 2.5.3
|
## 2.5.3
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,10 @@
|
||||||
:always
|
:always
|
||||||
(update :data select-keys [:id :options :pages :pages-index :components]))
|
(update :data select-keys [:id :options :pages :pages-index :components]))
|
||||||
|
|
||||||
libs (files/get-file-libraries conn file-id)
|
libs (->> (files/get-file-libraries conn file-id)
|
||||||
|
(mapv (fn [{:keys [id] :as lib}]
|
||||||
|
(merge lib (files/get-file cfg id)))))
|
||||||
|
|
||||||
links (->> (db/query conn :share-link {:file-id file-id})
|
links (->> (db/query conn :share-link {:file-id file-id})
|
||||||
(mapv (fn [row]
|
(mapv (fn [row]
|
||||||
(-> row
|
(-> row
|
||||||
|
|
|
@ -1639,7 +1639,21 @@
|
||||||
(if (and (empty? roperations) (empty? applied-tokens))
|
(if (and (empty? roperations) (empty? applied-tokens))
|
||||||
changes
|
changes
|
||||||
(let [all-parents (cfh/get-parent-ids (:objects container)
|
(let [all-parents (cfh/get-parent-ids (:objects container)
|
||||||
(:id dest-shape))]
|
(:id dest-shape))
|
||||||
|
|
||||||
|
;; Sync tokens of attributes ignored above.
|
||||||
|
;; FIXME: this probably may be merged with the other calculation
|
||||||
|
;; of applied tokens, below, and to the calculation only once
|
||||||
|
;; for all sync-attrs.
|
||||||
|
applied-tokens (reduce (fn [applied-tokens attr]
|
||||||
|
(let [attr-group (get ctk/sync-attrs attr)
|
||||||
|
token-attrs (cto/shape-attr->token-attrs attr)]
|
||||||
|
(if (not (and (touched attr-group)
|
||||||
|
omit-touched?))
|
||||||
|
(into applied-tokens token-attrs)
|
||||||
|
applied-tokens)))
|
||||||
|
applied-tokens
|
||||||
|
ctk/swap-keep-attrs)]
|
||||||
(cond-> changes
|
(cond-> changes
|
||||||
(seq roperations)
|
(seq roperations)
|
||||||
(-> (update :redo-changes conj (make-change
|
(-> (update :redo-changes conj (make-change
|
||||||
|
|
|
@ -182,14 +182,27 @@
|
||||||
([shape-attr] (shape-attr->token-attrs shape-attr nil))
|
([shape-attr] (shape-attr->token-attrs shape-attr nil))
|
||||||
([shape-attr changed-sub-attr]
|
([shape-attr changed-sub-attr]
|
||||||
(cond
|
(cond
|
||||||
(= :fills shape-attr) #{:fill}
|
(= :fills shape-attr)
|
||||||
(and (= :strokes shape-attr) (nil? changed-sub-attr)) #{:stroke-width :stroke-color}
|
#{:fill}
|
||||||
|
|
||||||
|
(and (= :strokes shape-attr) (nil? changed-sub-attr))
|
||||||
|
#{:stroke-width :stroke-color}
|
||||||
|
|
||||||
(= :strokes shape-attr)
|
(= :strokes shape-attr)
|
||||||
(cond
|
(cond
|
||||||
(some #{:stroke-color} changed-sub-attr) #{:stroke-color}
|
(some #{:stroke-color} changed-sub-attr) #{:stroke-color}
|
||||||
(some #{:stroke-width} changed-sub-attr) #{:stroke-width})
|
(some #{:stroke-width} changed-sub-attr) #{:stroke-width})
|
||||||
(and (= :layout-padding shape-attr) (seq changed-sub-attr)) changed-sub-attr
|
|
||||||
(and (= :layout-item-margin shape-attr) (seq changed-sub-attr)) changed-sub-attr
|
(= :layout-padding shape-attr)
|
||||||
|
(if (seq changed-sub-attr)
|
||||||
|
changed-sub-attr
|
||||||
|
#{:p1 :p2 :p3 :p4})
|
||||||
|
|
||||||
|
(= :layout-item-margin shape-attr)
|
||||||
|
(if (seq changed-sub-attr)
|
||||||
|
changed-sub-attr
|
||||||
|
#{:m1 :m2 :m3 :m4})
|
||||||
|
|
||||||
(border-radius-keys shape-attr) #{shape-attr}
|
(border-radius-keys shape-attr) #{shape-attr}
|
||||||
(sizing-keys shape-attr) #{shape-attr}
|
(sizing-keys shape-attr) #{shape-attr}
|
||||||
(opacity-keys shape-attr) #{shape-attr}
|
(opacity-keys shape-attr) #{shape-attr}
|
||||||
|
|
|
@ -665,20 +665,20 @@
|
||||||
["$value" :map]
|
["$value" :map]
|
||||||
["$type" :string]]]))
|
["$type" :string]]]))
|
||||||
|
|
||||||
(defn has-legacy-format?
|
(defn get-json-format
|
||||||
"Searches through parsed token file and returns:
|
"Searches through parsed token file and returns:
|
||||||
- true when first node satisfies `legacy-node?` predicate
|
- `:json-format/legacy` when first node satisfies `legacy-node?` predicate
|
||||||
- false when first node satisfies `dtcg-node?` predicate
|
- `:json-format/dtcg` when first node satisfies `dtcg-node?` predicate
|
||||||
- nil if neither combination is found"
|
- `nil` if neither combination is found"
|
||||||
([data]
|
([data]
|
||||||
(has-legacy-format? data legacy-node? dtcg-node?))
|
(get-json-format data legacy-node? dtcg-node?))
|
||||||
([data legacy-node? dtcg-node?]
|
([data legacy-node? dtcg-node?]
|
||||||
(let [branch? map?
|
(let [branch? map?
|
||||||
children (fn [node] (vals node))
|
children (fn [node] (vals node))
|
||||||
check-node (fn [node]
|
check-node (fn [node]
|
||||||
(cond
|
(cond
|
||||||
(legacy-node? node) true
|
(legacy-node? node) :json-format/legacy
|
||||||
(dtcg-node? node) false
|
(dtcg-node? node) :json-format/dtcg
|
||||||
:else nil))
|
:else nil))
|
||||||
walk (fn walk [node]
|
walk (fn walk [node]
|
||||||
(lazy-seq
|
(lazy-seq
|
||||||
|
@ -690,6 +690,10 @@
|
||||||
(filter some?)
|
(filter some?)
|
||||||
first))))
|
first))))
|
||||||
|
|
||||||
|
(defn single-set? [data]
|
||||||
|
(and (not (contains? data "$metadata"))
|
||||||
|
(not (contains? data "$themes"))))
|
||||||
|
|
||||||
;; DEPRECATED
|
;; DEPRECATED
|
||||||
(defn walk-sets-tree-seq
|
(defn walk-sets-tree-seq
|
||||||
"Walk sets tree as a flat list.
|
"Walk sets tree as a flat list.
|
||||||
|
@ -826,6 +830,24 @@
|
||||||
|
|
||||||
(declare make-tokens-lib)
|
(declare make-tokens-lib)
|
||||||
|
|
||||||
|
(defn- legacy-nodes->dtcg-nodes [sets-data]
|
||||||
|
(walk/postwalk
|
||||||
|
(fn [node]
|
||||||
|
(cond-> node
|
||||||
|
(and (map? node)
|
||||||
|
(contains? node "value")
|
||||||
|
(sequential? (get node "value")))
|
||||||
|
(update "value"
|
||||||
|
(fn [seq-value]
|
||||||
|
(map #(set/rename-keys % {"type" "$type"}) seq-value)))
|
||||||
|
|
||||||
|
(and (map? node)
|
||||||
|
(and (contains? node "type")
|
||||||
|
(contains? node "value")))
|
||||||
|
(set/rename-keys {"value" "$value"
|
||||||
|
"type" "$type"})))
|
||||||
|
sets-data))
|
||||||
|
|
||||||
(defprotocol ITokensLib
|
(defprotocol ITokensLib
|
||||||
"A library of tokens, sets and themes."
|
"A library of tokens, sets and themes."
|
||||||
(set-path-exists? [_ path] "if a set at `path` exists")
|
(set-path-exists? [_ path] "if a set at `path` exists")
|
||||||
|
@ -844,6 +866,8 @@ Will return a value that matches this schema:
|
||||||
(get-active-themes-set-tokens [_] "set of set names that are active in the the active themes")
|
(get-active-themes-set-tokens [_] "set of set names that are active in the the active themes")
|
||||||
(encode-dtcg [_] "Encodes library to a dtcg compatible json string")
|
(encode-dtcg [_] "Encodes library to a dtcg compatible json string")
|
||||||
(decode-dtcg-json [_ parsed-json] "Decodes parsed json containing tokens and converts to library")
|
(decode-dtcg-json [_ parsed-json] "Decodes parsed json containing tokens and converts to library")
|
||||||
|
(decode-single-set-json [_ set-name tokens] "Decodes parsed json containing single token set and converts to library")
|
||||||
|
(decode-single-set-legacy-json [_ set-name tokens] "Decodes parsed legacy json containing single token set and converts to library")
|
||||||
(decode-legacy-json [_ parsed-json] "Decodes parsed legacy json containing tokens and converts to library")
|
(decode-legacy-json [_ parsed-json] "Decodes parsed legacy json containing tokens and converts to library")
|
||||||
(get-all-tokens [_] "all tokens in the lib")
|
(get-all-tokens [_] "all tokens in the lib")
|
||||||
(validate [_]))
|
(validate [_]))
|
||||||
|
@ -1287,6 +1311,17 @@ Will return a value that matches this schema:
|
||||||
(assoc-in ["$metadata" "activeThemes"] active-themes-clear)
|
(assoc-in ["$metadata" "activeThemes"] active-themes-clear)
|
||||||
(assoc-in ["$metadata" "activeSets"] active-sets))))
|
(assoc-in ["$metadata" "activeSets"] active-sets))))
|
||||||
|
|
||||||
|
(decode-single-set-json [this set-name tokens]
|
||||||
|
(assert (map? tokens) "expected a map data structure for `data`")
|
||||||
|
|
||||||
|
(add-set this (make-token-set :name (normalize-set-name set-name)
|
||||||
|
:tokens (flatten-nested-tokens-json tokens ""))))
|
||||||
|
|
||||||
|
|
||||||
|
(decode-single-set-legacy-json [this set-name tokens]
|
||||||
|
(assert (map? tokens) "expected a map data structure for `data`")
|
||||||
|
(decode-single-set-json this set-name (legacy-nodes->dtcg-nodes tokens)))
|
||||||
|
|
||||||
(decode-dtcg-json [_ data]
|
(decode-dtcg-json [_ data]
|
||||||
(assert (map? data) "expected a map data structure for `data`")
|
(assert (map? data) "expected a map data structure for `data`")
|
||||||
|
|
||||||
|
@ -1370,22 +1405,7 @@ Will return a value that matches this schema:
|
||||||
(decode-legacy-json [this parsed-legacy-json]
|
(decode-legacy-json [this parsed-legacy-json]
|
||||||
(let [other-data (select-keys parsed-legacy-json ["$themes" "$metadata"])
|
(let [other-data (select-keys parsed-legacy-json ["$themes" "$metadata"])
|
||||||
sets-data (dissoc parsed-legacy-json "$themes" "$metadata")
|
sets-data (dissoc parsed-legacy-json "$themes" "$metadata")
|
||||||
dtcg-sets-data (walk/postwalk
|
dtcg-sets-data (legacy-nodes->dtcg-nodes sets-data)]
|
||||||
(fn [node]
|
|
||||||
(cond-> node
|
|
||||||
(and (map? node)
|
|
||||||
(contains? node "value")
|
|
||||||
(sequential? (get node "value")))
|
|
||||||
(update "value"
|
|
||||||
(fn [seq-value]
|
|
||||||
(map #(set/rename-keys % {"type" "$type"}) seq-value)))
|
|
||||||
|
|
||||||
(and (map? node)
|
|
||||||
(and (contains? node "type")
|
|
||||||
(contains? node "value")))
|
|
||||||
(set/rename-keys {"value" "$value"
|
|
||||||
"type" "$type"})))
|
|
||||||
sets-data)]
|
|
||||||
(decode-dtcg-json this (merge other-data
|
(decode-dtcg-json this (merge other-data
|
||||||
dtcg-sets-data))))
|
dtcg-sets-data))))
|
||||||
(get-all-tokens [this]
|
(get-all-tokens [this]
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
{"color":
|
||||||
|
{"red":
|
||||||
|
{"100":
|
||||||
|
{"value":"red",
|
||||||
|
"type":"color",
|
||||||
|
"description":""}}}}
|
6
common/test/common_tests/types/data/single-set.json
Normal file
6
common/test/common_tests/types/data/single-set.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{"color":
|
||||||
|
{"red":
|
||||||
|
{"100":
|
||||||
|
{"$value":"red",
|
||||||
|
"$type":"color",
|
||||||
|
"$description":""}}}}
|
|
@ -1371,6 +1371,30 @@
|
||||||
(t/testing "invalid tokens got discarded"
|
(t/testing "invalid tokens got discarded"
|
||||||
(t/is (nil? (get-set-token "typography" "H1.Bold")))))))
|
(t/is (nil? (get-set-token "typography" "H1.Bold")))))))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(t/deftest single-set-legacy-json-decoding
|
||||||
|
(let [json (-> (slurp "test/common_tests/types/data/legacy-single-set.json")
|
||||||
|
(tr/decode-str))
|
||||||
|
lib (ctob/decode-single-set-legacy-json (ctob/ensure-tokens-lib nil) "single_set" json)
|
||||||
|
get-set-token (fn [set-name token-name]
|
||||||
|
(some-> (ctob/get-set lib set-name)
|
||||||
|
(ctob/get-token token-name)))]
|
||||||
|
(t/is (= '("single_set") (ctob/get-ordered-set-names lib)))
|
||||||
|
(t/testing "token added"
|
||||||
|
(t/is (some? (get-set-token "single_set" "color.red.100")))))))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(t/deftest single-set-dtcg-json-decoding
|
||||||
|
(let [json (-> (slurp "test/common_tests/types/data/single-set.json")
|
||||||
|
(tr/decode-str))
|
||||||
|
lib (ctob/decode-single-set-json (ctob/ensure-tokens-lib nil) "single_set" json)
|
||||||
|
get-set-token (fn [set-name token-name]
|
||||||
|
(some-> (ctob/get-set lib set-name)
|
||||||
|
(ctob/get-token token-name)))]
|
||||||
|
(t/is (= '("single_set") (ctob/get-ordered-set-names lib)))
|
||||||
|
(t/testing "token added"
|
||||||
|
(t/is (some? (get-set-token "single_set" "color.red.100")))))))
|
||||||
|
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(t/deftest dtcg-encoding-decoding-json
|
(t/deftest dtcg-encoding-decoding-json
|
||||||
(let [json (-> (slurp "test/common_tests/types/data/tokens-multi-set-example.json")
|
(let [json (-> (slurp "test/common_tests/types/data/tokens-multi-set-example.json")
|
||||||
|
|
|
@ -8,12 +8,12 @@ source ~/.bashrc
|
||||||
|
|
||||||
echo "[start-tmux.sh] Installing node dependencies"
|
echo "[start-tmux.sh] Installing node dependencies"
|
||||||
pushd ~/penpot/frontend/
|
pushd ~/penpot/frontend/
|
||||||
corepack up;
|
corepack install;
|
||||||
yarn install;
|
yarn install;
|
||||||
yarn run playwright install --with-deps chromium
|
yarn run playwright install --with-deps chromium
|
||||||
popd
|
popd
|
||||||
pushd ~/penpot/exporter/
|
pushd ~/penpot/exporter/
|
||||||
corepack up;
|
corepack install;
|
||||||
yarn install
|
yarn install
|
||||||
yarn run playwright install --with-deps chromium
|
yarn run playwright install --with-deps chromium
|
||||||
popd
|
popd
|
||||||
|
|
|
@ -52,7 +52,7 @@ services:
|
||||||
## penpot to the internet, or a different host than `localhost`.
|
## penpot to the internet, or a different host than `localhost`.
|
||||||
|
|
||||||
# traefik:
|
# traefik:
|
||||||
# image: traefik:v2.9
|
# image: traefik:v3.3
|
||||||
# networks:
|
# networks:
|
||||||
# - penpot
|
# - penpot
|
||||||
# command:
|
# command:
|
||||||
|
@ -88,28 +88,15 @@ services:
|
||||||
- penpot
|
- penpot
|
||||||
|
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
# - "traefik.enable=true"
|
||||||
|
|
||||||
## HTTP: example of labels for the case where penpot will be exposed to the
|
# ## HTTPS: example of labels for the case where penpot will be exposed to the
|
||||||
## internet with only HTTP (without HTTPS) using traefik.
|
# ## internet with HTTPS using traefik.
|
||||||
|
|
||||||
# - "traefik.http.routers.penpot-http.entrypoints=web"
|
|
||||||
# - "traefik.http.routers.penpot-http.rule=Host(`<DOMAIN_NAME>`)"
|
|
||||||
# - "traefik.http.services.penpot-http.loadbalancer.server.port=80"
|
|
||||||
|
|
||||||
## HTTPS: example of labels for the case where penpot will be exposed to the
|
|
||||||
## internet with HTTPS using traefik.
|
|
||||||
|
|
||||||
# - "traefik.http.middlewares.http-redirect.redirectscheme.scheme=https"
|
|
||||||
# - "traefik.http.middlewares.http-redirect.redirectscheme.permanent=true"
|
|
||||||
# - "traefik.http.routers.penpot-http.entrypoints=web"
|
|
||||||
# - "traefik.http.routers.penpot-http.rule=Host(`<DOMAIN_NAME>`)"
|
|
||||||
# - "traefik.http.routers.penpot-http.middlewares=http-redirect"
|
|
||||||
# - "traefik.http.routers.penpot-https.entrypoints=websecure"
|
|
||||||
# - "traefik.http.routers.penpot-https.rule=Host(`<DOMAIN_NAME>`)"
|
# - "traefik.http.routers.penpot-https.rule=Host(`<DOMAIN_NAME>`)"
|
||||||
# - "traefik.http.services.penpot-https.loadbalancer.server.port=80"
|
# - "traefik.http.routers.penpot-https.entrypoints=websecure"
|
||||||
# - "traefik.http.routers.penpot-https.tls=true"
|
|
||||||
# - "traefik.http.routers.penpot-https.tls.certresolver=letsencrypt"
|
# - "traefik.http.routers.penpot-https.tls.certresolver=letsencrypt"
|
||||||
|
# - "traefik.http.routers.penpot-https.tls=true"
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
<< : [*penpot-flags, *penpot-http-body-size]
|
<< : [*penpot-flags, *penpot-http-body-size]
|
||||||
|
@ -130,8 +117,7 @@ services:
|
||||||
networks:
|
networks:
|
||||||
- penpot
|
- penpot
|
||||||
|
|
||||||
## Configuration envronment variables for the backend
|
## Configuration envronment variables for the backend container.
|
||||||
## container.
|
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
<< : [*penpot-flags, *penpot-public-uri, *penpot-http-body-size]
|
<< : [*penpot-flags, *penpot-public-uri, *penpot-http-body-size]
|
||||||
|
|
|
@ -200,6 +200,8 @@ server {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For full documentation, go to the [official website][2]
|
||||||
|
|
||||||
### Example with CADDY SERVER
|
### Example with CADDY SERVER
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -212,4 +214,15 @@ penpot.mycompany.com {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For full documentation, go to the [official website][3]
|
||||||
|
|
||||||
|
### Example with TRAEFIK
|
||||||
|
|
||||||
|
In the [Penpot's docker-compose.yaml][4] file, there is a simple example with Traefik.
|
||||||
|
For full documentation, go to the [official website][5]
|
||||||
|
|
||||||
[1]: /technical-guide/configuration/
|
[1]: /technical-guide/configuration/
|
||||||
|
[2]: https://nginx.org/en/docs/index.html
|
||||||
|
[3]: https://caddyserver.com/docs/
|
||||||
|
[4]: https://github.com/penpot/penpot/blob/develop/docker/images/docker-compose.yaml
|
||||||
|
[5]: https://doc.traefik.io/traefik/
|
||||||
|
|
|
@ -245,6 +245,9 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||||
async clickAssets(clickOptions = {}) {
|
async clickAssets(clickOptions = {}) {
|
||||||
await this.sidebar.getByText("Assets").click(clickOptions);
|
await this.sidebar.getByText("Assets").click(clickOptions);
|
||||||
}
|
}
|
||||||
|
async clickLayers(clickOptions = {}) {
|
||||||
|
await this.sidebar.getByText("Layers").click(clickOptions);
|
||||||
|
}
|
||||||
|
|
||||||
async openLibrariesModal(clickOptions = {}) {
|
async openLibrariesModal(clickOptions = {}) {
|
||||||
await this.sidebar.getByTestId("libraries").click(clickOptions);
|
await this.sidebar.getByTestId("libraries").click(clickOptions);
|
||||||
|
|
|
@ -70,3 +70,55 @@ test("[Taiga #9116] Copy CSS background color in the selected format in the INSP
|
||||||
);
|
);
|
||||||
expect(rgbaColorText).toContain("background: rgba(");
|
expect(rgbaColorText).toContain("background: rgba(");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("[Taiga #10630] [INSPECT] Style assets not being displayed on info tab", async ({
|
||||||
|
page,
|
||||||
|
context,
|
||||||
|
}) => {
|
||||||
|
const workspacePage = new WorkspacePage(page);
|
||||||
|
await workspacePage.setupEmptyFile(page);
|
||||||
|
await workspacePage.goToWorkspace();
|
||||||
|
await workspacePage.mockRPC(
|
||||||
|
"link-file-to-library",
|
||||||
|
"workspace/link-file-to-library.json",
|
||||||
|
);
|
||||||
|
|
||||||
|
await workspacePage.mockRPC(
|
||||||
|
"unlink-file-from-library",
|
||||||
|
"workspace/unlink-file-from-library.json",
|
||||||
|
);
|
||||||
|
|
||||||
|
await workspacePage.mockRPC(
|
||||||
|
"get-team-shared-files?team-id=*",
|
||||||
|
"workspace/get-team-shared-libraries-non-empty.json",
|
||||||
|
);
|
||||||
|
|
||||||
|
await workspacePage.clickColorPalette();
|
||||||
|
await workspacePage.clickAssets();
|
||||||
|
await workspacePage.mockRPC(/get\-file\?/, "workspace/get-file-library.json");
|
||||||
|
await workspacePage.openLibrariesModal();
|
||||||
|
await workspacePage.clickLibrary("Testing library 1");
|
||||||
|
await workspacePage.closeLibrariesModal();
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
workspacePage.palette.getByRole("button", { name: "test-color-187cd5" }),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await workspacePage.clickLayers();
|
||||||
|
|
||||||
|
await workspacePage.rectShapeButton.click();
|
||||||
|
await workspacePage.clickWithDragViewportAt(128, 128, 200, 100);
|
||||||
|
await workspacePage.clickLeafLayer("Rectangle");
|
||||||
|
await workspacePage.palette
|
||||||
|
.getByRole("button", { name: "test-color-187cd5" })
|
||||||
|
.click();
|
||||||
|
|
||||||
|
const inspectButton = workspacePage.page.getByRole("tab", {
|
||||||
|
name: "Inspect",
|
||||||
|
});
|
||||||
|
await inspectButton.click();
|
||||||
|
|
||||||
|
const colorLibraryName = workspacePage.page.getByTestId("color-library-name");
|
||||||
|
|
||||||
|
await expect(colorLibraryName).toHaveText("test-color-187cd5");
|
||||||
|
});
|
||||||
|
|
|
@ -192,3 +192,5 @@
|
||||||
:height 720}])
|
:height 720}])
|
||||||
|
|
||||||
(def zoom-half-pixel-precision 8)
|
(def zoom-half-pixel-precision 8)
|
||||||
|
|
||||||
|
(def max-input-length 255)
|
||||||
|
|
|
@ -189,6 +189,8 @@
|
||||||
(assoc :share-links share-links)
|
(assoc :share-links share-links)
|
||||||
(assoc :current-team-id team-id)
|
(assoc :current-team-id team-id)
|
||||||
(assoc :teams {team-id team})
|
(assoc :teams {team-id team})
|
||||||
|
(assoc :files (-> (d/index-by :id libraries)
|
||||||
|
(assoc (:id file) file)))
|
||||||
(assoc :viewer {:libraries (d/index-by :id libraries)
|
(assoc :viewer {:libraries (d/index-by :id libraries)
|
||||||
:users (d/index-by :id users)
|
:users (d/index-by :id users)
|
||||||
:permissions permissions
|
:permissions permissions
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
[app.main.style :as stl])
|
[app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
[app.main.constants :refer [max-input-length]]
|
||||||
[app.main.ui.ds.controls.shared.options-dropdown :refer [options-dropdown*]]
|
[app.main.ui.ds.controls.shared.options-dropdown :refer [options-dropdown*]]
|
||||||
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list] :as i]
|
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list] :as i]
|
||||||
[app.util.array :as array]
|
[app.util.array :as array]
|
||||||
|
@ -60,6 +61,7 @@
|
||||||
[:id {:optional true} :string]
|
[:id {:optional true} :string]
|
||||||
[:options [:vector schema:combobox-option]]
|
[:options [:vector schema:combobox-option]]
|
||||||
[:class {:optional true} :string]
|
[:class {:optional true} :string]
|
||||||
|
[:max-length {:optional true} :int]
|
||||||
[:placeholder {:optional true} :string]
|
[:placeholder {:optional true} :string]
|
||||||
[:disabled {:optional true} :boolean]
|
[:disabled {:optional true} :boolean]
|
||||||
[:default-selected {:optional true} :string]
|
[:default-selected {:optional true} :string]
|
||||||
|
@ -69,7 +71,7 @@
|
||||||
(mf/defc combobox*
|
(mf/defc combobox*
|
||||||
{::mf/props :obj
|
{::mf/props :obj
|
||||||
::mf/schema schema:combobox}
|
::mf/schema schema:combobox}
|
||||||
[{:keys [id options class placeholder disabled has-error default-selected on-change] :rest props}]
|
[{:keys [id options class placeholder disabled has-error default-selected on-change max-length] :rest props}]
|
||||||
(let [open* (mf/use-state false)
|
(let [open* (mf/use-state false)
|
||||||
open (deref open*)
|
open (deref open*)
|
||||||
|
|
||||||
|
@ -240,6 +242,7 @@
|
||||||
:aria-activedescendant focused
|
:aria-activedescendant focused
|
||||||
:class (stl/css :input)
|
:class (stl/css :input)
|
||||||
:data-testid "combobox-input"
|
:data-testid "combobox-input"
|
||||||
|
:maxlength (d/nilv max-length max-input-length)
|
||||||
:disabled disabled
|
:disabled disabled
|
||||||
:value selected
|
:value selected
|
||||||
:on-change on-input-change
|
:on-change on-input-change
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
[app.main.style :as stl])
|
[app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
[app.main.constants :refer [max-input-length]]
|
||||||
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
|
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
@ -20,13 +21,14 @@
|
||||||
[:icon {:optional true}
|
[:icon {:optional true}
|
||||||
[:and :string [:fn #(contains? icon-list %)]]]
|
[:and :string [:fn #(contains? icon-list %)]]]
|
||||||
[:type {:optional true} :string]
|
[:type {:optional true} :string]
|
||||||
|
[:max-length {:optional true} :int]
|
||||||
[:variant {:optional true} :string]])
|
[:variant {:optional true} :string]])
|
||||||
|
|
||||||
(mf/defc input*
|
(mf/defc input*
|
||||||
{::mf/props :obj
|
{::mf/props :obj
|
||||||
::mf/forward-ref true
|
::mf/forward-ref true
|
||||||
::mf/schema schema:input}
|
::mf/schema schema:input}
|
||||||
[{:keys [icon class type variant] :rest props} ref]
|
[{:keys [icon class type max-length variant] :rest props} ref]
|
||||||
(let [ref (or ref (mf/use-ref))
|
(let [ref (or ref (mf/use-ref))
|
||||||
type (d/nilv type "text")
|
type (d/nilv type "text")
|
||||||
props (mf/spread-props props
|
props (mf/spread-props props
|
||||||
|
@ -34,6 +36,7 @@
|
||||||
:input true
|
:input true
|
||||||
:input-with-icon (some? icon))
|
:input-with-icon (some? icon))
|
||||||
:ref ref
|
:ref ref
|
||||||
|
:maxlength (d/nilv max-length (str max-input-length))
|
||||||
:type type})
|
:type type})
|
||||||
|
|
||||||
on-icon-click
|
on-icon-click
|
||||||
|
|
|
@ -32,16 +32,11 @@
|
||||||
(get-in state [libraries-place file-id :data :colors]))]
|
(get-in state [libraries-place file-id :data :colors]))]
|
||||||
(l/derived get-library st/state)))
|
(l/derived get-library st/state)))
|
||||||
|
|
||||||
(defn- get-colors-library [color]
|
(defn- use-colors-library [color]
|
||||||
(let [colors-library-v (-> (mf/use-memo
|
(-> (mf/use-memo
|
||||||
(mf/deps (:file-id color))
|
(mf/deps (:file-id color))
|
||||||
#(make-colors-library-ref :viewer-libraries (:file-id color)))
|
#(make-colors-library-ref :files (:file-id color)))
|
||||||
mf/deref)
|
mf/deref))
|
||||||
colors-library-ws (-> (mf/use-memo
|
|
||||||
(mf/deps (:file-id color))
|
|
||||||
#(make-colors-library-ref :libraries (:file-id color)))
|
|
||||||
mf/deref)]
|
|
||||||
(or colors-library-v colors-library-ws)))
|
|
||||||
|
|
||||||
(defn- get-file-colors []
|
(defn- get-file-colors []
|
||||||
(or (mf/deref file-colors-ref) (mf/deref refs/workspace-file-colors)))
|
(or (mf/deref file-colors-ref) (mf/deref refs/workspace-file-colors)))
|
||||||
|
@ -54,7 +49,7 @@
|
||||||
(str/capital $)))
|
(str/capital $)))
|
||||||
|
|
||||||
(mf/defc color-row [{:keys [color format copy-data on-change-format]}]
|
(mf/defc color-row [{:keys [color format copy-data on-change-format]}]
|
||||||
(let [colors-library (get-colors-library color)
|
(let [colors-library (use-colors-library color)
|
||||||
file-colors (get-file-colors)
|
file-colors (get-file-colors)
|
||||||
color-library-name (get-in (or colors-library file-colors) [(:id color) :name])
|
color-library-name (get-in (or colors-library file-colors) [(:id color) :name])
|
||||||
color (assoc color :color-library-name color-library-name)
|
color (assoc color :color-library-name color-library-name)
|
||||||
|
@ -85,7 +80,8 @@
|
||||||
|
|
||||||
(when color-library-name
|
(when color-library-name
|
||||||
[:div {:class (stl/css :second-row)}
|
[:div {:class (stl/css :second-row)}
|
||||||
[:div {:class (stl/css :color-name-library)}
|
[:div {:class (stl/css :color-name-library)
|
||||||
|
:data-testid "color-library-name"}
|
||||||
color-library-name]])]]
|
color-library-name]])]]
|
||||||
|
|
||||||
[:div {:class (stl/css :image-download)}
|
[:div {:class (stl/css :image-download)}
|
||||||
|
@ -146,6 +142,7 @@
|
||||||
|
|
||||||
(when color-library-name
|
(when color-library-name
|
||||||
[:div {:class (stl/css :second-row)}
|
[:div {:class (stl/css :second-row)}
|
||||||
[:div {:class (stl/css :color-name-library)}
|
[:div {:class (stl/css :color-name-library)
|
||||||
|
:data-testid "color-library-name"}
|
||||||
color-library-name]])]])))
|
color-library-name]])]])))
|
||||||
|
|
||||||
|
|
|
@ -70,36 +70,23 @@
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.one-line {
|
.one-line {
|
||||||
max-height: $s-32;
|
max-height: $s-32;
|
||||||
}
|
}
|
||||||
|
|
||||||
.two-line {
|
.two-line {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 1fr 1fr;
|
grid-template-rows: auto 1fr;
|
||||||
|
gap: $s-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-name-wrapper {
|
.color-name-wrapper {
|
||||||
@include bodySmallTypography;
|
@include bodySmallTypography;
|
||||||
@include flexColumn;
|
@include flexColumn;
|
||||||
padding: $s-8 $s-4 $s-8 $s-8;
|
padding: $s-8 $s-4 $s-8 $s-8;
|
||||||
height: $s-32;
|
height: $s-32;
|
||||||
max-width: $s-80;
|
max-width: $s-80;
|
||||||
|
|
||||||
&.gradient-color {
|
|
||||||
color: var(--menu-foreground-color);
|
|
||||||
max-width: $s-124;
|
|
||||||
}
|
|
||||||
.color-name-library {
|
|
||||||
@include bodySmallTypography;
|
|
||||||
@include textEllipsis;
|
|
||||||
text-align: left;
|
|
||||||
height: $s-16;
|
|
||||||
color: var(--menu-foreground-color-rest);
|
|
||||||
}
|
|
||||||
.color-value-wrapper {
|
|
||||||
@include bodySmallTypography;
|
|
||||||
height: $s-16;
|
|
||||||
color: var(--menu-foreground-color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.opacity-info {
|
.opacity-info {
|
||||||
|
@ -152,6 +139,7 @@
|
||||||
.color-name-library {
|
.color-name-library {
|
||||||
@include inspectValue;
|
@include inspectValue;
|
||||||
color: var(--menu-foreground-color-rest);
|
color: var(--menu-foreground-color-rest);
|
||||||
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-download {
|
.image-download {
|
||||||
|
|
|
@ -110,7 +110,9 @@
|
||||||
[:div {:class (stl/css :resize-area-horiz)
|
[:div {:class (stl/css :resize-area-horiz)
|
||||||
:on-pointer-down on-pointer-down-pages
|
:on-pointer-down on-pointer-down-pages
|
||||||
:on-lost-pointer-capture on-lost-pointer-capture-pages
|
:on-lost-pointer-capture on-lost-pointer-capture-pages
|
||||||
:on-pointer-move on-pointer-move-pages}])
|
:on-pointer-move on-pointer-move-pages}
|
||||||
|
|
||||||
|
[:div {:class (stl/css :resize-handle-horiz)}]])
|
||||||
|
|
||||||
[:& layers-toolbox {:size-parent size
|
[:& layers-toolbox {:size-parent size
|
||||||
:size size-pages}]])
|
:size size-pages}]])
|
||||||
|
|
|
@ -88,6 +88,12 @@ $width-settings-bar-max: $s-500;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
padding: $s-3 0 $s-1 0;
|
||||||
|
height: $s-6;
|
||||||
|
cursor: ns-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle-horiz {
|
||||||
border-bottom: $s-2 solid var(--resize-area-border-color);
|
border-bottom: $s-2 solid var(--resize-area-border-color);
|
||||||
cursor: ns-resize;
|
cursor: ns-resize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
(ns app.main.ui.workspace.tokens.components.controls.input-tokens
|
(ns app.main.ui.workspace.tokens.components.controls.input-tokens
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
[app.main.constants :refer [max-input-length]]
|
||||||
[app.main.ui.ds.controls.input :refer [input*]]
|
[app.main.ui.ds.controls.input :refer [input*]]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
@ -18,6 +20,7 @@
|
||||||
[:placeholder {:optional true} :string]
|
[:placeholder {:optional true} :string]
|
||||||
[:default-value {:optional true} [:maybe :string]]
|
[:default-value {:optional true} [:maybe :string]]
|
||||||
[:class {:optional true} :string]
|
[:class {:optional true} :string]
|
||||||
|
[:max-length {:optional true} :int]
|
||||||
[:error {:optional true} :boolean]
|
[:error {:optional true} :boolean]
|
||||||
[:value {:optional true} :string]])
|
[:value {:optional true} :string]])
|
||||||
|
|
||||||
|
@ -25,12 +28,13 @@
|
||||||
{::mf/props :obj
|
{::mf/props :obj
|
||||||
::mf/forward-ref true
|
::mf/forward-ref true
|
||||||
::mf/schema schema::input-tokens}
|
::mf/schema schema::input-tokens}
|
||||||
[{:keys [class label id error value children] :rest props} ref]
|
[{:keys [class label id max-length error value children] :rest props} ref]
|
||||||
(let [ref (or ref (mf/use-ref))
|
(let [ref (or ref (mf/use-ref))
|
||||||
props (mf/spread-props props {:id id
|
props (mf/spread-props props {:id id
|
||||||
:type "text"
|
:type "text"
|
||||||
:class (stl/css :input)
|
:class (stl/css :input)
|
||||||
:aria-invalid error
|
:aria-invalid error
|
||||||
|
:max-length (d/nilv max-length max-input-length)
|
||||||
:value value
|
:value value
|
||||||
:ref ref})]
|
:ref ref})]
|
||||||
[:div {:class (dm/str class " " (stl/css-case :wrapper true
|
[:div {:class (dm/str class " " (stl/css-case :wrapper true
|
||||||
|
|
|
@ -106,9 +106,9 @@
|
||||||
[:> heading* {:level 3
|
[:> heading* {:level 3
|
||||||
:class (stl/css :theme-group-label)
|
:class (stl/css :theme-group-label)
|
||||||
:typography "body-large"}
|
:typography "body-large"}
|
||||||
[:span {:class (stl/css :group-title) :title (tr "workspace.token.group-name")}
|
[:div {:class (stl/css :group-title) :title (str (tr "workspace.token.group-name") ": " group)}
|
||||||
[:> icon* {:icon-id "group"}]
|
[:> icon* {:icon-id "group" :class (stl/css :group-title-icon)}]
|
||||||
group]])
|
[:> text* {:as "span" :typography "body-medium" :class (stl/css :group-title-name)} group]]])
|
||||||
[:ul {:class (stl/css :theme-group-rows-wrapper)}
|
[:ul {:class (stl/css :theme-group-rows-wrapper)}
|
||||||
(for [[_ {:keys [group name] :as theme}] themes
|
(for [[_ {:keys [group name] :as theme}] themes
|
||||||
:let [theme-id (ctob/theme-path theme)
|
:let [theme-id (ctob/theme-path theme)
|
||||||
|
@ -126,7 +126,7 @@
|
||||||
:theme-path [(:id theme) (:group theme) (:name theme)]})))]]
|
:theme-path [(:id theme) (:group theme) (:name theme)]})))]]
|
||||||
[:li {:key theme-id
|
[:li {:key theme-id
|
||||||
:class (stl/css :theme-row)}
|
:class (stl/css :theme-row)}
|
||||||
[:div {:class (stl/css :theme-row-left)}
|
[:div {:class (stl/css :theme-switch-row)}
|
||||||
|
|
||||||
;; FIXME: FIREEEEEEEEEE THIS
|
;; FIXME: FIREEEEEEEEEE THIS
|
||||||
[:div {:on-click (fn [e]
|
[:div {:on-click (fn [e]
|
||||||
|
@ -135,11 +135,12 @@
|
||||||
(st/emit! (wdt/toggle-token-theme-active? group name)))}
|
(st/emit! (wdt/toggle-token-theme-active? group name)))}
|
||||||
[:& switch {:name (tr "workspace.token.theme-name" name)
|
[:& switch {:name (tr "workspace.token.theme-name" name)
|
||||||
:on-change (constantly nil)
|
:on-change (constantly nil)
|
||||||
:selected? selected?}]]
|
:selected? selected?}]]]
|
||||||
[:> text* {:as "span" :typography "body-medium" :class (stl/css :theme-name)} name]]
|
[:div {:class (stl/css :theme-name-row)}
|
||||||
|
[:> text* {:as "span" :typography "body-medium" :class (stl/css :theme-name) :title name} name]]
|
||||||
|
|
||||||
|
|
||||||
[:div {:class (stl/css :theme-row-right)}
|
[:div {:class (stl/css :theme-actions-row)}
|
||||||
(let [sets-count (some-> theme :sets seq count)]
|
(let [sets-count (some-> theme :sets seq count)]
|
||||||
[:> button* {:class (stl/css-case :sets-count-button sets-count
|
[:> button* {:class (stl/css-case :sets-count-button sets-count
|
||||||
:sets-count-empty-button (not sets-count))
|
:sets-count-empty-button (not sets-count))
|
||||||
|
@ -205,6 +206,7 @@
|
||||||
[:> input-tokens* {:id "theme-input"
|
[:> input-tokens* {:id "theme-input"
|
||||||
:label (tr "workspace.token.label.theme")
|
:label (tr "workspace.token.label.theme")
|
||||||
:type "text"
|
:type "text"
|
||||||
|
:max-length 256
|
||||||
:placeholder (tr "workspace.token.label.theme-placeholder")
|
:placeholder (tr "workspace.token.label.theme-placeholder")
|
||||||
:on-change on-update-name
|
:on-change on-update-name
|
||||||
:value (mf/ref-val theme-name-ref)
|
:value (mf/ref-val theme-name-ref)
|
||||||
|
|
|
@ -32,8 +32,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.themes-modal-wrapper {
|
.themes-modal-wrapper {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-rows: 0fr minmax(0, 1fr);
|
flex-direction: column;
|
||||||
gap: $s-16;
|
gap: $s-16;
|
||||||
max-height: $s-688;
|
max-height: $s-688;
|
||||||
}
|
}
|
||||||
|
@ -120,6 +120,15 @@
|
||||||
gap: $s-4;
|
gap: $s-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.group-title-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-title-name {
|
||||||
|
flex-grow: 1;
|
||||||
|
@include textEllipsis;
|
||||||
|
}
|
||||||
|
|
||||||
.theme-group-rows-wrapper {
|
.theme-group-rows-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -136,26 +145,26 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-row {
|
.theme-row {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: $s-12;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
gap: $s-16;
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-row-left {
|
.theme-name-row {
|
||||||
display: flex;
|
@include textEllipsis;
|
||||||
align-items: center;
|
flex-grow: 1;
|
||||||
gap: $s-16;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-name {
|
.theme-name {
|
||||||
color: var(--color-foreground-primary);
|
color: var(--color-foreground-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-row-right {
|
.theme-actions-row {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
gap: $s-6;
|
gap: $s-6;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sets-count-button {
|
.sets-count-button {
|
||||||
|
|
|
@ -94,6 +94,7 @@
|
||||||
:type "text"
|
:type "text"
|
||||||
:on-blur on-submit
|
:on-blur on-submit
|
||||||
:on-key-down on-key-down
|
:on-key-down on-key-down
|
||||||
|
:maxlength "256"
|
||||||
:auto-focus true
|
:auto-focus true
|
||||||
:placeholder (tr "workspace.token.set-edit-placeholder")
|
:placeholder (tr "workspace.token.set-edit-placeholder")
|
||||||
:default-value default-value}]))
|
:default-value default-value}]))
|
||||||
|
@ -226,6 +227,7 @@
|
||||||
:on-submit on-edit-submit'}]
|
:on-submit on-edit-submit'}]
|
||||||
[:*
|
[:*
|
||||||
[:div {:class (stl/css :set-name)
|
[:div {:class (stl/css :set-name)
|
||||||
|
:title label
|
||||||
:on-double-click on-double-click
|
:on-double-click on-double-click
|
||||||
:id label-id}
|
:id label-id}
|
||||||
label]
|
label]
|
||||||
|
@ -498,7 +500,7 @@
|
||||||
(when (fn? on-start-edition)
|
(when (fn? on-start-edition)
|
||||||
(on-start-edition v))))]
|
(on-start-edition v))))]
|
||||||
|
|
||||||
[:fieldset {:class (stl/css :sets-list)}
|
[:div {:class (stl/css :sets-list)}
|
||||||
(if ^boolean empty-state?
|
(if ^boolean empty-state?
|
||||||
[:> text* {:as "span" :typography "body-small" :class (stl/css :empty-state-message-sets)}
|
[:> text* {:as "span" :typography "body-small" :class (stl/css :empty-state-message-sets)}
|
||||||
(tr "workspace.token.no-sets-create")]
|
(tr "workspace.token.no-sets-create")]
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
|
flex-shrink: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: $s-20;
|
width: $s-20;
|
||||||
|
@ -82,6 +83,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox-style {
|
.checkbox-style {
|
||||||
|
flex-shrink: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
[app.util.i18n :refer [tr]]
|
[app.util.i18n :refer [tr]]
|
||||||
[app.util.webapi :as wapi]
|
[app.util.webapi :as wapi]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
|
[cuerdas.core :as str]
|
||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
[potok.v2.core :as ptk]
|
[potok.v2.core :as ptk]
|
||||||
[rumext.v2 :as mf]
|
[rumext.v2 :as mf]
|
||||||
|
@ -319,8 +320,7 @@
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
[:& token-context-menu]
|
[:& token-context-menu]
|
||||||
[:& title-bar {:all-clickable true
|
[:span {:class (stl/css :sets-header)} (tr "workspace.token.tokens-section-title" selected-token-set-name)]
|
||||||
:title (tr "workspace.token.tokens-section-title" selected-token-set-name)}]
|
|
||||||
|
|
||||||
(for [type filled-group]
|
(for [type filled-group]
|
||||||
(let [tokens (get tokens-by-type type)]
|
(let [tokens (get tokens-by-type type)]
|
||||||
|
@ -368,9 +368,10 @@
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [file (-> (dom/get-target event)
|
(let [file (-> (dom/get-target event)
|
||||||
(dom/get-files)
|
(dom/get-files)
|
||||||
(first))]
|
(first))
|
||||||
|
file-name (str/replace (.-name file) ".json" "")]
|
||||||
(->> (wapi/read-file-as-text file)
|
(->> (wapi/read-file-as-text file)
|
||||||
(sd/process-json-stream)
|
(sd/process-json-stream {:file-name file-name})
|
||||||
(rx/subs! (fn [lib]
|
(rx/subs! (fn [lib]
|
||||||
(st/emit! (ptk/data-event ::ev/event {::ev/name "import-tokens"})
|
(st/emit! (ptk/data-event ::ev/event {::ev/name "import-tokens"})
|
||||||
(dt/import-tokens-lib lib)))
|
(dt/import-tokens-lib lib)))
|
||||||
|
@ -439,6 +440,7 @@
|
||||||
[:div {:class (stl/css :resize-area-horiz)
|
[:div {:class (stl/css :resize-area-horiz)
|
||||||
:on-pointer-down on-pointer-down-pages
|
:on-pointer-down on-pointer-down-pages
|
||||||
:on-lost-pointer-capture on-lost-pointer-capture-pages
|
:on-lost-pointer-capture on-lost-pointer-capture-pages
|
||||||
:on-pointer-move on-pointer-move-pages}]
|
:on-pointer-move on-pointer-move-pages}
|
||||||
|
[:div {:class (stl/css :resize-handle-horiz)}]]
|
||||||
[:> tokens-section* {:tokens-lib tokens-lib}]]
|
[:> tokens-section* {:tokens-lib tokens-lib}]]
|
||||||
[:> import-export-button*]]))
|
[:> import-export-button*]]))
|
||||||
|
|
|
@ -38,12 +38,17 @@
|
||||||
padding-block-end: $s-16;
|
padding-block-end: $s-16;
|
||||||
}
|
}
|
||||||
|
|
||||||
.themes-header {
|
.themes-header,
|
||||||
|
.sets-header {
|
||||||
@include use-typography("headline-small");
|
@include use-typography("headline-small");
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: $s-8;
|
padding: $s-8;
|
||||||
padding-left: $s-8;
|
|
||||||
color: var(--title-foreground-color);
|
color: var(--title-foreground-color);
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sets-header {
|
||||||
|
margin-block-start: $s-8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.themes-wrapper {
|
.themes-wrapper {
|
||||||
|
@ -170,6 +175,12 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
padding: $s-3 0 $s-1 0;
|
||||||
|
height: $s-6;
|
||||||
|
cursor: ns-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-handle-horiz {
|
||||||
border-bottom: $s-2 solid var(--resize-area-border-color);
|
border-bottom: $s-2 solid var(--resize-area-border-color);
|
||||||
cursor: ns-resize;
|
cursor: ns-resize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.common.types.tokens-lib :as ctob]
|
[app.common.types.tokens-lib :as ctob]
|
||||||
|
[app.main.refs :as refs]
|
||||||
[app.main.ui.workspace.tokens.errors :as wte]
|
[app.main.ui.workspace.tokens.errors :as wte]
|
||||||
[app.main.ui.workspace.tokens.tinycolor :as tinycolor]
|
[app.main.ui.workspace.tokens.tinycolor :as tinycolor]
|
||||||
[app.main.ui.workspace.tokens.token :as wtt]
|
[app.main.ui.workspace.tokens.token :as wtt]
|
||||||
|
@ -249,33 +250,51 @@
|
||||||
(= header-2 "Reference Errors:"))
|
(= header-2 "Reference Errors:"))
|
||||||
errors)))
|
errors)))
|
||||||
|
|
||||||
(defn process-json-stream [data-stream]
|
(defn process-json-stream
|
||||||
(->> data-stream
|
([data-stream]
|
||||||
(rx/map (fn [data]
|
(process-json-stream nil data-stream))
|
||||||
(try
|
([params data-stream]
|
||||||
(t/decode-str data)
|
(let [{:keys [file-name]} params]
|
||||||
(catch js/Error e
|
(->> data-stream
|
||||||
(throw (wte/error-ex-info :error.import/json-parse-error data e))))))
|
(rx/map (fn [data]
|
||||||
(rx/map (fn [json-data]
|
|
||||||
(try
|
|
||||||
(if-not (ctob/has-legacy-format? json-data)
|
|
||||||
(ctob/decode-dtcg-json (ctob/ensure-tokens-lib nil) json-data)
|
|
||||||
(ctob/decode-legacy-json (ctob/ensure-tokens-lib nil) json-data))
|
|
||||||
(catch js/Error e
|
|
||||||
(throw (wte/error-ex-info :error.import/invalid-json-data json-data e))))))
|
|
||||||
(rx/mapcat (fn [tokens-lib]
|
|
||||||
(try
|
(try
|
||||||
(-> (ctob/get-all-tokens tokens-lib)
|
(t/decode-str data)
|
||||||
(resolve-tokens-with-errors+)
|
|
||||||
(p/then (fn [_] tokens-lib))
|
|
||||||
(p/catch (fn [sd-error]
|
|
||||||
(let [reference-errors (reference-errors sd-error)
|
|
||||||
err (if reference-errors
|
|
||||||
(wte/error-ex-info :error.import/style-dictionary-reference-errors reference-errors sd-error)
|
|
||||||
(wte/error-ex-info :error.import/style-dictionary-unknown-error sd-error sd-error))]
|
|
||||||
(throw err)))))
|
|
||||||
(catch js/Error e
|
(catch js/Error e
|
||||||
(p/rejected (wte/error-ex-info :error.import/style-dictionary-unknown-error "" e))))))))
|
(throw (wte/error-ex-info :error.import/json-parse-error data e))))))
|
||||||
|
(rx/map (fn [json-data]
|
||||||
|
(let [single-set? (ctob/single-set? json-data)
|
||||||
|
json-format (ctob/get-json-format json-data)]
|
||||||
|
(try
|
||||||
|
(cond
|
||||||
|
(and single-set?
|
||||||
|
(= :json-format/legacy json-format))
|
||||||
|
(ctob/decode-single-set-legacy-json (ctob/ensure-tokens-lib (deref refs/tokens-lib)) file-name json-data)
|
||||||
|
|
||||||
|
(and single-set?
|
||||||
|
(= :json-format/dtcg json-format))
|
||||||
|
(ctob/decode-single-set-json (ctob/ensure-tokens-lib (deref refs/tokens-lib)) file-name json-data)
|
||||||
|
|
||||||
|
(= :json-format/legacy json-format)
|
||||||
|
(ctob/decode-legacy-json (ctob/ensure-tokens-lib nil) json-data)
|
||||||
|
|
||||||
|
:else
|
||||||
|
(ctob/decode-dtcg-json (ctob/ensure-tokens-lib nil) json-data))
|
||||||
|
|
||||||
|
(catch js/Error e
|
||||||
|
(throw (wte/error-ex-info :error.import/invalid-json-data json-data e)))))))
|
||||||
|
(rx/mapcat (fn [tokens-lib]
|
||||||
|
(try
|
||||||
|
(-> (ctob/get-all-tokens tokens-lib)
|
||||||
|
(resolve-tokens-with-errors+)
|
||||||
|
(p/then (fn [_] tokens-lib))
|
||||||
|
(p/catch (fn [sd-error]
|
||||||
|
(let [reference-errors (reference-errors sd-error)
|
||||||
|
err (if reference-errors
|
||||||
|
(wte/error-ex-info :error.import/style-dictionary-reference-errors reference-errors sd-error)
|
||||||
|
(wte/error-ex-info :error.import/style-dictionary-unknown-error sd-error sd-error))]
|
||||||
|
(throw err)))))
|
||||||
|
(catch js/Error e
|
||||||
|
(p/rejected (wte/error-ex-info :error.import/style-dictionary-unknown-error "" e))))))))))
|
||||||
|
|
||||||
;; === Errors
|
;; === Errors
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
:sub-item grouped?
|
:sub-item grouped?
|
||||||
:is-selected selected?)
|
:is-selected selected?)
|
||||||
:on-click select-theme}
|
:on-click select-theme}
|
||||||
[:> text* {:as "span" :typography "body-small" :class (stl/css :label)} name]
|
[:> text* {:as "span" :typography "body-small" :class (stl/css :label) :title name} name]
|
||||||
[:> icon* {:icon-id i/tick
|
[:> icon* {:icon-id i/tick
|
||||||
:aria-hidden true
|
:aria-hidden true
|
||||||
:class (stl/css-case :check-icon true
|
:class (stl/css-case :check-icon true
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
:aria-labelledby (dm/str group "-label")
|
:aria-labelledby (dm/str group "-label")
|
||||||
:role "group"}
|
:role "group"}
|
||||||
(when (seq group)
|
(when (seq group)
|
||||||
[:> text* {:as "span" :typography "headline-small" :class (stl/css :group) :id (dm/str group "-label")} 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
|
[:& themes-list {:themes themes
|
||||||
:active-theme-paths active-theme-paths
|
:active-theme-paths active-theme-paths
|
||||||
:on-close on-close
|
:on-close on-close
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.group {
|
.group {
|
||||||
|
@include textEllipsis;
|
||||||
display: block;
|
display: block;
|
||||||
padding: $s-8;
|
padding: $s-8;
|
||||||
color: var(--color-foreground-secondary);
|
color: var(--color-foreground-secondary);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue