Compare commits
78 Commits
2.14.0-RC1
...
azazeln28-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2e689a645 | ||
|
|
32d4026641 | ||
|
|
4477b2b4a0 | ||
|
|
9e51fa198a | ||
|
|
d176da8012 | ||
|
|
20862c2da3 | ||
|
|
1b8afccba2 | ||
|
|
dd856ecf50 | ||
|
|
f4e79af3cd | ||
|
|
3e758826fe | ||
|
|
2cf66c948d | ||
|
|
145198c148 | ||
|
|
eddfc4c4b2 | ||
|
|
e6e34af391 | ||
|
|
4ee908fc89 | ||
|
|
bdcf448f3f | ||
|
|
c58054d19c | ||
|
|
a7ab506c5c | ||
|
|
c7f644ab2a | ||
|
|
3d41dc276e | ||
|
|
cb5cacbcee | ||
|
|
337cfc2d3e | ||
|
|
c2ee31e791 | ||
|
|
360937f613 | ||
|
|
f6d0414449 | ||
|
|
4d05827fa9 | ||
|
|
48fb9fa6ea | ||
|
|
cee974a906 | ||
|
|
c74cf3fa37 | ||
|
|
7c1ddd3d7d | ||
|
|
4965f6d859 | ||
|
|
a3cd90da7f | ||
|
|
2b130c7e52 | ||
|
|
a1a7f643ec | ||
|
|
70013fde74 | ||
|
|
916107ce04 | ||
|
|
8eb5bd3dd8 | ||
|
|
5718698bff | ||
|
|
c41b9214c5 | ||
|
|
fb80c8f45b | ||
|
|
009dc4485a | ||
|
|
b8f3bee3ac | ||
|
|
f00b222262 | ||
|
|
b28457860c | ||
|
|
23b268b414 | ||
|
|
32706a1460 | ||
|
|
cd4b9ddd47 | ||
|
|
f0e3f1a319 | ||
|
|
afb252f42e | ||
|
|
4185a7a6f3 | ||
|
|
0dda7bd9ee | ||
|
|
30106f8524 | ||
|
|
7ef16a2b69 | ||
|
|
137febcbab | ||
|
|
f98c0bbd16 | ||
|
|
71ec51919e | ||
|
|
1cb113dfeb | ||
|
|
b45aec13ab | ||
|
|
7f3212d5a4 | ||
|
|
19592fadd8 | ||
|
|
643cd6f61f | ||
|
|
0b2dfe7297 | ||
|
|
fe6fb0534c | ||
|
|
f2d09a6140 | ||
|
|
5ae2351e5a | ||
|
|
b5f4ce0a71 | ||
|
|
166dc05ff2 | ||
|
|
619e2387dc | ||
|
|
813c804d45 | ||
|
|
63f0c68977 | ||
|
|
1f2a234458 | ||
|
|
b281870c50 | ||
|
|
3909bc0fc1 | ||
|
|
b6427ecaac | ||
|
|
e82319c49e | ||
|
|
ce63bae92d | ||
|
|
1349789a7b | ||
|
|
d7203ef24c |
13
CHANGES.md
@@ -3,10 +3,7 @@
|
||||
## 2.14.0 (Unreleased)
|
||||
|
||||
### :boom: Breaking changes & Deprecations
|
||||
|
||||
### :rocket: Epics and highlights
|
||||
|
||||
### :heart: Community contributions (Thank you!)
|
||||
- Deprecate `PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE` in favour of `PENPOT_HTTP_SERVER_MAX_BODY_SIZE`.
|
||||
|
||||
### :sparkles: New features & Enhancements
|
||||
|
||||
@@ -35,12 +32,18 @@
|
||||
- Fix viewer can update library [Taiga #13186](https://tree.taiga.io/project/penpot/issue/13186)
|
||||
- Fix remove fill affects different element than selected [Taiga #13128](https://tree.taiga.io/project/penpot/issue/13128)
|
||||
|
||||
## 2.13.3
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
- Revert yetti (http server) update, because that caused a regression on multipart uploads
|
||||
|
||||
## 2.13.2
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
- Fix modifying shapes by apply negative tokens to border radius [Taiga #13317](https://tree.taiga.io/project/penpot/issue/13317)
|
||||
- Fix security issue (Path Traversal Vulnerability) on fonts related RPC method
|
||||
- Fix arbitrary file read security issue on create-font-variant rpc method (https://github.com/penpot/penpot/security/advisories/GHSA-xp3f-g8rq-9px2)
|
||||
|
||||
|
||||
## 2.13.1
|
||||
|
||||
@@ -98,7 +98,6 @@
|
||||
[:http-server-port {:optional true} ::sm/int]
|
||||
[:http-server-host {:optional true} :string]
|
||||
[:http-server-max-body-size {:optional true} ::sm/int]
|
||||
[:http-server-max-multipart-body-size {:optional true} ::sm/int]
|
||||
[:http-server-io-threads {:optional true} ::sm/int]
|
||||
[:http-server-max-worker-threads {:optional true} ::sm/int]
|
||||
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
(def default-params
|
||||
{::port 6060
|
||||
::host "0.0.0.0"
|
||||
::max-body-size 31457280 ; default 30 MiB
|
||||
::max-multipart-body-size 367001600}) ; default 350 MiB
|
||||
::max-body-size 367001600 ; default 350 MiB
|
||||
})
|
||||
|
||||
(defmethod ig/expand-key ::server
|
||||
[k v]
|
||||
@@ -56,7 +56,6 @@
|
||||
[::io-threads {:optional true} ::sm/int]
|
||||
[::max-worker-threads {:optional true} ::sm/int]
|
||||
[::max-body-size {:optional true} ::sm/int]
|
||||
[::max-multipart-body-size {:optional true} ::sm/int]
|
||||
[::router {:optional true} [:fn r/router?]]
|
||||
[::handler {:optional true} ::sm/fn]])
|
||||
|
||||
@@ -79,7 +78,7 @@
|
||||
{:http/port port
|
||||
:http/host host
|
||||
:http/max-body-size (::max-body-size cfg)
|
||||
:http/max-multipart-body-size (::max-multipart-body-size cfg)
|
||||
:http/max-multipart-body-size (::max-body-size cfg)
|
||||
:xnio/direct-buffers false
|
||||
:xnio/io-threads (::io-threads cfg)
|
||||
:xnio/max-worker-threads (::max-worker-threads cfg)
|
||||
|
||||
@@ -226,11 +226,10 @@
|
||||
::http/server
|
||||
{::http/port (cf/get :http-server-port)
|
||||
::http/host (cf/get :http-server-host)
|
||||
::http/router (ig/ref ::http/router)
|
||||
::http/io-threads (cf/get :http-server-io-threads)
|
||||
::http/max-worker-threads (cf/get :http-server-max-worker-threads)
|
||||
::http/max-body-size (cf/get :http-server-max-body-size)
|
||||
::http/max-multipart-body-size (cf/get :http-server-max-multipart-body-size)
|
||||
::http/router (ig/ref ::http/router)
|
||||
::mtx/metrics (ig/ref ::mtx/metrics)}
|
||||
|
||||
::ldap/provider
|
||||
|
||||
@@ -605,31 +605,31 @@
|
||||
add-undo-change-shape
|
||||
(fn [change-set id]
|
||||
(let [shape (get objects id)]
|
||||
(conj
|
||||
change-set
|
||||
{:type :add-obj
|
||||
:id id
|
||||
:page-id page-id
|
||||
:parent-id (:parent-id shape)
|
||||
:frame-id (:frame-id shape)
|
||||
:index (cfh/get-position-on-parent objects id)
|
||||
:obj (cond-> shape
|
||||
(contains? shape :shapes)
|
||||
(assoc :shapes []))})))
|
||||
(cond-> change-set
|
||||
(some? shape)
|
||||
(conj {:type :add-obj
|
||||
:id id
|
||||
:page-id page-id
|
||||
:parent-id (:parent-id shape)
|
||||
:frame-id (:frame-id shape)
|
||||
:index (cfh/get-position-on-parent objects id)
|
||||
:obj (cond-> shape
|
||||
(contains? shape :shapes)
|
||||
(assoc :shapes []))}))))
|
||||
|
||||
add-undo-change-parent
|
||||
(fn [change-set id]
|
||||
(let [shape (get objects id)
|
||||
prev-sibling (cfh/get-prev-sibling objects (:id shape))]
|
||||
(conj
|
||||
change-set
|
||||
{:type :mov-objects
|
||||
:page-id page-id
|
||||
:parent-id (:parent-id shape)
|
||||
:shapes [id]
|
||||
:after-shape prev-sibling
|
||||
:index 0
|
||||
:ignore-touched true})))]
|
||||
(cond-> change-set
|
||||
(some? shape)
|
||||
(conj {:type :mov-objects
|
||||
:page-id page-id
|
||||
:parent-id (:parent-id shape)
|
||||
:shapes [id]
|
||||
:after-shape prev-sibling
|
||||
:index 0
|
||||
:ignore-touched true}))))]
|
||||
|
||||
(-> changes
|
||||
(update :redo-changes #(reduce add-redo-change % ids))
|
||||
@@ -1150,3 +1150,24 @@
|
||||
[changes]
|
||||
(::page-id (meta changes)))
|
||||
|
||||
|
||||
(defn set-text-content
|
||||
[changes id content prev-content]
|
||||
(assert-page-id! changes)
|
||||
(let [page-id (::page-id (meta changes))
|
||||
|
||||
redo-change
|
||||
{:type :mod-obj
|
||||
:page-id page-id
|
||||
:id id
|
||||
:operations [{:type :set :attr :content :val content}]}
|
||||
|
||||
undo-change
|
||||
{:type :mod-obj
|
||||
:page-id page-id
|
||||
:id id
|
||||
:operations [{:type :set :attr :content :val prev-content}]}]
|
||||
|
||||
(-> changes
|
||||
(update :redo-changes conj redo-change)
|
||||
(update :undo-changes conj undo-change))))
|
||||
|
||||
@@ -50,6 +50,7 @@ services:
|
||||
- 4400:4400
|
||||
- 4401:4401
|
||||
- 4402:4402
|
||||
- 4403:4403
|
||||
|
||||
# Plugins
|
||||
- 4200:4200
|
||||
|
||||
@@ -68,7 +68,7 @@ RUN set -eux; \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
--strip-debug \
|
||||
--add-modules java.base,jdk.management.agent,java.se,jdk.compiler,jdk.javadoc,jdk.attach,jdk.unsupported \
|
||||
--add-modules java.base,jdk.management.agent,java.se,jdk.compiler,jdk.javadoc,jdk.attach,jdk.unsupported,jdk.jfr,jdk.jcmd \
|
||||
--output /opt/jre;
|
||||
|
||||
FROM ubuntu:24.04 AS image
|
||||
|
||||
@@ -5,7 +5,8 @@ ENV LANG=en_US.UTF-8 \
|
||||
LC_ALL=en_US.UTF-8 \
|
||||
NODE_VERSION=v22.22.0 \
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
PATH=/opt/node/bin:/opt/imagick/bin:$PATH
|
||||
PATH=/opt/node/bin:/opt/imagick/bin:$PATH \
|
||||
PLAYWRIGHT_BROWSERS_PATH=/opt/penpot/browsers
|
||||
|
||||
RUN set -ex; \
|
||||
useradd -U -M -u 1001 -s /bin/false -d /opt/penpot penpot; \
|
||||
|
||||
@@ -30,11 +30,9 @@ x-uri: &penpot-public-uri
|
||||
PENPOT_PUBLIC_URI: http://localhost:9001
|
||||
|
||||
x-body-size: &penpot-http-body-size
|
||||
# Max body size (30MiB); Used for plain requests, should never be
|
||||
# greater than multi-part size
|
||||
PENPOT_HTTP_SERVER_MAX_BODY_SIZE: 31457280
|
||||
|
||||
# Max multipart body size (350MiB)
|
||||
# Max body size
|
||||
PENPOT_HTTP_SERVER_MAX_BODY_SIZE: 367001600
|
||||
# Deprecation warning: this variable is deprecated. Use PENPOT_HTTP_SERVER_MAX_BODY (defaults to 367001600)
|
||||
PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE: 367001600
|
||||
|
||||
## Penpot SECRET KEY. It serves as a master key from which other keys for subsystems
|
||||
|
||||
@@ -30,8 +30,8 @@ update_flags /var/www/app/js/config.js
|
||||
export PENPOT_BACKEND_URI=${PENPOT_BACKEND_URI:-http://penpot-backend:6060}
|
||||
export PENPOT_EXPORTER_URI=${PENPOT_EXPORTER_URI:-http://penpot-exporter:6061}
|
||||
export PENPOT_NITRATE_URI=${PENPOT_NITRATE_URI:-http://penpot-nitrate:3000}
|
||||
export PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE=${PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE:-367001600} # Default to 350MiB
|
||||
envsubst "\$PENPOT_BACKEND_URI,\$PENPOT_EXPORTER_URI,\$PENPOT_NITRATE_URI,\$PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE" \
|
||||
export PENPOT_HTTP_SERVER_MAX_BODY_SIZE=${PENPOT_HTTP_SERVER_MAX_BODY_SIZE:-367001600} # Default to 350MiB
|
||||
envsubst "\$PENPOT_BACKEND_URI,\$PENPOT_EXPORTER_URI,\$PENPOT_NITRATE_URI,\$PENPOT_HTTP_SERVER_MAX_BODY_SIZE" \
|
||||
< /tmp/nginx.conf.template > /etc/nginx/nginx.conf
|
||||
|
||||
PENPOT_DEFAULT_INTERNAL_RESOLVER="$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf)"
|
||||
|
||||
@@ -76,7 +76,7 @@ http {
|
||||
listen [::]:8080 default_server;
|
||||
server_name _;
|
||||
|
||||
client_max_body_size $PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE;
|
||||
client_max_body_size $PENPOT_HTTP_SERVER_MAX_BODY_SIZE;
|
||||
charset utf-8;
|
||||
|
||||
etag off;
|
||||
|
||||
@@ -188,8 +188,8 @@ server {
|
||||
server_name penpot.mycompany.com;
|
||||
|
||||
# This value should be in sync with the corresponding in the docker-compose.yml
|
||||
# PENPOT_HTTP_SERVER_MAX_BODY_SIZE: 31457280
|
||||
client_max_body_size 31457280;
|
||||
# PENPOT_HTTP_SERVER_MAX_BODY_SIZE: 367001600
|
||||
client_max_body_size 367001600;
|
||||
|
||||
# Logs: Configure your logs following the best practices inside your company
|
||||
access_log /path/to/penpot.access.log;
|
||||
|
||||
@@ -15,6 +15,7 @@ pnpm run build;
|
||||
|
||||
cp pnpm-lock.yaml target/;
|
||||
cp package.json target/;
|
||||
touch target/pnpm-workspace.yaml;
|
||||
|
||||
cat <<EOF | tee target/setup
|
||||
#/usr/bin/env bash
|
||||
@@ -22,7 +23,7 @@ set -e;
|
||||
corepack enable;
|
||||
corepack install;
|
||||
pnpm install
|
||||
pnpx playwright install chromium;
|
||||
pnpm exec playwright install chromium;
|
||||
EOF
|
||||
|
||||
chmod +x target/setup;
|
||||
|
||||
@@ -40,14 +40,16 @@
|
||||
"watch:app:libs": "node ./scripts/build-libs.js --watch",
|
||||
"watch:app:main": "clojure -M:dev:shadow-cljs watch main worker storybook",
|
||||
"clear:shadow-cache": "rm -rf .shadow-cljs",
|
||||
"clear:wasm": "cargo clean --manifest-path ../render-wasm/Cargo.toml",
|
||||
"watch": "exit 0",
|
||||
"watch:app": "pnpm run clear:shadow-cache && pnpm run build:wasm && concurrently --kill-others-on-fail \"pnpm run watch:app:assets\" \"pnpm run watch:app:main\" \"pnpm run watch:app:libs\"",
|
||||
"watch:storybook": "pnpm run build:storybook:assets && concurrently --kill-others-on-fail \"storybook dev -p 6006 --no-open\" \"node ./scripts/watch-storybook.js\""
|
||||
"watch:app": "pnpm run clear:shadow-cache && pnpm run clear:wasm && pnpm run build:wasm && concurrently --kill-others-on-fail \"pnpm run watch:app:assets\" \"pnpm run watch:app:main\" \"pnpm run watch:app:libs\"",
|
||||
"watch:storybook": "pnpm run build:storybook:assets && concurrently --kill-others-on-fail \"storybook dev -p 6006 --no-open\" \"node ./scripts/watch-storybook.js\"",
|
||||
"postinstall": "(cd ../plugins/libs/plugins-runtime; pnpm install; pnpm run build)"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@penpot/draft-js": "workspace:./packages/draft-js",
|
||||
"@penpot/mousetrap": "workspace:./packages/mousetrap",
|
||||
"@penpot/plugins-runtime": "1.4.2",
|
||||
"@penpot/plugins-runtime": "link:../plugins/dist/plugins-runtime",
|
||||
"@penpot/svgo": "penpot/svgo#v3.2",
|
||||
"@penpot/text-editor": "workspace:./text-editor",
|
||||
"@penpot/tokenscript": "workspace:./packages/tokenscript",
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
[
|
||||
{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"variants/v1",
|
||||
"layout/grid",
|
||||
"styles/v2",
|
||||
"fdata/pointer-map",
|
||||
"fdata/objects-map",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type"
|
||||
]
|
||||
},
|
||||
"~:permissions": {
|
||||
"~:type": "~:membership",
|
||||
"~:is-owner": true,
|
||||
"~:is-admin": true,
|
||||
"~:can-edit": true
|
||||
},
|
||||
"~:name": "Default",
|
||||
"~:modified-at": "~m1713533116375",
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38e630f7920a",
|
||||
"~:created-at": "~m1713533116375",
|
||||
"~:is-default": true
|
||||
}
|
||||
]
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"~:email": "foo@example.com",
|
||||
"~:is-demo": false,
|
||||
"~:auth-backend": "penpot",
|
||||
"~:fullname": "Princesa Leia",
|
||||
"~:modified-at": "~m1713533116365",
|
||||
"~:is-active": true,
|
||||
"~:default-project-id": "~uc7ce0794-0992-8105-8004-38e630f7920b",
|
||||
"~:id": "~uc7ce0794-0992-8105-8004-38e630f29a9b",
|
||||
"~:is-muted": false,
|
||||
"~:default-team-id": "~uc7ce0794-0992-8105-8004-38e630f40f6d",
|
||||
"~:created-at": "~m1713533116365",
|
||||
"~:is-blocked": false,
|
||||
"~:props": {
|
||||
"~:nudge": {
|
||||
"~:big": 10,
|
||||
"~:small": 1
|
||||
},
|
||||
"~:v2-info-shown": true,
|
||||
"~:viewed-tutorial?": false,
|
||||
"~:viewed-walkthrough?": false,
|
||||
"~:onboarding-viewed": true,
|
||||
"~:builtin-templates-collapsed-status":
|
||||
true
|
||||
}
|
||||
}
|
||||
1161
frontend/playwright/data/render-wasm/get-solid-shadows.json
Normal file
2826
frontend/playwright/data/render-wasm/get-solid-strokes-shadows.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"~:file-id": "~u52c4e771-3853-8190-8007-9506c70e8100",
|
||||
"~:id": "~u4173a29d-4020-80b4-8007-96527ba9d8af",
|
||||
"~:created-at": "~m1771342236330",
|
||||
"~:modified-at": "~m1771342236330",
|
||||
"~:type": "fragment",
|
||||
"~:backend": "db",
|
||||
"~:data": {
|
||||
"~:id": "~uecb0cfd0-0f0b-81f7-8007-950628f9665b",
|
||||
"~:name": "Page 1",
|
||||
"~:objects": {
|
||||
"~#penpot/objects-map/v2": {
|
||||
"~ude9c6736-45ce-80a1-8007-950643da554d": "[\"~#shape\",[\"^ \",\"~:y\",383.99998939037323,\"~: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\",\"R1\",\"~:width\",74,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",831.999992787838,\"~:y\",383.99998939037323]],[\"^<\",[\"^ \",\"~:x\",905.999992787838,\"~:y\",383.99998939037323]],[\"^<\",[\"^ \",\"~:x\",905.999992787838,\"~:y\",429.99998664855957]],[\"^<\",[\"^ \",\"~:x\",831.999992787838,\"~:y\",429.99998664855957]]],\"~: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]],\"~:page-id\",\"~uecb0cfd0-0f0b-81f7-8007-950628f9665b\",\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~ude9c6736-45ce-80a1-8007-950643da554d\",\"~:parent-id\",\"~ude9c6736-45ce-80a1-8007-95063a202e52\",\"~:frame-id\",\"~ude9c6736-45ce-80a1-8007-95063a202e52\",\"~:strokes\",[],\"~:x\",831.999992787838,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",831.999992787838,\"~:y\",383.99998939037323,\"^8\",74,\"~:height\",45.99999725818634,\"~:x1\",831.999992787838,\"~:y1\",383.99998939037323,\"~:x2\",905.999992787838,\"~:y2\",429.99998664855957]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^K\",45.99999725818634,\"~:flip-y\",null]]",
|
||||
"~ude9c6736-45ce-80a1-8007-95065b4599ea": "[\"~#shape\",[\"^ \",\"~:y\",439.999969256975,\"~: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\",\"R2\",\"~:width\",300.00007388362076,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",832.0000015918991,\"~:y\",439.99996925697496]],[\"^<\",[\"^ \",\"~:x\",1132.00007547552,\"~:y\",439.99996925697496]],[\"^<\",[\"^ \",\"~:x\",1132.00007547552,\"~:y\",589.9999658711585]],[\"^<\",[\"^ \",\"~:x\",832.0000015918991,\"~:y\",589.9999658711585]]],\"~:r2\",0,\"~:layout-item-h-sizing\",\"~:fix\",\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^2\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~uecb0cfd0-0f0b-81f7-8007-950628f9665b\",\"~:layout-item-v-sizing\",\"^?\",\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~ude9c6736-45ce-80a1-8007-95065b4599ea\",\"~:parent-id\",\"~ude9c6736-45ce-80a1-8007-95063a202e52\",\"~:frame-id\",\"~ude9c6736-45ce-80a1-8007-95063a202e52\",\"~:strokes\",[],\"~:x\",832.0000015918993,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",832.0000015918993,\"~:y\",439.999969256975,\"^8\",300.00007388362076,\"~:height\",149.9999966141835,\"~:x1\",832.0000015918993,\"~:y1\",439.999969256975,\"~:x2\",1132.0000754755201,\"~:y2\",589.9999658711586]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^N\",149.9999966141835,\"~:flip-y\",null]]",
|
||||
"~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]],\"~:page-id\",\"~uecb0cfd0-0f0b-81f7-8007-950628f9665b\",\"~: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,\"^I\",0.01,\"~:flip-y\",null,\"~:shapes\",[\"~ude9c6736-45ce-80a1-8007-95062aa41d6b\"]]]",
|
||||
"~ude9c6736-45ce-80a1-8007-95062aa41d6b": "[\"~#shape\",[\"^ \",\"~:y\",342.0000208153068,\"~:hide-fill-on-export\",false,\"~:layout-gap-type\",\"~:multiple\",\"~:layout-padding\",[\"^ \",\"~:p1\",0,\"~:p2\",0,\"~:p3\",0,\"~:p4\",0],\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:layout-wrap-type\",\"~:nowrap\",\"~:grow-type\",\"~:fixed\",\"~:layout\",\"~:flex\",\"~:hide-in-viewer\",false,\"~:name\",\"A\",\"~:layout-align-items\",\"~:start\",\"~:width\",392.9999889135361,\"~:layout-padding-type\",\"~:simple\",\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",787.9999763965607,\"~:y\",342.0000208153068]],[\"^L\",[\"^ \",\"~:x\",1180.9999653100967,\"~:y\",342.0000208153068]],[\"^L\",[\"^ \",\"~:x\",1180.9999653100967,\"~:y\",704.000018450968]],[\"^L\",[\"^ \",\"~:x\",787.9999763965607,\"~:y\",704.000018450968]]],\"~:r2\",0,\"~:proportion-lock\",false,\"~:layout-gap\",[\"^ \",\"~:row-gap\",0,\"~:column-gap\",0],\"~:transform-inverse\",[\"^:\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~uecb0cfd0-0f0b-81f7-8007-950628f9665b\",\"~:layout-item-v-sizing\",\"~:fix\",\"~:r3\",0,\"~:layout-justify-content\",\"^E\",\"~:r1\",0,\"~:id\",\"~ude9c6736-45ce-80a1-8007-95062aa41d6b\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:layout-flex-dir\",\"~:column\",\"~:layout-align-content\",\"~:stretch\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",787.9999763965607,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",787.9999763965607,\"~:y\",342.0000208153068,\"^F\",392.9999889135361,\"~:height\",361.9999976356612,\"~:x1\",787.9999763965607,\"~:y1\",342.0000208153068,\"~:x2\",1180.9999653100967,\"~:y2\",704.000018450968]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^19\",361.9999976356612,\"~:flip-y\",null,\"~:shapes\",[\"~ude9c6736-45ce-80a1-8007-95062fafbb88\"]]]",
|
||||
"~ude9c6736-45ce-80a1-8007-95063a202e52": "[\"~#shape\",[\"^ \",\"~:y\",374.00001145409465,\"~:hide-fill-on-export\",false,\"~:layout-gap-type\",\"~:multiple\",\"~:layout-padding\",[\"^ \",\"~:p1\",10,\"~:p2\",10,\"~:p3\",10,\"~:p4\",10],\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:layout-wrap-type\",\"~:nowrap\",\"~:grow-type\",\"~:fixed\",\"~:layout\",\"~:flex\",\"~:hide-in-viewer\",true,\"~:name\",\"C\",\"~:layout-align-items\",\"~:start\",\"~:width\",320.00009969013945,\"~:layout-padding-type\",\"~:simple\",\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",821.9999915631233,\"~:y\",374.0000114540946]],[\"^L\",[\"^ \",\"~:x\",1142.0000912532628,\"~:y\",374.0000114540946]],[\"^L\",[\"^ \",\"~:x\",1142.0000912532628,\"~:y\",600.0000518384436]],[\"^L\",[\"^ \",\"~:x\",821.9999915631233,\"~:y\",600.0000518384436]]],\"~:r2\",0,\"~:layout-item-h-sizing\",\"~:auto\",\"~:proportion-lock\",false,\"~:layout-gap\",[\"^ \",\"~:row-gap\",10,\"~:column-gap\",0],\"~:transform-inverse\",[\"^:\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~uecb0cfd0-0f0b-81f7-8007-950628f9665b\",\"~:layout-item-v-sizing\",\"^O\",\"~:r3\",0,\"~:layout-justify-content\",\"^E\",\"~:r1\",0,\"~:id\",\"~ude9c6736-45ce-80a1-8007-95063a202e52\",\"~:parent-id\",\"~ude9c6736-45ce-80a1-8007-95062fafbb88\",\"~:layout-flex-dir\",\"~:column\",\"~:layout-align-content\",\"~:stretch\",\"~:frame-id\",\"~ude9c6736-45ce-80a1-8007-95062fafbb88\",\"~:strokes\",[[\"^ \",\"~:stroke-alignment\",\"~:inner\",\"~:stroke-style\",\"~:solid\",\"~:stroke-color\",\"#000000\",\"~:stroke-opacity\",1,\"~:stroke-width\",1]],\"~:x\",821.9999915631233,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",821.9999915631233,\"~:y\",374.00001145409465,\"^F\",320.00009969013945,\"~:height\",226.000040384349,\"~:x1\",821.9999915631233,\"~:y1\",374.00001145409465,\"~:x2\",1142.0000912532628,\"~:y2\",600.0000518384436]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^1A\",226.000040384349,\"~:flip-y\",null,\"~:shapes\",[\"~ude9c6736-45ce-80a1-8007-95065b4599ea\",\"~ude9c6736-45ce-80a1-8007-950643da554d\"]]]",
|
||||
"~ude9c6736-45ce-80a1-8007-95062fafbb88": "[\"~#shape\",[\"^ \",\"~:y\",342.0000083402533,\"~:hide-fill-on-export\",false,\"~:layout-gap-type\",\"~:multiple\",\"~:layout-padding\",[\"^ \",\"~:p1\",31.999953508377075,\"~:p2\",34.000026052944804,\"~:p3\",31.999953508377075,\"~:p4\",34.000026052944804],\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:layout-wrap-type\",\"~:nowrap\",\"~:grow-type\",\"~:fixed\",\"~:layout\",\"~:flex\",\"~:hide-in-viewer\",true,\"~:name\",\"B\",\"~:layout-align-items\",\"~:start\",\"~:width\",392.9999979687366,\"~:layout-padding-type\",\"~:simple\",\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",788.0000295450811,\"~:y\",342.00000834025326]],[\"^L\",[\"^ \",\"~:x\",1181.0000275138177,\"~:y\",342.00000834025326]],[\"^L\",[\"^ \",\"~:x\",1181.0000275138177,\"~:y\",631.9999659712]],[\"^L\",[\"^ \",\"~:x\",788.0000295450811,\"~:y\",631.9999659712]]],\"~:r2\",0,\"~:layout-item-h-sizing\",\"~:fill\",\"~:proportion-lock\",false,\"~:layout-gap\",[\"^ \",\"~:row-gap\",0,\"~:column-gap\",0],\"~:transform-inverse\",[\"^:\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~uecb0cfd0-0f0b-81f7-8007-950628f9665b\",\"~:layout-item-v-sizing\",\"~:auto\",\"~:r3\",0,\"~:layout-justify-content\",\"^E\",\"~:r1\",0,\"~:id\",\"~ude9c6736-45ce-80a1-8007-95062fafbb88\",\"~:parent-id\",\"~ude9c6736-45ce-80a1-8007-95062aa41d6b\",\"~:layout-flex-dir\",\"~:column\",\"~:layout-align-content\",\"~:stretch\",\"~:frame-id\",\"~ude9c6736-45ce-80a1-8007-95062aa41d6b\",\"~:strokes\",[[\"^ \",\"~:stroke-alignment\",\"~:inner\",\"~:stroke-style\",\"~:solid\",\"~:stroke-color\",\"#000000\",\"~:stroke-opacity\",1,\"~:stroke-width\",1]],\"~:x\",788.0000295450811,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",788.0000295450811,\"~:y\",342.0000083402533,\"^F\",392.9999979687366,\"~:height\",289.99995763094677,\"~:x1\",788.0000295450811,\"~:y1\",342.0000083402533,\"~:x2\",1181.0000275138177,\"~:y2\",631.9999659712]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^1B\",289.99995763094677,\"~:flip-y\",null,\"~:shapes\",[\"~ude9c6736-45ce-80a1-8007-95063a202e52\"]]]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
131
frontend/playwright/data/workspace/get-file-13382.json
Normal file
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"fdata/path-data",
|
||||
"design-tokens/v1",
|
||||
"variants/v1",
|
||||
"layout/grid",
|
||||
"fdata/pointer-map",
|
||||
"fdata/objects-map",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type"
|
||||
]
|
||||
},
|
||||
"~:team-id": "~ud715d0a5-a44e-8056-8005-a79999e18b64",
|
||||
"~: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": "bug flex",
|
||||
"~:revn": 33,
|
||||
"~:modified-at": "~m1771342236324",
|
||||
"~:vern": 0,
|
||||
"~:id": "~u52c4e771-3853-8190-8007-9506c70e8100",
|
||||
"~:is-shared": false,
|
||||
"~:migrations": {
|
||||
"~#ordered-set": [
|
||||
"legacy-2",
|
||||
"legacy-3",
|
||||
"legacy-5",
|
||||
"legacy-6",
|
||||
"legacy-7",
|
||||
"legacy-8",
|
||||
"legacy-9",
|
||||
"legacy-10",
|
||||
"legacy-11",
|
||||
"legacy-12",
|
||||
"legacy-13",
|
||||
"legacy-14",
|
||||
"legacy-16",
|
||||
"legacy-17",
|
||||
"legacy-18",
|
||||
"legacy-19",
|
||||
"legacy-25",
|
||||
"legacy-26",
|
||||
"legacy-27",
|
||||
"legacy-28",
|
||||
"legacy-29",
|
||||
"legacy-31",
|
||||
"legacy-32",
|
||||
"legacy-33",
|
||||
"legacy-34",
|
||||
"legacy-36",
|
||||
"legacy-37",
|
||||
"legacy-38",
|
||||
"legacy-39",
|
||||
"legacy-40",
|
||||
"legacy-41",
|
||||
"legacy-42",
|
||||
"legacy-43",
|
||||
"legacy-44",
|
||||
"legacy-45",
|
||||
"legacy-46",
|
||||
"legacy-47",
|
||||
"legacy-48",
|
||||
"legacy-49",
|
||||
"legacy-50",
|
||||
"legacy-51",
|
||||
"legacy-52",
|
||||
"legacy-53",
|
||||
"legacy-54",
|
||||
"legacy-55",
|
||||
"legacy-56",
|
||||
"legacy-57",
|
||||
"legacy-59",
|
||||
"legacy-62",
|
||||
"legacy-65",
|
||||
"legacy-66",
|
||||
"legacy-67",
|
||||
"0001-remove-tokens-from-groups",
|
||||
"0002-normalize-bool-content-v2",
|
||||
"0002-clean-shape-interactions",
|
||||
"0003-fix-root-shape",
|
||||
"0003-convert-path-content-v2",
|
||||
"0005-deprecate-image-type",
|
||||
"0006-fix-old-texts-fills",
|
||||
"0008-fix-library-colors-v4",
|
||||
"0009-clean-library-colors",
|
||||
"0009-add-partial-text-touched-flags",
|
||||
"0010-fix-swap-slots-pointing-non-existent-shapes",
|
||||
"0011-fix-invalid-text-touched-flags",
|
||||
"0012-fix-position-data",
|
||||
"0013-fix-component-path",
|
||||
"0013-clear-invalid-strokes-and-fills",
|
||||
"0014-fix-tokens-lib-duplicate-ids",
|
||||
"0014-clear-components-nil-objects",
|
||||
"0015-fix-text-attrs-blank-strings",
|
||||
"0015-clean-shadow-color",
|
||||
"0016-copy-fills-from-position-data-to-text-node"
|
||||
]
|
||||
},
|
||||
"~:version": 67,
|
||||
"~:project-id": "~u76eab896-accf-81a5-8007-2b264ebe7817",
|
||||
"~:created-at": "~m1771255281717",
|
||||
"~:backend": "legacy-db",
|
||||
"~:data": {
|
||||
"~:pages": [
|
||||
"~uecb0cfd0-0f0b-81f7-8007-950628f9665b"
|
||||
],
|
||||
"~:pages-index": {
|
||||
"~uecb0cfd0-0f0b-81f7-8007-950628f9665b": {
|
||||
"~#penpot/pointer": [
|
||||
"~u4173a29d-4020-80b4-8007-96527ba9d8af",
|
||||
{
|
||||
"~:created-at": "~m1771342236327"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"~:id": "~u52c4e771-3853-8190-8007-9506c70e8100",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
}
|
||||
}
|
||||
}
|
||||
136
frontend/playwright/data/workspace/get-file-13385-2.json
Normal file
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"fdata/path-data",
|
||||
"plugins/runtime",
|
||||
"design-tokens/v1",
|
||||
"variants/v1",
|
||||
"layout/grid",
|
||||
"styles/v2",
|
||||
"fdata/objects-map",
|
||||
"render-wasm/v1",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type"
|
||||
]
|
||||
},
|
||||
"~:team-id": "~u99e49e93-362f-80ef-8007-3450ea52c9a4",
|
||||
"~: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": "BUG 13385",
|
||||
"~:revn": 3,
|
||||
"~:modified-at": "~m1771254407745",
|
||||
"~:vern": 1173241426,
|
||||
"~:id": "~u3ea49ce0-9d99-8197-8007-950361d24e43",
|
||||
"~:is-shared": false,
|
||||
"~:migrations": {
|
||||
"~#ordered-set": [
|
||||
"legacy-2",
|
||||
"legacy-3",
|
||||
"legacy-5",
|
||||
"legacy-6",
|
||||
"legacy-7",
|
||||
"legacy-8",
|
||||
"legacy-9",
|
||||
"legacy-10",
|
||||
"legacy-11",
|
||||
"legacy-12",
|
||||
"legacy-13",
|
||||
"legacy-14",
|
||||
"legacy-16",
|
||||
"legacy-17",
|
||||
"legacy-18",
|
||||
"legacy-19",
|
||||
"legacy-25",
|
||||
"legacy-26",
|
||||
"legacy-27",
|
||||
"legacy-28",
|
||||
"legacy-29",
|
||||
"legacy-31",
|
||||
"legacy-32",
|
||||
"legacy-33",
|
||||
"legacy-34",
|
||||
"legacy-36",
|
||||
"legacy-37",
|
||||
"legacy-38",
|
||||
"legacy-39",
|
||||
"legacy-40",
|
||||
"legacy-41",
|
||||
"legacy-42",
|
||||
"legacy-43",
|
||||
"legacy-44",
|
||||
"legacy-45",
|
||||
"legacy-46",
|
||||
"legacy-47",
|
||||
"legacy-48",
|
||||
"legacy-49",
|
||||
"legacy-50",
|
||||
"legacy-51",
|
||||
"legacy-52",
|
||||
"legacy-53",
|
||||
"legacy-54",
|
||||
"legacy-55",
|
||||
"legacy-56",
|
||||
"legacy-57",
|
||||
"legacy-59",
|
||||
"legacy-62",
|
||||
"legacy-65",
|
||||
"legacy-66",
|
||||
"legacy-67",
|
||||
"0001-remove-tokens-from-groups",
|
||||
"0002-normalize-bool-content-v2",
|
||||
"0002-clean-shape-interactions",
|
||||
"0003-fix-root-shape",
|
||||
"0003-convert-path-content-v2",
|
||||
"0005-deprecate-image-type",
|
||||
"0006-fix-old-texts-fills",
|
||||
"0008-fix-library-colors-v4",
|
||||
"0009-clean-library-colors",
|
||||
"0009-add-partial-text-touched-flags",
|
||||
"0010-fix-swap-slots-pointing-non-existent-shapes",
|
||||
"0011-fix-invalid-text-touched-flags",
|
||||
"0012-fix-position-data",
|
||||
"0013-fix-component-path",
|
||||
"0013-clear-invalid-strokes-and-fills",
|
||||
"0014-fix-tokens-lib-duplicate-ids",
|
||||
"0014-clear-components-nil-objects",
|
||||
"0015-fix-text-attrs-blank-strings",
|
||||
"0015-clean-shadow-color",
|
||||
"0016-copy-fills-from-position-data-to-text-node"
|
||||
]
|
||||
},
|
||||
"~:version": 67,
|
||||
"~:project-id": "~ucd8f7672-e5d1-810f-8007-87e124eda82a",
|
||||
"~:created-at": "~m1771254391625",
|
||||
"~:backend": "legacy-db",
|
||||
"~:data": {
|
||||
"~:pages": [
|
||||
"~u3ea49ce0-9d99-8197-8007-950361d24e44"
|
||||
],
|
||||
"~:pages-index": {
|
||||
"~u3ea49ce0-9d99-8197-8007-950361d24e44": {
|
||||
"~: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\",[\"~ue0e81bed-4dc2-805c-8007-95036a4a3131\",\"~ue0e81bed-4dc2-805c-8007-95036c27428b\"]]]",
|
||||
"~ue0e81bed-4dc2-805c-8007-95036a4a3131": "[\"~#shape\",[\"^ \",\"~:y\",252,\"~: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\",177,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",156,\"~:y\",252]],[\"^<\",[\"^ \",\"~:x\",333,\"~:y\",252]],[\"^<\",[\"^ \",\"~:x\",333,\"~:y\",389]],[\"^<\",[\"^ \",\"~:x\",156,\"~:y\",389]]],\"~: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\",\"~ue0e81bed-4dc2-805c-8007-95036a4a3131\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",156,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",156,\"~:y\",252,\"^8\",177,\"~:height\",137,\"~:x1\",156,\"~:y1\",252,\"~:x2\",333,\"~:y2\",389]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^J\",137,\"~:flip-y\",null]]",
|
||||
"~ue0e81bed-4dc2-805c-8007-95036c27428b": "[\"~#shape\",[\"^ \",\"~:y\",250,\"~: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\",\"Ellipse\",\"~:width\",148,\"~:type\",\"~:circle\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",362,\"~:y\",250]],[\"^<\",[\"^ \",\"~:x\",510,\"~:y\",250]],[\"^<\",[\"^ \",\"~:x\",510,\"~:y\",389]],[\"^<\",[\"^ \",\"~:x\",362,\"~:y\",389]]],\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^2\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:id\",\"~ue0e81bed-4dc2-805c-8007-95036c27428b\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",362,\"~:proportion\",1,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",362,\"~:y\",250,\"^8\",148,\"~:height\",139,\"~:x1\",362,\"~:y1\",250,\"~:x2\",510,\"~:y2\",389]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^F\",139,\"~:flip-y\",null]]"
|
||||
}
|
||||
},
|
||||
"~:id": "~u3ea49ce0-9d99-8197-8007-950361d24e44",
|
||||
"~:name": "Page 1"
|
||||
}
|
||||
},
|
||||
"~:id": "~u3ea49ce0-9d99-8197-8007-950361d24e43",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
}
|
||||
}
|
||||
}
|
||||
135
frontend/playwright/data/workspace/get-file-13385.json
Normal file
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"fdata/path-data",
|
||||
"plugins/runtime",
|
||||
"design-tokens/v1",
|
||||
"variants/v1",
|
||||
"layout/grid",
|
||||
"styles/v2",
|
||||
"fdata/objects-map",
|
||||
"render-wasm/v1",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type"
|
||||
]
|
||||
},
|
||||
"~:team-id": "~u99e49e93-362f-80ef-8007-3450ea52c9a4",
|
||||
"~: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": "BUG 13385",
|
||||
"~:revn": 2,
|
||||
"~:modified-at": "~m1771254464312",
|
||||
"~:vern": 0,
|
||||
"~:id": "~u3ea49ce0-9d99-8197-8007-950361d24e43",
|
||||
"~:is-shared": false,
|
||||
"~:migrations": {
|
||||
"~#ordered-set": [
|
||||
"legacy-2",
|
||||
"legacy-3",
|
||||
"legacy-5",
|
||||
"legacy-6",
|
||||
"legacy-7",
|
||||
"legacy-8",
|
||||
"legacy-9",
|
||||
"legacy-10",
|
||||
"legacy-11",
|
||||
"legacy-12",
|
||||
"legacy-13",
|
||||
"legacy-14",
|
||||
"legacy-16",
|
||||
"legacy-17",
|
||||
"legacy-18",
|
||||
"legacy-19",
|
||||
"legacy-25",
|
||||
"legacy-26",
|
||||
"legacy-27",
|
||||
"legacy-28",
|
||||
"legacy-29",
|
||||
"legacy-31",
|
||||
"legacy-32",
|
||||
"legacy-33",
|
||||
"legacy-34",
|
||||
"legacy-36",
|
||||
"legacy-37",
|
||||
"legacy-38",
|
||||
"legacy-39",
|
||||
"legacy-40",
|
||||
"legacy-41",
|
||||
"legacy-42",
|
||||
"legacy-43",
|
||||
"legacy-44",
|
||||
"legacy-45",
|
||||
"legacy-46",
|
||||
"legacy-47",
|
||||
"legacy-48",
|
||||
"legacy-49",
|
||||
"legacy-50",
|
||||
"legacy-51",
|
||||
"legacy-52",
|
||||
"legacy-53",
|
||||
"legacy-54",
|
||||
"legacy-55",
|
||||
"legacy-56",
|
||||
"legacy-57",
|
||||
"legacy-59",
|
||||
"legacy-62",
|
||||
"legacy-65",
|
||||
"legacy-66",
|
||||
"legacy-67",
|
||||
"0001-remove-tokens-from-groups",
|
||||
"0002-normalize-bool-content-v2",
|
||||
"0002-clean-shape-interactions",
|
||||
"0003-fix-root-shape",
|
||||
"0003-convert-path-content-v2",
|
||||
"0005-deprecate-image-type",
|
||||
"0006-fix-old-texts-fills",
|
||||
"0008-fix-library-colors-v4",
|
||||
"0009-clean-library-colors",
|
||||
"0009-add-partial-text-touched-flags",
|
||||
"0010-fix-swap-slots-pointing-non-existent-shapes",
|
||||
"0011-fix-invalid-text-touched-flags",
|
||||
"0012-fix-position-data",
|
||||
"0013-fix-component-path",
|
||||
"0013-clear-invalid-strokes-and-fills",
|
||||
"0014-fix-tokens-lib-duplicate-ids",
|
||||
"0014-clear-components-nil-objects",
|
||||
"0015-fix-text-attrs-blank-strings",
|
||||
"0015-clean-shadow-color",
|
||||
"0016-copy-fills-from-position-data-to-text-node"
|
||||
]
|
||||
},
|
||||
"~:version": 67,
|
||||
"~:project-id": "~ucd8f7672-e5d1-810f-8007-87e124eda82a",
|
||||
"~:created-at": "~m1771254391625",
|
||||
"~:backend": "legacy-db",
|
||||
"~:data": {
|
||||
"~:pages": [
|
||||
"~u3ea49ce0-9d99-8197-8007-950361d24e44"
|
||||
],
|
||||
"~:pages-index": {
|
||||
"~u3ea49ce0-9d99-8197-8007-950361d24e44": {
|
||||
"~: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\",[\"~ue0e81bed-4dc2-805c-8007-95036a4a3131\"]]]",
|
||||
"~ue0e81bed-4dc2-805c-8007-95036a4a3131": "[\"~#shape\",[\"^ \",\"~:y\",252,\"~: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\",177,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",156,\"~:y\",252]],[\"^<\",[\"^ \",\"~:x\",333,\"~:y\",252]],[\"^<\",[\"^ \",\"~:x\",333,\"~:y\",389]],[\"^<\",[\"^ \",\"~:x\",156,\"~:y\",389]]],\"~: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\",\"~ue0e81bed-4dc2-805c-8007-95036a4a3131\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",156,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",156,\"~:y\",252,\"^8\",177,\"~:height\",137,\"~:x1\",156,\"~:y1\",252,\"~:x2\",333,\"~:y2\",389]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^J\",137,\"~:flip-y\",null]]"
|
||||
}
|
||||
},
|
||||
"~:id": "~u3ea49ce0-9d99-8197-8007-950361d24e44",
|
||||
"~:name": "Page 1"
|
||||
}
|
||||
},
|
||||
"~:id": "~u3ea49ce0-9d99-8197-8007-950361d24e43",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
}
|
||||
}
|
||||
}
|
||||
135
frontend/playwright/data/workspace/get-file-13415.json
Normal file
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"fdata/path-data",
|
||||
"plugins/runtime",
|
||||
"design-tokens/v1",
|
||||
"variants/v1",
|
||||
"layout/grid",
|
||||
"styles/v2",
|
||||
"fdata/objects-map",
|
||||
"render-wasm/v1",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type"
|
||||
]
|
||||
},
|
||||
"~:team-id": "~u99e49e93-362f-80ef-8007-3450ea52c9a4",
|
||||
"~: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": "BUG 13415",
|
||||
"~:revn": 14,
|
||||
"~:modified-at": "~m1771334256704",
|
||||
"~:vern": 0,
|
||||
"~:id": "~u0472abff-2573-8186-8007-961793e53f45",
|
||||
"~:is-shared": false,
|
||||
"~:migrations": {
|
||||
"~#ordered-set": [
|
||||
"legacy-2",
|
||||
"legacy-3",
|
||||
"legacy-5",
|
||||
"legacy-6",
|
||||
"legacy-7",
|
||||
"legacy-8",
|
||||
"legacy-9",
|
||||
"legacy-10",
|
||||
"legacy-11",
|
||||
"legacy-12",
|
||||
"legacy-13",
|
||||
"legacy-14",
|
||||
"legacy-16",
|
||||
"legacy-17",
|
||||
"legacy-18",
|
||||
"legacy-19",
|
||||
"legacy-25",
|
||||
"legacy-26",
|
||||
"legacy-27",
|
||||
"legacy-28",
|
||||
"legacy-29",
|
||||
"legacy-31",
|
||||
"legacy-32",
|
||||
"legacy-33",
|
||||
"legacy-34",
|
||||
"legacy-36",
|
||||
"legacy-37",
|
||||
"legacy-38",
|
||||
"legacy-39",
|
||||
"legacy-40",
|
||||
"legacy-41",
|
||||
"legacy-42",
|
||||
"legacy-43",
|
||||
"legacy-44",
|
||||
"legacy-45",
|
||||
"legacy-46",
|
||||
"legacy-47",
|
||||
"legacy-48",
|
||||
"legacy-49",
|
||||
"legacy-50",
|
||||
"legacy-51",
|
||||
"legacy-52",
|
||||
"legacy-53",
|
||||
"legacy-54",
|
||||
"legacy-55",
|
||||
"legacy-56",
|
||||
"legacy-57",
|
||||
"legacy-59",
|
||||
"legacy-62",
|
||||
"legacy-65",
|
||||
"legacy-66",
|
||||
"legacy-67",
|
||||
"0001-remove-tokens-from-groups",
|
||||
"0002-normalize-bool-content-v2",
|
||||
"0002-clean-shape-interactions",
|
||||
"0003-fix-root-shape",
|
||||
"0003-convert-path-content-v2",
|
||||
"0005-deprecate-image-type",
|
||||
"0006-fix-old-texts-fills",
|
||||
"0008-fix-library-colors-v4",
|
||||
"0009-clean-library-colors",
|
||||
"0009-add-partial-text-touched-flags",
|
||||
"0010-fix-swap-slots-pointing-non-existent-shapes",
|
||||
"0011-fix-invalid-text-touched-flags",
|
||||
"0012-fix-position-data",
|
||||
"0013-fix-component-path",
|
||||
"0013-clear-invalid-strokes-and-fills",
|
||||
"0014-fix-tokens-lib-duplicate-ids",
|
||||
"0014-clear-components-nil-objects",
|
||||
"0015-fix-text-attrs-blank-strings",
|
||||
"0015-clean-shadow-color",
|
||||
"0016-copy-fills-from-position-data-to-text-node"
|
||||
]
|
||||
},
|
||||
"~:version": 67,
|
||||
"~:project-id": "~ucd8f7672-e5d1-810f-8007-87e124eda82a",
|
||||
"~:created-at": "~m1771326794644",
|
||||
"~:backend": "legacy-db",
|
||||
"~:data": {
|
||||
"~:pages": [
|
||||
"~u0472abff-2573-8186-8007-961793e53f46"
|
||||
],
|
||||
"~:pages-index": {
|
||||
"~u0472abff-2573-8186-8007-961793e53f46": {
|
||||
"~: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\",[\"~uaef184da-e9c1-80f8-8007-961cf253d534\"]]]",
|
||||
"~uaef184da-e9c1-80f8-8007-961cf253d534": "[\"~#shape\",[\"^ \",\"~:y\",286,\"~:layout-grid-columns\",[[\"^ \",\"~:type\",\"~:flex\",\"~:value\",1],[\"^ \",\"^2\",\"^3\",\"^4\",1]],\"~:hide-fill-on-export\",false,\"~:layout-gap-type\",\"~:multiple\",\"~:layout-padding\",[\"^ \",\"~:p1\",0,\"~:p2\",0,\"~:p3\",0,\"~:p4\",0],\"~: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\",\"~:layout\",\"~:grid\",\"~:hide-in-viewer\",false,\"~:name\",\"Board\",\"~:layout-align-items\",\"~:start\",\"~:width\",298,\"~:layout-grid-cells\",[\"^ \",\"~uaef184da-e9c1-80f8-8007-961cf50d67b4\",[\"^ \",\"~:justify-self\",\"~:auto\",\"~:column\",1,\"~:id\",\"~uaef184da-e9c1-80f8-8007-961cf50d67b4\",\"~:position\",\"^L\",\"~:column-span\",1,\"~:align-self\",\"^L\",\"~:row\",1,\"~:row-span\",1,\"~:shapes\",[]],\"~uaef184da-e9c1-80f8-8007-961cf50d67b5\",[\"^ \",\"^K\",\"^L\",\"^M\",2,\"^N\",\"~uaef184da-e9c1-80f8-8007-961cf50d67b5\",\"^O\",\"^L\",\"^P\",1,\"^Q\",\"^L\",\"^R\",1,\"^S\",1,\"^T\",[]],\"~uaef184da-e9c1-80f8-8007-961cf50d67b6\",[\"^ \",\"^K\",\"^L\",\"^M\",1,\"^N\",\"~uaef184da-e9c1-80f8-8007-961cf50d67b6\",\"^O\",\"^L\",\"^P\",1,\"^Q\",\"^L\",\"^R\",2,\"^S\",1,\"^T\",[]],\"~uaef184da-e9c1-80f8-8007-961cf50d67b7\",[\"^ \",\"^K\",\"^L\",\"^M\",2,\"^N\",\"~uaef184da-e9c1-80f8-8007-961cf50d67b7\",\"^O\",\"^L\",\"^P\",1,\"^Q\",\"^L\",\"^R\",2,\"^S\",1,\"^T\",[]]],\"~:layout-padding-type\",\"~:simple\",\"^2\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",322,\"~:y\",286]],[\"^10\",[\"^ \",\"~:x\",620,\"~:y\",286]],[\"^10\",[\"^ \",\"~:x\",620,\"~:y\",552]],[\"^10\",[\"^ \",\"~:x\",322,\"~:y\",552]]],\"~:r2\",0,\"~:proportion-lock\",false,\"~:layout-gap\",[\"^ \",\"~:row-gap\",0,\"~:column-gap\",0],\"~:transform-inverse\",[\"^>\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:r3\",0,\"~:layout-justify-content\",\"~:stretch\",\"~:r1\",0,\"^N\",\"~uaef184da-e9c1-80f8-8007-961cf253d534\",\"~:layout-justify-items\",\"^G\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:layout-align-content\",\"^19\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",322,\"~:proportion\",1,\"~:r4\",0,\"~:layout-grid-rows\",[[\"^ \",\"^2\",\"^3\",\"^4\",1],[\"^ \",\"^2\",\"^3\",\"^4\",1]],\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",322,\"~:y\",286,\"^H\",298,\"~:height\",266,\"~:x1\",322,\"~:y1\",286,\"~:x2\",620,\"~:y2\",552]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:layout-grid-dir\",\"^R\",\"~:flip-x\",null,\"^1E\",266,\"~:flip-y\",null,\"^T\",[]]]"
|
||||
}
|
||||
},
|
||||
"~:id": "~u0472abff-2573-8186-8007-961793e53f46",
|
||||
"~:name": "Page 1"
|
||||
}
|
||||
},
|
||||
"~:id": "~u0472abff-2573-8186-8007-961793e53f45",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"~:file-id": "~u3a4d7ec7-c391-8146-8007-9a05c41da6b9",
|
||||
"~:id": "~u3a4d7ec7-c391-8146-8007-9dd6c998fbc4",
|
||||
"~:created-at": "~m1771846681191",
|
||||
"~:modified-at": "~m1771846681191",
|
||||
"~:type": "fragment",
|
||||
"~:backend": "db",
|
||||
"~:data": {
|
||||
"~:id": "~u95b23c15-79f9-81ba-8007-99d81b5290dd",
|
||||
"~:name": "Page 1",
|
||||
"~: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]],\"~:page-id\",\"~u95b23c15-79f9-81ba-8007-99d81b5290dd\",\"~: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,\"^I\",0.01,\"~:flip-y\",null,\"~:shapes\",[\"~ucfb31a9c-83c2-806f-8007-9dbf43043bdf\"]]]",
|
||||
"~ucfb31a9c-83c2-806f-8007-9dbf43043be0": "[\"~#shape\",[\"^ \",\"~:y\",-218.99999605032087,\"~:hide-fill-on-export\",false,\"~:layout-gap-type\",\"~:multiple\",\"~:layout-padding\",[\"^ \",\"~:p1\",5,\"~:p2\",5,\"~:p3\",5,\"~:p4\",5],\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:layout-wrap-type\",\"~:nowrap\",\"~:layout\",\"~:flex\",\"~:hide-in-viewer\",true,\"~:name\",\"Container\",\"~:layout-align-items\",\"~:start\",\"~:width\",431.99994866329087,\"~:layout-padding-type\",\"~:simple\",\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",608.9999813066789,\"~:y\",-218.99999605032087]],[\"^J\",[\"^ \",\"~:x\",1040.9999299699698,\"~:y\",-218.99999605032087]],[\"^J\",[\"^ \",\"~:x\",1040.9999299699698,\"~:y\",-177.00001533586985]],[\"^J\",[\"^ \",\"~:x\",608.9999813066789,\"~:y\",-177.00001533586985]]],\"~:show-content\",true,\"~:layout-item-h-sizing\",\"~:fill\",\"~:proportion-lock\",false,\"~:layout-gap\",[\"^ \",\"~:row-gap\",4,\"~:column-gap\",4],\"~:transform-inverse\",[\"^:\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~u95b23c15-79f9-81ba-8007-99d81b5290dd\",\"~:layout-item-v-sizing\",\"~:auto\",\"~:layout-justify-content\",\"^C\",\"~:constraints-v\",\"~:top\",\"~:constraints-h\",\"~:left\",\"~:id\",\"~ucfb31a9c-83c2-806f-8007-9dbf43043be0\",\"~:parent-id\",\"~ucfb31a9c-83c2-806f-8007-9dbf43043bdf\",\"~:layout-flex-dir\",\"~:column\",\"~:layout-align-content\",\"~:stretch\",\"~:frame-id\",\"~ucfb31a9c-83c2-806f-8007-9dbf43043bdf\",\"~:strokes\",[],\"~:x\",608.9999813066788,\"~:proportion\",1,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",608.9999813066788,\"~:y\",-218.99999605032087,\"^D\",431.99994866329087,\"~:height\",41.99998071445103,\"~:x1\",608.9999813066788,\"~:y1\",-218.99999605032087,\"~:x2\",1040.9999299699698,\"~:y2\",-177.00001533586985]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#ffc0cb\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^1:\",41.99998071445103,\"~:flip-y\",null,\"~:shapes\",[\"~ucfb31a9c-83c2-806f-8007-9dbf43043be2\",\"~ucfb31a9c-83c2-806f-8007-9dbf43043be3\"]]]",
|
||||
"~ucfb31a9c-83c2-806f-8007-9dbf43043be2": "[\"~#shape\",[\"^ \",\"~:y\",-178.00000568505413,\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:hide-in-viewer\",false,\"~:name\",\"show / hide me\",\"~:width\",99.98206911702209,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",614.0000002576337,\"~:y\",-178.00000568505413]],[\"^:\",[\"^ \",\"~:x\",713.9820693746558,\"~:y\",-178.00000568505413]],[\"^:\",[\"^ \",\"~:x\",713.9820693746558,\"~:y\",-148.0000135081636]],[\"^:\",[\"^ \",\"~:x\",614.0000002576337,\"~:y\",-148.0000135081636]]],\"~:r2\",0,\"~:layout-item-h-sizing\",\"~:fix\",\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^2\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:layout-item-v-sizing\",\"^=\",\"~:r3\",0,\"~:constraints-v\",\"~:top\",\"~:constraints-h\",\"~:left\",\"~:r1\",0,\"~:hidden\",true,\"~:id\",\"~ucfb31a9c-83c2-806f-8007-9dbf43043be2\",\"~:parent-id\",\"~ucfb31a9c-83c2-806f-8007-9dbf43043be0\",\"~:frame-id\",\"~ucfb31a9c-83c2-806f-8007-9dbf43043be0\",\"~:strokes\",[],\"~:x\",614.0000002576337,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",614.0000002576337,\"~:y\",-178.00000568505413,\"^6\",99.98206911702209,\"~:height\",29.999992176890544,\"~:x1\",614.0000002576337,\"~:y1\",-178.00000568505413,\"~:x2\",713.9820693746558,\"~:y2\",-148.0000135081636]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^P\",29.999992176890544,\"~:flip-y\",null]]",
|
||||
"~ucfb31a9c-83c2-806f-8007-9dbf43043be3": "[\"~#shape\",[\"^ \",\"~:y\",-213.99999587313152,\"~:hide-fill-on-export\",false,\"~:rx\",8,\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:hide-in-viewer\",true,\"~:name\",\"Full width\",\"~:width\",422.00001200500014,\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",613.9999939062393,\"~:y\",-213.99999587313152]],[\"^<\",[\"^ \",\"~:x\",1036.0000059112394,\"~:y\",-213.99999587313152]],[\"^<\",[\"^ \",\"~:x\",1036.0000059112394,\"~:y\",-182.00001303926604]],[\"^<\",[\"^ \",\"~:x\",613.9999939062393,\"~:y\",-182.00001303926604]]],\"~:r2\",8,\"~:show-content\",true,\"~:layout-item-h-sizing\",\"~:fix\",\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^4\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~u95b23c15-79f9-81ba-8007-99d81b5290dd\",\"~:layout-item-v-sizing\",\"^@\",\"~:r3\",8,\"~:r1\",8,\"~:id\",\"~ucfb31a9c-83c2-806f-8007-9dbf43043be3\",\"~:parent-id\",\"~ucfb31a9c-83c2-806f-8007-9dbf43043be0\",\"~:frame-id\",\"~ucfb31a9c-83c2-806f-8007-9dbf43043be0\",\"~:strokes\",[],\"~:x\",613.9999939062393,\"~:proportion\",1,\"~:r4\",8,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",613.9999939062393,\"~:y\",-213.99999587313152,\"^8\",422.00001200500014,\"~:height\",31.999982833865488,\"~:x1\",613.9999939062393,\"~:y1\",-213.99999587313152,\"~:x2\",1036.0000059112394,\"~:y2\",-182.00001303926604]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#212426\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"~:ry\",8,\"^O\",31.999982833865488,\"~:flip-y\",null,\"~:shapes\",[]]]",
|
||||
"~ucfb31a9c-83c2-806f-8007-9dbf43043bdf": "[\"~#shape\",[\"^ \",\"~:y\",-228.99999763039506,\"~:hide-fill-on-export\",false,\"~:layout-gap-type\",\"~:multiple\",\"~:layout-padding\",[\"^ \",\"~:p1\",10,\"~:p2\",10,\"~:p3\",10,\"~:p4\",10],\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:layout-wrap-type\",\"~:nowrap\",\"~:layout\",\"~:flex\",\"~:hide-in-viewer\",true,\"~:name\",\"Parent\",\"~:layout-align-items\",\"~:start\",\"~:width\",451.999905143128,\"~:layout-padding-type\",\"~:simple\",\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",599.0000149607649,\"~:y\",-228.99999763039506]],[\"^J\",[\"^ \",\"~:x\",1050.999920103893,\"~:y\",-228.99999763039506]],[\"^J\",[\"^ \",\"~:x\",1050.999920103893,\"~:y\",-167.0000160450801]],[\"^J\",[\"^ \",\"~:x\",599.0000149607649,\"~:y\",-167.0000160450801]]],\"~:r2\",0,\"~:show-content\",true,\"~:layout-item-h-sizing\",\"~:fix\",\"~:proportion-lock\",false,\"~:layout-gap\",[\"^ \",\"~:row-gap\",10,\"~:column-gap\",8],\"~:transform-inverse\",[\"^:\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:page-id\",\"~u95b23c15-79f9-81ba-8007-99d81b5290dd\",\"~:layout-item-v-sizing\",\"~:auto\",\"~:r3\",0,\"~:layout-justify-content\",\"^C\",\"~:r1\",0,\"~:id\",\"~ucfb31a9c-83c2-806f-8007-9dbf43043bdf\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:layout-flex-dir\",\"~:column\",\"~:layout-align-content\",\"~:stretch\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",599.0000149607649,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",599.0000149607649,\"~:y\",-228.99999763039506,\"^D\",451.999905143128,\"~:height\",61.99998158531497,\"~:x1\",599.0000149607649,\"~:y1\",-228.99999763039506,\"~:x2\",1050.999920103893,\"~:y2\",-167.0000160450801]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#000000\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^1:\",61.99998158531497,\"~:flip-y\",null,\"~:shapes\",[\"~ucfb31a9c-83c2-806f-8007-9dbf43043be0\"]]]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
131
frontend/playwright/data/workspace/get-file-13468.json
Normal file
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"~:features": {
|
||||
"~#set": [
|
||||
"fdata/path-data",
|
||||
"design-tokens/v1",
|
||||
"variants/v1",
|
||||
"layout/grid",
|
||||
"fdata/pointer-map",
|
||||
"fdata/objects-map",
|
||||
"components/v2",
|
||||
"fdata/shape-data-type"
|
||||
]
|
||||
},
|
||||
"~:team-id": "~ud715d0a5-a44e-8056-8005-a79999e18b64",
|
||||
"~: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": "test-bug-flex",
|
||||
"~:revn": 114,
|
||||
"~:modified-at": "~m1771846681183",
|
||||
"~:vern": 0,
|
||||
"~:id": "~u3a4d7ec7-c391-8146-8007-9a05c41da6b9",
|
||||
"~:is-shared": false,
|
||||
"~:migrations": {
|
||||
"~#ordered-set": [
|
||||
"legacy-2",
|
||||
"legacy-3",
|
||||
"legacy-5",
|
||||
"legacy-6",
|
||||
"legacy-7",
|
||||
"legacy-8",
|
||||
"legacy-9",
|
||||
"legacy-10",
|
||||
"legacy-11",
|
||||
"legacy-12",
|
||||
"legacy-13",
|
||||
"legacy-14",
|
||||
"legacy-16",
|
||||
"legacy-17",
|
||||
"legacy-18",
|
||||
"legacy-19",
|
||||
"legacy-25",
|
||||
"legacy-26",
|
||||
"legacy-27",
|
||||
"legacy-28",
|
||||
"legacy-29",
|
||||
"legacy-31",
|
||||
"legacy-32",
|
||||
"legacy-33",
|
||||
"legacy-34",
|
||||
"legacy-36",
|
||||
"legacy-37",
|
||||
"legacy-38",
|
||||
"legacy-39",
|
||||
"legacy-40",
|
||||
"legacy-41",
|
||||
"legacy-42",
|
||||
"legacy-43",
|
||||
"legacy-44",
|
||||
"legacy-45",
|
||||
"legacy-46",
|
||||
"legacy-47",
|
||||
"legacy-48",
|
||||
"legacy-49",
|
||||
"legacy-50",
|
||||
"legacy-51",
|
||||
"legacy-52",
|
||||
"legacy-53",
|
||||
"legacy-54",
|
||||
"legacy-55",
|
||||
"legacy-56",
|
||||
"legacy-57",
|
||||
"legacy-59",
|
||||
"legacy-62",
|
||||
"legacy-65",
|
||||
"legacy-66",
|
||||
"legacy-67",
|
||||
"0001-remove-tokens-from-groups",
|
||||
"0002-normalize-bool-content-v2",
|
||||
"0002-clean-shape-interactions",
|
||||
"0003-fix-root-shape",
|
||||
"0003-convert-path-content-v2",
|
||||
"0005-deprecate-image-type",
|
||||
"0006-fix-old-texts-fills",
|
||||
"0008-fix-library-colors-v4",
|
||||
"0009-clean-library-colors",
|
||||
"0009-add-partial-text-touched-flags",
|
||||
"0010-fix-swap-slots-pointing-non-existent-shapes",
|
||||
"0011-fix-invalid-text-touched-flags",
|
||||
"0012-fix-position-data",
|
||||
"0013-fix-component-path",
|
||||
"0013-clear-invalid-strokes-and-fills",
|
||||
"0014-fix-tokens-lib-duplicate-ids",
|
||||
"0014-clear-components-nil-objects",
|
||||
"0015-fix-text-attrs-blank-strings",
|
||||
"0015-clean-shadow-color",
|
||||
"0016-copy-fills-from-position-data-to-text-node"
|
||||
]
|
||||
},
|
||||
"~:version": 67,
|
||||
"~:project-id": "~u76eab896-accf-81a5-8007-2b264ebe7817",
|
||||
"~:created-at": "~m1771590560885",
|
||||
"~:backend": "legacy-db",
|
||||
"~:data": {
|
||||
"~:pages": [
|
||||
"~u95b23c15-79f9-81ba-8007-99d81b5290dd"
|
||||
],
|
||||
"~:pages-index": {
|
||||
"~u95b23c15-79f9-81ba-8007-99d81b5290dd": {
|
||||
"~#penpot/pointer": [
|
||||
"~u3a4d7ec7-c391-8146-8007-9dd6c998fbc4",
|
||||
{
|
||||
"~:created-at": "~m1771846681187"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"~:id": "~u3a4d7ec7-c391-8146-8007-9a05c41da6b9",
|
||||
"~:options": {
|
||||
"~:components-v2": true,
|
||||
"~:base-font-size": "16px"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
[
|
||||
{
|
||||
"~:id": "~u3ea49ce0-9d99-8197-8007-95037190405b",
|
||||
"~:label": "Version 000",
|
||||
"~:revn": 1,
|
||||
"~:version": 67,
|
||||
"~:created-at": "~m1771254407745",
|
||||
"~:modified-at": "~m1771254407745",
|
||||
"~:created-by": "user",
|
||||
"~:profile-id": "~u99e49e93-362f-80ef-8007-3450ea5204aa"
|
||||
},
|
||||
{
|
||||
"~:revn": 0,
|
||||
"~:modified-at": "~m1771254406526",
|
||||
"~:deleted-at": "~m1771340806524",
|
||||
"~:created-by": "system",
|
||||
"~:label": "internal/snapshot/0",
|
||||
"~:id": "~u3ea49ce0-9d99-8197-8007-9503705f8b9b",
|
||||
"~:profile-id": "~u99e49e93-362f-80ef-8007-3450ea5204aa",
|
||||
"~:version": 67,
|
||||
"~:created-at": "~m1771254406526"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,9 @@
|
||||
[
|
||||
{
|
||||
"~:id": "~u99e49e93-362f-80ef-8007-3450ea5204aa",
|
||||
"~:email": "belen@example.com",
|
||||
"~:name": "Belén Albeza",
|
||||
"~:fullname": "Belén Albeza",
|
||||
"~:is-active": true
|
||||
}
|
||||
]
|
||||
18
frontend/playwright/data/workspace/update-file-13415.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"~:revn": 14,
|
||||
"~:lagged": [
|
||||
{
|
||||
"~:id": "~u0472abff-2573-8186-8007-96347d525f65",
|
||||
"~:revn": 15,
|
||||
"~:file-id": "~u0472abff-2573-8186-8007-961793e53f45",
|
||||
"~:session-id": "~uf25e6d2f-d10c-8021-8007-96344433f08d",
|
||||
"~:changes": [
|
||||
{
|
||||
"~:type": "~:del-obj",
|
||||
"~:page-id": "~u0472abff-2573-8186-8007-961793e53f46",
|
||||
"~:id": "~uaef184da-e9c1-80f8-8007-961cf253d534"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
export class BasePage {
|
||||
static async init(page) {
|
||||
await BasePage.mockConfigFlags(page, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mocks multiple RPC calls in a single call.
|
||||
*
|
||||
@@ -22,7 +26,7 @@ export class BasePage {
|
||||
* @param {*} options
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
static async mockRPC(page, path, jsonFilename, options) {
|
||||
static async mockRPC(page, path, jsonFilename = "", options = {}) {
|
||||
if (!page) {
|
||||
throw new TypeError("Invalid page argument. Must be a Playwright page.");
|
||||
}
|
||||
@@ -41,7 +45,7 @@ export class BasePage {
|
||||
return page.route(url, (route) =>
|
||||
route.fulfill({
|
||||
...interceptConfig,
|
||||
path: `playwright/data/${jsonFilename}`,
|
||||
path: jsonFilename ? `playwright/data/${jsonFilename}` : undefined,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,13 +2,8 @@ import { MockWebSocketHelper } from "../../helpers/MockWebSocketHelper";
|
||||
import BasePage from "./BasePage";
|
||||
|
||||
export class BaseWebSocketPage extends BasePage {
|
||||
/**
|
||||
* This should be called on `test.beforeEach`.
|
||||
*
|
||||
* @param {Page} page
|
||||
* @returns
|
||||
*/
|
||||
static async initWebSockets(page) {
|
||||
static async init(page) {
|
||||
await super.init(page);
|
||||
await MockWebSocketHelper.init(page);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,54 +3,62 @@ import { BaseWebSocketPage } from "./BaseWebSocketPage";
|
||||
|
||||
export class DashboardPage extends BaseWebSocketPage {
|
||||
static async init(page) {
|
||||
await BaseWebSocketPage.initWebSockets(page);
|
||||
await super.init(page);
|
||||
|
||||
await BaseWebSocketPage.mockRPC(
|
||||
await super.mockConfigFlags(page, ["disable-onboarding"]);
|
||||
|
||||
await super.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
"logged-in-user/get-teams-default.json",
|
||||
);
|
||||
await BaseWebSocketPage.mockRPC(
|
||||
await super.mockRPC(
|
||||
page,
|
||||
"get-font-variants?team-id=*",
|
||||
"workspace/get-font-variants-empty.json",
|
||||
);
|
||||
|
||||
await BaseWebSocketPage.mockRPC(
|
||||
await super.mockRPC(
|
||||
page,
|
||||
"get-projects?team-id=*",
|
||||
"logged-in-user/get-projects-default.json",
|
||||
);
|
||||
await BaseWebSocketPage.mockRPC(
|
||||
await super.mockRPC(
|
||||
page,
|
||||
"get-team-members?team-id=*",
|
||||
"logged-in-user/get-team-members-your-penpot.json",
|
||||
);
|
||||
await BaseWebSocketPage.mockRPC(
|
||||
await super.mockRPC(
|
||||
page,
|
||||
"get-team-users?team-id=*",
|
||||
"logged-in-user/get-team-users-single-user.json",
|
||||
);
|
||||
await BaseWebSocketPage.mockRPC(
|
||||
await super.mockRPC(
|
||||
page,
|
||||
"get-unread-comment-threads?team-id=*",
|
||||
"logged-in-user/get-team-users-single-user.json",
|
||||
);
|
||||
await BaseWebSocketPage.mockRPC(
|
||||
await super.mockRPC(
|
||||
page,
|
||||
"get-team-recent-files?team-id=*",
|
||||
"logged-in-user/get-team-recent-files-empty.json",
|
||||
);
|
||||
await BaseWebSocketPage.mockRPC(
|
||||
await super.mockRPC(
|
||||
page,
|
||||
"get-profiles-for-file-comments",
|
||||
"workspace/get-profile-for-file-comments.json",
|
||||
);
|
||||
await BaseWebSocketPage.mockRPC(
|
||||
await super.mockRPC(
|
||||
page,
|
||||
"get-builtin-templates",
|
||||
"logged-in-user/get-built-in-templates-empty.json",
|
||||
);
|
||||
|
||||
await super.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"logged-in-user/get-profile-logged-in.json",
|
||||
);
|
||||
}
|
||||
|
||||
static anyTeamId = "c7ce0794-0992-8105-8004-38e630f40f6d";
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { BasePage } from "./BasePage";
|
||||
|
||||
export class LoginPage extends BasePage {
|
||||
static async init(page) {
|
||||
await super.init(page);
|
||||
}
|
||||
|
||||
constructor(page) {
|
||||
super(page);
|
||||
this.loginButton = page.getByRole("button", { name: "Continue" });
|
||||
|
||||
@@ -29,8 +29,13 @@ export class RegisterPage extends BasePage {
|
||||
);
|
||||
}
|
||||
|
||||
static async init(page) {
|
||||
await BasePage.init(page);
|
||||
}
|
||||
|
||||
static async initWithLoggedOutUser(page) {
|
||||
await this.mockRPC(page, "get-profile", "get-profile-anonymous.json");
|
||||
await BasePage.init(page);
|
||||
await BasePage.mockRPC(page, "get-profile", "get-profile-anonymous.json");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ import { DashboardPage } from "./DashboardPage";
|
||||
|
||||
export class SubscriptionProfilePage extends DashboardPage {
|
||||
static async init(page) {
|
||||
await DashboardPage.initWebSockets(page);
|
||||
await super.init(page);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
await super.mockRPC(
|
||||
page,
|
||||
"get-subscription-usage",
|
||||
"subscription/get-subscription-usage.json",
|
||||
|
||||
@@ -4,16 +4,6 @@ export class ViewerPage extends BaseWebSocketPage {
|
||||
static anyFileId = "c7ce0794-0992-8105-8004-38f280443849";
|
||||
static anyPageId = "c7ce0794-0992-8105-8004-38f28044384a";
|
||||
|
||||
/**
|
||||
* This should be called on `test.beforeEach`.
|
||||
*
|
||||
* @param {Page} page
|
||||
* @returns
|
||||
*/
|
||||
static async init(page) {
|
||||
await BaseWebSocketPage.initWebSockets(page);
|
||||
}
|
||||
|
||||
async setupLoggedInUser() {
|
||||
await this.mockRPC(
|
||||
"get-profile",
|
||||
|
||||
@@ -35,8 +35,8 @@ export class WasmWorkspacePage extends WorkspacePage {
|
||||
return WasmWorkspacePage.mockConfigFlags(this.page, flags);
|
||||
}
|
||||
|
||||
constructor(page) {
|
||||
super(page);
|
||||
constructor(page, options) {
|
||||
super(page, options);
|
||||
this.canvas = page.getByTestId("canvas-wasm-shapes");
|
||||
}
|
||||
|
||||
@@ -54,6 +54,19 @@ export class WasmWorkspacePage extends WorkspacePage {
|
||||
await this.hideUI();
|
||||
}
|
||||
|
||||
async getRenderCount() {
|
||||
return this.page.evaluate(() => window.wasmRenderCount || 0);
|
||||
}
|
||||
|
||||
async waitForNextRender(previousCount = null) {
|
||||
const baseCount =
|
||||
previousCount === null ? await this.getRenderCount() : previousCount;
|
||||
await this.page.waitForFunction(
|
||||
(count) => (window.wasmRenderCount || 0) > count,
|
||||
baseCount,
|
||||
);
|
||||
}
|
||||
|
||||
async hideUI() {
|
||||
await this.page.keyboard.press("\\");
|
||||
await expect(this.pageName).not.toBeVisible();
|
||||
|
||||
@@ -35,45 +35,9 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||
}
|
||||
|
||||
async waitForEditor() {
|
||||
return this.page.waitForSelector('[data-itype="editor"]');
|
||||
}
|
||||
|
||||
async waitForRoot() {
|
||||
return this.page.waitForSelector('[data-itype="root"]');
|
||||
}
|
||||
|
||||
async waitForParagraph(nth) {
|
||||
if (!nth) {
|
||||
return this.page.waitForSelector('[data-itype="paragraph"]');
|
||||
}
|
||||
return this.page.waitForSelector(
|
||||
`[data-itype="paragraph"]:nth-child(${nth})`,
|
||||
);
|
||||
}
|
||||
|
||||
async waitForParagraphStyle(nth, styleName) {
|
||||
const paragraph = await this.waitForParagraph(nth);
|
||||
return this.waitForStyle(paragraph, styleName);
|
||||
}
|
||||
|
||||
async waitForTextSpan(nth = 0) {
|
||||
if (!nth) {
|
||||
return this.page.waitForSelector('[data-itype="span"]');
|
||||
}
|
||||
return this.page.waitForSelector(
|
||||
`[data-itype="span"]:nth-child(${nth})`,
|
||||
);
|
||||
}
|
||||
|
||||
async waitForTextSpanContent(nth = 0) {
|
||||
const textSpan = await this.waitForTextSpan(nth);
|
||||
const textContent = await textSpan.textContent();
|
||||
return textContent;
|
||||
}
|
||||
|
||||
async waitForTextSpanStyle(nth, styleName) {
|
||||
const textSpan = await this.waitForTextSpan(nth);
|
||||
return this.waitForStyle(textSpan, styleName);
|
||||
const typographyInput =
|
||||
this.workspacePage.rightSidebar.getByLabel("Font Size");
|
||||
await expect(typographyInput).toBeVisible();
|
||||
}
|
||||
|
||||
async startEditing() {
|
||||
@@ -81,24 +45,27 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||
return this.waitForEditor();
|
||||
}
|
||||
|
||||
stopEditing() {
|
||||
return this.page.keyboard.press("Escape");
|
||||
async stopEditing() {
|
||||
await this.page.keyboard.press("Escape");
|
||||
}
|
||||
|
||||
async moveToLeft(amount = 0) {
|
||||
for (let i = 0; i < amount; i++) {
|
||||
await this.page.keyboard.press("ArrowLeft");
|
||||
}
|
||||
await this.waitForIdle();
|
||||
}
|
||||
|
||||
async moveToRight(amount = 0) {
|
||||
for (let i = 0; i < amount; i++) {
|
||||
await this.page.keyboard.press("ArrowRight");
|
||||
}
|
||||
await this.waitForIdle();
|
||||
}
|
||||
|
||||
async moveFromStart(offset = 0) {
|
||||
await this.page.keyboard.press("ArrowLeft");
|
||||
await this.page.keyboard.press("Home");
|
||||
await this.waitForIdle();
|
||||
await this.moveToRight(offset);
|
||||
}
|
||||
|
||||
@@ -125,7 +92,7 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||
await expect(locator).toBeVisible();
|
||||
await locator.focus();
|
||||
await locator.fill(`${newValue}`);
|
||||
await locator.blur();
|
||||
await this.page.keyboard.press("Enter");
|
||||
}
|
||||
|
||||
changeFontSize(newValue) {
|
||||
@@ -139,6 +106,10 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||
changeLetterSpacing(newValue) {
|
||||
return this.changeNumericInput(this.letterSpacing, newValue);
|
||||
}
|
||||
|
||||
async waitForIdle() {
|
||||
await this.page.evaluate(() => new Promise((resolve) => globalThis.requestIdleCallback(resolve)));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -148,9 +119,9 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||
* @returns
|
||||
*/
|
||||
static async init(page) {
|
||||
await BaseWebSocketPage.initWebSockets(page);
|
||||
await super.init(page);
|
||||
|
||||
await BaseWebSocketPage.mockRPCs(page, {
|
||||
await super.mockRPCs(page, {
|
||||
"get-profile": "logged-in-user/get-profile-logged-in.json",
|
||||
"get-team-users?file-id=*":
|
||||
"logged-in-user/get-team-users-single-user.json",
|
||||
@@ -198,10 +169,10 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||
`[id="shape-00000000-0000-0000-0000-000000000000"]`,
|
||||
);
|
||||
this.toolbarOptions = page.getByTestId("toolbar-options");
|
||||
this.rectShapeButton = page.getByTestId("toolbar-options").getByRole("button", { name: "Rectangle" });
|
||||
this.ellipseShapeButton = page.getByTestId("toolbar-options").getByRole("button", { name: "Ellipse" });
|
||||
this.moveButton = page.getByTestId("toolbar-options").getByRole("button", { name: "Move" });
|
||||
this.boardButton = page.getByTestId("toolbar-options").getByRole("button", { name: "Board" });
|
||||
this.rectShapeButton = page.getByRole("button", { name: "Rectangle (R)" });
|
||||
this.ellipseShapeButton = page.getByRole("button", { name: "Ellipse (E)" });
|
||||
this.moveButton = page.getByRole("button", { name: "Move (V)" });
|
||||
this.boardButton = page.getByRole("button", { name: "Board (B)" });
|
||||
this.toggleToolbarButton = page.getByRole("button", {
|
||||
name: "Toggle toolbar",
|
||||
});
|
||||
@@ -317,7 +288,6 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||
body,
|
||||
}),
|
||||
);
|
||||
// await this.mockRPC(/get\-file\?/, jsonFile);
|
||||
}
|
||||
|
||||
async mockGetAsset(regex, asset) {
|
||||
@@ -391,10 +361,12 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||
const timeToWait = options?.timeToWait ?? 100;
|
||||
await this.page.keyboard.press("T");
|
||||
await this.page.waitForTimeout(timeToWait);
|
||||
|
||||
const layersCountBefore = await this.layers.getByTestId("layer-row").count();
|
||||
await this.clickAndMove(x1, y1, x2, y2);
|
||||
await expect(this.page.getByTestId("text-editor")).toBeVisible();
|
||||
|
||||
if (initialText) {
|
||||
await this.waitForSelectedShapeName("Text");
|
||||
await this.page.keyboard.type(initialText);
|
||||
}
|
||||
}
|
||||
@@ -494,10 +466,23 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||
|
||||
async expectSelectedLayer(name) {
|
||||
await expect(
|
||||
this.layers
|
||||
.getByTestId("layer-row")
|
||||
.filter({ has: this.page.getByText(name) }),
|
||||
).toHaveClass(/selected/);
|
||||
this.layers.getByRole("checkbox", { name, checked: true }),
|
||||
).toBeVisible();
|
||||
}
|
||||
|
||||
async getSelectedShapeName() {
|
||||
const selectedLayer = this.layers
|
||||
.getByRole("checkbox", { checked: true })
|
||||
.first();
|
||||
await selectedLayer.waitFor({ state: "visible" });
|
||||
return (await selectedLayer.innerText()).trim();
|
||||
}
|
||||
|
||||
async waitForSelectedShapeName(expectedName) {
|
||||
const selectedLayer = this.layers
|
||||
.getByRole("checkbox", { checked: true })
|
||||
.first();
|
||||
await expect(selectedLayer).toHaveText(expectedName);
|
||||
}
|
||||
|
||||
async expectHiddenToolbarOptions() {
|
||||
|
||||
@@ -243,6 +243,46 @@ test("Renders a file with a closed path shape with multiple segments using strok
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("Renders solid shadows after select all and zoom to selected", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = new WasmWorkspacePage(page);
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.mockGetFile("render-wasm/get-solid-shadows.json");
|
||||
|
||||
await workspace.goToWorkspace({
|
||||
id: "93113137-fe66-80fb-8007-99ca9fd96841",
|
||||
pageId: "93113137-fe66-80fb-8007-99ca9fd96842",
|
||||
});
|
||||
await workspace.waitForFirstRender();
|
||||
|
||||
await workspace.viewport.click();
|
||||
await page.keyboard.press("ControlOrMeta+A");
|
||||
const previousRenderCount = await workspace.getRenderCount();
|
||||
await page.keyboard.press("f");
|
||||
await workspace.waitForNextRender(previousRenderCount);
|
||||
|
||||
await workspace.hideUI();
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("Renders strokes with solid shadows", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = new WasmWorkspacePage(page);
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.mockGetFile("render-wasm/get-solid-strokes-shadows.json");
|
||||
|
||||
await workspace.goToWorkspace({
|
||||
id: "93113137-fe66-80fb-8007-99cfd5cbf361",
|
||||
pageId: "93113137-fe66-80fb-8007-99cfd5cbf362",
|
||||
});
|
||||
await workspace.waitForFirstRender();
|
||||
|
||||
await workspace.hideUI();
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("Renders a file with paths and svg attrs", async ({ page }) => {
|
||||
const workspace = new WasmWorkspacePage(page);
|
||||
await workspace.setupEmptyFile();
|
||||
@@ -356,3 +396,39 @@ test("Renders shapes with multiple fills and blur", async ({
|
||||
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("Keeps component visible when focusing after creating it", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = new WasmWorkspacePage(page);
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.mockRPC(/get\-file\?/, "workspace/get-file-not-empty.json");
|
||||
await workspace.mockRPC(
|
||||
"update-file?id=*",
|
||||
"workspace/update-file-create-rect.json",
|
||||
);
|
||||
|
||||
await workspace.goToWorkspace({
|
||||
fileId: "6191cd35-bb1f-81f7-8004-7cc63d087374",
|
||||
pageId: "6191cd35-bb1f-81f7-8004-7cc63d087375",
|
||||
});
|
||||
await workspace.waitForFirstRender();
|
||||
|
||||
await workspace.clickLayers();
|
||||
await workspace.clickLeafLayer("Rectangle");
|
||||
await page.keyboard.press("ControlOrMeta+k");
|
||||
|
||||
const componentLayer = workspace.layers
|
||||
.getByTestId("layer-row")
|
||||
.filter({ has: page.getByTestId("icon-component") })
|
||||
.first();
|
||||
await expect(componentLayer).toBeVisible();
|
||||
await componentLayer.click();
|
||||
|
||||
const previousRenderCount = await workspace.getRenderCount();
|
||||
await page.keyboard.press("f");
|
||||
await workspace.waitForNextRender(previousRenderCount);
|
||||
|
||||
await workspace.hideUI();
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 348 KiB After Width: | Height: | Size: 348 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 140 KiB |
@@ -3,11 +3,6 @@ import DashboardPage from "../pages/DashboardPage";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await DashboardPage.init(page);
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"logged-in-user/get-profile-logged-in-no-onboarding.json",
|
||||
);
|
||||
});
|
||||
|
||||
test.describe("Dashboard Deleted Page", () => {
|
||||
|
||||
@@ -3,11 +3,6 @@ import DashboardPage from "../pages/DashboardPage";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await DashboardPage.init(page);
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"logged-in-user/get-profile-logged-in-no-onboarding.json",
|
||||
);
|
||||
});
|
||||
|
||||
test("BUG 10421 - Fix libraries context menu", async ({ page }) => {
|
||||
|
||||
@@ -3,11 +3,6 @@ import DashboardPage from "../pages/DashboardPage";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await DashboardPage.init(page);
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"logged-in-user/get-profile-logged-in-no-onboarding.json",
|
||||
);
|
||||
});
|
||||
|
||||
test("BUG 12359 - Selected invitations count is not pluralized", async ({
|
||||
|
||||
@@ -3,11 +3,7 @@ import DashboardPage from "../pages/DashboardPage";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await DashboardPage.init(page);
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"logged-in-user/get-profile-logged-in-no-onboarding.json",
|
||||
);
|
||||
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-teams",
|
||||
|
||||
@@ -3,11 +3,6 @@ import DashboardPage from "../pages/DashboardPage";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await DashboardPage.init(page);
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"logged-in-user/get-profile-logged-in-no-onboarding.json",
|
||||
);
|
||||
});
|
||||
|
||||
test("Dashboad page has title ", async ({ page }) => {
|
||||
|
||||
@@ -189,8 +189,8 @@ test("BUG 7760 - Layout losing properties when changing parents", async ({
|
||||
await workspacePage.clickLeafLayer("Flex Board");
|
||||
|
||||
// Move the first board into the second
|
||||
const hAuto = await workspacePage.page.getByTestId("behaviour-h-auto");
|
||||
const vAuto = await workspacePage.page.getByTestId("behaviour-v-auto");
|
||||
const hAuto = await workspacePage.page.getByTitle("Fit content (Horizontal)");
|
||||
const vAuto = await workspacePage.page.getByTitle("Fit content (Vertical)");
|
||||
|
||||
await expect(vAuto.locator("input")).toBeChecked();
|
||||
await expect(hAuto.locator("input")).toBeChecked();
|
||||
|
||||
@@ -2,6 +2,8 @@ import { test, expect } from "@playwright/test";
|
||||
import { LoginPage } from "../pages/LoginPage";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await LoginPage.init(page);
|
||||
|
||||
const login = new LoginPage(page);
|
||||
await login.initWithLoggedOutUser();
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import OnboardingPage from "../pages/OnboardingPage";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await DashboardPage.init(page);
|
||||
await DashboardPage.mockConfigFlags(page, ["enable-onboarding"]);
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
|
||||
@@ -3,11 +3,6 @@ import DashboardPage from "../pages/DashboardPage";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await DashboardPage.init(page);
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"logged-in-user/get-profile-logged-in-no-onboarding.json",
|
||||
);
|
||||
});
|
||||
|
||||
test("Navigate to penpot changelog from profile menu", async ({ page }) => {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { Clipboard } from "../../helpers/Clipboard";
|
||||
import { WorkspacePage } from "../pages/WorkspacePage";
|
||||
|
||||
const timeToWait = 100;
|
||||
import { WasmWorkspacePage } from "../pages/WasmWorkspacePage";
|
||||
|
||||
test.beforeEach(async ({ page, context }) => {
|
||||
await Clipboard.enable(context, Clipboard.Permission.ALL);
|
||||
|
||||
await WorkspacePage.init(page);
|
||||
await WorkspacePage.mockConfigFlags(page, ["enable-feature-text-editor-v2"]);
|
||||
await WasmWorkspacePage.init(page);
|
||||
await WasmWorkspacePage.mockConfigFlags(page, ["enable-feature-text-editor-v2"]);
|
||||
});
|
||||
|
||||
test.afterEach(async ({ context }) => {
|
||||
@@ -17,39 +15,36 @@ test.afterEach(async ({ context }) => {
|
||||
|
||||
test("Create a new text shape", async ({ page }) => {
|
||||
const initialText = "Lorem ipsum";
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.goToWorkspace();
|
||||
await workspace.createTextShape(190, 150, 300, 200, initialText);
|
||||
|
||||
const textContent = await workspace.textEditor.waitForTextSpanContent();
|
||||
expect(textContent).toBe(initialText);
|
||||
|
||||
await workspace.textEditor.stopEditing();
|
||||
|
||||
await workspace.waitForSelectedShapeName(initialText);
|
||||
});
|
||||
|
||||
test("Create a new text shape from pasting text", async ({ page, context }) => {
|
||||
const textToPaste = "Lorem ipsum";
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.mockRPC("update-file?id=*", "text-editor/update-file.json");
|
||||
await workspace.goToWorkspace();
|
||||
await workspace.moveButton.click();
|
||||
|
||||
await Clipboard.writeText(page, textToPaste);
|
||||
|
||||
await workspace.clickAt(190, 150);
|
||||
await workspace.paste("keyboard");
|
||||
|
||||
await page.waitForTimeout(timeToWait);
|
||||
|
||||
const textContent = await workspace.textEditor.waitForTextSpanContent();
|
||||
expect(textContent).toBe(textToPaste);
|
||||
|
||||
await workspace.textEditor.stopEditing();
|
||||
|
||||
await expect(workspace.layers.getByText(textToPaste)).toBeVisible();
|
||||
});
|
||||
|
||||
test("Create a new text shape from pasting text using context menu", async ({
|
||||
@@ -57,27 +52,26 @@ test("Create a new text shape from pasting text using context menu", async ({
|
||||
context,
|
||||
}) => {
|
||||
const textToPaste = "Lorem ipsum";
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.goToWorkspace();
|
||||
await workspace.moveButton.click();
|
||||
|
||||
await Clipboard.writeText(page, textToPaste);
|
||||
|
||||
await workspace.clickAt(190, 150);
|
||||
await workspace.paste("context-menu");
|
||||
|
||||
const textContent = await workspace.textEditor.waitForTextSpanContent();
|
||||
expect(textContent).toBe(textToPaste);
|
||||
|
||||
await workspace.textEditor.stopEditing();
|
||||
|
||||
await expect(workspace.layers.getByText(textToPaste)).toBeVisible();
|
||||
});
|
||||
|
||||
test("Update an already created text shape by appending text", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
@@ -87,15 +81,14 @@ test("Update an already created text shape by appending text", async ({
|
||||
await workspace.textEditor.startEditing();
|
||||
await workspace.textEditor.moveFromEnd(0);
|
||||
await page.keyboard.type(" dolor sit amet");
|
||||
const textContent = await workspace.textEditor.waitForTextSpanContent();
|
||||
expect(textContent).toBe("Lorem ipsum dolor sit amet");
|
||||
await workspace.textEditor.stopEditing();
|
||||
await workspace.waitForSelectedShapeName("Lorem ipsum dolor sit amet");
|
||||
});
|
||||
|
||||
test("Update an already created text shape by prepending text", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
@@ -105,15 +98,14 @@ test("Update an already created text shape by prepending text", async ({
|
||||
await workspace.textEditor.startEditing();
|
||||
await workspace.textEditor.moveFromStart(0);
|
||||
await page.keyboard.type("Dolor sit amet ");
|
||||
const textContent = await workspace.textEditor.waitForTextSpanContent();
|
||||
expect(textContent).toBe("Dolor sit amet Lorem ipsum");
|
||||
await workspace.textEditor.stopEditing();
|
||||
await workspace.waitForSelectedShapeName("Dolor sit amet Lorem ipsum");
|
||||
});
|
||||
|
||||
test.skip("Update an already created text shape by inserting text in between", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
@@ -123,9 +115,8 @@ test.skip("Update an already created text shape by inserting text in between", a
|
||||
await workspace.textEditor.startEditing();
|
||||
await workspace.textEditor.moveFromStart(5);
|
||||
await page.keyboard.type(" dolor sit amet");
|
||||
const textContent = await workspace.textEditor.waitForTextSpanContent();
|
||||
expect(textContent).toBe("Lorem dolor sit amet ipsum");
|
||||
await workspace.textEditor.stopEditing();
|
||||
await workspace.waitForSelectedShapeName("Lorem dolor sit amet ipsum");
|
||||
});
|
||||
|
||||
test("Update a new text shape appending text by pasting text", async ({
|
||||
@@ -133,7 +124,7 @@ test("Update a new text shape appending text by pasting text", async ({
|
||||
context,
|
||||
}) => {
|
||||
const textToPaste = " dolor sit amet";
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
@@ -146,9 +137,8 @@ test("Update a new text shape appending text by pasting text", async ({
|
||||
await workspace.textEditor.startEditing();
|
||||
await workspace.textEditor.moveFromEnd();
|
||||
await workspace.paste("keyboard");
|
||||
const textContent = await workspace.textEditor.waitForTextSpanContent();
|
||||
expect(textContent).toBe("Lorem ipsum dolor sit amet");
|
||||
await workspace.textEditor.stopEditing();
|
||||
await workspace.waitForSelectedShapeName("Lorem ipsum dolor sit amet");
|
||||
});
|
||||
|
||||
test.skip("Update a new text shape prepending text by pasting text", async ({
|
||||
@@ -156,7 +146,7 @@ test.skip("Update a new text shape prepending text by pasting text", async ({
|
||||
context,
|
||||
}) => {
|
||||
const textToPaste = "Dolor sit amet ";
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
@@ -169,16 +159,17 @@ test.skip("Update a new text shape prepending text by pasting text", async ({
|
||||
await workspace.textEditor.startEditing();
|
||||
await workspace.textEditor.moveFromStart();
|
||||
await workspace.paste("keyboard");
|
||||
const textContent = await workspace.textEditor.waitForTextSpanContent();
|
||||
expect(textContent).toBe("Dolor sit amet Lorem ipsum");
|
||||
await workspace.textEditor.stopEditing();
|
||||
|
||||
await workspace.hideUI();
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("Update a new text shape replacing (starting) text with pasted text", async ({
|
||||
page,
|
||||
}) => {
|
||||
const textToPaste = "Dolor sit amet";
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
@@ -192,17 +183,15 @@ test("Update a new text shape replacing (starting) text with pasted text", async
|
||||
|
||||
await workspace.paste("keyboard");
|
||||
|
||||
const textContent = await workspace.textEditor.waitForTextSpanContent();
|
||||
expect(textContent).toBe("Dolor sit amet ipsum");
|
||||
|
||||
await workspace.textEditor.stopEditing();
|
||||
await workspace.waitForSelectedShapeName("Dolor sit amet ipsum");
|
||||
});
|
||||
|
||||
test("Update a new text shape replacing (ending) text with pasted text", async ({
|
||||
page,
|
||||
}) => {
|
||||
const textToPaste = "dolor sit amet";
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
@@ -216,17 +205,15 @@ test("Update a new text shape replacing (ending) text with pasted text", async (
|
||||
|
||||
await workspace.paste("keyboard");
|
||||
|
||||
const textContent = await workspace.textEditor.waitForTextSpanContent();
|
||||
expect(textContent).toBe("Lorem dolor sit amet");
|
||||
|
||||
await workspace.textEditor.stopEditing();
|
||||
await workspace.waitForSelectedShapeName("Lorem dolor sit amet");
|
||||
});
|
||||
|
||||
test("Update a new text shape replacing (in between) text with pasted text", async ({
|
||||
page,
|
||||
}) => {
|
||||
const textToPaste = "dolor sit amet";
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
@@ -240,16 +227,14 @@ test("Update a new text shape replacing (in between) text with pasted text", asy
|
||||
|
||||
await workspace.paste("keyboard");
|
||||
|
||||
const textContent = await workspace.textEditor.waitForTextSpanContent();
|
||||
expect(textContent).toBe("Lordolor sit ametsum");
|
||||
|
||||
await workspace.textEditor.stopEditing();
|
||||
await workspace.waitForSelectedShapeName("Lordolor sit ametsum");
|
||||
});
|
||||
|
||||
test("Update text font size selecting a part of it (starting)", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
@@ -260,18 +245,16 @@ test("Update text font size selecting a part of it (starting)", async ({
|
||||
await workspace.textEditor.startEditing();
|
||||
await workspace.textEditor.selectFromStart(5);
|
||||
await workspace.textEditor.changeFontSize(36);
|
||||
|
||||
const textContent1 = await workspace.textEditor.waitForTextSpanContent(1);
|
||||
expect(textContent1).toBe("Lorem");
|
||||
const textContent2 = await workspace.textEditor.waitForTextSpanContent(2);
|
||||
expect(textContent2).toBe(" ipsum");
|
||||
await workspace.textEditor.stopEditing();
|
||||
|
||||
await workspace.hideUI();
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test.skip("Update text line height selecting a part of it (starting)", async ({
|
||||
test("Update text line height selecting a part of it (starting)", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
@@ -281,24 +264,17 @@ test.skip("Update text line height selecting a part of it (starting)", async ({
|
||||
await workspace.clickLeafLayer("Lorem ipsum");
|
||||
await workspace.textEditor.startEditing();
|
||||
await workspace.textEditor.selectFromStart(5);
|
||||
await workspace.textEditor.changeLineHeight(1.4);
|
||||
|
||||
const lineHeight = await workspace.textEditor.waitForParagraphStyle(
|
||||
1,
|
||||
"line-height",
|
||||
);
|
||||
expect(lineHeight).toBe("1.4");
|
||||
|
||||
const textContent = await workspace.textEditor.waitForTextSpanContent();
|
||||
expect(textContent).toBe("Lorem ipsum");
|
||||
|
||||
await workspace.textEditor.changeLineHeight(4.4);
|
||||
await workspace.textEditor.stopEditing();
|
||||
|
||||
await workspace.hideUI();
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test.skip("Update text letter spacing selecting a part of it (starting)", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = new WorkspacePage(page, {
|
||||
const workspace = new WasmWorkspacePage(page, {
|
||||
textEditor: true,
|
||||
});
|
||||
await workspace.setupEmptyFile();
|
||||
@@ -309,16 +285,14 @@ test.skip("Update text letter spacing selecting a part of it (starting)", async
|
||||
await workspace.textEditor.startEditing();
|
||||
await workspace.textEditor.selectFromStart(5);
|
||||
await workspace.textEditor.changeLetterSpacing(10);
|
||||
|
||||
const textContent1 = await workspace.textEditor.waitForTextSpanContent(1);
|
||||
expect(textContent1).toBe("Lorem");
|
||||
const textContent2 = await workspace.textEditor.waitForTextSpanContent(2);
|
||||
expect(textContent2).toBe(" ipsum");
|
||||
await workspace.textEditor.stopEditing();
|
||||
|
||||
await workspace.hideUI();
|
||||
await expect(workspace.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
test("BUG 11552 - Apply styles to the current caret", async ({ page }) => {
|
||||
const workspace = new WorkspacePage(page);
|
||||
const workspace = new WasmWorkspacePage(page);
|
||||
await workspace.setupEmptyFile();
|
||||
await workspace.mockGetFile("text-editor/get-file-11552.json");
|
||||
await workspace.mockRPC(
|
||||
|
||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -1493,10 +1493,8 @@ test.describe("Tokens - creation", () => {
|
||||
const nameField = tokensUpdateCreateModal.getByLabel("Name");
|
||||
await nameField.fill(newTokenTitle);
|
||||
|
||||
const referenceTabButton = tokensUpdateCreateModal.getByRole("button", {
|
||||
name: "Use a reference",
|
||||
});
|
||||
referenceTabButton.click();
|
||||
const referenceTabButton = tokensUpdateCreateModal.getByTestId("reference-opt");
|
||||
await referenceTabButton.click();
|
||||
|
||||
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {
|
||||
name: "Reference",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { WasmWorkspacePage } from "../pages/WasmWorkspacePage";
|
||||
import { WasmWorkspacePage } from "../pages/WasmWorkspacePage";
|
||||
import { BaseWebSocketPage } from "../pages/BaseWebSocketPage";
|
||||
import { Clipboard } from "../../helpers/Clipboard";
|
||||
|
||||
@@ -7,7 +7,7 @@ test.beforeEach(async ({ page, context }) => {
|
||||
await Clipboard.enable(context, Clipboard.Permission.ALL);
|
||||
|
||||
await WasmWorkspacePage.init(page);
|
||||
await BaseWebSocketPage.mockRPC(page, "get-teams", "get-teams-variants.json");
|
||||
await WasmWorkspacePage.mockConfigFlags(page, ["enable-feature-variants"]);
|
||||
});
|
||||
|
||||
test.afterEach(async ({ context }) => {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { WasmWorkspacePage } from "../pages/WasmWorkspacePage";
|
||||
import { presenceFixture } from "../../data/workspace/ws-notifications";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await WasmWorkspacePage.init(page);
|
||||
@@ -106,9 +105,37 @@ test("BUG 11006 - Fix history panel shortcut", async ({ page }) => {
|
||||
|
||||
await workspacePage.goToWorkspace();
|
||||
|
||||
await page.keyboard.press("Control+Alt+h");
|
||||
await page.keyboard.press("ControlOrMeta+Alt+h");
|
||||
|
||||
await expect(
|
||||
workspacePage.rightSidebar.getByText("There are no versions yet"),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("BUG 13385 - Fix viewport not updating when restoring version", async ({ page }) => {
|
||||
const workspacePage = new WasmWorkspacePage(page);
|
||||
await workspacePage.setupEmptyFile();
|
||||
await workspacePage.mockGetFile("workspace/get-file-13385.json");
|
||||
await workspacePage.mockRPC("get-profiles-for-file-comments?file-id=*", "workspace/get-profiles-for-file-comments-13385.json");
|
||||
|
||||
// navigate to workspace and check that the circle shape is not there
|
||||
await workspacePage.goToWorkspace();
|
||||
await expect(workspacePage.layers.getByText("Ellipse")).not.toBeVisible();
|
||||
|
||||
// mock network requests to restore the version
|
||||
await workspacePage.mockGetFile("workspace/get-file-13385-2.json");
|
||||
await workspacePage.mockRPC("get-file-snapshots?file-id=*", "workspace/get-file-snapshots-13385.json");
|
||||
await workspacePage.mockRPC("restore-file-snapshot", "", {
|
||||
status: 204,
|
||||
});
|
||||
|
||||
// request to restore the version
|
||||
await workspacePage.rightSidebar.getByRole("button", { name: "History" }).click();
|
||||
await workspacePage.rightSidebar.getByRole("button", { name: "Open version menu" }).click();
|
||||
await workspacePage.rightSidebar.getByRole("button", { name: "Restore" }).click();
|
||||
// confirm modal
|
||||
await workspacePage.page.getByRole("button", { name: /Restore/i }).click();
|
||||
|
||||
// assert that the circle shape exists
|
||||
await expect(workspacePage.layers.getByText("Ellipse")).toBeVisible();
|
||||
});
|
||||
@@ -23,4 +23,63 @@ test("BUG 13305 - Fix resize board to fit content", async ({ page }) => {
|
||||
await expect(workspacePage.rightSidebar.getByTitle("Height").getByRole("textbox")).toHaveValue("630");
|
||||
await expect(workspacePage.rightSidebar.getByTitle("X axis").getByRole("textbox")).toHaveValue("110");
|
||||
await expect(workspacePage.rightSidebar.getByTitle("Y axis").getByRole("textbox")).toHaveValue("110");
|
||||
});
|
||||
});
|
||||
|
||||
test("BUG 13382 - Fix problem with flex layout", async ({ page }) => {
|
||||
const workspacePage = new WasmWorkspacePage(page);
|
||||
await workspacePage.setupEmptyFile();
|
||||
await workspacePage.mockGetFile("workspace/get-file-13382.json");
|
||||
|
||||
await workspacePage.mockRPC(
|
||||
"get-file-fragment?file-id=*&fragment-id=*",
|
||||
"workspace/get-file-13382-fragment.json",
|
||||
);
|
||||
|
||||
await workspacePage.mockRPC("update-file?id=*", "workspace/update-file-empty.json");
|
||||
|
||||
await workspacePage.goToWorkspace({
|
||||
fileId: "52c4e771-3853-8190-8007-9506c70e8100",
|
||||
pageId: "ecb0cfd0-0f0b-81f7-8007-950628f9665b",
|
||||
});
|
||||
|
||||
await workspacePage.clickToggableLayer("A");
|
||||
await workspacePage.clickToggableLayer("B");
|
||||
await workspacePage.clickToggableLayer("C");
|
||||
await workspacePage.clickLeafLayer("R2");
|
||||
|
||||
const heightText = workspacePage.rightSidebar.getByTitle("Height").getByPlaceholder('--');
|
||||
await heightText.fill("200");
|
||||
await heightText.press("Enter");
|
||||
|
||||
await workspacePage.clickLeafLayer("B");
|
||||
await expect(workspacePage.rightSidebar.getByTitle("Height").getByRole("textbox")).toHaveValue("340");
|
||||
|
||||
});
|
||||
|
||||
test("BUG 13468 - Fix problem with flex propagation", async ({ page }) => {
|
||||
const workspacePage = new WasmWorkspacePage(page);
|
||||
await workspacePage.setupEmptyFile();
|
||||
await workspacePage.mockGetFile("workspace/get-file-13468.json");
|
||||
|
||||
await workspacePage.mockRPC(
|
||||
"get-file-fragment?file-id=*&fragment-id=*",
|
||||
"workspace/get-file-13468-fragment.json",
|
||||
);
|
||||
|
||||
await workspacePage.mockRPC("update-file?id=*", "workspace/update-file-empty.json");
|
||||
|
||||
await workspacePage.goToWorkspace({
|
||||
fileId: "3a4d7ec7-c391-8146-8007-9a05c41da6b9",
|
||||
pageId: "95b23c15-79f9-81ba-8007-99d81b5290dd",
|
||||
});
|
||||
0
|
||||
await workspacePage.clickToggableLayer("Parent");
|
||||
await workspacePage.clickToggableLayer("Container");
|
||||
|
||||
await workspacePage.sidebar.getByRole('button', { name: 'Show' }).click();
|
||||
|
||||
await workspacePage.clickLeafLayer("Container");
|
||||
await expect(workspacePage.rightSidebar.getByTitle("Height").getByRole("textbox")).toHaveValue("76");
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -353,33 +353,24 @@ test("Copy/paste properties", async ({ page, context }) => {
|
||||
await page.getByText("Copy/Paste as").hover();
|
||||
await page.getByText("Paste properties").click();
|
||||
|
||||
await page
|
||||
.getByTestId("layer-item")
|
||||
.getByText("Rectangle")
|
||||
.first()
|
||||
.click({ button: "right" });
|
||||
await page.getByText("Rectangle").first().click({ button: "right" });
|
||||
await page.getByText("Copy/Paste as").hover();
|
||||
await page.getByText("Paste properties").click();
|
||||
|
||||
await page.getByText("Board").nth(2).click({ button: "right" });
|
||||
await page.getByText("Copy/Paste as").hover();
|
||||
await page.getByText("Paste properties").click();
|
||||
|
||||
await page
|
||||
.getByTestId("layer-item")
|
||||
.getByText("Board")
|
||||
.locator("div")
|
||||
.filter({ hasText: "Path" })
|
||||
.nth(1)
|
||||
.click({ button: "right" });
|
||||
await page.getByText("Copy/Paste as").hover();
|
||||
await page.getByText("Paste properties").click();
|
||||
|
||||
await page
|
||||
.getByTestId("layer-item")
|
||||
.getByText("Path")
|
||||
.click({ button: "right" });
|
||||
await page.getByText("Copy/Paste as").hover();
|
||||
await page.getByText("Paste properties").click();
|
||||
|
||||
await page
|
||||
.getByTestId("layer-item")
|
||||
.getByText("Ellipse")
|
||||
.click({ button: "right" });
|
||||
await page.getByText("Ellipse").click({ button: "right" });
|
||||
await page.getByText("Copy/Paste as").hover();
|
||||
await page.getByText("Paste properties").click();
|
||||
});
|
||||
@@ -492,3 +483,25 @@ test("Bug 8371 - Flatten option is not visible in context menu", async ({
|
||||
.filter({ visible: true }),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("BUG 13415 - Grid layout overlay is not removed when deleting a board", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspacePage = new WasmWorkspacePage(page);
|
||||
await workspacePage.setupEmptyFile(page);
|
||||
await workspacePage.mockGetFile("workspace/get-file-13415.json");
|
||||
await workspacePage.mockRPC(
|
||||
"update-file?id=*",
|
||||
"workspace/update-file-13415.json",
|
||||
);
|
||||
|
||||
await workspacePage.goToWorkspace();
|
||||
await workspacePage.clickLeafLayer("Board");
|
||||
|
||||
const currentRenderCount = await workspacePage.getRenderCount();
|
||||
await workspacePage.page.keyboard.press("Delete");
|
||||
|
||||
await workspacePage.waitForNextRender(currentRenderCount);
|
||||
await workspacePage.hideUI();
|
||||
await expect(workspacePage.canvas).toHaveScreenshot();
|
||||
});
|
||||
|
||||
|
After Width: | Height: | Size: 9.3 KiB |
@@ -3,11 +3,6 @@ import DashboardPage from "../pages/DashboardPage";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await DashboardPage.init(page);
|
||||
await DashboardPage.mockRPC(
|
||||
page,
|
||||
"get-profile",
|
||||
"logged-in-user/get-profile-logged-in-no-onboarding.json",
|
||||
);
|
||||
});
|
||||
|
||||
test("User goes to an empty dashboard", async ({ page }) => {
|
||||
|
||||
@@ -2,6 +2,8 @@ import { test, expect } from "@playwright/test";
|
||||
import { LoginPage } from "../pages/LoginPage";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await LoginPage.init(page);
|
||||
|
||||
const login = new LoginPage(page);
|
||||
await login.initWithLoggedOutUser();
|
||||
await login.page.goto("/#/auth/login");
|
||||
|
||||
47
frontend/pnpm-lock.yaml
generated
@@ -20,8 +20,8 @@ importers:
|
||||
specifier: workspace:./packages/mousetrap
|
||||
version: link:packages/mousetrap
|
||||
'@penpot/plugins-runtime':
|
||||
specifier: 1.4.2
|
||||
version: 1.4.2
|
||||
specifier: link:../plugins/dist/plugins-runtime
|
||||
version: link:../plugins/dist/plugins-runtime
|
||||
'@penpot/svgo':
|
||||
specifier: penpot/svgo#v3.2
|
||||
version: svgo@https://codeload.github.com/penpot/svgo/tar.gz/8c9b0e32e9cb5f106085260bd9375f3c91a5010b
|
||||
@@ -581,15 +581,6 @@ packages:
|
||||
'@dabh/diagnostics@2.0.8':
|
||||
resolution: {integrity: sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==}
|
||||
|
||||
'@endo/cache-map@1.1.0':
|
||||
resolution: {integrity: sha512-owFGshs/97PDw9oguZqU/px8Lv1d0KjAUtDUiPwKHNXRVUE/jyettEbRoTbNJR1OaI8biMn6bHr9kVJsOh6dXw==}
|
||||
|
||||
'@endo/env-options@1.1.11':
|
||||
resolution: {integrity: sha512-p9OnAPsdqoX4YJsE98e3NBVhIr2iW9gNZxHhAI2/Ul5TdRfoOViItzHzTqrgUVopw6XxA1u1uS6CykLMDUxarA==}
|
||||
|
||||
'@endo/immutable-arraybuffer@1.1.2':
|
||||
resolution: {integrity: sha512-u+NaYB2aqEugQ3u7w3c5QNkPogf8q/xGgsPaqdY6pUiGWtYiTiFspKFcha6+oeZhWXWQ23rf0KrUq0kfuzqYyQ==}
|
||||
|
||||
'@esbuild/aix-ppc64@0.21.5':
|
||||
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -1258,12 +1249,6 @@ packages:
|
||||
resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
|
||||
'@penpot/plugin-types@1.4.2':
|
||||
resolution: {integrity: sha512-O8wU6RSYE8bIVU7g8cSTYi32ppxs3R13dq7X3Nn9tmDaJjBOKOBpVLuoRPIp3fJC65fv8/7om0sdrtFoL5v19g==}
|
||||
|
||||
'@penpot/plugins-runtime@1.4.2':
|
||||
resolution: {integrity: sha512-y9TDZOnb96JBW9E33dHKpmTMeAPXLtHDIZruUVjtM8hBJWZK7RCv+vAGDGxeoZJC/OB2YAHrCZG+mukePBzcuQ==}
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -4636,9 +4621,6 @@ packages:
|
||||
resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
ses@1.14.0:
|
||||
resolution: {integrity: sha512-T07hNgOfVRTLZGwSS50RnhqrG3foWP+rM+Q5Du4KUQyMLFI3A8YA4RKl0jjZzhihC1ZvDGrWi/JMn4vqbgr/Jg==}
|
||||
|
||||
set-function-length@1.2.2:
|
||||
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -5499,9 +5481,6 @@ packages:
|
||||
peerDependencies:
|
||||
zod: ^3.25.0 || ^4.0.0
|
||||
|
||||
zod@3.25.76:
|
||||
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
|
||||
|
||||
zod@4.3.6:
|
||||
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
||||
|
||||
@@ -5775,12 +5754,6 @@ snapshots:
|
||||
enabled: 2.0.0
|
||||
kuler: 2.0.0
|
||||
|
||||
'@endo/cache-map@1.1.0': {}
|
||||
|
||||
'@endo/env-options@1.1.11': {}
|
||||
|
||||
'@endo/immutable-arraybuffer@1.1.2': {}
|
||||
|
||||
'@esbuild/aix-ppc64@0.21.5':
|
||||
optional: true
|
||||
|
||||
@@ -6297,14 +6270,6 @@ snapshots:
|
||||
'@parcel/watcher-win32-x64': 2.5.6
|
||||
optional: true
|
||||
|
||||
'@penpot/plugin-types@1.4.2': {}
|
||||
|
||||
'@penpot/plugins-runtime@1.4.2':
|
||||
dependencies:
|
||||
'@penpot/plugin-types': 1.4.2
|
||||
ses: 1.14.0
|
||||
zod: 3.25.76
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
@@ -10000,12 +9965,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
ses@1.14.0:
|
||||
dependencies:
|
||||
'@endo/cache-map': 1.1.0
|
||||
'@endo/env-options': 1.1.11
|
||||
'@endo/immutable-arraybuffer': 1.1.2
|
||||
|
||||
set-function-length@1.2.2:
|
||||
dependencies:
|
||||
define-data-property: 1.1.4
|
||||
@@ -10974,6 +10933,4 @@ snapshots:
|
||||
dependencies:
|
||||
zod: 4.3.6
|
||||
|
||||
zod@3.25.76: {}
|
||||
|
||||
zod@4.3.6: {}
|
||||
|
||||
@@ -244,6 +244,13 @@
|
||||
--assets-component-second-border-selected: var(--color-background-primary);
|
||||
--assets-component-hightlight: var(--color-accent-secondary);
|
||||
|
||||
--radio-btns-background-color: var(--color-background-tertiary);
|
||||
--radio-btn-background-color-selected: var(--color-background-quaternary);
|
||||
--radio-btn-foreground-color: var(--color-foreground-secondary);
|
||||
--radio-btn-foreground-color-selected: var(--color-accent-primary);
|
||||
--radio-btn-border-color: var(--color-background-tertiary);
|
||||
--radio-btn-border-color-selected: var(--color-background-quaternary);
|
||||
|
||||
--library-name-foreground-color: var(--color-foreground-primary);
|
||||
--library-content-foreground-color: var(--color-foreground-secondary);
|
||||
|
||||
@@ -416,6 +423,13 @@
|
||||
--tab-border-color: var(--color-background-tertiary);
|
||||
--tab-border-color-selected: var(--color-background-secondary);
|
||||
|
||||
--radio-btns-background-color: var(--color-background-tertiary);
|
||||
--radio-btn-background-color-selected: var(--color-background-primary);
|
||||
--radio-btn-foreground-color: var(--color-foreground-secondary);
|
||||
--radio-btn-foreground-color-selected: var(--color-accent-primary);
|
||||
--radio-btn-border-color: var(--color-background-tertiary);
|
||||
--radio-btn-border-color-selected: var(--color-background-secondary);
|
||||
|
||||
--button-icon-background-color-selected: var(--color-background-primary);
|
||||
--button-icon-border-color-selected: var(--color-background-secondary);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<meta name="twitter:creator" content="@penpotapp">
|
||||
<meta name="theme-color" content="#FFFFFF" media="(prefers-color-scheme: light)">
|
||||
<link id="theme" href="css/main.css?version={{& version_tag}}" rel="stylesheet" type="text/css" />
|
||||
<link href="css/ui.css?ts={{& ts}}" rel="stylesheet" type="text/css" />
|
||||
<link href="css/ui.css?ts={{& version_tag}}" rel="stylesheet" type="text/css" />
|
||||
{{#isDebug}}
|
||||
<link href="css/debug.css?version={{& version_tag}}" rel="stylesheet" type="text/css" />
|
||||
{{/isDebug}}
|
||||
|
||||
@@ -4,4 +4,9 @@ TARGET=${1:-app};
|
||||
|
||||
set -ex
|
||||
|
||||
exec pnpm run watch:$TARGET
|
||||
rm -rf node_modules;
|
||||
|
||||
corepack enable;
|
||||
corepack install;
|
||||
pnpm install;
|
||||
pnpm run watch:$TARGET
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
Structured tokens are non-primitive token types like `typography` or `box-shadow`."
|
||||
[^js token-symbol]
|
||||
(if (instance? js/Array (.-value token-symbol))
|
||||
(mapv structured-token->penpot-map (.-value token-symbol))
|
||||
(mapv tokenscript-symbols->penpot-unit (.-value token-symbol))
|
||||
(let [entries (es6-iterator-seq (.entries (.-value token-symbol)))]
|
||||
(into {} (map (fn [[k v :as V]]
|
||||
[(keyword k) (tokenscript-symbols->penpot-unit v)])
|
||||
@@ -88,7 +88,7 @@
|
||||
(defn tokenscript-symbols->penpot-unit [^js v]
|
||||
(cond
|
||||
(structured-token? v) (structured-token->penpot-map v)
|
||||
(list-symbol? v) (tokenscript-symbols->penpot-unit (.nth 1 v))
|
||||
(list-symbol? v) (structured-token->penpot-map v)
|
||||
(color-symbol? v) (.-value (.to v "hex"))
|
||||
(rem-number-with-unit? v) (rem->px v)
|
||||
:else (.-value v)))
|
||||
|
||||
@@ -222,9 +222,16 @@
|
||||
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc :thumbnails thumbnails)
|
||||
(update :files assoc file-id file)))))
|
||||
(let [pending-version-id (:workspace-pending-file-version-id state)
|
||||
state (-> state
|
||||
(assoc :thumbnails thumbnails)
|
||||
(update :files assoc file-id file)
|
||||
(dissoc :workspace-pending-file-version-id))]
|
||||
(cond-> state
|
||||
(some? pending-version-id)
|
||||
(assoc :workspace-file-version-id pending-version-id)
|
||||
(nil? pending-version-id)
|
||||
(dissoc :workspace-file-version-id))))))
|
||||
|
||||
(defn zoom-to-frame
|
||||
[]
|
||||
@@ -280,192 +287,197 @@
|
||||
(wasm.api/process-object shape))))))
|
||||
|
||||
(defn initialize-workspace
|
||||
[team-id file-id]
|
||||
(assert (uuid? team-id) "expected valud uuid for `team-id`")
|
||||
(assert (uuid? file-id) "expected valud uuid for `file-id`")
|
||||
([team-id file-id]
|
||||
(initialize-workspace team-id file-id nil))
|
||||
([team-id file-id version-id]
|
||||
(assert (uuid? team-id) "expected valud uuid for `team-id`")
|
||||
(assert (uuid? file-id) "expected valud uuid for `file-id`")
|
||||
|
||||
(ptk/reify ::initialize-workspace
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc :recent-colors (:recent-colors storage/user))
|
||||
(assoc :recent-fonts (:recent-fonts storage/user))
|
||||
(assoc :current-file-id file-id)
|
||||
(assoc :workspace-presence {})))
|
||||
(ptk/reify ::initialize-workspace
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc :recent-colors (:recent-colors storage/user))
|
||||
(assoc :recent-fonts (:recent-fonts storage/user))
|
||||
(assoc :current-file-id file-id)
|
||||
(assoc :workspace-presence {})
|
||||
;; Store pending version-id; bundle-fetched will set workspace-file-version-id
|
||||
;; when the new bundle is applied so the viewport re-inits with new data
|
||||
(assoc :workspace-pending-file-version-id version-id)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stoper-s (rx/filter (ptk/type? ::finalize-workspace) stream)
|
||||
rparams (rt/get-params state)
|
||||
features (features/get-enabled-features state team-id)
|
||||
render-wasm? (contains? features "render-wasm/v1")]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stoper-s (rx/filter (ptk/type? ::finalize-workspace) stream)
|
||||
rparams (rt/get-params state)
|
||||
features (features/get-enabled-features state team-id)
|
||||
render-wasm? (contains? features "render-wasm/v1")]
|
||||
|
||||
(log/debug :hint "initialize-workspace"
|
||||
:team-id (dm/str team-id)
|
||||
:file-id (dm/str file-id))
|
||||
(log/debug :hint "initialize-workspace"
|
||||
:team-id (dm/str team-id)
|
||||
:file-id (dm/str file-id))
|
||||
|
||||
(->> (rx/merge
|
||||
(rx/concat
|
||||
;; Fetch all essential data that should be loaded before the file
|
||||
(rx/merge
|
||||
(if ^boolean render-wasm?
|
||||
(->> (rx/from @wasm/module)
|
||||
(rx/filter true?)
|
||||
(rx/tap (fn [_]
|
||||
(let [event (ug/event "penpot:wasm:loaded")]
|
||||
(ug/dispatch! event))))
|
||||
(rx/ignore))
|
||||
(rx/empty))
|
||||
(->> (rx/merge
|
||||
(rx/concat
|
||||
;; Fetch all essential data that should be loaded before the file
|
||||
(rx/merge
|
||||
(if ^boolean render-wasm?
|
||||
(->> (rx/from @wasm/module)
|
||||
(rx/filter true?)
|
||||
(rx/tap (fn [_]
|
||||
(let [event (ug/event "penpot:wasm:loaded")]
|
||||
(ug/dispatch! event))))
|
||||
(rx/ignore))
|
||||
(rx/empty))
|
||||
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::df/fonts-loaded))
|
||||
(rx/take 1)
|
||||
(rx/ignore))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::df/fonts-loaded))
|
||||
(rx/take 1)
|
||||
(rx/ignore))
|
||||
|
||||
(rx/of (ntf/hide)
|
||||
(dcmt/retrieve-comment-threads file-id)
|
||||
(dcmt/fetch-profiles)
|
||||
(df/fetch-fonts team-id)))
|
||||
(rx/of (ntf/hide)
|
||||
(dcmt/retrieve-comment-threads file-id)
|
||||
(dcmt/fetch-profiles)
|
||||
(df/fetch-fonts team-id)))
|
||||
|
||||
;; Once the essential data is fetched, lets proceed to
|
||||
;; fetch teh file bunldle
|
||||
(rx/of (fetch-bundle file-id features)))
|
||||
;; Once the essential data is fetched, lets proceed to
|
||||
;; fetch teh file bunldle
|
||||
(rx/of (fetch-bundle file-id features)))
|
||||
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::bundle-fetched))
|
||||
(rx/take 1)
|
||||
(rx/map deref)
|
||||
(rx/mapcat
|
||||
(fn [{:keys [file]}]
|
||||
(log/debug :hint "bundle fetched"
|
||||
:team-id (dm/str team-id)
|
||||
:file-id (dm/str file-id))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::bundle-fetched))
|
||||
(rx/take 1)
|
||||
(rx/map deref)
|
||||
(rx/mapcat
|
||||
(fn [{:keys [file]}]
|
||||
(log/debug :hint "bundle fetched"
|
||||
:team-id (dm/str team-id)
|
||||
:file-id (dm/str file-id))
|
||||
|
||||
(rx/of (dpj/initialize-project (:project-id file))
|
||||
(dwn/initialize team-id file-id)
|
||||
(dwsl/initialize-shape-layout)
|
||||
(fetch-libraries file-id features)
|
||||
(-> (workspace-initialized file-id)
|
||||
(with-meta {:team-id team-id
|
||||
:file-id file-id}))))))
|
||||
(rx/of (dpj/initialize-project (:project-id file))
|
||||
(dwn/initialize team-id file-id)
|
||||
(dwsl/initialize-shape-layout)
|
||||
(fetch-libraries file-id features)
|
||||
(-> (workspace-initialized file-id)
|
||||
(with-meta {:team-id team-id
|
||||
:file-id file-id}))))))
|
||||
|
||||
;; Install dev perf observers once the workspace is ready
|
||||
(when (contains? cf/flags :perf-logs)
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::workspace-initialized))
|
||||
(rx/take 1)
|
||||
(rx/tap (fn [_] (perf/setup)))))
|
||||
;; Install dev perf observers once the workspace is ready
|
||||
(when (contains? cf/flags :perf-logs)
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::workspace-initialized))
|
||||
(rx/take 1)
|
||||
(rx/tap (fn [_] (perf/setup)))))
|
||||
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::dps/persistence-notification))
|
||||
(rx/take 1)
|
||||
(rx/map dwc/set-workspace-visited))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::dps/persistence-notification))
|
||||
(rx/take 1)
|
||||
(rx/map dwc/set-workspace-visited))
|
||||
|
||||
(when-let [component-id (some-> rparams :component-id uuid/parse)]
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::workspace-initialized))
|
||||
(rx/observe-on :async)
|
||||
(rx/take 1)
|
||||
(rx/map #(dwl/go-to-local-component :id component-id :update-layout? (:update-layout rparams)))))
|
||||
(when-let [component-id (some-> rparams :component-id uuid/parse)]
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::workspace-initialized))
|
||||
(rx/observe-on :async)
|
||||
(rx/take 1)
|
||||
(rx/map #(dwl/go-to-local-component :id component-id :update-layout? (:update-layout rparams)))))
|
||||
|
||||
(when (:board-id rparams)
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::dwv/initialize-viewport))
|
||||
(rx/take 1)
|
||||
(rx/map zoom-to-frame)))
|
||||
(when (:board-id rparams)
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::dwv/initialize-viewport))
|
||||
(rx/take 1)
|
||||
(rx/map zoom-to-frame)))
|
||||
|
||||
(when-let [comment-id (some-> rparams :comment-id uuid/parse)]
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::workspace-initialized))
|
||||
(rx/observe-on :async)
|
||||
(rx/take 1)
|
||||
(rx/map #(dwcm/navigate-to-comment-id comment-id))))
|
||||
(when-let [comment-id (some-> rparams :comment-id uuid/parse)]
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::workspace-initialized))
|
||||
(rx/observe-on :async)
|
||||
(rx/take 1)
|
||||
(rx/map #(dwcm/navigate-to-comment-id comment-id))))
|
||||
|
||||
(when render-wasm?
|
||||
(->> stream
|
||||
(rx/filter dch/commit?)
|
||||
(rx/map deref)
|
||||
(rx/mapcat
|
||||
(fn [{:keys [redo-changes]}]
|
||||
(let [added (->> redo-changes
|
||||
(filter #(= (:type %) :add-obj))
|
||||
(map :id))]
|
||||
(->> (rx/from added)
|
||||
(rx/map process-wasm-object)))))))
|
||||
(when render-wasm?
|
||||
(->> stream
|
||||
(rx/filter dch/commit?)
|
||||
(rx/map deref)
|
||||
(rx/mapcat
|
||||
(fn [{:keys [redo-changes]}]
|
||||
(let [added (->> redo-changes
|
||||
(filter #(= (:type %) :add-obj))
|
||||
(map :id))]
|
||||
(->> (rx/from added)
|
||||
(rx/map process-wasm-object)))))))
|
||||
|
||||
(when render-wasm?
|
||||
(let [local-commits-s
|
||||
(->> stream
|
||||
(rx/filter dch/commit?)
|
||||
(rx/map deref)
|
||||
(rx/filter #(and (= :local (:source %))
|
||||
(not (contains? (:tags %) :position-data))))
|
||||
(rx/filter (complement empty?)))
|
||||
(when render-wasm?
|
||||
(let [local-commits-s
|
||||
(->> stream
|
||||
(rx/filter dch/commit?)
|
||||
(rx/map deref)
|
||||
(rx/filter #(and (= :local (:source %))
|
||||
(not (contains? (:tags %) :position-data))))
|
||||
(rx/filter (complement empty?)))
|
||||
|
||||
notifier-s
|
||||
(rx/merge
|
||||
(->> local-commits-s (rx/debounce 1000))
|
||||
(->> stream (rx/filter dps/force-persist?)))
|
||||
notifier-s
|
||||
(rx/merge
|
||||
(->> local-commits-s (rx/debounce 1000))
|
||||
(->> stream (rx/filter dps/force-persist?)))
|
||||
|
||||
objects-s
|
||||
(rx/from-atom refs/workspace-page-objects {:emit-current-value? true})
|
||||
objects-s
|
||||
(rx/from-atom refs/workspace-page-objects {:emit-current-value? true})
|
||||
|
||||
current-page-id-s
|
||||
(rx/from-atom refs/current-page-id {:emit-current-value? true})]
|
||||
current-page-id-s
|
||||
(rx/from-atom refs/current-page-id {:emit-current-value? true})]
|
||||
|
||||
(->> local-commits-s
|
||||
(rx/buffer-until notifier-s)
|
||||
(rx/with-latest-from objects-s)
|
||||
(rx/map
|
||||
(fn [[commits objects]]
|
||||
(->> commits
|
||||
(mapcat :redo-changes)
|
||||
(filter #(contains? #{:mod-obj :add-obj} (:type %)))
|
||||
(filter #(cfh/text-shape? objects (:id %)))
|
||||
(map #(vector
|
||||
(:id %)
|
||||
(wasm.api/calculate-position-data (get objects (:id %))))))))
|
||||
(->> local-commits-s
|
||||
(rx/buffer-until notifier-s)
|
||||
(rx/with-latest-from objects-s)
|
||||
(rx/map
|
||||
(fn [[commits objects]]
|
||||
(->> commits
|
||||
(mapcat :redo-changes)
|
||||
(filter #(contains? #{:mod-obj :add-obj} (:type %)))
|
||||
(filter #(cfh/text-shape? objects (:id %)))
|
||||
(map #(vector
|
||||
(:id %)
|
||||
(wasm.api/calculate-position-data (get objects (:id %))))))))
|
||||
|
||||
(rx/with-latest-from current-page-id-s)
|
||||
(rx/map
|
||||
(fn [[text-position-data page-id]]
|
||||
(let [changes
|
||||
(->> text-position-data
|
||||
(mapv (fn [[id position-data]]
|
||||
{:type :mod-obj
|
||||
:id id
|
||||
:page-id page-id
|
||||
:operations
|
||||
[{:type :set
|
||||
:attr :position-data
|
||||
:val position-data
|
||||
:ignore-touched true
|
||||
:ignore-geometry true}]})))]
|
||||
(when (d/not-empty? changes)
|
||||
(dch/commit-changes
|
||||
{:redo-changes changes :undo-changes []
|
||||
:save-undo? false
|
||||
:tags #{:position-data}})))))
|
||||
(rx/take-until stoper-s))))
|
||||
(rx/with-latest-from current-page-id-s)
|
||||
(rx/map
|
||||
(fn [[text-position-data page-id]]
|
||||
(let [changes
|
||||
(->> text-position-data
|
||||
(mapv (fn [[id position-data]]
|
||||
{:type :mod-obj
|
||||
:id id
|
||||
:page-id page-id
|
||||
:operations
|
||||
[{:type :set
|
||||
:attr :position-data
|
||||
:val position-data
|
||||
:ignore-touched true
|
||||
:ignore-geometry true}]})))]
|
||||
(when (d/not-empty? changes)
|
||||
(dch/commit-changes
|
||||
{:redo-changes changes :undo-changes []
|
||||
:save-undo? false
|
||||
:tags #{:position-data}})))))
|
||||
(rx/take-until stoper-s))))
|
||||
|
||||
(->> stream
|
||||
(rx/filter dch/commit?)
|
||||
(rx/map deref)
|
||||
(rx/mapcat
|
||||
(fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo?]}]
|
||||
(if (and save-undo? (seq undo-changes))
|
||||
(let [entry {:undo-changes undo-changes
|
||||
:redo-changes redo-changes
|
||||
:undo-group undo-group
|
||||
:tags tags}]
|
||||
(rx/of (dwu/append-undo entry stack-undo?)))
|
||||
(rx/empty))))))
|
||||
(rx/take-until stoper-s))))
|
||||
(->> stream
|
||||
(rx/filter dch/commit?)
|
||||
(rx/map deref)
|
||||
(rx/mapcat
|
||||
(fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo?]}]
|
||||
(if (and save-undo? (seq undo-changes))
|
||||
(let [entry {:undo-changes undo-changes
|
||||
:redo-changes redo-changes
|
||||
:undo-group undo-group
|
||||
:tags tags}]
|
||||
(rx/of (dwu/append-undo entry stack-undo?)))
|
||||
(rx/empty))))))
|
||||
(rx/take-until stoper-s))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
(let [name (dm/str "workspace-" file-id)]
|
||||
(unchecked-set ug/global "name" name)))))
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
(let [name (dm/str "workspace-" file-id)]
|
||||
(unchecked-set ug/global "name" name))))))
|
||||
|
||||
(defn finalize-workspace
|
||||
[_team-id file-id]
|
||||
|
||||
@@ -197,11 +197,12 @@
|
||||
objects (:objects page)
|
||||
|
||||
undo-id (or (:undo-id options) (js/Symbol))
|
||||
[all-parents changes] (-> (pcb/empty-changes it (:id page))
|
||||
(cls/generate-delete-shapes fdata page objects ids
|
||||
{:ignore-touched (:allow-altering-copies options)
|
||||
:undo-group (:undo-group options)
|
||||
:undo-id undo-id}))]
|
||||
[all-parents changes]
|
||||
(-> (pcb/empty-changes it (:id page))
|
||||
(cls/generate-delete-shapes fdata page objects ids
|
||||
{:ignore-touched (:allow-altering-copies options)
|
||||
:undo-group (:undo-group options)
|
||||
:undo-id undo-id}))]
|
||||
|
||||
(rx/of (dwu/start-undo-transaction undo-id)
|
||||
(dc/detach-comment-thread ids)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
[app.common.attrs :as attrs]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.changes-builder :as pcb]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
@@ -19,6 +20,7 @@
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[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.common :as dwc]
|
||||
@@ -916,11 +918,11 @@
|
||||
(update-in state [:workspace-text-modifier shape-id] {:position-data position-data}))))
|
||||
|
||||
(defn v2-update-text-shape-content
|
||||
[id content & {:keys [update-name? name finalize? save-undo?]
|
||||
:or {update-name? false name nil finalize? false save-undo? true}}]
|
||||
[id content & {:keys [update-name? name finalize? save-undo? original-content]
|
||||
:or {update-name? false name nil finalize? false save-undo? true original-content nil}}]
|
||||
(ptk/reify ::v2-update-text-shape-content
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(watch [it state _]
|
||||
(if (features/active-feature? state "render-wasm/v1")
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
shape (get objects id)
|
||||
@@ -950,11 +952,11 @@
|
||||
new-shape))
|
||||
{:save-undo? save-undo? :undo-group (when new-shape? id)})
|
||||
|
||||
(let [modifiers (dwwt/resize-wasm-text-modifiers shape content)
|
||||
options {:undo-group (when new-shape? id)}]
|
||||
(if (and (not= :fixed (:grow-type shape)) finalize?)
|
||||
(dwm/apply-wasm-modifiers modifiers options)
|
||||
(dwm/set-wasm-modifiers modifiers options))))
|
||||
(when-let [modifiers (dwwt/resize-wasm-text-modifiers shape content)]
|
||||
(let [options {:undo-group (when new-shape? id)}]
|
||||
(if (and (not= :fixed (:grow-type shape)) finalize?)
|
||||
(dwm/apply-wasm-modifiers modifiers options)
|
||||
(dwm/set-wasm-modifiers modifiers options)))))
|
||||
|
||||
(when finalize?
|
||||
(rx/concat
|
||||
@@ -970,7 +972,13 @@
|
||||
{:save-undo? false}))
|
||||
(dws/deselect-shape id)
|
||||
(dwsh/delete-shapes #{id})))
|
||||
(rx/of (dwt/finish-transform))))))
|
||||
(rx/of
|
||||
;; This commit is necesary for undo and component propagation
|
||||
;; on finalization
|
||||
(dch/commit-changes
|
||||
(-> (pcb/empty-changes it (:current-page-id state))
|
||||
(pcb/set-text-content id content original-content)))
|
||||
(dwt/finish-transform))))))
|
||||
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
shape (get objects id)
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
(rx/take 1)
|
||||
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id}))
|
||||
(rx/tap #(th/clear-queue!))
|
||||
(rx/map #(dw/initialize-workspace team-id file-id)))
|
||||
(rx/map #(dw/initialize-workspace team-id file-id id)))
|
||||
(case origin
|
||||
:version
|
||||
(rx/of (ptk/event ::ev/event {::ev/name "restore-pin-version"}))
|
||||
@@ -231,7 +231,7 @@
|
||||
(rx/filter #(or (nil? %) (= :saved %)))
|
||||
(rx/take 1)
|
||||
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id}))
|
||||
(rx/map #(dw/initialize-workspace team-id file-id)))
|
||||
(rx/map #(dw/initialize-workspace team-id file-id id)))
|
||||
|
||||
(->> (rx/of 1)
|
||||
(rx/tap resolve)
|
||||
|
||||
@@ -27,27 +27,28 @@
|
||||
(resize-wasm-text-modifiers shape (:content shape)))
|
||||
|
||||
([{:keys [id points selrect grow-type] :as shape} content]
|
||||
(wasm.api/use-shape id)
|
||||
(wasm.api/set-shape-text-content id content)
|
||||
(wasm.api/set-shape-text-images id content)
|
||||
(when id
|
||||
(wasm.api/use-shape id)
|
||||
(wasm.api/set-shape-text-content id content)
|
||||
(wasm.api/set-shape-text-images id content)
|
||||
|
||||
(let [dimension (wasm.api/get-text-dimensions)
|
||||
width-scale (if (#{:fixed :auto-height} grow-type)
|
||||
1.0
|
||||
(/ (:width dimension) (:width selrect)))
|
||||
height-scale (if (= :fixed grow-type)
|
||||
1.0
|
||||
(/ (:height dimension) (:height selrect)))
|
||||
resize-v (gpt/point width-scale height-scale)
|
||||
origin (first points)]
|
||||
(let [dimension (wasm.api/get-text-dimensions)
|
||||
width-scale (if (#{:fixed :auto-height} grow-type)
|
||||
1.0
|
||||
(/ (:width dimension) (:width selrect)))
|
||||
height-scale (if (= :fixed grow-type)
|
||||
1.0
|
||||
(/ (:height dimension) (:height selrect)))
|
||||
resize-v (gpt/point width-scale height-scale)
|
||||
origin (first points)]
|
||||
|
||||
{id
|
||||
{:modifiers
|
||||
(ctm/resize-modifiers
|
||||
resize-v
|
||||
origin
|
||||
(:transform shape (gmt/matrix))
|
||||
(:transform-inverse shape (gmt/matrix)))}})))
|
||||
{id
|
||||
{:modifiers
|
||||
(ctm/resize-modifiers
|
||||
resize-v
|
||||
origin
|
||||
(:transform shape (gmt/matrix))
|
||||
(:transform-inverse shape (gmt/matrix)))}}))))
|
||||
|
||||
(defn resize-wasm-text
|
||||
"Resize a single text shape (auto-width/auto-height) by id.
|
||||
|
||||
@@ -256,6 +256,9 @@
|
||||
(def workspace-layout
|
||||
(l/derived :workspace-layout st/state))
|
||||
|
||||
(def workspace-file-version-id
|
||||
(l/derived :workspace-file-version-id st/state))
|
||||
|
||||
(def snap-pixel?
|
||||
(l/derived #(contains? % :snap-pixel-grid) workspace-layout))
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
[app.util.dom :as dom]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc file-uploader*
|
||||
(mf/defc file-uploader
|
||||
{::mf/forward-ref true}
|
||||
[{:keys [accept multi label-text label-class input-id on-selected data-testid]} input-ref]
|
||||
[{:keys [accept multi label-text label-class input-id on-selected data-testid] :as props} input-ref]
|
||||
(let [opt-pick-one #(if multi % (first %))
|
||||
|
||||
on-files-selected
|
||||
|
||||
107
frontend/src/app/main/ui/components/radio_buttons.cljs
Normal file
@@ -0,0 +1,107 @@
|
||||
;; 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
|
||||
|
||||
(ns app.main.ui.components.radio-buttons
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*]]
|
||||
[app.main.ui.formats :as fmt]
|
||||
[app.util.dom :as dom]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def context
|
||||
(mf/create-context nil))
|
||||
|
||||
(mf/defc radio-button
|
||||
{::mf/props :obj}
|
||||
[{:keys [icon id value disabled title icon-class type]}]
|
||||
(let [context (mf/use-ctx context)
|
||||
allow-empty (unchecked-get context "allow-empty")
|
||||
type (if ^boolean type
|
||||
type
|
||||
(if ^boolean allow-empty
|
||||
"checkbox"
|
||||
"radio"))
|
||||
|
||||
on-change (unchecked-get context "on-change")
|
||||
selected (unchecked-get context "selected")
|
||||
name (unchecked-get context "name")
|
||||
|
||||
encode-fn (unchecked-get context "encode-fn")
|
||||
checked? (= selected value)
|
||||
|
||||
value (encode-fn value)]
|
||||
|
||||
|
||||
[:label {:html-for id
|
||||
:data-testid id
|
||||
:title title
|
||||
:class (stl/css-case
|
||||
:radio-icon true
|
||||
:checked checked?
|
||||
:disabled disabled)}
|
||||
|
||||
(if (some? icon)
|
||||
[:> icon* {:icon-id icon :class icon-class :aria-hidden true}]
|
||||
[:span {:class (stl/css :title-name)} value])
|
||||
|
||||
[:input {:id id
|
||||
:on-change on-change
|
||||
:type type
|
||||
:name name
|
||||
:disabled disabled
|
||||
:value value
|
||||
:default-checked checked?}]]))
|
||||
|
||||
(mf/defc radio-buttons
|
||||
{::mf/props :obj}
|
||||
[{:keys [name children on-change selected class wide encode-fn decode-fn allow-empty] :as props}]
|
||||
(let [encode-fn (d/nilv encode-fn identity)
|
||||
decode-fn (d/nilv decode-fn identity)
|
||||
nitems (if (array? children)
|
||||
(count (keep identity children))
|
||||
1)
|
||||
;; FIXME: we should handle this with CSS
|
||||
width (mf/with-memo [nitems]
|
||||
(if (= wide true)
|
||||
"unset"
|
||||
(fmt/format-pixels
|
||||
(+ (* 4 (- nitems 1))
|
||||
(* 32 nitems)))))
|
||||
|
||||
on-change'
|
||||
(mf/use-fn
|
||||
(mf/deps selected on-change)
|
||||
(fn [event]
|
||||
(let [input (dom/get-target event)
|
||||
value (dom/get-target-val event)
|
||||
|
||||
;; Only allow null values when the "allow-empty" prop is true
|
||||
value (when (or (not allow-empty)
|
||||
(not= value selected)) value)]
|
||||
(when (fn? on-change)
|
||||
(on-change (decode-fn value) event))
|
||||
(dom/blur! input))))
|
||||
|
||||
context-value
|
||||
(mf/spread-object props
|
||||
;; We pass a special metadata for disable
|
||||
;; key casing transformation in this
|
||||
;; concrete case, because this component
|
||||
;; uses legacy mode and props are in
|
||||
;; kebab-case style
|
||||
^{::mf/transform false}
|
||||
{:on-change on-change'
|
||||
:encode-fn encode-fn
|
||||
:decode-fn decode-fn})]
|
||||
|
||||
[:& (mf/provider context) {:value context-value}
|
||||
[:div {:class (dm/str class " " (stl/css :radio-btn-wrapper))
|
||||
:style {:width width}
|
||||
:key (dm/str name "-" selected)}
|
||||
children]]))
|
||||
79
frontend/src/app/main/ui/components/radio_buttons.scss
Normal file
@@ -0,0 +1,79 @@
|
||||
// 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
|
||||
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
|
||||
.radio-btn-wrapper {
|
||||
@include deprecated.flexCenter;
|
||||
border-radius: deprecated.$br-8;
|
||||
height: deprecated.$s-32;
|
||||
background-color: var(--input-background-color);
|
||||
gap: deprecated.$s-4;
|
||||
}
|
||||
|
||||
.radio-icon {
|
||||
--radio-icon-border-color: var(--radio-btn-border-color);
|
||||
|
||||
@include deprecated.buttonStyle;
|
||||
@include deprecated.flexCenter;
|
||||
@include deprecated.focusRadio;
|
||||
height: deprecated.$s-32;
|
||||
flex-grow: 1;
|
||||
border-radius: deprecated.$s-8;
|
||||
box-sizing: border-box;
|
||||
border: deprecated.$br-2 solid var(--radio-icon-border-color);
|
||||
|
||||
input {
|
||||
display: none;
|
||||
}
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--radio-btn-foreground-color);
|
||||
}
|
||||
.title-name {
|
||||
@include deprecated.uppercaseTitleTipography;
|
||||
color: var(--radio-btn-foreground-color);
|
||||
}
|
||||
&:hover {
|
||||
svg {
|
||||
stroke: var(--radio-btn-foreground-color-selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.checked {
|
||||
--radio-icon-border-color: var(--radio-btn-border-color-selected);
|
||||
|
||||
background-color: var(--radio-btn-background-color-selected);
|
||||
svg {
|
||||
stroke: var(--radio-btn-foreground-color-selected);
|
||||
}
|
||||
.title-name {
|
||||
color: var(--radio-btn-foreground-color-selected);
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
cursor: default;
|
||||
background-color: transparent;
|
||||
border: deprecated.$s-2 solid transparent;
|
||||
svg {
|
||||
stroke: var(--button-foreground-color-disabled);
|
||||
}
|
||||
.title-name {
|
||||
color: var(--button-foreground-color-disabled);
|
||||
}
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
border: deprecated.$s-2 solid transparent;
|
||||
svg {
|
||||
stroke: var(--button-foreground-color-disabled);
|
||||
}
|
||||
.title-name {
|
||||
color: var(--button-foreground-color-disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.context-menu-a11y :refer [context-menu*]]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader*]]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||
[app.main.ui.ds.product.empty-placeholder :refer [empty-placeholder*]]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||
@@ -184,11 +184,11 @@
|
||||
:on-click on-click
|
||||
:tab-index "0"}
|
||||
[:span (tr "labels.add-custom-font")]
|
||||
[:> file-uploader* {:input-id "font-upload"
|
||||
:accept accept-font-types
|
||||
:multi true
|
||||
:ref input-ref
|
||||
:on-selected on-selected}]]
|
||||
[:& file-uploader {:input-id "font-upload"
|
||||
:accept accept-font-types
|
||||
:multi true
|
||||
:ref input-ref
|
||||
:on-selected on-selected}]]
|
||||
|
||||
(when-let [url cf/terms-of-service-uri]
|
||||
[:& context-notification {:content (tr "dashboard.fonts.hero-text2" url)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader*]]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||
[app.main.ui.ds.product.loader :refer [loader*]]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||
@@ -58,10 +58,10 @@
|
||||
[{:keys [project-id on-finish-import]} external-ref]
|
||||
(let [on-file-selected (use-import-file project-id on-finish-import)]
|
||||
[:form.import-file {:aria-hidden "true"}
|
||||
[:> file-uploader* {:accept ".penpot,.zip"
|
||||
:multi true
|
||||
:ref external-ref
|
||||
:on-selected on-file-selected}]]))
|
||||
[:& file-uploader {:accept ".penpot,.zip"
|
||||
:multi true
|
||||
:ref external-ref
|
||||
:on-selected on-file-selected}]]))
|
||||
|
||||
(defn- update-entry-name
|
||||
[entries file-id new-name]
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader*]]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
[app.main.ui.dashboard.change-owner]
|
||||
[app.main.ui.dashboard.subscription :refer [members-cta*
|
||||
@@ -1315,10 +1315,10 @@
|
||||
[:img {:class (stl/css :team-image)
|
||||
:src (cfg/resolve-team-photo-url team)}]
|
||||
(when can-edit
|
||||
[:> file-uploader* {:accept "image/jpeg,image/png"
|
||||
:multi false
|
||||
:ref finput
|
||||
:on-selected on-file-selected}])]
|
||||
[:& file-uploader {:accept "image/jpeg,image/png"
|
||||
:multi false
|
||||
:ref finput
|
||||
:on-selected on-file-selected}])]
|
||||
[:div {:class (stl/css :block-label)}
|
||||
(tr "dashboard.team-info")]
|
||||
[:div {:class (stl/css :block-text)}
|
||||
|
||||
@@ -11,10 +11,8 @@
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
[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.notifications.context-notification :refer [context-notification*]]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as k]
|
||||
@@ -99,11 +97,8 @@
|
||||
[:div {:class (stl/css :modal-container)}
|
||||
[:div {:class (stl/css :modal-header)}
|
||||
[:h2 {:class (stl/css :modal-title)} title]
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:class (stl/css :modal-close-btn)
|
||||
:icon i/close
|
||||
:aria-label (tr "labels.close")
|
||||
:on-click cancel-fn}]]
|
||||
[:button {:class (stl/css :modal-close-btn)
|
||||
:on-click cancel-fn} deprecated-icon/close]]
|
||||
|
||||
[:div {:class (stl/css :modal-content)}
|
||||
(when (and (string? subtitle) (not= subtitle ""))
|
||||
@@ -129,10 +124,14 @@
|
||||
[:div {:class (stl/css :modal-footer)}
|
||||
[:div {:class (stl/css :action-buttons)}
|
||||
(when-not (= cancel-label :omit)
|
||||
[:> button* {:variant "secondary"
|
||||
:on-click cancel-fn}
|
||||
cancel-label])
|
||||
[:input {:class (stl/css :cancel-button)
|
||||
:type "button"
|
||||
:value cancel-label
|
||||
:on-click cancel-fn}])
|
||||
|
||||
[:> button* {:variant (if (= accept-style :danger) "destructive" "primary")
|
||||
:on-click accept-fn}
|
||||
accept-label]]]]]))
|
||||
[:input {:class (stl/css-case :accept-btn true
|
||||
:danger (= accept-style :danger)
|
||||
:primary (= accept-style :primary))
|
||||
:type "button"
|
||||
:value accept-label
|
||||
:on-click accept-fn}]]]]]))
|
||||
|
||||
@@ -33,9 +33,7 @@
|
||||
}
|
||||
|
||||
.modal-close-btn {
|
||||
position: absolute;
|
||||
top: var(--sp-s);
|
||||
right: var(--sp-s);
|
||||
@extend .modal-close-btn-base;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
@@ -55,6 +53,17 @@
|
||||
@extend .modal-action-btns;
|
||||
}
|
||||
|
||||
.cancel-button {
|
||||
@extend .modal-cancel-btn;
|
||||
}
|
||||
|
||||
.accept-btn {
|
||||
@extend .modal-accept-btn;
|
||||
&.danger {
|
||||
@extend .modal-danger-btn;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-scd-msg {
|
||||
margin-block: 0;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
column-gap: var(--sp-xs);
|
||||
}
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
;; FIXME: deprecated, should be refactored in two components and use
|
||||
;; the generic progress reporter
|
||||
|
||||
(mf/defc progress-widget*
|
||||
(mf/defc progress-widget
|
||||
{::mf/wrap [mf/memo]}
|
||||
[]
|
||||
(let [state (mf/deref refs/export)
|
||||
|
||||
@@ -19,10 +19,7 @@
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.code-block :refer [code-block]]
|
||||
[app.main.ui.components.copy-button :refer [copy-button*]]
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]]
|
||||
[app.main.ui.hooks.resize :refer [use-resize-hook]]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.main.ui.shapes.text.fontfaces :refer [shapes->fonts]]
|
||||
@@ -263,9 +260,8 @@
|
||||
[:div {:class (stl/css-case :element-options true
|
||||
:viewer-code-block (= :viewer from))}
|
||||
[:div {:class (stl/css :attributes-block)}
|
||||
[:> button* {:variant "secondary"
|
||||
:class (stl/css :download-button)
|
||||
:on-click handle-copy-all-code}
|
||||
[:button {:class (stl/css :download-button)
|
||||
:on-click handle-copy-all-code}
|
||||
"Copy all code"]]
|
||||
|
||||
#_[:div.attributes-block
|
||||
@@ -292,10 +288,10 @@
|
||||
;; :options [{:label "CSS" :value "css"}]}]
|
||||
|
||||
[:div {:class (stl/css :action-btns)}
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label "Expand"
|
||||
:on-click on-expand
|
||||
:icon i/code}]
|
||||
[:button {:class (stl/css :expand-button)
|
||||
:on-click on-expand}
|
||||
deprecated-icon/code]
|
||||
|
||||
[:> copy-button* {:data copy-css-fn
|
||||
:class (stl/css :css-copy-btn)
|
||||
:on-copied on-style-copied}]]]
|
||||
@@ -322,21 +318,21 @@
|
||||
:rotated collapsed-markup?)}
|
||||
deprecated-icon/arrow]]
|
||||
|
||||
[:> radio-buttons* {:selected markup-type
|
||||
:on-change set-markup
|
||||
:name "listing-style"
|
||||
:options [{:id "html"
|
||||
:label "HTML"
|
||||
:value "html"}
|
||||
{:id "svg"
|
||||
:label "SVG"
|
||||
:value "svg"}]}]
|
||||
[:& radio-buttons {:selected markup-type
|
||||
:on-change set-markup
|
||||
:class (stl/css :code-lang-options)
|
||||
:wide true
|
||||
:name "listing-style"}
|
||||
[:& radio-button {:value "html"
|
||||
:id :html}]
|
||||
[:& radio-button {:value "svg"
|
||||
:id :svg}]]
|
||||
|
||||
[:div {:class (stl/css :action-btns)}
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label "Expand"
|
||||
:on-click on-expand
|
||||
:icon i/code}]
|
||||
[:button {:class (stl/css :expand-button)
|
||||
:on-click on-expand}
|
||||
deprecated-icon/code]
|
||||
|
||||
[:> copy-button* {:data copy-html-fn
|
||||
:class (stl/css :html-copy-btn)
|
||||
:on-copied on-markup-copied}]]]
|
||||
|
||||
@@ -17,18 +17,16 @@
|
||||
padding-inline: var(--sp-m);
|
||||
}
|
||||
|
||||
.attributes-block {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 12px;
|
||||
}
|
||||
|
||||
.viewer-code-block {
|
||||
height: calc(100vh - #{deprecated.$s-108}); // TODO: Fix this hardcoded value
|
||||
}
|
||||
|
||||
.download-button {
|
||||
margin: var(--sp-s) 0;
|
||||
@extend .button-secondary;
|
||||
@include deprecated.uppercaseTitleTipography;
|
||||
height: deprecated.$s-32;
|
||||
width: 100%;
|
||||
margin: deprecated.$s-8 0;
|
||||
}
|
||||
|
||||
.code-block {
|
||||
@@ -75,6 +73,7 @@
|
||||
gap: deprecated.$s-4;
|
||||
}
|
||||
|
||||
.expand-button,
|
||||
.css-copy-btn,
|
||||
.html-copy-btn {
|
||||
@extend .button-tertiary;
|
||||
@@ -86,6 +85,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.code-lang-options {
|
||||
max-width: deprecated.$s-108;
|
||||
}
|
||||
.code-lang-select {
|
||||
@include deprecated.uppercaseTitleTipography;
|
||||
width: deprecated.$s-72;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
[app.main.data.profile :as du]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader*]]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
@@ -110,11 +110,11 @@
|
||||
[:span {:class (stl/css :update-overlay)
|
||||
:on-click on-image-click} (tr "labels.update")]
|
||||
[:img {:src photo}]
|
||||
[:> file-uploader* {:accept "image/jpeg,image/png"
|
||||
:multi false
|
||||
:ref input-ref
|
||||
:on-selected on-file-selected
|
||||
:data-testid "profile-image-input"}]]]))
|
||||
[:& file-uploader {:accept "image/jpeg,image/png"
|
||||
:multi false
|
||||
:ref input-ref
|
||||
:on-selected on-file-selected
|
||||
:data-testid "profile-image-input"}]]]))
|
||||
|
||||
;; --- Profile Page
|
||||
|
||||
|
||||
@@ -27,8 +27,9 @@
|
||||
[okulary.core :as l]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc comments-menu*
|
||||
{::mf/memo true}
|
||||
(mf/defc comments-menu
|
||||
{::mf/props :obj
|
||||
::mf/memo true}
|
||||
[]
|
||||
(let [state (mf/deref refs/comments-local)
|
||||
cmode (:mode state)
|
||||
|
||||
@@ -14,13 +14,10 @@
|
||||
[app.main.data.viewer.shortcuts :as sc]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
[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.exports.assets :refer [progress-widget*]]
|
||||
[app.main.ui.exports.assets :refer [progress-widget]]
|
||||
[app.main.ui.formats :as fmt]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.main.ui.viewer.comments :refer [comments-menu*]]
|
||||
[app.main.ui.viewer.comments :refer [comments-menu]]
|
||||
[app.main.ui.viewer.interactions :refer [flows-menu* interactions-menu*]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
@@ -36,12 +33,20 @@
|
||||
[]
|
||||
(modal/show! :login-register {}))
|
||||
|
||||
(mf/defc zoom-widget*
|
||||
{::mf/memo true}
|
||||
[{:keys [zoom on-increase on-decrease on-zoom-reset on-fullscreen on-zoom-fit on-zoom-fill]}]
|
||||
(let [open* (mf/use-state false)
|
||||
open? (deref open*)
|
||||
(mf/defc zoom-widget
|
||||
{::mf/memo true
|
||||
::mf/props :obj}
|
||||
[{:keys [zoom
|
||||
on-increase
|
||||
on-decrease
|
||||
on-zoom-reset
|
||||
on-fullscreen
|
||||
on-zoom-fit
|
||||
on-zoom-fill]
|
||||
:as props}]
|
||||
|
||||
(let [open* (mf/use-state false)
|
||||
open? (deref open*)
|
||||
open-dropdown
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
@@ -70,7 +75,7 @@
|
||||
|
||||
[:div {:class (stl/css-case :zoom-widget true
|
||||
:selected open?)
|
||||
:on-click (if open? close-dropdown open-dropdown)
|
||||
:on-click open-dropdown
|
||||
:title (tr "workspace.header.zoom")}
|
||||
[:span {:class (stl/css :label)} (fmt/format-percent zoom)]
|
||||
[:& dropdown {:show open?
|
||||
@@ -78,18 +83,18 @@
|
||||
[:ul {:class (stl/css :dropdown)}
|
||||
[:li {:class (stl/css :basic-zoom-bar)}
|
||||
[:span {:class (stl/css :zoom-btns)}
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "shortcuts.decrease-zoom")
|
||||
:on-click on-decrease
|
||||
:icon i/remove}]
|
||||
[:p {:class (stl/css :zoom-text)}
|
||||
[:button {:class (stl/css :zoom-btn)
|
||||
:on-click on-decrease}
|
||||
[:span {:class (stl/css :zoom-icon)}
|
||||
deprecated-icon/remove-icon]]
|
||||
[:p {:class (stl/css :zoom-text)}
|
||||
(fmt/format-percent zoom)]
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "shortcuts.increase-zoom")
|
||||
:on-click on-increase
|
||||
:icon i/add}]]
|
||||
[:> button* {:variant "ghost"
|
||||
:on-click on-zoom-reset}
|
||||
[:button {:class (stl/css :zoom-btn)
|
||||
:on-click on-increase}
|
||||
[:span {:class (stl/css :zoom-icon)}
|
||||
deprecated-icon/add]]]
|
||||
[:button {:class (stl/css :reset-btn)
|
||||
:on-click on-zoom-reset}
|
||||
(tr "workspace.header.reset-zoom")]]
|
||||
|
||||
[:li {:class (stl/css :zoom-option)
|
||||
@@ -114,7 +119,7 @@
|
||||
[:span {:class (stl/css :shortcut-key)
|
||||
:key (dm/str "zoom-fullscreen-" sc)} sc])]]]]]))
|
||||
|
||||
(mf/defc header-options*
|
||||
(mf/defc header-options
|
||||
[{:keys [section zoom page file index permissions interactions-mode share]}]
|
||||
(let [fullscreen? (mf/deref fullscreen-ref)
|
||||
|
||||
@@ -154,7 +159,6 @@
|
||||
handle-zoom-fit
|
||||
(mf/use-fn
|
||||
#(st/emit! dv/zoom-to-fit))]
|
||||
|
||||
(mf/with-effect [permissions share]
|
||||
(when (and
|
||||
(:in-team permissions)
|
||||
@@ -163,7 +167,7 @@
|
||||
(open-share-dialog)))
|
||||
|
||||
[:div {:class (stl/css :options-zone)}
|
||||
[:> progress-widget*]
|
||||
[:& progress-widget]
|
||||
|
||||
(case section
|
||||
:interactions [:*
|
||||
@@ -171,41 +175,40 @@
|
||||
[:> flows-menu* {:page page :index index}])
|
||||
[:> interactions-menu*
|
||||
{:interactions-mode interactions-mode}]]
|
||||
:comments [:> comments-menu*]
|
||||
:comments [:& comments-menu]
|
||||
[:div {:class (stl/css :view-options)}])
|
||||
|
||||
[:> zoom-widget* {:zoom zoom
|
||||
:on-increase handle-increase
|
||||
:on-decrease handle-decrease
|
||||
:on-zoom-reset handle-zoom-reset
|
||||
:on-zoom-fill handle-zoom-fill
|
||||
:on-zoom-fit handle-zoom-fit
|
||||
:on-fullscreen toggle-fullscreen}]
|
||||
[:& zoom-widget
|
||||
{:zoom zoom
|
||||
:on-increase handle-increase
|
||||
:on-decrease handle-decrease
|
||||
:on-zoom-reset handle-zoom-reset
|
||||
:on-zoom-fill handle-zoom-fill
|
||||
:on-zoom-fit handle-zoom-fit
|
||||
:on-fullscreen toggle-fullscreen}]
|
||||
|
||||
(when (:in-team permissions)
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "viewer.header.edit-in-workspace")
|
||||
:on-click go-to-workspace
|
||||
:icon i/curve}])
|
||||
[:span {:on-click go-to-workspace
|
||||
:class (stl/css :edit-btn)}
|
||||
deprecated-icon/curve])
|
||||
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-pressed fullscreen?
|
||||
:aria-label (tr "viewer.header.fullscreen")
|
||||
:on-click toggle-fullscreen
|
||||
:icon i/expand}]
|
||||
[:span {:title (tr "viewer.header.fullscreen")
|
||||
:class (stl/css-case :fullscreen-btn true
|
||||
:selected fullscreen?)
|
||||
:on-click toggle-fullscreen}
|
||||
deprecated-icon/expand]
|
||||
|
||||
(when (:in-team permissions)
|
||||
[:> button* {:variant "primary"
|
||||
:class (stl/css :share-btn)
|
||||
:on-click open-share-dialog}
|
||||
[:button {:on-click open-share-dialog
|
||||
:class (stl/css :share-btn)}
|
||||
(tr "labels.share")])
|
||||
|
||||
(when-not (:is-logged permissions)
|
||||
[:span {:on-click open-login-dialog
|
||||
:class (stl/css :go-log-btn)} (tr "labels.log-or-sign")])]))
|
||||
|
||||
(mf/defc header-sitemap*
|
||||
[{:keys [project file page frame toggle-thumbnails]}]
|
||||
(mf/defc header-sitemap
|
||||
[{:keys [project file page frame toggle-thumbnails] :as props}]
|
||||
(let [project-name (:name project)
|
||||
file-name (:name file)
|
||||
page-name (:name page)
|
||||
@@ -314,44 +317,44 @@
|
||||
:pointer-events (when-not (:in-team permissions) "none")}}
|
||||
penpot-logo-icon]
|
||||
|
||||
[:> header-sitemap* {:project project
|
||||
:file file
|
||||
:page page
|
||||
:frame frame
|
||||
:toggle-thumbnails toggle-thumbnails
|
||||
:index index}]]
|
||||
[:& header-sitemap {:project project
|
||||
:file file
|
||||
:page page
|
||||
:frame frame
|
||||
:toggle-thumbnails toggle-thumbnails
|
||||
:index index}]]
|
||||
|
||||
[:div {:class (stl/css :mode-zone)}
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-pressed (= section :interactions)
|
||||
:aria-label (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))
|
||||
:data-value "interactions"
|
||||
:on-click navigate
|
||||
:icon i/play}]
|
||||
[:button {:on-click navigate
|
||||
:data-value "interactions"
|
||||
:class (stl/css-case :mode-zone-btn true
|
||||
:selected (= section :interactions))
|
||||
:title (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))}
|
||||
deprecated-icon/play]
|
||||
|
||||
(when (or (:in-team permissions)
|
||||
(= (:who-comment permissions) "all"))
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-pressed (= section :comments)
|
||||
:aria-label (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))
|
||||
:data-value "comments"
|
||||
:on-click navigate
|
||||
:icon i/comments}])
|
||||
[:button {:on-click navigate
|
||||
:data-value "comments"
|
||||
:class (stl/css-case :mode-zone-btn true
|
||||
:selected (= section :comments))
|
||||
:title (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))}
|
||||
deprecated-icon/comments])
|
||||
|
||||
(when (or (:in-team permissions)
|
||||
(and (= (:type permissions) :share-link)
|
||||
(= (:who-inspect permissions) "all")))
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-pressed (= section :inspect)
|
||||
:aria-label (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))
|
||||
:on-click go-to-inspect
|
||||
:icon i/code}])]
|
||||
[:button {:on-click go-to-inspect
|
||||
:class (stl/css-case :mode-zone-btn true
|
||||
:selected (= section :inspect))
|
||||
:title (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))}
|
||||
deprecated-icon/code])]
|
||||
|
||||
[:> header-options* {:section section
|
||||
:permissions permissions
|
||||
:page page
|
||||
:file file
|
||||
:index index
|
||||
:zoom zoom
|
||||
:interactions-mode interactions-mode
|
||||
:share share}]]))
|
||||
[:& header-options {:section section
|
||||
:permissions permissions
|
||||
:page page
|
||||
:file file
|
||||
:index index
|
||||
:zoom zoom
|
||||
:interactions-mode interactions-mode
|
||||
:share share}]]))
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
grid-column: 1 / span 1;
|
||||
grid-row: 1 / span 1;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
grid-template-columns: 1fr deprecated.$s-92 1fr;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: deprecated.$s-48;
|
||||
@@ -130,9 +130,23 @@
|
||||
|
||||
// SECTION BUTTONS
|
||||
.mode-zone {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: var(--sp-xs);
|
||||
@include deprecated.flexRow;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.mode-zone-btn {
|
||||
@extend .button-tertiary;
|
||||
@include deprecated.flexCenter;
|
||||
height: deprecated.$s-32;
|
||||
width: deprecated.$s-28;
|
||||
padding: 0;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
}
|
||||
}
|
||||
|
||||
.selected {
|
||||
@extend .button-icon-selected;
|
||||
}
|
||||
|
||||
// OPTION AREA
|
||||
@@ -151,8 +165,33 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
@extend .button-tertiary;
|
||||
@include deprecated.flexCenter;
|
||||
height: deprecated.$s-32;
|
||||
width: deprecated.$s-28;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.share-btn {
|
||||
margin-left: var(--sp-xs);
|
||||
@extend .button-primary;
|
||||
height: deprecated.$s-32;
|
||||
min-width: deprecated.$s-72;
|
||||
margin-left: deprecated.$s-4;
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
@extend .button-tertiary;
|
||||
@include deprecated.flexCenter;
|
||||
height: deprecated.$s-32;
|
||||
width: deprecated.$s-28;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.go-log-btn {
|
||||
@@ -206,15 +245,43 @@
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.zoom-btn {
|
||||
@extend .button-tertiary;
|
||||
height: deprecated.$s-28;
|
||||
width: deprecated.$s-28;
|
||||
border-radius: deprecated.$br-8;
|
||||
.zoom-icon {
|
||||
@include deprecated.flexCenter;
|
||||
width: deprecated.$s-24;
|
||||
height: deprecated.$s-32;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.zoom-icon svg {
|
||||
stroke: var(--button-tertiary-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.zoom-text {
|
||||
@include deprecated.flexCenter;
|
||||
height: 100%;
|
||||
min-width: deprecated.$s-48;
|
||||
min-width: deprecated.$s-64;
|
||||
padding: 0;
|
||||
margin: 0 deprecated.$s-2;
|
||||
color: var(--modal-title-foreground-color);
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
@extend .button-tertiary;
|
||||
color: var(--button-tertiary-foreground-color-hover);
|
||||
height: deprecated.$s-28;
|
||||
border-radius: deprecated.$br-8;
|
||||
}
|
||||
|
||||
.zoom-option {
|
||||
@extend .menu-item-base;
|
||||
.shortcuts {
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.select :refer [select]]
|
||||
[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.icons :as deprecated-icon]
|
||||
[app.util.clipboard :as clipboard]
|
||||
[app.util.dom :as dom]
|
||||
@@ -174,11 +171,10 @@
|
||||
[:div {:class (stl/css :share-link-header)}
|
||||
[:h2 {:class (stl/css :share-link-title)}
|
||||
(tr "common.share-link.title")]
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:class (stl/css :modal-close-button)
|
||||
:aria-label (tr "labels.close")
|
||||
:on-click on-close
|
||||
:icon i/close}]]
|
||||
[:button {:class (stl/css :modal-close-button)
|
||||
:on-click on-close
|
||||
:title (tr "labels.close")}
|
||||
deprecated-icon/close]]
|
||||
[:div {:class (stl/css :modal-content)}
|
||||
[:div {:class (stl/css :share-link-section)}
|
||||
(when (and (not confirm?) (some? current-link))
|
||||
@@ -189,10 +185,10 @@
|
||||
:placeholder (tr "common.share-link.placeholder")
|
||||
:read-only true}]
|
||||
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "viewer.header.share.copy-link")
|
||||
:on-click copy-link
|
||||
:icon i/clipboard}]])
|
||||
[:button {:class (stl/css :copy-button)
|
||||
:title (tr "viewer.header.share.copy-link")
|
||||
:on-click copy-link}
|
||||
deprecated-icon/clipboard]])
|
||||
|
||||
[:div {:class (stl/css :hint-wrapper)}
|
||||
(when (not ^boolean confirm?)
|
||||
@@ -203,22 +199,28 @@
|
||||
[:div {:class (stl/css :description)}
|
||||
(tr "common.share-link.confirm-deletion-link-description")]
|
||||
[:div {:class (stl/css :actions)}
|
||||
[:> button* {:variant "secondary"
|
||||
:on-click #(reset! confirm* false)}
|
||||
(tr "labels.cancel")]
|
||||
[:> button* {:variant "destructive"
|
||||
:on-click delete-link}
|
||||
(tr "common.share-link.destroy-link")]]]
|
||||
[:input {:type "button"
|
||||
:class (stl/css :button-cancel)
|
||||
:on-click #(reset! confirm* false)
|
||||
:value (tr "labels.cancel")}]
|
||||
[:input {:type "button"
|
||||
:class (stl/css :button-danger)
|
||||
:on-click delete-link
|
||||
:value (tr "common.share-link.destroy-link")}]]]
|
||||
|
||||
(some? current-link)
|
||||
[:> button* {:variant "destructive"
|
||||
:on-click try-delete-link}
|
||||
(tr "common.share-link.destroy-link")]
|
||||
[:input
|
||||
{:type "button"
|
||||
:class (stl/css :button-danger)
|
||||
:on-click try-delete-link
|
||||
:value (tr "common.share-link.destroy-link")}]
|
||||
|
||||
:else
|
||||
[:> button* {:variant "primary"
|
||||
:on-click create-link}
|
||||
(tr "common.share-link.get-link")])]]
|
||||
[:input
|
||||
{:type "button"
|
||||
:class (stl/css :button-active)
|
||||
:on-click create-link
|
||||
:value (tr "common.share-link.get-link")}])]]
|
||||
|
||||
|
||||
(when (not ^boolean confirm?)
|
||||
@@ -303,7 +305,6 @@
|
||||
:options [{:value "team" :label (tr "common.share-link.team-members")}
|
||||
{:value "all" :label (tr "common.share-link.all-users")}]
|
||||
:on-change on-comment-change}]]]
|
||||
|
||||
[:div {:class (stl/css :inspect-mode)}
|
||||
[:div {:class (stl/css :subtitle)}
|
||||
(tr "common.share-link.permissions-can-inspect")]
|
||||
@@ -314,3 +315,6 @@
|
||||
:options [{:value "team" :label (tr "common.share-link.team-members")}
|
||||
{:value "all" :label (tr "common.share-link.all-users")}]
|
||||
:on-change on-inspect-change}]]]])])]]]))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -30,9 +30,7 @@
|
||||
}
|
||||
|
||||
.modal-close-button {
|
||||
position: absolute;
|
||||
top: var(--sp-s);
|
||||
right: var(--sp-s);
|
||||
@extend .modal-close-btn-base;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
@@ -76,6 +74,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
@extend .button-secondary;
|
||||
@include deprecated.flexRow;
|
||||
gap: deprecated.$s-8;
|
||||
height: deprecated.$s-32;
|
||||
width: deprecated.$s-28;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
@include deprecated.bodySmallTypography;
|
||||
color: var(--modal-text-foreground-color);
|
||||
@@ -87,6 +97,18 @@
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.button-active {
|
||||
@extend .modal-accept-btn;
|
||||
}
|
||||
|
||||
.button-cancel {
|
||||
@extend .modal-cancel-btn;
|
||||
}
|
||||
|
||||
.button-danger {
|
||||
@extend .modal-danger-btn;
|
||||
}
|
||||
|
||||
.permissions-section {
|
||||
@include deprecated.flexColumn;
|
||||
gap: deprecated.$s-8;
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
(mf/defc workspace-content*
|
||||
{::mf/private true}
|
||||
[{:keys [file layout page wglobal]}]
|
||||
[{:keys [file layout page wglobal file-version-id]}]
|
||||
|
||||
(let [palete-size (mf/use-state nil)
|
||||
selected (mf/deref refs/selected-shapes)
|
||||
@@ -109,6 +109,7 @@
|
||||
:wglobal wglobal
|
||||
:selected selected
|
||||
:layout layout
|
||||
:file-version-id file-version-id
|
||||
:palete-size
|
||||
(when (and (or colorpalette? textpalette?) (not hide-ui?))
|
||||
@palete-size)}]]]
|
||||
@@ -168,7 +169,7 @@
|
||||
|
||||
(mf/defc workspace-inner*
|
||||
{::mf/private true}
|
||||
[{:keys [page-id file-id file layout wglobal]}]
|
||||
[{:keys [page-id file-id file layout wglobal file-version-id]}]
|
||||
(let [page-ref (mf/with-memo [file-id page-id]
|
||||
(make-page-ref file-id page-id))
|
||||
page (mf/deref page-ref)]
|
||||
@@ -187,7 +188,8 @@
|
||||
[:> workspace-content* {:file file
|
||||
:page page
|
||||
:wglobal wglobal
|
||||
:layout layout}]
|
||||
:layout layout
|
||||
:file-version-id file-version-id}]
|
||||
[:> workspace-loader*])))
|
||||
|
||||
(mf/defc workspace*
|
||||
@@ -199,6 +201,7 @@
|
||||
|
||||
layout (mf/deref refs/workspace-layout)
|
||||
wglobal (mf/deref refs/workspace-global)
|
||||
file-version-id (mf/deref refs/workspace-file-version-id)
|
||||
|
||||
team-ref (mf/with-memo [team-id]
|
||||
(make-team-ref team-id))
|
||||
@@ -274,7 +277,8 @@
|
||||
:file-id file-id
|
||||
:file file
|
||||
:wglobal wglobal
|
||||
:layout layout}])
|
||||
:layout layout
|
||||
:file-version-id file-version-id}])
|
||||
(when (or (not (and file-loaded? page-id))
|
||||
;; in wasm renderer, extend the pixel loader until the first frame is rendered
|
||||
;; but do not apply it when switching pages
|
||||
|
||||
@@ -25,11 +25,10 @@
|
||||
[app.main.features :as features]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader*]]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||
[app.main.ui.components.numeric-input :refer [numeric-input*]]
|
||||
[app.main.ui.components.radio-buttons :refer [radio-buttons radio-button]]
|
||||
[app.main.ui.components.select :refer [select]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
@@ -416,25 +415,24 @@
|
||||
:on-change handle-change-mode}]])
|
||||
|
||||
(when (and (= origin :sidebar) show-tokens? token-color)
|
||||
[:> radio-buttons* {:selected color-style
|
||||
:on-change toggle-token-color
|
||||
:name "color-style"
|
||||
:options [{:id "swap-opt-list"
|
||||
:icon i/swatches
|
||||
:label (tr "labels.color")
|
||||
:value :direct-color}
|
||||
{:id "swap-opt-grid"
|
||||
:icon i/tokens
|
||||
:label (tr "workspace.colorpicker.color-tokens")
|
||||
:value :token-color}]}])]
|
||||
[:& radio-buttons {:selected color-style
|
||||
:on-change toggle-token-color
|
||||
:name "color-style"}
|
||||
[:& radio-button {:icon i/swatches
|
||||
:value :direct-color
|
||||
:title (tr "labels.color")
|
||||
:id "opt-color"}]
|
||||
[:& radio-button {:icon i/tokens
|
||||
:value :token-color
|
||||
:title (tr "workspace.colorpicker.color-tokens")
|
||||
:id "opt-token-color"}]])]
|
||||
|
||||
(when (and (not= selected-mode :image)
|
||||
(= color-style :direct-color))
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "workspace.colorpicker.get-color")
|
||||
:aria-pressed picking-color?
|
||||
:on-click handle-click-picker
|
||||
:icon i/picker}])
|
||||
[:button {:class (stl/css-case :picker-btn true
|
||||
:selected picking-color?)
|
||||
:on-click handle-click-picker}
|
||||
deprecated-icon/picker])
|
||||
|
||||
(when (= color-style :token-color)
|
||||
[:div {:class (stl/css :token-color-title)}
|
||||
@@ -485,11 +483,12 @@
|
||||
:aria-label (tr "media.choose-image")
|
||||
:on-click on-fill-image-click}
|
||||
(tr "media.choose-image")
|
||||
[:> file-uploader* {:input-id "fill-image-upload"
|
||||
:accept "image/jpeg,image/png"
|
||||
:multi false
|
||||
:ref fill-image-ref
|
||||
:on-selected on-fill-image-selected}]]])
|
||||
[:& file-uploader
|
||||
{:input-id "fill-image-upload"
|
||||
:accept "image/jpeg,image/png"
|
||||
:multi false
|
||||
:ref fill-image-ref
|
||||
:on-selected on-fill-image-selected}]]])
|
||||
|
||||
[:*
|
||||
[:div {:class (stl/css :colorpicker-tabs)}
|
||||
|
||||
@@ -46,6 +46,52 @@
|
||||
width: px2rem(68);
|
||||
}
|
||||
|
||||
// TODO: change to DS button component
|
||||
.picker-btn {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
border-radius: $br-8;
|
||||
background-color: transparent;
|
||||
border: $b-1 solid transparent;
|
||||
height: var(--sp-xl);
|
||||
width: var(--sp-xl);
|
||||
border-radius: $br-4;
|
||||
padding: 0;
|
||||
margin-top: var(--sp-xs);
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--button-tertiary-foreground-color-rest);
|
||||
}
|
||||
&:hover {
|
||||
svg {
|
||||
stroke: var(--button-tertiary-foreground-color-focus);
|
||||
}
|
||||
}
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
svg {
|
||||
stroke: var(--button-secondary-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
&:active {
|
||||
outline: none;
|
||||
border: $b-1 solid transparent;
|
||||
svg {
|
||||
stroke: var(--button-tertiary-foreground-color-active);
|
||||
}
|
||||
}
|
||||
&.selected {
|
||||
svg {
|
||||
stroke: var(--button-tertiary-foreground-color-active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gradient-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
[app.main.ui.components.search-bar :refer [search-bar*]]
|
||||
[app.main.ui.components.title-bar :refer [title-bar*]]
|
||||
[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.layout.tab-switcher :refer [tab-switcher*]]
|
||||
@@ -45,6 +44,12 @@
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private close-icon
|
||||
(deprecated-icon/icon-xref :close (stl/css :close-icon)))
|
||||
|
||||
(def ^:private add-icon
|
||||
(deprecated-icon/icon-xref :add (stl/css :add-icon)))
|
||||
|
||||
(defn- get-library-summary
|
||||
"Given a library data return a summary representation of this library"
|
||||
[data]
|
||||
@@ -163,10 +168,12 @@
|
||||
[:div {:class (stl/css :sample-library-item)
|
||||
:key (dm/str id)}
|
||||
[:div {:class (stl/css :sample-library-item-name)} (:name library)]
|
||||
[:> button* {:variant "secondary"
|
||||
:on-click import-library
|
||||
:disabled (some? importing?)}
|
||||
(if (= importing? id) (tr "labels.adding") (tr "labels.add"))]]))
|
||||
[:input {:class (stl/css-case :sample-library-button true
|
||||
:sample-library-add (nil? importing?)
|
||||
:sample-library-adding (some? importing?))
|
||||
:type "button"
|
||||
:value (if (= importing? id) (tr "labels.adding") (tr "labels.add"))
|
||||
:on-click import-library}]]))
|
||||
|
||||
(defn- empty-library?
|
||||
"Check if currentt library summary has elements or not"
|
||||
@@ -315,12 +322,14 @@
|
||||
[:> library-description* {:summary summary}]]]
|
||||
|
||||
(if ^boolean is-shared
|
||||
[:> button* {:variant "secondary"
|
||||
:on-click unpublish}
|
||||
(tr "common.unpublish")]
|
||||
[:> button* {:variant "primary"
|
||||
:on-click publish}
|
||||
(tr "common.publish")])]
|
||||
[:input {:class (stl/css :item-unpublish)
|
||||
:type "button"
|
||||
:value (tr "common.unpublish")
|
||||
:on-click unpublish}]
|
||||
[:input {:class (stl/css :item-publish)
|
||||
:type "button"
|
||||
:value (tr "common.publish")
|
||||
:on-click publish}])]
|
||||
|
||||
(for [{:keys [id name data connected-to connected-to-names] :as library} linked-libraries]
|
||||
(let [disabled? (some #(contains? linked-libraries-ids %) connected-to)]
|
||||
@@ -368,11 +377,12 @@
|
||||
(let [summary (-> (:library-summary library)
|
||||
(adapt-backend-summary))]
|
||||
[:> library-description* {:summary summary}])]]
|
||||
[:> icon-button* {:variant "secondary"
|
||||
:aria-label (tr "workspace.libraries.shared-library-btn")
|
||||
:icon i/add
|
||||
:data-library-id (dm/str id)
|
||||
:on-click link-library}]])]
|
||||
|
||||
[:button {:class (stl/css :item-button-shared)
|
||||
:data-library-id (dm/str id)
|
||||
:title (tr "workspace.libraries.shared-library-btn")
|
||||
:on-click link-library}
|
||||
add-icon]])]
|
||||
|
||||
(when (empty? shared-libraries)
|
||||
[:div {:class (stl/css :section-list-empty)}
|
||||
@@ -637,13 +647,11 @@
|
||||
:on-click close-dialog-outside
|
||||
:data-testid "libraries-modal"}
|
||||
[:div {:class (stl/css :modal-dialog)}
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:class (stl/css :close-btn)
|
||||
:icon i/close
|
||||
:aria-label (tr "labels.close")
|
||||
:data-testid "close-libraries"
|
||||
:on-click close-dialog}]
|
||||
|
||||
[:button {:class (stl/css :close-btn)
|
||||
:on-click close-dialog
|
||||
:aria-label (tr "labels.close")
|
||||
:data-testid "close-libraries"}
|
||||
close-icon]
|
||||
[:div {:class (stl/css :modal-title)}
|
||||
(tr "workspace.libraries.libraries")]
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
background-color: var(--modal-background-color);
|
||||
border: $b-2 solid var(--modal-border-color);
|
||||
display: grid;
|
||||
grid-template-rows: 0 auto 1fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
min-width: $sz-364;
|
||||
min-height: $sz-192;
|
||||
height: $sz-520;
|
||||
@@ -42,10 +42,21 @@
|
||||
max-width: $sz-712;
|
||||
}
|
||||
|
||||
// TODO: Remove this extended creating modal component
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: var(--sp-s);
|
||||
right: var(--sp-s);
|
||||
@extend .modal-close-btn-base;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: $sz-16;
|
||||
width: $sz-16;
|
||||
color: transparent;
|
||||
fill: none;
|
||||
stroke-width: $b-1;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
@@ -109,6 +120,46 @@
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.item-publish,
|
||||
.item-unpublish {
|
||||
// TODO: remove this extended by using DS button component
|
||||
@extend .button-primary;
|
||||
@include t.use-typography("headline-small");
|
||||
height: $sz-32;
|
||||
min-width: px2rem(92);
|
||||
padding: var(--sp-s) var(--sp-xxl);
|
||||
margin: 0;
|
||||
border-radius: $br-8;
|
||||
}
|
||||
|
||||
.item-unpublish {
|
||||
// TODO: remove this extended by using DS button component
|
||||
@extend .button-secondary;
|
||||
}
|
||||
|
||||
.item-button,
|
||||
.item-button-shared {
|
||||
// TODO: remove this extended by using DS button component
|
||||
@extend .button-secondary;
|
||||
height: $sz-32;
|
||||
width: $sz-32;
|
||||
margin-inline-start: var(--sp-xxs);
|
||||
padding: var(--sp-s);
|
||||
}
|
||||
|
||||
.detach-icon,
|
||||
.add-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: $sz-16;
|
||||
width: $sz-16;
|
||||
color: transparent;
|
||||
fill: none;
|
||||
stroke-width: $b-1;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
|
||||
.section-list-shared {
|
||||
max-height: px2rem(272);
|
||||
}
|
||||
@@ -119,6 +170,26 @@
|
||||
color: var(--title-foreground-color);
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: px2rem(20);
|
||||
padding: 0 0 0 var(--sp-s);
|
||||
|
||||
svg {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: transparent;
|
||||
fill: none;
|
||||
height: px2rem(12);
|
||||
width: px2rem(12);
|
||||
stroke-width: 1.33px;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
// empty state
|
||||
.section-list-empty {
|
||||
display: grid;
|
||||
@@ -357,3 +428,24 @@
|
||||
text-overflow: ellipsis;
|
||||
max-width: px2rem(232);
|
||||
}
|
||||
|
||||
// TODO: Remove this extended using a DS component
|
||||
.sample-library-add {
|
||||
@extend .button-secondary;
|
||||
}
|
||||
|
||||
// TODO: Remove this extended using a DS component
|
||||
.sample-library-adding {
|
||||
@extend .button-disabled;
|
||||
}
|
||||
|
||||
.sample-library-button {
|
||||
@include t.use-typography("headline-small");
|
||||
height: $sz-32;
|
||||
width: px2rem(80);
|
||||
margin: 0;
|
||||
border-radius: $br-8;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@@ -853,9 +853,8 @@
|
||||
|
||||
[:*
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-pressed show-menu?
|
||||
:aria-label (tr "shortcut-subsection.main-menu")
|
||||
:on-click (if show-menu? close-all-menus open-menu)
|
||||
:on-click open-menu
|
||||
:icon i/menu}]
|
||||
|
||||
[:> dropdown-menu* {:show show-menu?
|
||||
|
||||