mirror of
https://github.com/penpot/penpot.git
synced 2025-05-23 08:16:11 +02:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
da738ba1e9
20 changed files with 760 additions and 23 deletions
|
@ -108,7 +108,7 @@ jobs:
|
||||||
command: |
|
command: |
|
||||||
yarn install
|
yarn install
|
||||||
yarn run compile
|
yarn run compile
|
||||||
yarn run compile:cljs
|
clojure -M:dev:shadow-cljs release main
|
||||||
yarn playwright install --with-deps chromium
|
yarn playwright install --with-deps chromium
|
||||||
yarn e2e:test
|
yarn e2e:test
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
### :sparkles: New features
|
### :sparkles: New features
|
||||||
|
|
||||||
|
- Fix clickable area of Penptot logo in the viewer [Taiga #7988](https://tree.taiga.io/project/penpot/issue/7988)
|
||||||
|
- Fix constraints dropdown when selecting multiple shapes [Taiga #7686](https://tree.taiga.io/project/penpot/issue/7686)
|
||||||
- Improve auth process [Taiga #7094](https://tree.taiga.io/project/penpot/us/7094)
|
- Improve auth process [Taiga #7094](https://tree.taiga.io/project/penpot/us/7094)
|
||||||
- Add locking degrees increment (hold shift) on path edition [Taiga #7761](https://tree.taiga.io/project/penpot/issue/7761)
|
- Add locking degrees increment (hold shift) on path edition [Taiga #7761](https://tree.taiga.io/project/penpot/issue/7761)
|
||||||
- Persistence & Concurrent Edition Enhancements [Taiga #5657](https://tree.taiga.io/project/penpot/us/5657)
|
- Persistence & Concurrent Edition Enhancements [Taiga #5657](https://tree.taiga.io/project/penpot/us/5657)
|
||||||
|
|
|
@ -375,8 +375,11 @@
|
||||||
{:skip-components? true
|
{:skip-components? true
|
||||||
:bottom-frames? true
|
:bottom-frames? true
|
||||||
;; We must avoid that destiny frame is inside the component frame
|
;; We must avoid that destiny frame is inside the component frame
|
||||||
:validator #(nil? (get component-children (:id %)))}))
|
:validator #(and
|
||||||
|
;; We must avoid that destiny frame is inside the component frame
|
||||||
|
(nil? (get component-children (:id %)))
|
||||||
|
;; We must avoid that destiny frame is inside a copy
|
||||||
|
(not (ctk/in-component-copy? %)))}))
|
||||||
frame (get-shape container frame-id)
|
frame (get-shape container frame-id)
|
||||||
component-frame (get-component-shape objects frame {:allow-main? true})
|
component-frame (get-component-shape objects frame {:allow-main? true})
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,7 @@
|
||||||
"workerpool": "^9.1.1"
|
"workerpool": "^9.1.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"compression": "^1.7.4",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"eventsource-parser": "^1.1.2",
|
"eventsource-parser": "^1.1.2",
|
||||||
"highlight.js": "^11.9.0",
|
"highlight.js": "^11.9.0",
|
||||||
|
|
|
@ -0,0 +1,363 @@
|
||||||
|
{
|
||||||
|
"~:id": "~u03bff843-920f-81a1-8004-7563acdc8ca1",
|
||||||
|
"~:file-id": "~u03bff843-920f-81a1-8004-756365e1eb6a",
|
||||||
|
"~:created-at": "~m1717592543081",
|
||||||
|
"~:content": {
|
||||||
|
"~:options": {},
|
||||||
|
"~:objects": {
|
||||||
|
"~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,
|
||||||
|
"~:y": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 0.01,
|
||||||
|
"~:y": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 0.01,
|
||||||
|
"~:y": 0.01
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 0,
|
||||||
|
"~:y": 0.01
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:proportion-lock": false,
|
||||||
|
"~:transform-inverse": {
|
||||||
|
"~#matrix": {
|
||||||
|
"~:a": 1.0,
|
||||||
|
"~:b": 0.0,
|
||||||
|
"~:c": 0.0,
|
||||||
|
"~:d": 1.0,
|
||||||
|
"~:e": 0.0,
|
||||||
|
"~:f": 0.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,
|
||||||
|
"~:selrect": {
|
||||||
|
"~#rect": {
|
||||||
|
"~:x": 0,
|
||||||
|
"~:y": 0,
|
||||||
|
"~:width": 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,
|
||||||
|
"~:height": 0.01,
|
||||||
|
"~:flip-y": null,
|
||||||
|
"~:shapes": [
|
||||||
|
"~ub574c052-1a31-80bb-8004-75636879759b"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~ub574c052-1a31-80bb-8004-75636879759b": {
|
||||||
|
"~#shape": {
|
||||||
|
"~:y": 128,
|
||||||
|
"~: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,
|
||||||
|
"~:grow-type": "~:fixed",
|
||||||
|
"~:hide-in-viewer": false,
|
||||||
|
"~:name": "Board",
|
||||||
|
"~:width": 256,
|
||||||
|
"~:type": "~:frame",
|
||||||
|
"~:points": [
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 128,
|
||||||
|
"~:y": 128
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 384,
|
||||||
|
"~:y": 128
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 384,
|
||||||
|
"~:y": 384
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 128,
|
||||||
|
"~:y": 384
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:proportion-lock": false,
|
||||||
|
"~:transform-inverse": {
|
||||||
|
"~#matrix": {
|
||||||
|
"~:a": 1.0,
|
||||||
|
"~:b": 0.0,
|
||||||
|
"~:c": 0.0,
|
||||||
|
"~:d": 1.0,
|
||||||
|
"~:e": 0.0,
|
||||||
|
"~:f": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:id": "~ub574c052-1a31-80bb-8004-75636879759b",
|
||||||
|
"~:parent-id": "~u00000000-0000-0000-0000-000000000000",
|
||||||
|
"~:frame-id": "~u00000000-0000-0000-0000-000000000000",
|
||||||
|
"~:strokes": [],
|
||||||
|
"~:x": 128,
|
||||||
|
"~:proportion": 1,
|
||||||
|
"~:selrect": {
|
||||||
|
"~#rect": {
|
||||||
|
"~:x": 128,
|
||||||
|
"~:y": 128,
|
||||||
|
"~:width": 256,
|
||||||
|
"~:height": 256,
|
||||||
|
"~:x1": 128,
|
||||||
|
"~:y1": 128,
|
||||||
|
"~:x2": 384,
|
||||||
|
"~:y2": 384
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:fills": [
|
||||||
|
{
|
||||||
|
"~:fill-color": "#FFFFFF",
|
||||||
|
"~:fill-opacity": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:flip-x": null,
|
||||||
|
"~:height": 256,
|
||||||
|
"~:flip-y": null,
|
||||||
|
"~:shapes": [
|
||||||
|
"~ub574c052-1a31-80bb-8004-75636a9b8205",
|
||||||
|
"~ub574c052-1a31-80bb-8004-756392461069"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~ub574c052-1a31-80bb-8004-75636a9b8205": {
|
||||||
|
"~#shape": {
|
||||||
|
"~:y": 136,
|
||||||
|
"~:rx": 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",
|
||||||
|
"~:hide-in-viewer": false,
|
||||||
|
"~:name": "Rectangle",
|
||||||
|
"~:width": 64,
|
||||||
|
"~:type": "~:rect",
|
||||||
|
"~:points": [
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 136,
|
||||||
|
"~:y": 136
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 200,
|
||||||
|
"~:y": 136
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 200,
|
||||||
|
"~:y": 199.99999999999997
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 136,
|
||||||
|
"~:y": 199.99999999999997
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:proportion-lock": false,
|
||||||
|
"~:transform-inverse": {
|
||||||
|
"~#matrix": {
|
||||||
|
"~:a": 1.0,
|
||||||
|
"~:b": 0.0,
|
||||||
|
"~:c": 0.0,
|
||||||
|
"~:d": 1.0,
|
||||||
|
"~:e": 0.0,
|
||||||
|
"~:f": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:id": "~ub574c052-1a31-80bb-8004-75636a9b8205",
|
||||||
|
"~:parent-id": "~ub574c052-1a31-80bb-8004-75636879759b",
|
||||||
|
"~:frame-id": "~ub574c052-1a31-80bb-8004-75636879759b",
|
||||||
|
"~:strokes": [],
|
||||||
|
"~:x": 136,
|
||||||
|
"~:proportion": 1,
|
||||||
|
"~:selrect": {
|
||||||
|
"~#rect": {
|
||||||
|
"~:x": 136,
|
||||||
|
"~:y": 136,
|
||||||
|
"~:width": 64,
|
||||||
|
"~:height": 63.99999999999997,
|
||||||
|
"~:x1": 136,
|
||||||
|
"~:y1": 136,
|
||||||
|
"~:x2": 200,
|
||||||
|
"~:y2": 199.99999999999997
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:fills": [
|
||||||
|
{
|
||||||
|
"~:fill-color": "#B1B2B5",
|
||||||
|
"~:fill-opacity": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:flip-x": null,
|
||||||
|
"~:ry": 0,
|
||||||
|
"~:height": 63.99999999999997,
|
||||||
|
"~:flip-y": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~ub574c052-1a31-80bb-8004-756392461069": {
|
||||||
|
"~#shape": {
|
||||||
|
"~:y": 136,
|
||||||
|
"~: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": 64,
|
||||||
|
"~:type": "~:circle",
|
||||||
|
"~:points": [
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 256,
|
||||||
|
"~:y": 136
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 320,
|
||||||
|
"~:y": 136
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 320,
|
||||||
|
"~:y": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 256,
|
||||||
|
"~:y": 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:proportion-lock": false,
|
||||||
|
"~:transform-inverse": {
|
||||||
|
"~#matrix": {
|
||||||
|
"~:a": 1.0,
|
||||||
|
"~:b": 0.0,
|
||||||
|
"~:c": 0.0,
|
||||||
|
"~:d": 1.0,
|
||||||
|
"~:e": 0.0,
|
||||||
|
"~:f": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:constraints-v": "~:bottom",
|
||||||
|
"~:constraints-h": "~:right",
|
||||||
|
"~:id": "~ub574c052-1a31-80bb-8004-756392461069",
|
||||||
|
"~:parent-id": "~ub574c052-1a31-80bb-8004-75636879759b",
|
||||||
|
"~:frame-id": "~ub574c052-1a31-80bb-8004-75636879759b",
|
||||||
|
"~:strokes": [],
|
||||||
|
"~:x": 256,
|
||||||
|
"~:proportion": 1,
|
||||||
|
"~:selrect": {
|
||||||
|
"~#rect": {
|
||||||
|
"~:x": 256,
|
||||||
|
"~:y": 136,
|
||||||
|
"~:width": 64,
|
||||||
|
"~:height": 64,
|
||||||
|
"~:x1": 256,
|
||||||
|
"~:y1": 136,
|
||||||
|
"~:x2": 320,
|
||||||
|
"~:y2": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:fills": [
|
||||||
|
{
|
||||||
|
"~:fill-color": "#B1B2B5",
|
||||||
|
"~:fill-opacity": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:flip-x": null,
|
||||||
|
"~:height": 64,
|
||||||
|
"~:flip-y": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:id": "~u03bff843-920f-81a1-8004-756365e1eb6b",
|
||||||
|
"~:name": "Page 1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
{
|
||||||
|
"~:features": {
|
||||||
|
"~#set": [
|
||||||
|
"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,
|
||||||
|
"~:can-read": true,
|
||||||
|
"~:is-logged": true
|
||||||
|
},
|
||||||
|
"~:has-media-trimmed": false,
|
||||||
|
"~:comment-thread-seqn": 0,
|
||||||
|
"~:name": "New File 2",
|
||||||
|
"~:revn": 9,
|
||||||
|
"~:modified-at": "~m1717592543083",
|
||||||
|
"~:id": "~u03bff843-920f-81a1-8004-756365e1eb6a",
|
||||||
|
"~:is-shared": false,
|
||||||
|
"~:version": 48,
|
||||||
|
"~:project-id": "~u0515a066-e303-8169-8004-73eb401b5d55",
|
||||||
|
"~:created-at": "~m1717592470408",
|
||||||
|
"~:data": {
|
||||||
|
"~:pages": [
|
||||||
|
"~u03bff843-920f-81a1-8004-756365e1eb6b"
|
||||||
|
],
|
||||||
|
"~:pages-index": {
|
||||||
|
"~u03bff843-920f-81a1-8004-756365e1eb6b": {
|
||||||
|
"~#penpot/pointer": [
|
||||||
|
"~u03bff843-920f-81a1-8004-7563acdc8ca1",
|
||||||
|
{
|
||||||
|
"~:created-at": "~m1717592543090"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:id": "~u03bff843-920f-81a1-8004-756365e1eb6a",
|
||||||
|
"~:options": {
|
||||||
|
"~:components-v2": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"03bff843-920f-81a1-8004-756365e1eb6a/03bff843-920f-81a1-8004-756365e1eb6b/b574c052-1a31-80bb-8004-75636879759b/frame": "http://localhost:3449/assets/by-id/bdc9e592-f685-4b08-9a44-127ce20efee6"
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
{
|
||||||
|
"~:id": "~u0515a066-e303-8169-8004-73eb58e899c2",
|
||||||
|
"~:file-id": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||||
|
"~:created-at": "~m1717493890966",
|
||||||
|
"~:content": {
|
||||||
|
"~:options": {},
|
||||||
|
"~:objects": {
|
||||||
|
"~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,
|
||||||
|
"~:y": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 0.01,
|
||||||
|
"~:y": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 0.01,
|
||||||
|
"~:y": 0.01
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~#point": {
|
||||||
|
"~:x": 0,
|
||||||
|
"~:y": 0.01
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:proportion-lock": false,
|
||||||
|
"~:transform-inverse": {
|
||||||
|
"~#matrix": {
|
||||||
|
"~:a": 1.0,
|
||||||
|
"~:b": 0.0,
|
||||||
|
"~:c": 0.0,
|
||||||
|
"~:d": 1.0,
|
||||||
|
"~:e": 0.0,
|
||||||
|
"~:f": 0.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,
|
||||||
|
"~:selrect": {
|
||||||
|
"~#rect": {
|
||||||
|
"~:x": 0,
|
||||||
|
"~:y": 0,
|
||||||
|
"~:width": 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,
|
||||||
|
"~:height": 0.01,
|
||||||
|
"~:flip-y": null,
|
||||||
|
"~:shapes": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:id": "~uc7ce0794-0992-8105-8004-38f28044384a",
|
||||||
|
"~:name": "Page 1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
{
|
||||||
|
"~:users": [
|
||||||
|
{
|
||||||
|
"~:id": "~uc7ce0794-0992-8105-8004-38e630f29a9b",
|
||||||
|
"~:email": "leia@example.com",
|
||||||
|
"~:name": "Princesa Leia",
|
||||||
|
"~:fullname": "Princesa Leia",
|
||||||
|
"~:is-active": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"~:fonts": [],
|
||||||
|
"~:project": {
|
||||||
|
"~:id": "~uc7ce0794-0992-8105-8004-38e630f7920b",
|
||||||
|
"~:name": "Drafts",
|
||||||
|
"~:team-id": "~uc7ce0794-0992-8105-8004-38e630f40f6d"
|
||||||
|
},
|
||||||
|
"~:share-links": [],
|
||||||
|
"~:libraries": [],
|
||||||
|
"~:file": {
|
||||||
|
"~:features": {
|
||||||
|
"~#set": [
|
||||||
|
"layout/grid",
|
||||||
|
"styles/v2",
|
||||||
|
"fdata/pointer-map",
|
||||||
|
"fdata/objects-map",
|
||||||
|
"components/v2",
|
||||||
|
"fdata/shape-data-type"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"~:has-media-trimmed": false,
|
||||||
|
"~:comment-thread-seqn": 0,
|
||||||
|
"~:name": "New File 1",
|
||||||
|
"~:revn": 0,
|
||||||
|
"~:modified-at": "~m1717493891000",
|
||||||
|
"~:id": "~uc7ce0794-0992-8105-8004-38f280443849",
|
||||||
|
"~:is-shared": false,
|
||||||
|
"~:version": 48,
|
||||||
|
"~:project-id": "~uc7ce0794-0992-8105-8004-38e630f7920b",
|
||||||
|
"~:created-at": "~m1717493891000",
|
||||||
|
"~:data": {
|
||||||
|
"~:id": "~uc7ce0794-0992-8105-8004-38e630f7920b",
|
||||||
|
"~:options": {
|
||||||
|
"~:components-v2": true
|
||||||
|
},
|
||||||
|
"~:pages": [
|
||||||
|
"~uc7ce0794-0992-8105-8004-38f28044384a"
|
||||||
|
],
|
||||||
|
"~:pages-index": {
|
||||||
|
"~uc7ce0794-0992-8105-8004-38f28044384a": {
|
||||||
|
"~#penpot/pointer": [
|
||||||
|
"~u0515a066-e303-8169-8004-73eb58e899c2",
|
||||||
|
{
|
||||||
|
"~:created-at": "~m1717493890978"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"~:team": {
|
||||||
|
"~:id": "~uc7ce0794-0992-8105-8004-38e630f40f6d",
|
||||||
|
"~:created-at": "~m1717493865581",
|
||||||
|
"~:modified-at": "~m1717493865581",
|
||||||
|
"~:name": "Default",
|
||||||
|
"~:is-default": true,
|
||||||
|
"~:features": {
|
||||||
|
"~#set": [
|
||||||
|
"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,
|
||||||
|
"~:can-read": true,
|
||||||
|
"~:is-logged": true,
|
||||||
|
"~:in-team": true
|
||||||
|
}
|
||||||
|
}
|
48
frontend/playwright/ui/pages/ViewerPage.js
Normal file
48
frontend/playwright/ui/pages/ViewerPage.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import { BaseWebSocketPage } from "./BaseWebSocketPage";
|
||||||
|
|
||||||
|
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", "logged-in-user/get-profile-logged-in.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
async setupEmptyFile() {
|
||||||
|
await this.mockRPC(/get\-view\-only\-bundle\?/, "viewer/get-view-only-bundle-empty-file.json");
|
||||||
|
await this.mockRPC("get-comment-threads?file-id=*", "workspace/get-comment-threads-empty.json");
|
||||||
|
await this.mockRPC(
|
||||||
|
"get-file-fragment?file-id=*&fragment-id=*",
|
||||||
|
"viewer/get-file-fragment-empty-file.json",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ws = null;
|
||||||
|
|
||||||
|
constructor(page) {
|
||||||
|
super(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
async goToViewer() {
|
||||||
|
await this.page.goto(
|
||||||
|
`/#/view/${ViewerPage.anyFileId}?page-id=${ViewerPage.anyPageId}§ion=interactions&index=0`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#ws = await this.waitForNotificationsWebSocket();
|
||||||
|
await this.#ws.mockOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
async cleanUp() {
|
||||||
|
await this.#ws.mockClose();
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,6 +45,7 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||||
this.rootShape = page.locator(`[id="shape-00000000-0000-0000-0000-000000000000"]`);
|
this.rootShape = page.locator(`[id="shape-00000000-0000-0000-0000-000000000000"]`);
|
||||||
this.rectShapeButton = page.getByRole("button", { name: "Rectangle (R)" });
|
this.rectShapeButton = page.getByRole("button", { name: "Rectangle (R)" });
|
||||||
this.colorpicker = page.getByTestId("colorpicker");
|
this.colorpicker = page.getByTestId("colorpicker");
|
||||||
|
this.layers = page.getByTestId("layers");
|
||||||
this.palette = page.getByTestId("palette");
|
this.palette = page.getByTestId("palette");
|
||||||
this.assets = page.getByTestId("assets");
|
this.assets = page.getByTestId("assets");
|
||||||
this.libraries = page.getByTestId("libraries");
|
this.libraries = page.getByTestId("libraries");
|
||||||
|
@ -52,10 +53,8 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||||
this.librariesModal = page.getByTestId("libraries-modal");
|
this.librariesModal = page.getByTestId("libraries-modal");
|
||||||
}
|
}
|
||||||
|
|
||||||
async goToWorkspace() {
|
async goToWorkspace({ fileId = WorkspacePage.anyFileId, pageId = WorkspacePage.anyPageId } = {}) {
|
||||||
await this.page.goto(
|
await this.page.goto(`/#/workspace/${WorkspacePage.anyProjectId}/${fileId}?page-id=${pageId}`);
|
||||||
`/#/workspace/${WorkspacePage.anyProjectId}/${WorkspacePage.anyFileId}?page-id=${WorkspacePage.anyPageId}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.#ws = await this.waitForNotificationsWebSocket();
|
this.#ws = await this.waitForNotificationsWebSocket();
|
||||||
await this.#ws.mockOpen();
|
await this.#ws.mockOpen();
|
||||||
|
@ -103,6 +102,16 @@ export class WorkspacePage extends BaseWebSocketPage {
|
||||||
await this.page.mouse.up();
|
await this.page.mouse.up();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async clickLeafLayer(name, clickOptions = {}) {
|
||||||
|
const layer = this.layers.getByText(name);
|
||||||
|
await layer.click(clickOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickToggableLayer(name, clickOptions = {}) {
|
||||||
|
const layer = this.layers.getByTestId("layer-item").filter({ has: this.page.getByText(name) });
|
||||||
|
await layer.getByRole("button").click(clickOptions);
|
||||||
|
}
|
||||||
|
|
||||||
async clickAssets(clickOptions = {}) {
|
async clickAssets(clickOptions = {}) {
|
||||||
await this.assets.click(clickOptions);
|
await this.assets.click(clickOptions);
|
||||||
}
|
}
|
||||||
|
|
46
frontend/playwright/ui/specs/design-tab.spec.js
Normal file
46
frontend/playwright/ui/specs/design-tab.spec.js
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import { test, expect } from "@playwright/test";
|
||||||
|
import { WorkspacePage } from "../pages/WorkspacePage";
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await WorkspacePage.init(page);
|
||||||
|
});
|
||||||
|
|
||||||
|
const multipleConstraintsFileId = `03bff843-920f-81a1-8004-756365e1eb6a`;
|
||||||
|
const multipleConstraintsPageId = `03bff843-920f-81a1-8004-756365e1eb6b`;
|
||||||
|
|
||||||
|
const setupFileWithMultipeConstraints = async (workspace) => {
|
||||||
|
await workspace.setupEmptyFile();
|
||||||
|
await workspace.mockRPC(/get\-file\?/, "design/get-file-multiple-constraints.json");
|
||||||
|
await workspace.mockRPC(
|
||||||
|
"get-file-object-thumbnails?file-id=*",
|
||||||
|
"design/get-file-object-thumbnails-multiple-constraints.json",
|
||||||
|
);
|
||||||
|
await workspace.mockRPC(
|
||||||
|
"get-file-fragment?file-id=*",
|
||||||
|
"design/get-file-fragment-multiple-constraints.json",
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
test.describe("Constraints", () => {
|
||||||
|
test("Constraint dropdown shows 'Mixed' when multiple layers are selected with different constraints", async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const workspace = new WorkspacePage(page);
|
||||||
|
await setupFileWithMultipeConstraints(workspace);
|
||||||
|
await workspace.goToWorkspace({
|
||||||
|
fileId: multipleConstraintsFileId,
|
||||||
|
pageId: multipleConstraintsPageId,
|
||||||
|
});
|
||||||
|
|
||||||
|
await workspace.clickToggableLayer("Board");
|
||||||
|
await workspace.clickLeafLayer("Ellipse");
|
||||||
|
await workspace.clickLeafLayer("Rectangle", { modifiers: ["Shift"] });
|
||||||
|
|
||||||
|
const constraintVDropdown = workspace.page.getByTestId("constraint-v-select");
|
||||||
|
await expect(constraintVDropdown).toContainText("Mixed");
|
||||||
|
const constraintHDropdown = workspace.page.getByTestId("constraint-h-select");
|
||||||
|
await expect(constraintHDropdown).toContainText("Mixed");
|
||||||
|
|
||||||
|
expect(false);
|
||||||
|
});
|
||||||
|
});
|
23
frontend/playwright/ui/specs/viewer-header.spec.js
Normal file
23
frontend/playwright/ui/specs/viewer-header.spec.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { test, expect } from "@playwright/test";
|
||||||
|
import { ViewerPage } from "../pages/ViewerPage";
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await ViewerPage.init(page);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Clips link area of the logo", async ({ page }) => {
|
||||||
|
const viewerPage = new ViewerPage(page);
|
||||||
|
await viewerPage.setupLoggedInUser();
|
||||||
|
await viewerPage.setupEmptyFile();
|
||||||
|
|
||||||
|
await viewerPage.goToViewer();
|
||||||
|
|
||||||
|
const viewerUrl = page.url();
|
||||||
|
|
||||||
|
const logoLink = viewerPage.page.getByTestId("penpot-logo-link");
|
||||||
|
await expect(logoLink).toBeVisible();
|
||||||
|
|
||||||
|
const { x, y } = await logoLink.boundingBox();
|
||||||
|
await viewerPage.page.mouse.click(x, y + 100);
|
||||||
|
await expect(page.url()).toBe(viewerUrl);
|
||||||
|
});
|
|
@ -1,10 +1,14 @@
|
||||||
import express from "express";
|
import express from "express";
|
||||||
|
import compression from "compression";
|
||||||
|
|
||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = 3000;
|
const port = 3000;
|
||||||
|
|
||||||
|
app.use(compression());
|
||||||
|
|
||||||
const staticPath = path.join(fileURLToPath(import.meta.url), "../../resources/public");
|
const staticPath = path.join(fileURLToPath(import.meta.url), "../../resources/public");
|
||||||
app.use(express.static(staticPath));
|
app.use(express.static(staticPath));
|
||||||
|
|
||||||
|
|
|
@ -341,7 +341,7 @@
|
||||||
(defn- add-component2
|
(defn- add-component2
|
||||||
"This is the second step of the component creation."
|
"This is the second step of the component creation."
|
||||||
([selected components-v2]
|
([selected components-v2]
|
||||||
(add-component2 selected components-v2))
|
(add-component2 nil selected components-v2))
|
||||||
([id-ref selected components-v2]
|
([id-ref selected components-v2]
|
||||||
(ptk/reify ::add-component2
|
(ptk/reify ::add-component2
|
||||||
ev/Event
|
ev/Event
|
||||||
|
|
|
@ -256,6 +256,10 @@
|
||||||
[:span {:class (stl/css :frame-name)} frame-name]
|
[:span {:class (stl/css :frame-name)} frame-name]
|
||||||
[:span {:class (stl/css :icon)} i/arrow]]]]))
|
[:span {:class (stl/css :icon)} i/arrow]]]]))
|
||||||
|
|
||||||
|
(def ^:private penpot-logo-icon
|
||||||
|
(i/icon-xref :penpot-logo-icon (stl/css :logo-icon)))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc header
|
(mf/defc header
|
||||||
[{:keys [project file page frame zoom section permissions index interactions-mode shown-thumbnails]}]
|
[{:keys [project file page frame zoom section permissions index interactions-mode shown-thumbnails]}]
|
||||||
(let [go-to-dashboard
|
(let [go-to-dashboard
|
||||||
|
@ -303,10 +307,10 @@
|
||||||
;; If the user doesn't have permission we disable the link
|
;; If the user doesn't have permission we disable the link
|
||||||
[:a {:class (stl/css :home-link)
|
[:a {:class (stl/css :home-link)
|
||||||
:on-click go-to-dashboard
|
:on-click go-to-dashboard
|
||||||
|
:data-testid "penpot-logo-link"
|
||||||
:style {:cursor (when-not (:in-team permissions) "auto")
|
:style {:cursor (when-not (:in-team permissions) "auto")
|
||||||
:pointer-events (when-not (:in-team permissions) "none")}}
|
:pointer-events (when-not (:in-team permissions) "none")}}
|
||||||
[:span {:class (stl/css :logo-icon)}
|
penpot-logo-icon]
|
||||||
i/logo-icon]]
|
|
||||||
|
|
||||||
[:& header-sitemap {:project project
|
[:& header-sitemap {:project project
|
||||||
:file file
|
:file file
|
||||||
|
|
|
@ -34,16 +34,14 @@
|
||||||
|
|
||||||
.home-link {
|
.home-link {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
display: grid;
|
||||||
|
place-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo-icon {
|
.logo-icon {
|
||||||
@include flexCenter;
|
width: $s-28;
|
||||||
width: $s-32;
|
height: $s-28;
|
||||||
height: $s-32;
|
fill: var(--icon-foreground-hover);
|
||||||
svg {
|
|
||||||
width: $s-28;
|
|
||||||
fill: var(--icon-foreground-hover);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sitemap-zone {
|
.sitemap-zone {
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
highlighted (mf/deref refs/highlighted-shapes)
|
highlighted (mf/deref refs/highlighted-shapes)
|
||||||
highlighted (hooks/use-equal-memo highlighted)
|
highlighted (hooks/use-equal-memo highlighted)
|
||||||
root (get objects uuid/zero)]
|
root (get objects uuid/zero)]
|
||||||
[:div {:class (stl/css :element-list)}
|
[:div {:class (stl/css :element-list) :data-testid "layer-item"}
|
||||||
[:& hooks/sortable-container {}
|
[:& hooks/sortable-container {}
|
||||||
(for [[index id] (reverse (d/enumerate (:shapes root)))]
|
(for [[index id] (reverse (d/enumerate (:shapes root)))]
|
||||||
(when-let [obj (get objects id)]
|
(when-let [obj (get objects id)]
|
||||||
|
@ -510,7 +510,7 @@
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
#(st/emit! (dw/toggle-focus-mode)))]
|
#(st/emit! (dw/toggle-focus-mode)))]
|
||||||
|
|
||||||
[:div#layers {:class (stl/css :layers)}
|
[:div#layers {:class (stl/css :layers) :data-testid "layers"}
|
||||||
(if (d/not-empty? focus)
|
(if (d/not-empty? focus)
|
||||||
[:div {:class (stl/css :tool-window-bar)}
|
[:div {:class (stl/css :tool-window-bar)}
|
||||||
[:button {:class (stl/css :focus-title)
|
[:button {:class (stl/css :focus-title)
|
||||||
|
|
|
@ -207,14 +207,14 @@
|
||||||
:on-click on-constraint-button-clicked}
|
:on-click on-constraint-button-clicked}
|
||||||
[:span {:class (stl/css :resalted-area)}]]]]
|
[:span {:class (stl/css :resalted-area)}]]]]
|
||||||
[:div {:class (stl/css :contraints-selects)}
|
[:div {:class (stl/css :contraints-selects)}
|
||||||
[:div {:class (stl/css :horizontal-select)}
|
[:div {:class (stl/css :horizontal-select) :data-testid "constraint-h-select"}
|
||||||
[:& select
|
[:& select
|
||||||
{:default-value (d/nilv (d/name constraints-h) "scale")
|
{:default-value (if (not= constraints-h :multiple) (d/nilv (d/name constraints-h) "scale") "")
|
||||||
:options options-h
|
:options options-h
|
||||||
:on-change on-constraint-h-select-changed}]]
|
:on-change on-constraint-h-select-changed}]]
|
||||||
[:div {:class (stl/css :vertical-select)}
|
[:div {:class (stl/css :vertical-select) :data-testid "constraint-v-select"}
|
||||||
[:& select
|
[:& select
|
||||||
{:default-value (d/nilv (d/name constraints-v) "scale")
|
{:default-value (if (not= constraints-v :multiple) (d/nilv (d/name constraints-v) "scale") "")
|
||||||
:options options-v
|
:options options-v
|
||||||
:on-change on-constraint-v-select-changed}]]
|
:on-change on-constraint-v-select-changed}]]
|
||||||
(when first-level?
|
(when first-level?
|
||||||
|
|
|
@ -7924,6 +7924,7 @@ __metadata:
|
||||||
"@types/node": "npm:^20.11.20"
|
"@types/node": "npm:^20.11.20"
|
||||||
animate.css: "npm:^4.1.1"
|
animate.css: "npm:^4.1.1"
|
||||||
autoprefixer: "npm:^10.4.19"
|
autoprefixer: "npm:^10.4.19"
|
||||||
|
compression: "npm:^1.7.4"
|
||||||
concurrently: "npm:^8.2.2"
|
concurrently: "npm:^8.2.2"
|
||||||
date-fns: "npm:^3.6.0"
|
date-fns: "npm:^3.6.0"
|
||||||
draft-js: "git+https://github.com/penpot/draft-js.git#commit=4a99b2a6020b2af97f6dc5fa1b4275ec16b559a0"
|
draft-js: "git+https://github.com/penpot/draft-js.git#commit=4a99b2a6020b2af97f6dc5fa1b4275ec16b559a0"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue