mirror of
https://github.com/penpot/penpot.git
synced 2026-01-21 21:00:26 -05:00
Compare commits
33 Commits
eva-replac
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1335961b4 | ||
|
|
b70eb768e0 | ||
|
|
b8c70be9a2 | ||
|
|
525adcfcbe | ||
|
|
7cce4c6532 | ||
|
|
a3fdd8b691 | ||
|
|
b6a9579c98 | ||
|
|
4397ede5c1 | ||
|
|
ff25df0457 | ||
|
|
8c7fd0af4b | ||
|
|
cf46051f56 | ||
|
|
079b3fbfad | ||
|
|
299f628951 | ||
|
|
32d0fe6463 | ||
|
|
6393330ee1 | ||
|
|
8252bc485e | ||
|
|
cecd3d4a90 | ||
|
|
1c2c0987f5 | ||
|
|
0418147e74 | ||
|
|
47775a9e2c | ||
|
|
8191d04114 | ||
|
|
b7c2d9a079 | ||
|
|
aeb34a6f64 | ||
|
|
6fa0c3af0c | ||
|
|
260b9fb040 | ||
|
|
884954f4ff | ||
|
|
88f0f75174 | ||
|
|
1ffa956251 | ||
|
|
31054099ff | ||
|
|
983487d73c | ||
|
|
5c71c57dd9 | ||
|
|
5abc1aafb4 | ||
|
|
935728aa39 |
2
.github/workflows/build-bundle.yml
vendored
2
.github/workflows/build-bundle.yml
vendored
@@ -40,7 +40,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build-bundle:
|
build-bundle:
|
||||||
name: Build and Upload Penpot Bundle
|
name: Build and Upload Penpot Bundle
|
||||||
runs-on: ubuntu-24.04
|
runs-on: penpot-runner-01
|
||||||
env:
|
env:
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
|||||||
73
.github/workflows/plugins-deploy-api-doc.yml
vendored
Normal file
73
.github/workflows/plugins-deploy-api-doc.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
name: Plugins/api-doc deployer
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
- staging
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "plugins/**"
|
||||||
|
- ".github/workflows/deploy-plugin-docs.yml"
|
||||||
|
- "wrangle-penpot-plugins-api-doc.toml"
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
gh_ref:
|
||||||
|
description: 'Name of the branch or ref'
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
default: 'develop'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: plugins
|
||||||
|
steps:
|
||||||
|
- name: Extract some useful variables
|
||||||
|
id: vars
|
||||||
|
run: |
|
||||||
|
echo "gh_ref=${{ inputs.gh_ref || github.ref_name }}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: ${{ steps.vars.outputs.gh_ref }}
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
cache: "pnpm"
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
run_install: false
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Build docs
|
||||||
|
run: pnpm run build:doc
|
||||||
|
|
||||||
|
- name: Select Worker name
|
||||||
|
run: |
|
||||||
|
REF="${{ steps.vars.outputs.gh_ref }}"
|
||||||
|
case "$REF" in
|
||||||
|
main) echo "WORKER_NAME=penpot-plugins-api-doc-pro" >> $GITHUB_ENV ;;
|
||||||
|
staging) echo "WORKER_NAME=penpot-plugins-api-doc-pre" >> $GITHUB_ENV ;;
|
||||||
|
develop) echo "WORKER_NAME=penpot-plugins-api-doc-hourly" >> $GITHUB_ENV ;;
|
||||||
|
*) echo "Unsupported branch ${REF}" && exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
- name: Deploy to Cloudflare Workers
|
||||||
|
uses: cloudflare/wrangler-action@v3
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
command: deploy --config wrangle-penpot-plugins-api-doc.toml --name ${{ env.WORKER_NAME }}
|
||||||
40
.travis.yml
40
.travis.yml
@@ -1,40 +0,0 @@
|
|||||||
dist: xenial
|
|
||||||
|
|
||||||
language: generic
|
|
||||||
sudo: required
|
|
||||||
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $HOME/.m2
|
|
||||||
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
- develop
|
|
||||||
|
|
||||||
install:
|
|
||||||
- curl -O https://download.clojure.org/install/linux-install-1.10.1.447.sh
|
|
||||||
- chmod +x linux-install-1.10.1.447.sh
|
|
||||||
- sudo ./linux-install-1.10.1.447.sh
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- env | sort
|
|
||||||
|
|
||||||
script:
|
|
||||||
- ./manage.sh build-devenv
|
|
||||||
- ./manage.sh run-frontend-tests
|
|
||||||
- ./manage.sh run-backend-tests
|
|
||||||
- ./manage.sh build-images
|
|
||||||
- ./manage.sh run
|
|
||||||
|
|
||||||
after_script:
|
|
||||||
- docker images
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email: false
|
|
||||||
|
|
||||||
env:
|
|
||||||
- NODE_VERSION=10.16.0
|
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
- Fix wrong register image [Taiga #12955](https://tree.taiga.io/project/penpot/task/12955)
|
- Fix wrong register image [Taiga #12955](https://tree.taiga.io/project/penpot/task/12955)
|
||||||
- Fix error message on components doesn't close automatically [Taiga #12012](https://tree.taiga.io/project/penpot/issue/12012)
|
- Fix error message on components doesn't close automatically [Taiga #12012](https://tree.taiga.io/project/penpot/issue/12012)
|
||||||
- Fix incorrect default option on tokens import dialog [Github #8051](https://github.com/penpot/penpot/pull/8051)
|
- Fix incorrect default option on tokens import dialog [Github #8051](https://github.com/penpot/penpot/pull/8051)
|
||||||
|
- Fix unhandled exception tokens creation dialog [Github #8110](https://github.com/penpot/penpot/issues/8110)
|
||||||
|
|
||||||
## 2.13.0 (Unreleased)
|
## 2.13.0 (Unreleased)
|
||||||
|
|
||||||
|
|||||||
@@ -474,8 +474,8 @@
|
|||||||
:height #{:sizing :dimensions}
|
:height #{:sizing :dimensions}
|
||||||
:max-width #{:sizing :dimensions}
|
:max-width #{:sizing :dimensions}
|
||||||
:max-height #{:sizing :dimensions}
|
:max-height #{:sizing :dimensions}
|
||||||
:x #{:dimensions}
|
:x #{:spacing :dimensions}
|
||||||
:y #{:dimensions}
|
:y #{:spacing :dimensions}
|
||||||
:rotation #{:number :rotation}
|
:rotation #{:number :rotation}
|
||||||
:border-radius #{:border-radius :dimensions}
|
:border-radius #{:border-radius :dimensions}
|
||||||
:row-gap #{:spacing :dimensions}
|
:row-gap #{:spacing :dimensions}
|
||||||
@@ -488,7 +488,6 @@
|
|||||||
:sided-margins #{:spacing :dimensions}
|
:sided-margins #{:spacing :dimensions}
|
||||||
:line-height #{:line-height :number}
|
:line-height #{:line-height :number}
|
||||||
:opacity #{:opacity}
|
:opacity #{:opacity}
|
||||||
:stroke-width #{:stroke-width}
|
|
||||||
:font-size #{:font-size}
|
:font-size #{:font-size}
|
||||||
:letter-spacing #{:letter-spacing}
|
:letter-spacing #{:letter-spacing}
|
||||||
:fill #{:color}
|
:fill #{:color}
|
||||||
|
|||||||
@@ -152,9 +152,9 @@ services:
|
|||||||
|
|
||||||
# AWS_ACCESS_KEY_ID: <KEY_ID>
|
# AWS_ACCESS_KEY_ID: <KEY_ID>
|
||||||
# AWS_SECRET_ACCESS_KEY: <ACCESS_KEY>
|
# AWS_SECRET_ACCESS_KEY: <ACCESS_KEY>
|
||||||
# PENPOT_ASSETS_STORAGE_BACKEND: assets-s3
|
# PENPOT_OBJECTS_STORAGE_BACKEND: s3
|
||||||
# PENPOT_STORAGE_ASSETS_S3_ENDPOINT: <ENDPOINT>
|
# PENPOT_OBJECTS_STORAGE_S3_ENDPOINT: <ENDPOINT>
|
||||||
# PENPOT_STORAGE_ASSETS_S3_BUCKET: <BUKET_NAME>
|
# PENPOT_OBJECTS_STORAGE_S3_BUCKET: <BUKET_NAME>
|
||||||
|
|
||||||
## Telemetry. When enabled, a periodical process will send anonymous data about this
|
## Telemetry. When enabled, a periodical process will send anonymous data about this
|
||||||
## instance. Telemetry data will enable us to learn how the application is used,
|
## instance. Telemetry data will enable us to learn how the application is used,
|
||||||
|
|||||||
@@ -114,14 +114,7 @@ configuration.
|
|||||||
The callback has the following format:
|
The callback has the following format:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
https://<your_domain>/api/auth/oauth/<oauth_provider>/callback
|
https://<your_domain>/api/auth/oidc/callback
|
||||||
```
|
|
||||||
|
|
||||||
You will need to change <your_domain> and <oauth_provider> according to your setup.
|
|
||||||
This is how it looks with Gitlab provider:
|
|
||||||
|
|
||||||
```html
|
|
||||||
https://<your_domain>/api/auth/oauth/gitlab/callback
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Google
|
#### Google
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
"watch:app:main": "clojure -M:dev:shadow-cljs watch main worker storybook",
|
"watch:app:main": "clojure -M:dev:shadow-cljs watch main worker storybook",
|
||||||
"clear:shadow-cache": "rm -rf .shadow-cljs",
|
"clear:shadow-cache": "rm -rf .shadow-cljs",
|
||||||
"watch": "exit 0",
|
"watch": "exit 0",
|
||||||
"watch:app": "yarn run clear:shadow-cache && concurrently --kill-others-on-fail \"yarn run watch:app:assets\" \"yarn run watch:app:main\" \"yarn run watch:app:libs\"",
|
"watch:app": "yarn run clear:shadow-cache && yarn run build:wasm && concurrently --kill-others-on-fail \"yarn run watch:app:assets\" \"yarn run watch:app:main\" \"yarn run watch:app:libs\"",
|
||||||
"watch:storybook": "yarn run build:storybook:assets && concurrently --kill-others-on-fail \"storybook dev -p 6006 --no-open\" \"node ./scripts/watch-storybook.js\""
|
"watch:storybook": "yarn run build:storybook:assets && concurrently --kill-others-on-fail \"storybook dev -p 6006 --no-open\" \"node ./scripts/watch-storybook.js\""
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,352 +0,0 @@
|
|||||||
{
|
|
||||||
"~:features": {
|
|
||||||
"~#set": [
|
|
||||||
"fdata/path-data",
|
|
||||||
"plugins/runtime",
|
|
||||||
"design-tokens/v1",
|
|
||||||
"variants/v1",
|
|
||||||
"layout/grid",
|
|
||||||
"styles/v2",
|
|
||||||
"fdata/objects-map",
|
|
||||||
"components/v2",
|
|
||||||
"fdata/shape-data-type"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"~:team-id": "~u55ffbd0f-2d3f-8023-8007-6b89af7ca1aa",
|
|
||||||
"~: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": "Nuevo Archivo 2",
|
|
||||||
"~:revn": 18,
|
|
||||||
"~:modified-at": "~m1768994999265",
|
|
||||||
"~:vern": 0,
|
|
||||||
"~:id": "~u8bb92298-e24e-805c-8007-6ce64314bfe8",
|
|
||||||
"~: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": "~u55ffbd0f-2d3f-8023-8007-6b89af7cd5eb",
|
|
||||||
"~:created-at": "~m1768562403410",
|
|
||||||
"~:backend": "legacy-db",
|
|
||||||
"~:data": {
|
|
||||||
"~:pages": [
|
|
||||||
"~u8bb92298-e24e-805c-8007-6ce64314cfc5"
|
|
||||||
],
|
|
||||||
"~:pages-index": {
|
|
||||||
"~u8bb92298-e24e-805c-8007-6ce64314cfc5": {
|
|
||||||
"~: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\",[\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~u8506e3f3-e05b-807c-8007-6ceac380abc1\"]]]",
|
|
||||||
"~u6c65a5dc-fb40-8072-8007-6ce644905054": "[\"~#shape\",[\"^ \",\"~:y\",159,\"~: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\",\"Board\",\"~:layout-align-items\",\"~:start\",\"~:width\",389,\"~:layout-padding-type\",\"~:simple\",\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",303,\"~:y\",159]],[\"^L\",[\"^ \",\"~:x\",692,\"~:y\",159]],[\"^L\",[\"^ \",\"~:x\",692,\"~:y\",599]],[\"^L\",[\"^ \",\"~:x\",303,\"~:y\",599]]],\"~: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\",\"^E\",\"~:r1\",0,\"~:id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:layout-flex-dir\",\"~:row\",\"~:layout-align-content\",\"~:stretch\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",303,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",303,\"~:y\",159,\"^F\",389,\"~:height\",440,\"~:x1\",303,\"~:y1\",159,\"~:x2\",692,\"~:y2\",599]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^16\",440,\"~:flip-y\",null,\"~:shapes\",[\"~u6c65a5dc-fb40-8072-8007-6ce655b5dbe9\",\"~u6c65a5dc-fb40-8072-8007-6ce65472f217\",\"~u6c65a5dc-fb40-8072-8007-6ce6535e8d62\"]]]",
|
|
||||||
"~u6c65a5dc-fb40-8072-8007-6ce6535e8d62": "[\"~#shape\",[\"^ \",\"~:y\",159,\"~: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\",95,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",303,\"~:y\",159]],[\"^<\",[\"^ \",\"~:x\",398,\"~:y\",159]],[\"^<\",[\"^ \",\"~:x\",398,\"~:y\",259]],[\"^<\",[\"^ \",\"~:x\",303,\"~:y\",259]]],\"~: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\",\"~u6c65a5dc-fb40-8072-8007-6ce6535e8d62\",\"~:parent-id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:frame-id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:strokes\",[],\"~:x\",303,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",303,\"~:y\",159,\"^8\",95,\"~:height\",100,\"~:x1\",303,\"~:y1\",159,\"~:x2\",398,\"~:y2\",259]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^J\",100,\"~:flip-y\",null]]",
|
|
||||||
"~u6c65a5dc-fb40-8072-8007-6ce65472f217": "[\"~#shape\",[\"^ \",\"~:y\",159,\"~: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\",140.99999999999994,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",398,\"~:y\",159]],[\"^<\",[\"^ \",\"~:x\",539,\"~:y\",159]],[\"^<\",[\"^ \",\"~:x\",539,\"~:y\",296]],[\"^<\",[\"^ \",\"~:x\",398,\"~:y\",296]]],\"~: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\",\"~u6c65a5dc-fb40-8072-8007-6ce65472f217\",\"~:parent-id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:frame-id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:strokes\",[],\"~:x\",398.00000000000006,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",398.00000000000006,\"~:y\",159,\"^8\",140.99999999999994,\"~:height\",137,\"~:x1\",398.00000000000006,\"~:y1\",159,\"~:x2\",539,\"~:y2\",296]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^J\",137,\"~:flip-y\",null]]",
|
|
||||||
"~u6c65a5dc-fb40-8072-8007-6ce655b5dbe9": "[\"~#shape\",[\"^ \",\"~:y\",159,\"~: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\",82,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",539,\"~:y\",159]],[\"^<\",[\"^ \",\"~:x\",621,\"~:y\",159]],[\"^<\",[\"^ \",\"~:x\",621,\"~:y\",259]],[\"^<\",[\"^ \",\"~:x\",539,\"~:y\",259]]],\"~: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\",\"~u6c65a5dc-fb40-8072-8007-6ce655b5dbe9\",\"~:parent-id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:frame-id\",\"~u6c65a5dc-fb40-8072-8007-6ce644905054\",\"~:strokes\",[],\"~:x\",539,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",539,\"~:y\",159,\"^8\",82,\"~:height\",100,\"~:x1\",539,\"~:y1\",159,\"~:x2\",621,\"~:y2\",259]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^J\",100,\"~:flip-y\",null]]",
|
|
||||||
"~u8506e3f3-e05b-807c-8007-6ceac380abc1": "[\"~#shape\",[\"^ \",\"~:y\",405,\"~: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\",59,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",817,\"~:y\",405]],[\"^<\",[\"^ \",\"~:x\",876,\"~:y\",405]],[\"^<\",[\"^ \",\"~:x\",876,\"~:y\",472]],[\"^<\",[\"^ \",\"~:x\",817,\"~:y\",472]]],\"~: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\",\"~u8506e3f3-e05b-807c-8007-6ceac380abc1\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",817,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",817,\"~:y\",405,\"^8\",59,\"~:height\",67,\"~:x1\",817,\"~:y1\",405,\"~:x2\",876,\"~:y2\",472]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^J\",67,\"~:flip-y\",null]]"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"~:id": "~u8bb92298-e24e-805c-8007-6ce64314cfc5",
|
|
||||||
"~:name": "Page 1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"~:id": "~u8bb92298-e24e-805c-8007-6ce64314bfe8",
|
|
||||||
"~:options": {
|
|
||||||
"~:components-v2": true,
|
|
||||||
"~:base-font-size": "16px"
|
|
||||||
},
|
|
||||||
"~:tokens-lib": {
|
|
||||||
"~#penpot/tokens-lib": {
|
|
||||||
"~:sets": {
|
|
||||||
"~#ordered-map": [
|
|
||||||
[
|
|
||||||
"S-Global",
|
|
||||||
{
|
|
||||||
"~#penpot/token-set": {
|
|
||||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce67f8f2592",
|
|
||||||
"~:name": "Global",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768994999268",
|
|
||||||
"~:tokens": {
|
|
||||||
"~#ordered-map": [
|
|
||||||
[
|
|
||||||
"dim.xs",
|
|
||||||
{
|
|
||||||
"~#penpot/token": {
|
|
||||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce67f8f2591",
|
|
||||||
"~:name": "dim.xs",
|
|
||||||
"~:type": "~:dimensions",
|
|
||||||
"~:value": "20",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768562465340"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"dim.md",
|
|
||||||
{
|
|
||||||
"~#penpot/token": {
|
|
||||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce68a2f3c3f",
|
|
||||||
"~:name": "dim.md",
|
|
||||||
"~:type": "~:dimensions",
|
|
||||||
"~:value": "50",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768562476220"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"dim.xl",
|
|
||||||
{
|
|
||||||
"~#penpot/token": {
|
|
||||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce694f47726",
|
|
||||||
"~:name": "dim.xl",
|
|
||||||
"~:type": "~:dimensions",
|
|
||||||
"~:value": "100",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768562487249"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"sz.sm",
|
|
||||||
{
|
|
||||||
"~#penpot/token": {
|
|
||||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce6d6e519b1",
|
|
||||||
"~:name": "sz.sm",
|
|
||||||
"~:type": "~:sizing",
|
|
||||||
"~:value": "200",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768562554772"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"sz.xl",
|
|
||||||
{
|
|
||||||
"~#penpot/token": {
|
|
||||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce6e4165307",
|
|
||||||
"~:name": "sz.xl",
|
|
||||||
"~:type": "~:sizing",
|
|
||||||
"~:value": "500",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768562568281"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"sp.mid",
|
|
||||||
{
|
|
||||||
"~#penpot/token": {
|
|
||||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce6f5fb2867",
|
|
||||||
"~:name": "sp.mid",
|
|
||||||
"~:type": "~:spacing",
|
|
||||||
"~:value": "50",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768562586604"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"sp.l",
|
|
||||||
{
|
|
||||||
"~#penpot/token": {
|
|
||||||
"~:id": "~u7c1a66f7-5186-8060-8007-6ce71009cd91",
|
|
||||||
"~:name": "sp.l",
|
|
||||||
"~:type": "~:spacing",
|
|
||||||
"~:value": "{dim.xl}",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768562613287"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"test",
|
|
||||||
{
|
|
||||||
"~#penpot/token": {
|
|
||||||
"~:id": "~uc49f25e6-1298-8004-8007-709f660875be",
|
|
||||||
"~:name": "test",
|
|
||||||
"~:type": "~:dimensions",
|
|
||||||
"~:value": "20",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768812262433"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"width-big",
|
|
||||||
{
|
|
||||||
"~#penpot/token": {
|
|
||||||
"~:id": "~u3b3e4320-53fb-8096-8007-73585edb4dd6",
|
|
||||||
"~:name": "width-big",
|
|
||||||
"~:type": "~:stroke-width",
|
|
||||||
"~:value": "20",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768994969453"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"width-small",
|
|
||||||
{
|
|
||||||
"~#penpot/token": {
|
|
||||||
"~:id": "~u3b3e4320-53fb-8096-8007-73586a5ec516",
|
|
||||||
"~:name": "width-small",
|
|
||||||
"~:type": "~:stroke-width",
|
|
||||||
"~:value": "5",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768994981243"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"red",
|
|
||||||
{
|
|
||||||
"~#penpot/token": {
|
|
||||||
"~:id": "~u3b3e4320-53fb-8096-8007-735871dccede",
|
|
||||||
"~:name": "red",
|
|
||||||
"~:type": "~:color",
|
|
||||||
"~:value": "red",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768994988915"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"green",
|
|
||||||
{
|
|
||||||
"~#penpot/token": {
|
|
||||||
"~:id": "~u3b3e4320-53fb-8096-8007-735879045aa2",
|
|
||||||
"~:name": "green",
|
|
||||||
"~:type": "~:color",
|
|
||||||
"~:value": "green",
|
|
||||||
"~:description": "",
|
|
||||||
"~:modified-at": "~m1768994996241"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"~:themes": {
|
|
||||||
"~#ordered-map": [
|
|
||||||
[
|
|
||||||
"",
|
|
||||||
{
|
|
||||||
"~#ordered-map": [
|
|
||||||
[
|
|
||||||
"__PENPOT__HIDDEN__TOKEN__THEME__",
|
|
||||||
{
|
|
||||||
"~#penpot/token-theme": {
|
|
||||||
"~:id": "~u00000000-0000-0000-0000-000000000000",
|
|
||||||
"~:name": "__PENPOT__HIDDEN__TOKEN__THEME__",
|
|
||||||
"~:group": "",
|
|
||||||
"~:description": "",
|
|
||||||
"~:is-source": false,
|
|
||||||
"~:external-id": "",
|
|
||||||
"~:modified-at": "~m1768562468391",
|
|
||||||
"~:sets": {
|
|
||||||
"~#set": [
|
|
||||||
"Global"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"~:active-themes": {
|
|
||||||
"~#set": [
|
|
||||||
"/__PENPOT__HIDDEN__TOKEN__THEME__"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -149,14 +149,12 @@ test.describe("Tokens: Apply token", () => {
|
|||||||
await detachButton.click();
|
await detachButton.click();
|
||||||
|
|
||||||
// Open dropdown from input
|
// Open dropdown from input
|
||||||
const dropdownBtn = layerMenuSection.getByLabel("Open token list");
|
const dropdownBtn = layerMenuSection.getByLabel('Open token list');
|
||||||
await expect(dropdownBtn).toBeVisible();
|
await expect(dropdownBtn).toBeVisible();
|
||||||
await dropdownBtn.click();
|
await dropdownBtn.click();
|
||||||
|
|
||||||
// Change token from dropdown
|
// Change token from dropdown
|
||||||
const opacityLowOption = layerMenuSection.getByRole("option", {
|
const opacityLowOption = layerMenuSection.getByRole('option', { name: 'opacity.low' });
|
||||||
name: "opacity.low",
|
|
||||||
});
|
|
||||||
await expect(opacityLowOption).toBeVisible();
|
await expect(opacityLowOption).toBeVisible();
|
||||||
await opacityLowOption.click();
|
await opacityLowOption.click();
|
||||||
|
|
||||||
@@ -484,279 +482,4 @@ test.describe("Tokens: Apply token", () => {
|
|||||||
await expect(shadowSection).toHaveCount(2);
|
await expect(shadowSection).toHaveCount(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("User applies dimension token to a shape on width and height", async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
||||||
await setupTokensFile(page);
|
|
||||||
|
|
||||||
// Unfolds dimensions on token panel
|
|
||||||
await page.getByRole("tab", { name: "Layers" }).click();
|
|
||||||
|
|
||||||
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
||||||
|
|
||||||
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
||||||
await tokensTabButton.click();
|
|
||||||
|
|
||||||
unfoldTokenTree(tokensSidebar, "dimensions", "dimension.dimension.sm");
|
|
||||||
|
|
||||||
// Apply token to width and height token from token panel
|
|
||||||
await tokensSidebar.getByRole("button", { name: "dimension.sm" }).click();
|
|
||||||
|
|
||||||
// Check if measures sections is visible on right sidebar
|
|
||||||
const measuresSection = page.getByRole("region", {
|
|
||||||
name: "shape-measures-section",
|
|
||||||
});
|
|
||||||
await expect(measuresSection).toBeVisible();
|
|
||||||
|
|
||||||
// Check if token pill is visible on design tab on right sidebar
|
|
||||||
const dimensionSMTokenPill = measuresSection.getByRole("button", {
|
|
||||||
name: "dimension.sm",
|
|
||||||
});
|
|
||||||
await expect(dimensionSMTokenPill).toHaveCount(2);
|
|
||||||
await dimensionSMTokenPill.nth(1).click();
|
|
||||||
|
|
||||||
// Change token from dropdown
|
|
||||||
const dimensionTokenOptionXl = measuresSection.getByLabel("dimension.xl");
|
|
||||||
await expect(dimensionTokenOptionXl).toBeVisible();
|
|
||||||
await dimensionTokenOptionXl.click();
|
|
||||||
|
|
||||||
await expect(dimensionSMTokenPill).toHaveCount(1);
|
|
||||||
const dimensionXLTokenPill = measuresSection.getByRole("button", {
|
|
||||||
name: "dimension.xl",
|
|
||||||
});
|
|
||||||
await expect(dimensionXLTokenPill).toBeVisible();
|
|
||||||
|
|
||||||
// Detach token from design tab on right sidebar
|
|
||||||
const detachButton = measuresSection.getByRole("button", {
|
|
||||||
name: "Detach token",
|
|
||||||
});
|
|
||||||
await detachButton.nth(1).click();
|
|
||||||
await expect(dimensionXLTokenPill).not.toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("User applies dimension token to a shape on x position", async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
||||||
await setupTokensFile(page);
|
|
||||||
|
|
||||||
// Unfolds dimensions on token panel
|
|
||||||
await page.getByRole("tab", { name: "Layers" }).click();
|
|
||||||
|
|
||||||
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
||||||
|
|
||||||
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
||||||
await tokensTabButton.click();
|
|
||||||
|
|
||||||
unfoldTokenTree(tokensSidebar, "dimensions", "dimension.dimension.sm");
|
|
||||||
|
|
||||||
// Apply token to width and height token from token panel
|
|
||||||
await tokensSidebar
|
|
||||||
.getByRole("button", { name: "dimension.sm" })
|
|
||||||
.click({ button: "right" });
|
|
||||||
await tokenContextMenuForToken.getByText("AxisX").click();
|
|
||||||
|
|
||||||
// Check if measures sections is visible on right sidebar
|
|
||||||
const measuresSection = page.getByRole("region", {
|
|
||||||
name: "shape-measures-section",
|
|
||||||
});
|
|
||||||
await expect(measuresSection).toBeVisible();
|
|
||||||
|
|
||||||
// Check if token pill is visible on design tab on right sidebar
|
|
||||||
const dimensionSMTokenPill = measuresSection.getByRole("button", {
|
|
||||||
name: "dimension.sm",
|
|
||||||
});
|
|
||||||
await expect(dimensionSMTokenPill).toBeVisible();
|
|
||||||
await dimensionSMTokenPill.click();
|
|
||||||
|
|
||||||
// Change token from dropdown
|
|
||||||
const dimensionTokenOptionXl = measuresSection.getByLabel("dimension.xl");
|
|
||||||
await expect(dimensionTokenOptionXl).toBeVisible();
|
|
||||||
await dimensionTokenOptionXl.click();
|
|
||||||
|
|
||||||
await expect(dimensionSMTokenPill).not.toBeVisible();
|
|
||||||
const dimensionXLTokenPill = measuresSection.getByRole("button", {
|
|
||||||
name: "dimension.xl",
|
|
||||||
});
|
|
||||||
await expect(dimensionXLTokenPill).toBeVisible();
|
|
||||||
|
|
||||||
// Detach token from design tab on right sidebar
|
|
||||||
const detachButton = measuresSection.getByRole("button", {
|
|
||||||
name: "Detach token",
|
|
||||||
});
|
|
||||||
await detachButton.nth(0).click();
|
|
||||||
await expect(dimensionXLTokenPill).not.toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("User applies dimension token to a shape on y position", async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
||||||
await setupTokensFile(page);
|
|
||||||
|
|
||||||
// Unfolds dimensions on token panel
|
|
||||||
await page.getByRole("tab", { name: "Layers" }).click();
|
|
||||||
|
|
||||||
await workspacePage.layers.getByTestId("layer-row").nth(1).click();
|
|
||||||
|
|
||||||
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
||||||
await tokensTabButton.click();
|
|
||||||
|
|
||||||
unfoldTokenTree(tokensSidebar, "dimensions", "dimension.dimension.sm");
|
|
||||||
|
|
||||||
// Apply token to width and height token from token panel
|
|
||||||
await tokensSidebar
|
|
||||||
.getByRole("button", { name: "dimension.sm" })
|
|
||||||
.click({ button: "right" });
|
|
||||||
await tokenContextMenuForToken.getByText("Y").click();
|
|
||||||
|
|
||||||
// Check if measures sections is visible on right sidebar
|
|
||||||
const measuresSection = page.getByRole("region", {
|
|
||||||
name: "shape-measures-section",
|
|
||||||
});
|
|
||||||
await expect(measuresSection).toBeVisible();
|
|
||||||
|
|
||||||
// Check if token pill is visible on design tab on right sidebar
|
|
||||||
const dimensionSMTokenPill = measuresSection.getByRole("button", {
|
|
||||||
name: "dimension.sm",
|
|
||||||
});
|
|
||||||
await expect(dimensionSMTokenPill).toBeVisible();
|
|
||||||
await dimensionSMTokenPill.click();
|
|
||||||
|
|
||||||
// Change token from dropdown
|
|
||||||
const dimensionTokenOptionXl = measuresSection.getByLabel("dimension.xl");
|
|
||||||
await expect(dimensionTokenOptionXl).toBeVisible();
|
|
||||||
await dimensionTokenOptionXl.click();
|
|
||||||
|
|
||||||
await expect(dimensionSMTokenPill).not.toBeVisible();
|
|
||||||
const dimensionXLTokenPill = measuresSection.getByRole("button", {
|
|
||||||
name: "dimension.xl",
|
|
||||||
});
|
|
||||||
await expect(dimensionXLTokenPill).toBeVisible();
|
|
||||||
|
|
||||||
// Detach token from design tab on right sidebar
|
|
||||||
const detachButton = measuresSection.getByRole("button", {
|
|
||||||
name: "Detach token",
|
|
||||||
});
|
|
||||||
await detachButton.nth(0).click();
|
|
||||||
await expect(dimensionXLTokenPill).not.toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("User applies dimension token to a shape border-radius", async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const { workspacePage, tokensSidebar, tokenContextMenuForToken } =
|
|
||||||
await setupTokensFile(page);
|
|
||||||
|
|
||||||
// Unfolds dimensions on token panel
|
|
||||||
await page.getByRole("tab", { name: "Layers" }).click();
|
|
||||||
|
|
||||||
await workspacePage.layers.getByTestId("layer-row").nth(2).click();
|
|
||||||
|
|
||||||
const tokensTabButton = page.getByRole("tab", { name: "Tokens" });
|
|
||||||
await tokensTabButton.click();
|
|
||||||
|
|
||||||
unfoldTokenTree(tokensSidebar, "dimensions", "dimension.dimension.xs");
|
|
||||||
|
|
||||||
// Apply token to width and height token from token panel
|
|
||||||
await tokensSidebar
|
|
||||||
.getByRole("button", { name: "dimension.xs" })
|
|
||||||
.click({ button: "right" });
|
|
||||||
await tokenContextMenuForToken.getByText("Border radius").hover();
|
|
||||||
await tokenContextMenuForToken.getByText("RadiusAll").click();
|
|
||||||
|
|
||||||
// Check if border radius sections is visible on right sidebar
|
|
||||||
const borderRadiusSection = page.getByRole("region", {
|
|
||||||
name: "border-radius-section",
|
|
||||||
});
|
|
||||||
await expect(borderRadiusSection).toBeVisible();
|
|
||||||
|
|
||||||
// Check if token pill is visible on design tab on right sidebar
|
|
||||||
const dimensionXSTokenPill = borderRadiusSection.getByRole("button", {
|
|
||||||
name: "dimension.xs",
|
|
||||||
});
|
|
||||||
await expect(dimensionXSTokenPill).toBeVisible();
|
|
||||||
await dimensionXSTokenPill.click();
|
|
||||||
|
|
||||||
// Change token from dropdown
|
|
||||||
const dimensionTokenOptionXl =
|
|
||||||
borderRadiusSection.getByLabel("dimension.xl");
|
|
||||||
await expect(dimensionTokenOptionXl).toBeVisible();
|
|
||||||
await dimensionTokenOptionXl.click();
|
|
||||||
|
|
||||||
await expect(dimensionXSTokenPill).not.toBeVisible();
|
|
||||||
const dimensionXLTokenPill = borderRadiusSection.getByRole("button", {
|
|
||||||
name: "dimension.xl",
|
|
||||||
});
|
|
||||||
await expect(dimensionXLTokenPill).toBeVisible();
|
|
||||||
|
|
||||||
// Detach token from design tab on right sidebar
|
|
||||||
const detachButton = borderRadiusSection.getByRole("button", {
|
|
||||||
name: "Detach token",
|
|
||||||
});
|
|
||||||
await detachButton.nth(0).click();
|
|
||||||
await expect(dimensionXLTokenPill).not.toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("User applies stroke width token to a shape", async ({ page }) => {
|
|
||||||
const workspace = new WorkspacePage(page, {
|
|
||||||
textEditor: true,
|
|
||||||
});
|
|
||||||
// Set up
|
|
||||||
await workspace.mockConfigFlags(["enable-feature-token-input"]);
|
|
||||||
await workspace.setupEmptyFile();
|
|
||||||
await workspace.mockGetFile("workspace/get-file-layout-stroke-token-json");
|
|
||||||
await workspace.goToWorkspace();
|
|
||||||
|
|
||||||
// Select shape apply stroke
|
|
||||||
await workspace.layers.getByTestId("layer-row").nth(0).click();
|
|
||||||
const rightSidebar = page.getByTestId("right-sidebar");
|
|
||||||
await expect(rightSidebar).toBeVisible();
|
|
||||||
await rightSidebar.getByTestId("add-stroke").click();
|
|
||||||
|
|
||||||
// Apply stroke width token from token panel
|
|
||||||
const tokensTab = page.getByRole("tab", { name: "Tokens" });
|
|
||||||
await expect(tokensTab).toBeVisible();
|
|
||||||
await tokensTab.click();
|
|
||||||
await page.getByRole("button", { name: "Stroke Width 2" }).click();
|
|
||||||
const tokensSidebar = workspace.tokensSidebar;
|
|
||||||
await expect(
|
|
||||||
tokensSidebar.getByRole("button", { name: "width-big" }),
|
|
||||||
).toBeVisible();
|
|
||||||
await tokensSidebar.getByRole("button", { name: "width-big" }).click();
|
|
||||||
|
|
||||||
// Check if token pill is visible on right sidebar
|
|
||||||
const strokeSectionSidebar = rightSidebar.getByRole("region", {
|
|
||||||
name: "stroke-section",
|
|
||||||
});
|
|
||||||
await expect(strokeSectionSidebar).toBeVisible();
|
|
||||||
const firstStrokeRow = strokeSectionSidebar.getByLabel("stroke-row-0");
|
|
||||||
await expect(firstStrokeRow).toBeVisible();
|
|
||||||
const StrokeWidthPill = firstStrokeRow.getByRole("button", {
|
|
||||||
name: "width-big",
|
|
||||||
});
|
|
||||||
await expect(StrokeWidthPill).toBeVisible();
|
|
||||||
|
|
||||||
// Detach token from right sidebar and apply another from dropdown
|
|
||||||
const detachButton = firstStrokeRow.getByRole("button", {
|
|
||||||
name: "Detach token",
|
|
||||||
});
|
|
||||||
await detachButton.click();
|
|
||||||
await expect(StrokeWidthPill).not.toBeVisible();
|
|
||||||
|
|
||||||
const tokenDropdown = firstStrokeRow.getByRole("button", {
|
|
||||||
name: "Open token list",
|
|
||||||
});
|
|
||||||
await tokenDropdown.click();
|
|
||||||
|
|
||||||
const widthOptionSmall = firstStrokeRow.getByLabel("width-small");
|
|
||||||
await expect(widthOptionSmall).toBeVisible();
|
|
||||||
await widthOptionSmall.click();
|
|
||||||
const StrokeWidthPillSmall = firstStrokeRow.getByRole("button", {
|
|
||||||
name: "width-small",
|
|
||||||
});
|
|
||||||
await expect(StrokeWidthPillSmall).toBeVisible();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
--app-background: var(--color-background-primary);
|
--app-background: var(--color-background-primary);
|
||||||
--loader-background: var(--color-background-primary);
|
--loader-background: var(--color-background-primary);
|
||||||
--panel-title-background-color: var(--color-background-secondary);
|
|
||||||
|
|
||||||
// BUTTONS
|
// BUTTONS
|
||||||
--button-foreground-hover: var(--color-accent-primary);
|
--button-foreground-hover: var(--color-accent-primary);
|
||||||
|
|||||||
@@ -17,17 +17,18 @@
|
|||||||
<meta name="twitter:site" content="@penpotapp">
|
<meta name="twitter:site" content="@penpotapp">
|
||||||
<meta name="twitter:creator" content="@penpotapp">
|
<meta name="twitter:creator" content="@penpotapp">
|
||||||
<meta name="theme-color" content="#FFFFFF" media="(prefers-color-scheme: light)">
|
<meta name="theme-color" content="#FFFFFF" media="(prefers-color-scheme: light)">
|
||||||
<link id="theme" href="css/main.css?version={{& version}}" rel="stylesheet" type="text/css" />
|
<link id="theme" href="css/main.css?version={{& version_tag}}" rel="stylesheet" type="text/css" />
|
||||||
{{#isDebug}}
|
{{#isDebug}}
|
||||||
<link href="css/debug.css?version={{& version}}" rel="stylesheet" type="text/css" />
|
<link href="css/debug.css?version={{& version_tag}}" rel="stylesheet" type="text/css" />
|
||||||
{{/isDebug}}
|
{{/isDebug}}
|
||||||
|
|
||||||
<link rel="icon" href="images/favicon.png" />
|
<link rel="icon" href="images/favicon.png?version={{& version_tag }}" />
|
||||||
|
|
||||||
<script type="importmap">{{& manifest.importmap }}</script>
|
<script type="importmap">{{& manifest.importmap }}</script>
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
globalThis.penpotVersion = "{{& version}}";
|
globalThis.penpotVersion = "{{& version}}";
|
||||||
|
globalThis.penpotVersionTag = "{{& version_tag}}";
|
||||||
globalThis.penpotBuildDate = "{{& build_date}}";
|
globalThis.penpotBuildDate = "{{& build_date}}";
|
||||||
globalThis.penpotWorkerURI = "{{& manifest.worker_main}}";
|
globalThis.penpotWorkerURI = "{{& manifest.worker_main}}";
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Penpot - Rasterizer</title>
|
<title>Penpot - Rasterizer</title>
|
||||||
<link rel="icon" href="images/favicon.png" />
|
<link rel="icon" href="images/favicon.png?version={{& version_tag }}" />
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
globalThis.penpotVersion = "{{& version}}";
|
globalThis.penpotVersion = "{{& version}}";
|
||||||
|
globalThis.penpotVersionTag = "{{& version_tag}}";
|
||||||
globalThis.penpotBuildDate = "{{& build_date}}";
|
globalThis.penpotBuildDate = "{{& build_date}}";
|
||||||
globalThis.penpotWorkerURI = "{{& manifest.worker_main}}";
|
globalThis.penpotWorkerURI = "{{& manifest.worker_main}}";
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -4,10 +4,12 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="x-ua-compatible" content="ie=edge" />
|
<meta http-equiv="x-ua-compatible" content="ie=edge" />
|
||||||
<title>Penpot - Render</title>
|
<title>Penpot - Render</title>
|
||||||
<link rel="icon" href="images/favicon.png" />
|
|
||||||
|
<link rel="icon" href="images/favicon.png?version={{& version_tag }}" />
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
globalThis.penpotVersion = "{{& version}}";
|
globalThis.penpotVersion = "{{& version}}";
|
||||||
|
globalThis.penpotVersionTag = "{{& version_tag}}";
|
||||||
globalThis.penpotBuildDate = "{{& build_date}}";
|
globalThis.penpotBuildDate = "{{& build_date}}";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,11 @@ export function startWorker() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isDebug = process.env.NODE_ENV !== "production";
|
export const IS_DEBUG = process.env.NODE_ENV !== "production";
|
||||||
export const CURRENT_VERSION = process.env.CURRENT_VERSION || "develop";
|
export const BUILD_DATE = process.env.BUILD_DATE || (new Date().toString()) ;
|
||||||
export const BUILD_DATE = process.env.BUILD_DATE || "" + new Date();
|
export const BUILD_TS = process.env.BUILD_TS || Date.now();
|
||||||
|
export const VERSION = process.env.VERSION || "develop";
|
||||||
|
export const VERSION_TAG = process.env.VERSION_TAG || VERSION;
|
||||||
|
|
||||||
async function findFiles(basePath, predicate, options = {}) {
|
async function findFiles(basePath, predicate, options = {}) {
|
||||||
predicate =
|
predicate =
|
||||||
@@ -172,6 +174,7 @@ export async function watch(baseDir, predicate, callback) {
|
|||||||
const watcher = new Watcher(baseDir, {
|
const watcher = new Watcher(baseDir, {
|
||||||
persistent: true,
|
persistent: true,
|
||||||
recursive: true,
|
recursive: true,
|
||||||
|
debounce: 500
|
||||||
});
|
});
|
||||||
|
|
||||||
watcher.on("change", (path) => {
|
watcher.on("change", (path) => {
|
||||||
@@ -179,8 +182,19 @@ export async function watch(baseDir, predicate, callback) {
|
|||||||
callback(path);
|
callback(path);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
watcher.on("error", (cause) => {
|
||||||
|
console.log("WATCHER ERROR", cause);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function ensureDirectories() {
|
||||||
|
await fs.mkdir("./resources/public/js/worker/", { recursive: true });
|
||||||
|
await fs.mkdir("./resources/public/css/", { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async function readManifestFile(resource) {
|
async function readManifestFile(resource) {
|
||||||
const manifestPath = "resources/public/" + resource;
|
const manifestPath = "resources/public/" + resource;
|
||||||
let content = await fs.readFile(manifestPath, { encoding: "utf8" });
|
let content = await fs.readFile(manifestPath, { encoding: "utf8" });
|
||||||
@@ -193,25 +207,25 @@ async function generateManifest() {
|
|||||||
render_main: "./js/render.js",
|
render_main: "./js/render.js",
|
||||||
rasterizer_main: "./js/rasterizer.js",
|
rasterizer_main: "./js/rasterizer.js",
|
||||||
|
|
||||||
config: "./js/config.js?version=" + CURRENT_VERSION,
|
config: "./js/config.js?version=" + VERSION_TAG,
|
||||||
polyfills: "./js/polyfills.js?version=" + CURRENT_VERSION,
|
polyfills: "./js/polyfills.js?version=" + VERSION_TAG,
|
||||||
libs: "./js/libs.js?version=" + CURRENT_VERSION,
|
libs: "./js/libs.js?version=" + VERSION_TAG,
|
||||||
worker_main: "./js/worker/main.js?version=" + CURRENT_VERSION,
|
worker_main: "./js/worker/main.js?version=" + VERSION_TAG,
|
||||||
default_translations: "./js/translation.en.js?version=" + CURRENT_VERSION,
|
default_translations: "./js/translation.en.js?version=" + VERSION_TAG,
|
||||||
|
|
||||||
importmap: JSON.stringify({
|
importmap: JSON.stringify({
|
||||||
"imports": {
|
"imports": {
|
||||||
"./js/shared.js": "./js/shared.js?version=" + CURRENT_VERSION,
|
"./js/shared.js": "./js/shared.js?version=" + VERSION_TAG,
|
||||||
"./js/main.js": "./js/main.js?version=" + CURRENT_VERSION,
|
"./js/main.js": "./js/main.js?version=" + VERSION_TAG,
|
||||||
"./js/render.js": "./js/render.js?version=" + CURRENT_VERSION,
|
"./js/render.js": "./js/render.js?version=" + VERSION_TAG,
|
||||||
"./js/render-wasm.js": "./js/render-wasm.js?version=" + CURRENT_VERSION,
|
"./js/render-wasm.js": "./js/render-wasm.js?version=" + VERSION_TAG,
|
||||||
"./js/rasterizer.js": "./js/rasterizer.js?version=" + CURRENT_VERSION,
|
"./js/rasterizer.js": "./js/rasterizer.js?version=" + VERSION_TAG,
|
||||||
"./js/main-dashboard.js": "./js/main-dashboard.js?version=" + CURRENT_VERSION,
|
"./js/main-dashboard.js": "./js/main-dashboard.js?version=" + VERSION_TAG,
|
||||||
"./js/main-auth.js": "./js/main-auth.js?version=" + CURRENT_VERSION,
|
"./js/main-auth.js": "./js/main-auth.js?version=" + VERSION_TAG,
|
||||||
"./js/main-viewer.js": "./js/main-viewer.js?version=" + CURRENT_VERSION,
|
"./js/main-viewer.js": "./js/main-viewer.js?version=" + VERSION_TAG,
|
||||||
"./js/main-settings.js": "./js/main-settings.js?version=" + CURRENT_VERSION,
|
"./js/main-settings.js": "./js/main-settings.js?version=" + VERSION_TAG,
|
||||||
"./js/main-workspace.js": "./js/main-workspace.js?version=" + CURRENT_VERSION,
|
"./js/main-workspace.js": "./js/main-workspace.js?version=" + VERSION_TAG,
|
||||||
"./js/util-highlight.js": "./js/util-highlight.js?version=" + CURRENT_VERSION
|
"./js/util-highlight.js": "./js/util-highlight.js?version=" + VERSION_TAG
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
@@ -222,11 +236,12 @@ async function generateManifest() {
|
|||||||
async function renderTemplate(path, context = {}, partials = {}) {
|
async function renderTemplate(path, context = {}, partials = {}) {
|
||||||
const content = await fs.readFile(path, { encoding: "utf-8" });
|
const content = await fs.readFile(path, { encoding: "utf-8" });
|
||||||
|
|
||||||
const ts = Math.floor(new Date());
|
|
||||||
|
|
||||||
context = Object.assign({}, context, {
|
context = Object.assign({}, context, {
|
||||||
ts: ts,
|
isDebug: IS_DEBUG,
|
||||||
isDebug,
|
version: VERSION,
|
||||||
|
version_tag: VERSION_TAG,
|
||||||
|
build_date: BUILD_DATE,
|
||||||
|
build_ts: BUILD_TS,
|
||||||
});
|
});
|
||||||
|
|
||||||
return mustache.render(content, context, partials);
|
return mustache.render(content, context, partials);
|
||||||
@@ -257,6 +272,9 @@ const markedOptions = {
|
|||||||
marked.use(markedOptions);
|
marked.use(markedOptions);
|
||||||
|
|
||||||
export async function compileTranslations() {
|
export async function compileTranslations() {
|
||||||
|
const outputDir = "resources/public/js/";
|
||||||
|
await fs.mkdir(outputDir, { recursive: true });
|
||||||
|
|
||||||
const langs = [
|
const langs = [
|
||||||
"ar",
|
"ar",
|
||||||
"ca",
|
"ca",
|
||||||
@@ -338,7 +356,6 @@ export async function compileTranslations() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const esm = `export default ${JSON.stringify(result, null, 0)};\n`;
|
const esm = `export default ${JSON.stringify(result, null, 0)};\n`;
|
||||||
const outputDir = "resources/public/js/";
|
|
||||||
const outputFile = ph.join(outputDir, "translation." + lang + ".js");
|
const outputFile = ph.join(outputDir, "translation." + lang + ".js");
|
||||||
await fs.writeFile(outputFile, esm);
|
await fs.writeFile(outputFile, esm);
|
||||||
}
|
}
|
||||||
@@ -390,7 +407,6 @@ async function generateSvgSprites() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function generateTemplates() {
|
async function generateTemplates() {
|
||||||
const isDebug = process.env.NODE_ENV !== "production";
|
|
||||||
await fs.mkdir("./resources/public/", { recursive: true });
|
await fs.mkdir("./resources/public/", { recursive: true });
|
||||||
|
|
||||||
const manifest = await generateManifest();
|
const manifest = await generateManifest();
|
||||||
@@ -415,10 +431,7 @@ async function generateTemplates() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const context = {
|
const context = {
|
||||||
manifest: manifest,
|
manifest: manifest
|
||||||
version: CURRENT_VERSION,
|
|
||||||
build_date: BUILD_DATE,
|
|
||||||
isDebug,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
content = await renderTemplate(
|
content = await renderTemplate(
|
||||||
@@ -487,7 +500,7 @@ export async function compileStyles() {
|
|||||||
await fs.mkdir("./resources/public/css", { recursive: true });
|
await fs.mkdir("./resources/public/css", { recursive: true });
|
||||||
await fs.writeFile("./resources/public/css/main.css", result);
|
await fs.writeFile("./resources/public/css/main.css", result);
|
||||||
|
|
||||||
if (isDebug) {
|
if (IS_DEBUG) {
|
||||||
let debugCSS = await compileSassDebug(worker);
|
let debugCSS = await compileSassDebug(worker);
|
||||||
await fs.writeFile("./resources/public/css/debug.css", debugCSS);
|
await fs.writeFile("./resources/public/css/debug.css", debugCSS);
|
||||||
}
|
}
|
||||||
@@ -500,18 +513,44 @@ export async function compileStyles() {
|
|||||||
export async function compileSvgSprites() {
|
export async function compileSvgSprites() {
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
log.info("init: compile svgsprite");
|
log.info("init: compile svgsprite");
|
||||||
|
let error = false;
|
||||||
|
|
||||||
|
try {
|
||||||
await generateSvgSprites();
|
await generateSvgSprites();
|
||||||
|
} catch (cause) {
|
||||||
|
error = cause;
|
||||||
|
}
|
||||||
|
|
||||||
const end = process.hrtime(start);
|
const end = process.hrtime(start);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
log.error("error: compile svgsprite", `(${ppt(end)})`);
|
||||||
|
console.error(error);
|
||||||
|
} else {
|
||||||
log.info("done: compile svgsprite", `(${ppt(end)})`);
|
log.info("done: compile svgsprite", `(${ppt(end)})`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function compileTemplates() {
|
export async function compileTemplates() {
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
|
let error = false;
|
||||||
log.info("init: compile templates");
|
log.info("init: compile templates");
|
||||||
|
|
||||||
|
try {
|
||||||
await generateTemplates();
|
await generateTemplates();
|
||||||
|
} catch (cause) {
|
||||||
|
error = cause;
|
||||||
|
}
|
||||||
|
|
||||||
const end = process.hrtime(start);
|
const end = process.hrtime(start);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
log.error("error: compile templates", `(${ppt(end)})`);
|
||||||
|
console.error(error);
|
||||||
|
} else {
|
||||||
log.info("done: compile templates", `(${ppt(end)})`);
|
log.info("done: compile templates", `(${ppt(end)})`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function compilePolyfills() {
|
export async function compilePolyfills() {
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
|
|||||||
@@ -28,14 +28,12 @@ async function compileFile(path) {
|
|||||||
],
|
],
|
||||||
sourceMap: false,
|
sourceMap: false,
|
||||||
});
|
});
|
||||||
// console.dir(result);
|
|
||||||
resolve({
|
resolve({
|
||||||
inputPath: path,
|
inputPath: path,
|
||||||
outputPath: dest,
|
outputPath: dest,
|
||||||
css: result.css,
|
css: result.css,
|
||||||
});
|
});
|
||||||
} catch (cause) {
|
} catch (cause) {
|
||||||
console.error(cause);
|
|
||||||
reject(cause);
|
reject(cause);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,26 +2,26 @@
|
|||||||
# NOTE: this script should be called from the parent directory to
|
# NOTE: this script should be called from the parent directory to
|
||||||
# properly work.
|
# properly work.
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
export INCLUDE_STORYBOOK=${BUILD_STORYBOOK:-no};
|
export INCLUDE_STORYBOOK=${BUILD_STORYBOOK:-no};
|
||||||
export INCLUDE_WASM=${BUILD_WASM:-yes};
|
export INCLUDE_WASM=${BUILD_WASM:-yes};
|
||||||
export CURRENT_VERSION=$1;
|
|
||||||
export BUILD_DATE=$(date -R);
|
|
||||||
export CURRENT_HASH=${CURRENT_HASH:-$(git rev-parse --short HEAD)};
|
|
||||||
export EXTRA_PARAMS=$SHADOWCLJS_EXTRA_PARAMS;
|
export EXTRA_PARAMS=$SHADOWCLJS_EXTRA_PARAMS;
|
||||||
export TS=$(date +%s);
|
|
||||||
|
export BUILD_DATE=$(date -R);
|
||||||
|
export BUILD_TS=$(date +%s);
|
||||||
|
|
||||||
|
export VERSION=${1:-develop};
|
||||||
|
export VERSION_TAG="${VERSION}-${BUILD_TS}";
|
||||||
|
|
||||||
# Some cljs reacts on this environment variable for define more
|
# Some cljs reacts on this environment variable for define more
|
||||||
# performant code on macros (example: rumext)
|
# performant code on macros (example: rumext)
|
||||||
export NODE_ENV=production;
|
export NODE_ENV=production;
|
||||||
|
|
||||||
echo "Current path:"
|
|
||||||
echo $PATH
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
corepack enable;
|
corepack enable;
|
||||||
corepack install;
|
corepack install;
|
||||||
yarn install || exit 1;
|
yarn install;
|
||||||
|
|
||||||
rm -rf target/dist;
|
rm -rf target/dist;
|
||||||
rm -rf resources/public;
|
rm -rf resources/public;
|
||||||
@@ -37,7 +37,7 @@ yarn run build:app:main $EXTRA_PARAMS;
|
|||||||
yarn run build:app:libs;
|
yarn run build:app:libs;
|
||||||
yarn run build:app:assets;
|
yarn run build:app:assets;
|
||||||
|
|
||||||
sed -i "s/\.\/render.js/.\/render.js?version=$CURRENT_VERSION/g" resources/public/js/worker/main*.js
|
sed -i "s/\.\/render.js/.\/render.js?version=$VERSION_TAG/g" resources/public/js/worker/main*.js
|
||||||
|
|
||||||
rsync -avr resources/public/ target/dist/
|
rsync -avr resources/public/ target/dist/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import * as h from "./_helpers.js";
|
import * as h from "./_helpers.js";
|
||||||
|
|
||||||
|
await h.ensureDirectories();
|
||||||
await h.compileStyles();
|
await h.compileStyles();
|
||||||
await h.copyAssets();
|
await h.copyAssets();
|
||||||
await h.copyWasmPlayground();
|
await h.copyWasmPlayground();
|
||||||
|
|||||||
@@ -2,18 +2,16 @@
|
|||||||
# NOTE: this script should be called from the parent directory to
|
# NOTE: this script should be called from the parent directory to
|
||||||
# properly work.
|
# properly work.
|
||||||
|
|
||||||
export CURRENT_VERSION=$1;
|
set -ex
|
||||||
|
|
||||||
|
export BUILD_TS=$(date +%s);
|
||||||
export BUILD_DATE=$(date -R);
|
export BUILD_DATE=$(date -R);
|
||||||
export CURRENT_HASH=${CURRENT_HASH:-$(git rev-parse --short HEAD)};
|
|
||||||
export TS=$(date +%s);
|
export VERSION=${1:-develop};
|
||||||
|
export VERSION_TAG="${VERSION}-${BUILD_TS}";
|
||||||
|
|
||||||
export NODE_ENV=production;
|
export NODE_ENV=production;
|
||||||
|
|
||||||
echo "Current path:"
|
|
||||||
echo $PATH
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
corepack enable;
|
corepack enable;
|
||||||
corepack install || exit 1;
|
corepack install || exit 1;
|
||||||
yarn install || exit 1;
|
yarn install || exit 1;
|
||||||
|
|||||||
@@ -12,8 +12,11 @@ let sass = null;
|
|||||||
|
|
||||||
async function compileSassAll() {
|
async function compileSassAll() {
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
|
let error = false;
|
||||||
|
|
||||||
log.info("init: compile styles");
|
log.info("init: compile styles");
|
||||||
|
|
||||||
|
try {
|
||||||
sass = await h.compileSassAll(worker);
|
sass = await h.compileSassAll(worker);
|
||||||
let output = await h.concatSass(sass);
|
let output = await h.concatSass(sass);
|
||||||
await fs.writeFile("./resources/public/css/main.css", output);
|
await fs.writeFile("./resources/public/css/main.css", output);
|
||||||
@@ -22,10 +25,19 @@ async function compileSassAll() {
|
|||||||
let debugCSS = await h.compileSassDebug(worker);
|
let debugCSS = await h.compileSassDebug(worker);
|
||||||
await fs.writeFile("./resources/public/css/debug.css", debugCSS);
|
await fs.writeFile("./resources/public/css/debug.css", debugCSS);
|
||||||
}
|
}
|
||||||
|
} catch (cause) {
|
||||||
|
error = cause;
|
||||||
|
}
|
||||||
|
|
||||||
const end = process.hrtime(start);
|
const end = process.hrtime(start);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
log.error("error: compile styles", `(${ppt(end)})`);
|
||||||
|
console.error(error);
|
||||||
|
} else {
|
||||||
log.info("done: compile styles", `(${ppt(end)})`);
|
log.info("done: compile styles", `(${ppt(end)})`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function compileSass(path) {
|
async function compileSass(path) {
|
||||||
const start = process.hrtime();
|
const start = process.hrtime();
|
||||||
@@ -48,7 +60,7 @@ async function compileSass(path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await fs.mkdir("./resources/public/css/", { recursive: true });
|
await h.ensureDirectories();
|
||||||
await compileSassAll();
|
await compileSassAll();
|
||||||
await h.copyAssets();
|
await h.copyAssets();
|
||||||
await h.copyWasmPlayground();
|
await h.copyWasmPlayground();
|
||||||
|
|||||||
@@ -95,6 +95,7 @@
|
|||||||
(def browser (parse-browser))
|
(def browser (parse-browser))
|
||||||
(def platform (parse-platform))
|
(def platform (parse-platform))
|
||||||
|
|
||||||
|
(def version-tag (obj/get global "penpotVersionTag"))
|
||||||
(def terms-of-service-uri (obj/get global "penpotTermsOfServiceURI"))
|
(def terms-of-service-uri (obj/get global "penpotTermsOfServiceURI"))
|
||||||
(def privacy-policy-uri (obj/get global "penpotPrivacyPolicyURI"))
|
(def privacy-policy-uri (obj/get global "penpotPrivacyPolicyURI"))
|
||||||
(def flex-help-uri (obj/get global "penpotGridHelpURI" "https://help.penpot.app/user-guide/flexible-layouts/"))
|
(def flex-help-uri (obj/get global "penpotGridHelpURI" "https://help.penpot.app/user-guide/flexible-layouts/"))
|
||||||
@@ -190,9 +191,8 @@
|
|||||||
|
|
||||||
(defn resolve-href
|
(defn resolve-href
|
||||||
[resource]
|
[resource]
|
||||||
(let [version (get version :full)
|
(let [href (-> public-uri
|
||||||
href (-> public-uri
|
|
||||||
(u/ensure-path-slash)
|
(u/ensure-path-slash)
|
||||||
(u/join resource)
|
(u/join resource)
|
||||||
(get :path))]
|
(get :path))]
|
||||||
(str href "?version=" version)))
|
(str href "?version=" version-tag)))
|
||||||
|
|||||||
@@ -27,8 +27,10 @@
|
|||||||
[app.main.data.workspace.colors :as wdc]
|
[app.main.data.workspace.colors :as wdc]
|
||||||
[app.main.data.workspace.shape-layout :as dwsl]
|
[app.main.data.workspace.shape-layout :as dwsl]
|
||||||
[app.main.data.workspace.shapes :as dwsh]
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
|
[app.main.data.workspace.texts :as dwt]
|
||||||
[app.main.data.workspace.transforms :as dwtr]
|
[app.main.data.workspace.transforms :as dwtr]
|
||||||
[app.main.data.workspace.undo :as dwu]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
|
[app.main.features :as features]
|
||||||
[app.main.fonts :as fonts]
|
[app.main.fonts :as fonts]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.util.i18n :refer [tr]]
|
[app.util.i18n :refer [tr]]
|
||||||
@@ -191,6 +193,16 @@
|
|||||||
(when (:fill attributes) (update-fill value shape-ids attributes page-id))
|
(when (:fill attributes) (update-fill value shape-ids attributes page-id))
|
||||||
(when (:stroke-color attributes) (update-stroke-color value shape-ids attributes page-id)))))))
|
(when (:stroke-color attributes) (update-stroke-color value shape-ids attributes page-id)))))))
|
||||||
|
|
||||||
|
(defn update-shape-dimensions
|
||||||
|
([value shape-ids attributes] (update-shape-dimensions value shape-ids attributes nil))
|
||||||
|
([value shape-ids attributes page-id]
|
||||||
|
(ptk/reify ::update-shape-dimensions
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ _]
|
||||||
|
(when (number? value)
|
||||||
|
(rx/of
|
||||||
|
(when (:width attributes) (dwtr/update-dimensions shape-ids :width value {:ignore-touched true :page-id page-id}))
|
||||||
|
(when (:height attributes) (dwtr/update-dimensions shape-ids :height value {:ignore-touched true :page-id page-id}))))))))
|
||||||
|
|
||||||
(defn- attributes->layout-gap [attributes value]
|
(defn- attributes->layout-gap [attributes value]
|
||||||
(let [layout-gap (-> (set/intersection attributes #{:column-gap :row-gap})
|
(let [layout-gap (-> (set/intersection attributes #{:column-gap :row-gap})
|
||||||
@@ -238,6 +250,21 @@
|
|||||||
{:ignore-touched true
|
{:ignore-touched true
|
||||||
:page-id page-id}))))))))
|
:page-id page-id}))))))))
|
||||||
|
|
||||||
|
(defn update-layout-spacing
|
||||||
|
([value shape-ids attributes] (update-layout-spacing value shape-ids attributes nil))
|
||||||
|
([value shape-ids attributes page-id]
|
||||||
|
(ptk/reify ::update-layout-spacing
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(when (number? value)
|
||||||
|
(let [ids-with-layout (shape-ids-with-layout state (or page-id (:current-page-id state)) shape-ids)
|
||||||
|
layout-attributes (attributes->layout-gap attributes value)]
|
||||||
|
(rx/of
|
||||||
|
(dwsl/update-layout ids-with-layout
|
||||||
|
layout-attributes
|
||||||
|
{:ignore-touched true
|
||||||
|
:page-id page-id}))))))))
|
||||||
|
|
||||||
(defn update-shape-position
|
(defn update-shape-position
|
||||||
([value shape-ids attributes] (update-shape-position value shape-ids attributes nil))
|
([value shape-ids attributes] (update-shape-position value shape-ids attributes nil))
|
||||||
([value shape-ids attributes page-id]
|
([value shape-ids attributes page-id]
|
||||||
@@ -251,20 +278,6 @@
|
|||||||
{:ignore-touched true
|
{:ignore-touched true
|
||||||
:page-id page-id})))))))))
|
:page-id page-id})))))))))
|
||||||
|
|
||||||
(defn update-layout-gap
|
|
||||||
[value shape-ids attributes page-id]
|
|
||||||
(ptk/reify ::update-layout-gao
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state _]
|
|
||||||
(when (number? value)
|
|
||||||
(let [ids-with-layout (shape-ids-with-layout state (or page-id (:current-page-id state)) shape-ids)
|
|
||||||
layout-attributes (attributes->layout-gap attributes value)]
|
|
||||||
(rx/of
|
|
||||||
(dwsl/update-layout ids-with-layout
|
|
||||||
layout-attributes
|
|
||||||
{:ignore-touched true
|
|
||||||
:page-id page-id})))))))
|
|
||||||
|
|
||||||
(defn update-layout-sizing-limits
|
(defn update-layout-sizing-limits
|
||||||
([value shape-ids attributes] (update-layout-sizing-limits value shape-ids attributes nil))
|
([value shape-ids attributes] (update-layout-sizing-limits value shape-ids attributes nil))
|
||||||
([value shape-ids attributes page-id]
|
([value shape-ids attributes page-id]
|
||||||
@@ -289,11 +302,20 @@
|
|||||||
update-fn (fn [node _]
|
update-fn (fn [node _]
|
||||||
(-> node
|
(-> node
|
||||||
(d/txt-merge txt-attrs)
|
(d/txt-merge txt-attrs)
|
||||||
(cty/remove-typography-from-node)))]
|
(cty/remove-typography-from-node)))
|
||||||
(dwsh/update-shapes shape-ids
|
;; Check if any attribute affects text layout (requires resize)
|
||||||
|
affects-layout? (some #(contains? txt-attrs %) [:font-size :font-family :font-weight :letter-spacing :line-height])]
|
||||||
|
(ptk/reify ::generate-text-shape-update
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(cond-> (rx/of (dwsh/update-shapes shape-ids
|
||||||
#(txt/update-text-content % update-node? update-fn nil)
|
#(txt/update-text-content % update-node? update-fn nil)
|
||||||
{:ignore-touched true
|
{:ignore-touched true
|
||||||
:page-id page-id})))
|
:page-id page-id}))
|
||||||
|
(and affects-layout?
|
||||||
|
(features/active-feature? state "render-wasm/v1"))
|
||||||
|
(rx/merge
|
||||||
|
(rx/of (dwt/resize-wasm-text-all shape-ids))))))))
|
||||||
|
|
||||||
(defn update-line-height
|
(defn update-line-height
|
||||||
([value shape-ids attributes] (update-line-height value shape-ids attributes nil))
|
([value shape-ids attributes] (update-line-height value shape-ids attributes nil))
|
||||||
@@ -342,11 +364,17 @@
|
|||||||
(-> node
|
(-> node
|
||||||
(d/txt-merge txt-attrs)
|
(d/txt-merge txt-attrs)
|
||||||
(cty/remove-typography-from-node))))]
|
(cty/remove-typography-from-node))))]
|
||||||
(dwsh/update-shapes shape-ids
|
(ptk/reify ::generate-font-family-text-shape-update
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(cond-> (rx/of (dwsh/update-shapes shape-ids
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(txt/update-text-content shape update-node? #(update-fn %1 (ctst/font-weight-applied? shape)) nil))
|
(txt/update-text-content shape update-node? #(update-fn %1 (ctst/font-weight-applied? shape)) nil))
|
||||||
{:ignore-touched true
|
{:ignore-touched true
|
||||||
:page-id page-id})))
|
:page-id page-id}))
|
||||||
|
(features/active-feature? state "render-wasm/v1")
|
||||||
|
(rx/merge
|
||||||
|
(rx/of (dwt/resize-wasm-text-all shape-ids))))))))
|
||||||
|
|
||||||
(defn- create-font-family-text-attrs
|
(defn- create-font-family-text-attrs
|
||||||
[value]
|
[value]
|
||||||
@@ -414,10 +442,16 @@
|
|||||||
(-> node
|
(-> node
|
||||||
(d/txt-merge txt-attrs)
|
(d/txt-merge txt-attrs)
|
||||||
(cty/remove-typography-from-node))))]
|
(cty/remove-typography-from-node))))]
|
||||||
(dwsh/update-shapes shape-ids
|
(ptk/reify ::generate-font-weight-text-shape-update
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(cond-> (rx/of (dwsh/update-shapes shape-ids
|
||||||
#(txt/update-text-content % update-node? update-fn nil)
|
#(txt/update-text-content % update-node? update-fn nil)
|
||||||
{:ignore-touched true
|
{:ignore-touched true
|
||||||
:page-id page-id})))
|
:page-id page-id}))
|
||||||
|
(features/active-feature? state "render-wasm/v1")
|
||||||
|
(rx/merge
|
||||||
|
(rx/of (dwt/resize-wasm-text-all shape-ids))))))))
|
||||||
|
|
||||||
(defn update-font-weight
|
(defn update-font-weight
|
||||||
([value shape-ids attributes] (update-font-weight value shape-ids attributes nil))
|
([value shape-ids attributes] (update-font-weight value shape-ids attributes nil))
|
||||||
@@ -459,126 +493,20 @@
|
|||||||
value
|
value
|
||||||
[shape-ids attributes page-id])))))
|
[shape-ids attributes page-id])))))
|
||||||
|
|
||||||
(defn update-shape-dimensions
|
(defn update-typography-interactive
|
||||||
([value shape-ids attributes] (update-shape-dimensions value shape-ids attributes nil))
|
([value shape-ids attributes] (update-typography value shape-ids attributes nil))
|
||||||
([value shape-ids attributes page-id]
|
([value shape-ids attributes page-id]
|
||||||
(ptk/reify ::update-shape-dimensions
|
(when (map? value)
|
||||||
ptk/WatchEvent
|
(rx/merge
|
||||||
(watch [_ _ _]
|
(apply-functions-map
|
||||||
(when (number? value)
|
{:font-size update-font-size
|
||||||
(rx/of
|
:font-family update-font-family-interactive
|
||||||
(when (:width attributes) (dwtr/update-dimensions shape-ids :width value {:ignore-touched true :page-id page-id}))
|
:font-weight update-font-weight-interactive
|
||||||
(when (:height attributes) (dwtr/update-dimensions shape-ids :height value {:ignore-touched true :page-id page-id}))))))))
|
:letter-spacing update-letter-spacing
|
||||||
|
:text-case update-text-case
|
||||||
(defn- attributes->actions
|
:text-decoration update-text-decoration-interactive}
|
||||||
[{:keys [value shape-ids attributes page-id]}]
|
value
|
||||||
(cond-> []
|
[shape-ids attributes page-id])))))
|
||||||
(some attributes #{:width :height})
|
|
||||||
(conj #(update-shape-dimensions
|
|
||||||
value shape-ids
|
|
||||||
(set (filter attributes #{:width :height}))
|
|
||||||
page-id))
|
|
||||||
|
|
||||||
(some attributes #{:x :y})
|
|
||||||
(conj #(update-shape-position
|
|
||||||
value shape-ids
|
|
||||||
(set (filter attributes #{:x :y}))
|
|
||||||
page-id))
|
|
||||||
|
|
||||||
(some attributes #{:p1 :p2 :p3 :p4})
|
|
||||||
(conj #(update-layout-padding
|
|
||||||
value shape-ids
|
|
||||||
(set (filter attributes #{:p1 :p2 :p3 :p4}))
|
|
||||||
page-id))
|
|
||||||
|
|
||||||
(some attributes #{:m1 :m2 :m3 :m4})
|
|
||||||
(conj #(update-layout-item-margin
|
|
||||||
value shape-ids
|
|
||||||
(set (filter attributes #{:m1 :m2 :m3 :m4}))
|
|
||||||
page-id))
|
|
||||||
|
|
||||||
(some attributes #{:row-gap :column-gap})
|
|
||||||
(conj #(update-layout-gap
|
|
||||||
value shape-ids
|
|
||||||
(set (filter attributes #{:row-gap :column-gap}))
|
|
||||||
page-id))
|
|
||||||
|
|
||||||
(some attributes #{:r1 :r2 :r3 :r4})
|
|
||||||
(conj #(if (= attributes #{:r1 :r2 :r3 :r4})
|
|
||||||
(update-shape-radius-all value shape-ids attributes page-id)
|
|
||||||
(update-shape-radius-for-corners
|
|
||||||
value shape-ids
|
|
||||||
(set (filter attributes #{:r1 :r2 :r3 :r4}))
|
|
||||||
page-id)))
|
|
||||||
|
|
||||||
(some attributes #{:strole-width})
|
|
||||||
(conj #(update-stroke-width
|
|
||||||
value shape-ids
|
|
||||||
#{:strole-width}
|
|
||||||
page-id))
|
|
||||||
(some attributes #{:max-width :max-height})
|
|
||||||
(conj #(update-layout-sizing-limits
|
|
||||||
value shape-ids
|
|
||||||
(set (filter attributes #{:max-width :max-height}))
|
|
||||||
page-id))))
|
|
||||||
|
|
||||||
(defn use-dimensions-token
|
|
||||||
([value shape-ids attributes] (use-dimensions-token value shape-ids attributes nil))
|
|
||||||
([value shape-ids attributes page-id]
|
|
||||||
(ptk/reify ::use-dimensions-token
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state _]
|
|
||||||
(when (number? value)
|
|
||||||
(let [actions (attributes->actions
|
|
||||||
{:value value
|
|
||||||
:shape-ids shape-ids
|
|
||||||
:attributes attributes
|
|
||||||
:page-id page-id
|
|
||||||
:state state})]
|
|
||||||
(apply rx/of (map #(%) actions))))))))
|
|
||||||
|
|
||||||
(defn use-spacing-token
|
|
||||||
([value shape-ids attributes] (use-spacing-token value shape-ids attributes nil))
|
|
||||||
([value shape-ids attributes page-id]
|
|
||||||
(ptk/reify ::use-spacing-token
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state _]
|
|
||||||
(let [spacing-attrs
|
|
||||||
#{:row-gap :column-gap
|
|
||||||
:m1 :m2 :m3 :m4
|
|
||||||
:p1 :p2 :p3 :p4}]
|
|
||||||
(when (and (number? value)
|
|
||||||
(set? attributes)
|
|
||||||
(set/subset? attributes spacing-attrs))
|
|
||||||
|
|
||||||
(let [actions (attributes->actions
|
|
||||||
{:value value
|
|
||||||
:shape-ids shape-ids
|
|
||||||
:attributes attributes
|
|
||||||
:page-id page-id
|
|
||||||
:state state})]
|
|
||||||
(apply rx/of (map #(%) actions)))))))))
|
|
||||||
|
|
||||||
(defn use-sizing-token
|
|
||||||
([value shape-ids attributes] (use-sizing-token value shape-ids attributes nil))
|
|
||||||
([value shape-ids attributes page-id]
|
|
||||||
(ptk/reify ::use-sizing-token
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state _]
|
|
||||||
(let [sizing-attrs
|
|
||||||
#{:width :height
|
|
||||||
:max-width :max-height}]
|
|
||||||
(when (and (number? value)
|
|
||||||
(set? attributes)
|
|
||||||
(set/subset? attributes sizing-attrs))
|
|
||||||
|
|
||||||
(let [actions (attributes->actions
|
|
||||||
{:value value
|
|
||||||
:shape-ids shape-ids
|
|
||||||
:attributes attributes
|
|
||||||
:page-id page-id
|
|
||||||
:state state})]
|
|
||||||
(apply rx/of (map #(%) actions)))))))))
|
|
||||||
|
|
||||||
;; Events to apply / unapply tokens to shapes ------------------------------------------------------------
|
;; Events to apply / unapply tokens to shapes ------------------------------------------------------------
|
||||||
|
|
||||||
@@ -718,19 +646,54 @@
|
|||||||
:token token
|
:token token
|
||||||
:shape-ids shape-ids}))
|
:shape-ids shape-ids}))
|
||||||
(rx/of
|
(rx/of
|
||||||
(cond
|
(case (:type token)
|
||||||
(and (= (:type token) :spacing)
|
:spacing
|
||||||
(nil? attrs))
|
|
||||||
(apply-spacing-token {:token token
|
(apply-spacing-token {:token token
|
||||||
:attr attrs
|
:attr attrs
|
||||||
:shapes shapes})
|
:shapes shapes})
|
||||||
|
|
||||||
:else
|
|
||||||
(apply-token {:attributes (if (empty? attrs) attributes attrs)
|
(apply-token {:attributes (if (empty? attrs) attributes attrs)
|
||||||
:token token
|
:token token
|
||||||
:shape-ids shape-ids
|
:shape-ids shape-ids
|
||||||
:on-update-shape on-update-shape}))))))))
|
:on-update-shape on-update-shape}))))))))
|
||||||
|
|
||||||
|
(defn toggle-border-radius-token
|
||||||
|
[{:keys [token attrs shape-ids expand-with-children]}]
|
||||||
|
(ptk/reify ::on-toggle-border-radius-token
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [objects (dsh/lookup-page-objects state)
|
||||||
|
shapes (into [] (keep (d/getf objects)) shape-ids)
|
||||||
|
|
||||||
|
shapes
|
||||||
|
(if expand-with-children
|
||||||
|
(into []
|
||||||
|
(mapcat (fn [shape]
|
||||||
|
(if (= (:type shape) :group)
|
||||||
|
(keep objects (:shapes shape))
|
||||||
|
[shape])))
|
||||||
|
shapes)
|
||||||
|
shapes)
|
||||||
|
|
||||||
|
{:keys [attributes all-attributes]}
|
||||||
|
(get token-properties (:type token))
|
||||||
|
|
||||||
|
unapply-tokens?
|
||||||
|
(cft/shapes-token-applied? token shapes (or attrs all-attributes attributes))
|
||||||
|
|
||||||
|
shape-ids (map :id shapes)]
|
||||||
|
|
||||||
|
(if unapply-tokens?
|
||||||
|
(rx/of
|
||||||
|
(unapply-token {:attributes (or attrs all-attributes attributes)
|
||||||
|
:token token
|
||||||
|
:shape-ids shape-ids}))
|
||||||
|
(rx/of
|
||||||
|
(apply-token {:attributes attrs
|
||||||
|
:token token
|
||||||
|
:shape-ids shape-ids
|
||||||
|
:on-update-shape update-shape-radius-for-corners})))))))
|
||||||
|
|
||||||
|
|
||||||
(defn apply-token-on-selected
|
(defn apply-token-on-selected
|
||||||
[color-operations token]
|
[color-operations token]
|
||||||
(ptk/reify ::apply-token-on-selected
|
(ptk/reify ::apply-token-on-selected
|
||||||
@@ -860,7 +823,7 @@
|
|||||||
{:title "Sizing"
|
{:title "Sizing"
|
||||||
:attributes #{:width :height}
|
:attributes #{:width :height}
|
||||||
:all-attributes ctt/sizing-keys
|
:all-attributes ctt/sizing-keys
|
||||||
:on-update-shape use-sizing-token
|
:on-update-shape update-shape-dimensions
|
||||||
:modal {:key :tokens/sizing
|
:modal {:key :tokens/sizing
|
||||||
:fields [{:label "Sizing"
|
:fields [{:label "Sizing"
|
||||||
:key :sizing}]}}
|
:key :sizing}]}}
|
||||||
@@ -873,7 +836,7 @@
|
|||||||
ctt/border-radius-keys
|
ctt/border-radius-keys
|
||||||
ctt/axis-keys
|
ctt/axis-keys
|
||||||
ctt/stroke-width-keys)
|
ctt/stroke-width-keys)
|
||||||
:on-update-shape use-dimensions-token
|
:on-update-shape update-shape-dimensions
|
||||||
:modal {:key :tokens/dimensions
|
:modal {:key :tokens/dimensions
|
||||||
:fields [{:label "Dimensions"
|
:fields [{:label "Dimensions"
|
||||||
:key :dimensions}]}}
|
:key :dimensions}]}}
|
||||||
@@ -906,7 +869,7 @@
|
|||||||
{:title "Spacing"
|
{:title "Spacing"
|
||||||
:attributes #{:column-gap :row-gap}
|
:attributes #{:column-gap :row-gap}
|
||||||
:all-attributes ctt/spacing-keys
|
:all-attributes ctt/spacing-keys
|
||||||
:on-update-shape use-spacing-token
|
:on-update-shape update-layout-spacing
|
||||||
:modal {:key :tokens/spacing
|
:modal {:key :tokens/spacing
|
||||||
:fields [{:label "Spacing"
|
:fields [{:label "Spacing"
|
||||||
:key :spacing}]}}))
|
:key :spacing}]}}))
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
{ctt/border-radius-keys dwta/update-shape-radius-for-corners
|
{ctt/border-radius-keys dwta/update-shape-radius-for-corners
|
||||||
ctt/color-keys dwta/update-fill-stroke
|
ctt/color-keys dwta/update-fill-stroke
|
||||||
ctt/stroke-width-keys dwta/update-stroke-width
|
ctt/stroke-width-keys dwta/update-stroke-width
|
||||||
ctt/sizing-keys dwta/use-dimensions-token
|
ctt/sizing-keys dwta/update-shape-dimensions
|
||||||
ctt/opacity-keys dwta/update-opacity
|
ctt/opacity-keys dwta/update-opacity
|
||||||
ctt/rotation-keys dwta/update-rotation
|
ctt/rotation-keys dwta/update-rotation
|
||||||
|
|
||||||
@@ -73,8 +73,8 @@
|
|||||||
#{:x :y} dwta/update-shape-position
|
#{:x :y} dwta/update-shape-position
|
||||||
#{:p1 :p2 :p3 :p4} dwta/update-layout-padding
|
#{:p1 :p2 :p3 :p4} dwta/update-layout-padding
|
||||||
#{:m1 :m2 :m3 :m4} dwta/update-layout-item-margin
|
#{:m1 :m2 :m3 :m4} dwta/update-layout-item-margin
|
||||||
#{:column-gap :row-gap} dwta/update-layout-gap
|
#{:column-gap :row-gap} dwta/update-layout-spacing
|
||||||
#{:width :height} dwta/use-dimensions-token
|
#{:width :height} dwta/update-shape-dimensions
|
||||||
#{:layout-item-min-w :layout-item-min-h :layout-item-max-w :layout-item-max-h} dwta/update-layout-sizing-limits})
|
#{:layout-item-min-w :layout-item-min-h :layout-item-max-w :layout-item-max-h} dwta/update-layout-sizing-limits})
|
||||||
|
|
||||||
(def ^:private attribute-actions-map
|
(def ^:private attribute-actions-map
|
||||||
|
|||||||
@@ -483,6 +483,9 @@
|
|||||||
(def workspace-active-theme-paths
|
(def workspace-active-theme-paths
|
||||||
(l/derived (d/nilf ctob/get-active-theme-paths) tokens-lib))
|
(l/derived (d/nilf ctob/get-active-theme-paths) tokens-lib))
|
||||||
|
|
||||||
|
(def workspace-all-tokens-map
|
||||||
|
(l/derived (d/nilf ctob/get-all-tokens-map) tokens-lib))
|
||||||
|
|
||||||
(defn token-sets-at-path-all-active
|
(defn token-sets-at-path-all-active
|
||||||
[group-path]
|
[group-path]
|
||||||
(l/derived
|
(l/derived
|
||||||
|
|||||||
@@ -193,11 +193,11 @@
|
|||||||
restore-fn
|
restore-fn
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(st/emit! (dd/restore-files-immediately
|
(st/emit! (dd/restore-files-immediately
|
||||||
(with-meta {:team-id (:id current-team)
|
(with-meta {:team-id current-team-id
|
||||||
:ids (into #{} d/xf:map-id files)}
|
:ids (into #{} d/xf:map-id files)}
|
||||||
{:on-success #(st/emit! (ntf/success (tr "dashboard.restore-success-notification" (:name file)))
|
{:on-success #(st/emit! (ntf/success (tr "dashboard.restore-success-notification" (:name file)))
|
||||||
(dd/fetch-projects (:id current-team))
|
(dd/fetch-projects current-team-id)
|
||||||
(dd/fetch-deleted-files (:id current-team)))
|
(dd/fetch-deleted-files current-team-id))
|
||||||
:on-error #(st/emit! (ntf/error (tr "dashboard.errors.error-on-restore-file" (:name file))))}))))
|
:on-error #(st/emit! (ntf/error (tr "dashboard.errors.error-on-restore-file" (:name file))))}))))
|
||||||
|
|
||||||
on-restore-immediately
|
on-restore-immediately
|
||||||
@@ -214,7 +214,7 @@
|
|||||||
on-delete-immediately
|
on-delete-immediately
|
||||||
(fn []
|
(fn []
|
||||||
(let [accept-fn #(st/emit! (dd/delete-files-immediately
|
(let [accept-fn #(st/emit! (dd/delete-files-immediately
|
||||||
{:team-id (:id current-team)
|
{:team-id current-team-id
|
||||||
:ids (into #{} d/xf:map-id files)}))]
|
:ids (into #{} d/xf:map-id files)}))]
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(modal/show {:type :confirm
|
(modal/show {:type :confirm
|
||||||
@@ -244,8 +244,7 @@
|
|||||||
(for [project current-projects]
|
(for [project current-projects]
|
||||||
{:name (get-project-name project)
|
{:name (get-project-name project)
|
||||||
:id (get-project-id project)
|
:id (get-project-id project)
|
||||||
:handler (on-move (:id current-team)
|
:handler (on-move current-team-id (:id project))})
|
||||||
(:id project))})
|
|
||||||
(when (seq other-teams)
|
(when (seq other-teams)
|
||||||
[{:name (tr "dashboard.move-to-other-team")
|
[{:name (tr "dashboard.move-to-other-team")
|
||||||
:id "move-to-other-team"
|
:id "move-to-other-team"
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
[app.main.ui.ds.product.loader :refer [loader*]]
|
[app.main.ui.ds.product.loader :refer [loader*]]
|
||||||
[app.main.ui.ds.product.milestone :refer [milestone*]]
|
[app.main.ui.ds.product.milestone :refer [milestone*]]
|
||||||
[app.main.ui.ds.product.milestone-group :refer [milestone-group*]]
|
[app.main.ui.ds.product.milestone-group :refer [milestone-group*]]
|
||||||
|
[app.main.ui.ds.product.panel-title :refer [panel-title*]]
|
||||||
[app.main.ui.ds.storybook :as sb]
|
[app.main.ui.ds.storybook :as sb]
|
||||||
[app.main.ui.ds.tooltip.tooltip :refer [tooltip*]]
|
[app.main.ui.ds.tooltip.tooltip :refer [tooltip*]]
|
||||||
[app.main.ui.ds.utilities.date :refer [date*]]
|
[app.main.ui.ds.utilities.date :refer [date*]]
|
||||||
@@ -81,6 +82,7 @@
|
|||||||
:Milestone milestone*
|
:Milestone milestone*
|
||||||
:MilestoneGroup milestone-group*
|
:MilestoneGroup milestone-group*
|
||||||
:Date date*
|
:Date date*
|
||||||
|
:PanelTitle panel-title*
|
||||||
|
|
||||||
:set-default-translations
|
:set-default-translations
|
||||||
(fn [data]
|
(fn [data]
|
||||||
|
|||||||
34
frontend/src/app/main/ui/ds/product/panel_title.cljs
Normal file
34
frontend/src/app/main/ui/ds/product/panel_title.cljs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
;; 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.ds.product.panel-title
|
||||||
|
(:require-macros
|
||||||
|
[app.main.style :as stl])
|
||||||
|
(:require
|
||||||
|
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||||
|
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||||
|
[app.util.i18n :refer [tr]]
|
||||||
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(def ^:private schema:panel-title
|
||||||
|
[:map
|
||||||
|
[:class {:optional true} :string]
|
||||||
|
[:text :string]
|
||||||
|
[:on-close {:optional true} fn?]])
|
||||||
|
|
||||||
|
(mf/defc panel-title*
|
||||||
|
{::mf/schema schema:panel-title}
|
||||||
|
[{:keys [class text on-close] :rest props}]
|
||||||
|
(let [props
|
||||||
|
(mf/spread-props props {:class [class (stl/css :panel-title)]})]
|
||||||
|
|
||||||
|
[:> :div props
|
||||||
|
[:span {:class (stl/css :panel-title-text)} text]
|
||||||
|
(when on-close
|
||||||
|
[:> icon-button* {:variant "ghost"
|
||||||
|
:aria-label (tr "labels.close")
|
||||||
|
:on-click on-close
|
||||||
|
:icon i/close}])]))
|
||||||
26
frontend/src/app/main/ui/ds/product/panel_title.mdx
Normal file
26
frontend/src/app/main/ui/ds/product/panel_title.mdx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{ /* 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 */ }
|
||||||
|
|
||||||
|
import { Canvas, Meta } from '@storybook/addon-docs/blocks';
|
||||||
|
import * as PanelTitle from "./panel_title.stories";
|
||||||
|
|
||||||
|
<Meta title="Product/PanelTitle" />
|
||||||
|
|
||||||
|
# PanelTitle
|
||||||
|
|
||||||
|
The `panel-title*` is used as a header for some sidebar sections.
|
||||||
|
|
||||||
|
<Canvas of={PanelTitle.Default} />
|
||||||
|
|
||||||
|
## Technical notes
|
||||||
|
|
||||||
|
The only mandatory parameter is `text`. Usually you'll want to pass a function property `on-close` that will be called when the user clicks on the close button on the right.
|
||||||
|
|
||||||
|
```clj
|
||||||
|
[:> panel-title* {:class class
|
||||||
|
:text text
|
||||||
|
:on-close on-close}]
|
||||||
|
```
|
||||||
25
frontend/src/app/main/ui/ds/product/panel_title.scss
Normal file
25
frontend/src/app/main/ui/ds/product/panel_title.scss
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// 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 "ds/_sizes.scss" as *;
|
||||||
|
@use "ds/_borders.scss" as *;
|
||||||
|
@use "ds/typography.scss" as t;
|
||||||
|
|
||||||
|
.panel-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
block-size: $sz-32;
|
||||||
|
border-radius: $br-8;
|
||||||
|
background-color: var(--color-background-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title-text {
|
||||||
|
@include t.use-typography("headline-small");
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--color-foreground-primary);
|
||||||
|
}
|
||||||
21
frontend/src/app/main/ui/ds/product/panel_title.stories.jsx
Normal file
21
frontend/src/app/main/ui/ds/product/panel_title.stories.jsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import Components from "@target/components";
|
||||||
|
|
||||||
|
const { PanelTitle } = Components;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "Product/PanelTitle",
|
||||||
|
component: PanelTitle,
|
||||||
|
argTypes: {
|
||||||
|
text: {
|
||||||
|
control: { type: "text" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
text: "Lorem ipsum",
|
||||||
|
onClose: () => null,
|
||||||
|
},
|
||||||
|
render: ({ ...args }) => <PanelTitle {...args} />,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Default = {};
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
touched? (and (contains? (:data @form) input-name)
|
touched? (and (contains? (:data @form) input-name)
|
||||||
(get-in @form [:touched input-name]))
|
(get-in @form [:touched input-name]))
|
||||||
|
|
||||||
error (get-in @form [:errors input-name])
|
error (get-in @form [:errors input-name])
|
||||||
|
|
||||||
value (get-in @form [:data input-name] "")
|
value (get-in @form [:data input-name] "")
|
||||||
@@ -52,7 +53,8 @@
|
|||||||
(let [form (mf/use-ctx context)
|
(let [form (mf/use-ctx context)
|
||||||
disabled? (or (and (some? form)
|
disabled? (or (and (some? form)
|
||||||
(or (not (:valid @form))
|
(or (not (:valid @form))
|
||||||
(seq (:external-errors @form))))
|
(seq (:async-errors @form))
|
||||||
|
(seq (:extra-errors @form))))
|
||||||
(true? disabled))
|
(true? disabled))
|
||||||
handle-key-down-save
|
handle-key-down-save
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
[app.main.ui.comments :as cmt]
|
[app.main.ui.comments :as cmt]
|
||||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||||
[app.main.ui.context :as ctx]
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
|
||||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||||
[app.main.ui.ds.product.empty-state :refer [empty-state*]]
|
[app.main.ui.ds.product.empty-state :refer [empty-state*]]
|
||||||
|
[app.main.ui.ds.product.panel-title :refer [panel-title*]]
|
||||||
[app.main.ui.icons :as deprecated-icon]
|
[app.main.ui.icons :as deprecated-icon]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
@@ -123,13 +123,10 @@
|
|||||||
|
|
||||||
[:div {:class (stl/css-case :comments-section true
|
[:div {:class (stl/css-case :comments-section true
|
||||||
:from-viewer from-viewer)}
|
:from-viewer from-viewer)}
|
||||||
[:div {:class (stl/css-case :comments-section-title true
|
|
||||||
:viewer-title from-viewer)}
|
[:> panel-title* {:class (stl/css :comments-title)
|
||||||
[:span (tr "labels.comments")]
|
:text (tr "labels.comments")
|
||||||
[:> icon-button* {:variant "ghost"
|
:on-close close-section}]
|
||||||
:aria-label (tr "labels.close")
|
|
||||||
:on-click close-section
|
|
||||||
:icon i/close}]]
|
|
||||||
|
|
||||||
[:button {:class (stl/css :mode-dropdown-wrapper)
|
[:button {:class (stl/css :mode-dropdown-wrapper)
|
||||||
:on-click toggle-mode-selector}
|
:on-click toggle-mode-selector}
|
||||||
|
|||||||
@@ -18,25 +18,8 @@
|
|||||||
padding: 0 deprecated.$s-8;
|
padding: 0 deprecated.$s-8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comments-section-title {
|
.comments-title {
|
||||||
@include deprecated.flexCenter;
|
margin: var(--sp-s) var(--sp-s) 0 var(--sp-s);
|
||||||
@include deprecated.uppercaseTitleTipography;
|
|
||||||
position: relative;
|
|
||||||
height: deprecated.$s-32;
|
|
||||||
min-height: deprecated.$s-32;
|
|
||||||
margin: deprecated.$s-8 deprecated.$s-8 0 deprecated.$s-8;
|
|
||||||
border-radius: deprecated.$br-8;
|
|
||||||
background-color: var(--panel-title-background-color);
|
|
||||||
span {
|
|
||||||
@include deprecated.flexCenter;
|
|
||||||
flex-grow: 1;
|
|
||||||
color: var(--title-foreground-color-hover);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.viewer-title {
|
|
||||||
margin: 0;
|
|
||||||
margin-block-start: deprecated.$s-8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mode-dropdown-wrapper {
|
.mode-dropdown-wrapper {
|
||||||
|
|||||||
@@ -11,12 +11,11 @@
|
|||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
[app.main.ui.ds.product.panel-title :refer [panel-title*]]
|
||||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
|
||||||
[app.main.ui.icons :as deprecated-icon]
|
[app.main.ui.icons :as deprecated-icon]
|
||||||
[app.util.debug :as dbg]
|
[app.util.debug :as dbg]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :refer [tr]]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc debug-panel*
|
(mf/defc debug-panel*
|
||||||
@@ -35,12 +34,9 @@
|
|||||||
(st/emit! (dw/remove-layout-flag :debug-panel))))]
|
(st/emit! (dw/remove-layout-flag :debug-panel))))]
|
||||||
|
|
||||||
[:div {:class (dm/str class " " (stl/css :debug-panel))}
|
[:div {:class (dm/str class " " (stl/css :debug-panel))}
|
||||||
[:div {:class (stl/css :panel-title)}
|
[:> panel-title* {:class (stl/css :debug-panel-title)
|
||||||
[:span "Debugging tools"]
|
:text (tr "workspace.debug.title")
|
||||||
[:> icon-button* {:variant "ghost"
|
:on-close handle-close}]
|
||||||
:aria-label (tr "labels.close")
|
|
||||||
:on-click handle-close
|
|
||||||
:icon i/close}]]
|
|
||||||
|
|
||||||
[:div {:class (stl/css :debug-panel-inner)}
|
[:div {:class (stl/css :debug-panel-inner)}
|
||||||
(for [option (sort-by d/name dbg/options)]
|
(for [option (sort-by d/name dbg/options)]
|
||||||
|
|||||||
@@ -12,21 +12,12 @@
|
|||||||
background-color: var(--panel-background-color);
|
background-color: var(--panel-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-title {
|
.debug-panel-title {
|
||||||
@include deprecated.flexCenter;
|
margin: var(--sp-s) var(--sp-s) 0 var(--sp-s);
|
||||||
@include deprecated.uppercaseTitleTipography;
|
|
||||||
position: relative;
|
|
||||||
height: deprecated.$s-32;
|
|
||||||
min-height: deprecated.$s-32;
|
|
||||||
margin: deprecated.$s-8 deprecated.$s-8 0 deprecated.$s-8;
|
|
||||||
border-radius: deprecated.$br-8;
|
|
||||||
background-color: var(--panel-title-background-color);
|
|
||||||
|
|
||||||
span {
|
|
||||||
@include deprecated.flexCenter;
|
|
||||||
flex-grow: 1;
|
|
||||||
color: var(--title-foreground-color-hover);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.debug-panel-inner {
|
||||||
|
padding: deprecated.$s-16 deprecated.$s-8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox-wrapper {
|
.checkbox-wrapper {
|
||||||
@@ -39,7 +30,3 @@
|
|||||||
@extend .checkbox-icon;
|
@extend .checkbox-icon;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.debug-panel-inner {
|
|
||||||
padding: deprecated.$s-16 deprecated.$s-8;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.icons :as deprecated-icon]
|
[app.main.ui.ds.product.panel-title :refer [panel-title*]]
|
||||||
[debug :as dbg]
|
[debug :as dbg]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
@@ -125,11 +125,9 @@
|
|||||||
(map (d/getf objects)))]
|
(map (d/getf objects)))]
|
||||||
|
|
||||||
[:div {:class (stl/css :shape-info)}
|
[:div {:class (stl/css :shape-info)}
|
||||||
[:div {:class (stl/css :shape-info-title)}
|
[:> panel-title* {:class (stl/css :shape-info-title)
|
||||||
[:span "Debug"]
|
:text "Debug"
|
||||||
[:div {:class (stl/css :close-button)
|
:on-close #(dbg/disable! :shape-panel)}]
|
||||||
:on-click #(dbg/disable! :shape-panel)}
|
|
||||||
deprecated-icon/close]]
|
|
||||||
|
|
||||||
(if (empty? selected)
|
(if (empty? selected)
|
||||||
[:div {:class (stl/css :attrs-container)} "No shapes selected"]
|
[:div {:class (stl/css :attrs-container)} "No shapes selected"]
|
||||||
|
|||||||
@@ -16,34 +16,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.shape-info-title {
|
.shape-info-title {
|
||||||
@include deprecated.flexCenter;
|
margin: var(--sp-s) var(--sp-s) 0 var(--sp-s);
|
||||||
@include deprecated.uppercaseTitleTipography;
|
|
||||||
position: relative;
|
|
||||||
height: deprecated.$s-32;
|
|
||||||
min-height: deprecated.$s-32;
|
|
||||||
margin: deprecated.$s-8 deprecated.$s-8 0 deprecated.$s-8;
|
|
||||||
border-radius: deprecated.$br-8;
|
|
||||||
background-color: var(--panel-title-background-color);
|
|
||||||
|
|
||||||
span {
|
|
||||||
@include deprecated.flexCenter;
|
|
||||||
flex-grow: 1;
|
|
||||||
color: var(--title-foreground-color-hover);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-button {
|
|
||||||
@extend .button-tertiary;
|
|
||||||
position: absolute;
|
|
||||||
right: deprecated.$s-2;
|
|
||||||
top: deprecated.$s-2;
|
|
||||||
height: deprecated.$s-28;
|
|
||||||
width: deprecated.$s-28;
|
|
||||||
border-radius: deprecated.$br-6;
|
|
||||||
svg {
|
|
||||||
@extend .button-icon;
|
|
||||||
stroke: var(--icon-foreground);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.attrs-container {
|
.attrs-container {
|
||||||
|
|||||||
@@ -13,23 +13,6 @@
|
|||||||
background-color: var(--panel-background-color);
|
background-color: var(--panel-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-toolbox-title {
|
|
||||||
@include deprecated.flexCenter;
|
|
||||||
@include deprecated.uppercaseTitleTipography;
|
|
||||||
position: relative;
|
|
||||||
height: deprecated.$s-32;
|
|
||||||
min-height: deprecated.$s-32;
|
|
||||||
margin: deprecated.$s-8 deprecated.$s-8 0 deprecated.$s-8;
|
|
||||||
border-radius: deprecated.$br-8;
|
|
||||||
background-color: var(--panel-title-background-color);
|
|
||||||
|
|
||||||
span {
|
|
||||||
@include deprecated.flexCenter;
|
|
||||||
flex-grow: 1;
|
|
||||||
color: var(--title-foreground-color-hover);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-entry-empty {
|
.history-entry-empty {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -192,10 +192,11 @@
|
|||||||
(st/emit!
|
(st/emit!
|
||||||
(change-radius (fn [shape]
|
(change-radius (fn [shape]
|
||||||
(ctsr/set-radius-to-all-corners shape value))))
|
(ctsr/set-radius-to-all-corners shape value))))
|
||||||
|
(doseq [attr [:r1 :r2 :r3 :r4]]
|
||||||
(st/emit!
|
(st/emit!
|
||||||
(dwta/toggle-token {:token (first value)
|
(dwta/toggle-token {:token (first value)
|
||||||
:attrs #{:r1 :r2 :r3 :r4}
|
:attrs #{attr}
|
||||||
:shape-ids ids})))))
|
:shape-ids ids}))))))
|
||||||
|
|
||||||
|
|
||||||
on-single-radius-change
|
on-single-radius-change
|
||||||
@@ -204,10 +205,9 @@
|
|||||||
(fn [value attr]
|
(fn [value attr]
|
||||||
(if (or (string? value) (number? value))
|
(if (or (string? value) (number? value))
|
||||||
(st/emit! (change-one-radius #(ctsr/set-radius-to-single-corner % attr value) attr))
|
(st/emit! (change-one-radius #(ctsr/set-radius-to-single-corner % attr value) attr))
|
||||||
(st/emit! (st/emit!
|
(st/emit! (dwta/toggle-border-radius-token {:token (first value)
|
||||||
(dwta/toggle-token {:token (first value)
|
|
||||||
:attrs #{attr}
|
:attrs #{attr}
|
||||||
:shape-ids ids}))))))
|
:shape-ids ids})))))
|
||||||
|
|
||||||
on-radius-r1-change #(on-single-radius-change % :r1)
|
on-radius-r1-change #(on-single-radius-change % :r1)
|
||||||
on-radius-r2-change #(on-single-radius-change % :r2)
|
on-radius-r2-change #(on-single-radius-change % :r2)
|
||||||
|
|||||||
@@ -369,12 +369,12 @@
|
|||||||
(if (or (string? value) (int? value))
|
(if (or (string? value) (int? value))
|
||||||
(on-change :simple attr value event)
|
(on-change :simple attr value event)
|
||||||
(do
|
(do
|
||||||
(st/emit!
|
(let [resolved-value (:resolved-value (first value))
|
||||||
(dwta/toggle-token {:token (first value)
|
updated-attr (if (= :p1 attr) #{:p1 :p3} #{:p2 :p4})]
|
||||||
:attrs (if (= :p1 attr)
|
(st/emit! (dwta/toggle-token {:token (first value)
|
||||||
#{:p1 :p3}
|
:attrs updated-attr
|
||||||
#{:p2 :p4})
|
:shape-ids ids}))
|
||||||
:shape-ids ids}))))))
|
(on-change :simple attr resolved-value event))))))
|
||||||
|
|
||||||
on-detach-token
|
on-detach-token
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@@ -483,9 +483,11 @@
|
|||||||
(if (or (string? value) (int? value))
|
(if (or (string? value) (int? value))
|
||||||
(on-change :multiple attr value event)
|
(on-change :multiple attr value event)
|
||||||
(do
|
(do
|
||||||
|
(let [resolved-value (:resolved-value (first value))]
|
||||||
(st/emit! (dwta/toggle-token {:token (first value)
|
(st/emit! (dwta/toggle-token {:token (first value)
|
||||||
:attrs #{attr}
|
:attrs #{attr}
|
||||||
:shape-ids ids}))))))
|
:shape-ids ids}))
|
||||||
|
(on-change :multiple attr resolved-value event))))))
|
||||||
|
|
||||||
on-focus
|
on-focus
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@@ -714,12 +716,11 @@
|
|||||||
(if (or (string? value) (int? value))
|
(if (or (string? value) (int? value))
|
||||||
(on-change (= "nowrap" wrap-type) attr value event)
|
(on-change (= "nowrap" wrap-type) attr value event)
|
||||||
(do
|
(do
|
||||||
(st/emit!
|
(let [resolved-value (:resolved-value (first value))]
|
||||||
(dwta/toggle-token {:token (first value)
|
(st/emit! (dwta/toggle-token {:token (first value)
|
||||||
:attrs (if (= "nowrap" wrap-type)
|
:attrs #{attr}
|
||||||
#{:row-gap :colum-gap}
|
:shape-ids ids}))
|
||||||
#{attr})
|
(on-change (= "nowrap" wrap-type) attr resolved-value event))))))
|
||||||
:shape-ids ids}))))))
|
|
||||||
|
|
||||||
on-detach-token
|
on-detach-token
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
|||||||
@@ -284,17 +284,28 @@
|
|||||||
(st/emit! (udw/change-orientation ids (keyword orientation)))))
|
(st/emit! (udw/change-orientation ids (keyword orientation)))))
|
||||||
|
|
||||||
;; SIZE AND PROPORTION LOCK
|
;; SIZE AND PROPORTION LOCK
|
||||||
|
do-size-change
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps ids)
|
||||||
|
(fn [value attr]
|
||||||
|
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
||||||
|
(udw/update-dimensions ids attr value))))
|
||||||
|
|
||||||
on-size-change
|
on-size-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids shapes)
|
(mf/deps ids shapes)
|
||||||
(fn [value attr]
|
(fn [value attr]
|
||||||
(if (or (string? value) (number? value))
|
(if (or (string? value) (number? value))
|
||||||
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
(do
|
||||||
(udw/update-dimensions ids attr value))
|
(st/emit! (udw/trigger-bounding-box-cloaking ids))
|
||||||
|
(run! #(do-size-change value attr) shapes))
|
||||||
|
(do
|
||||||
|
(let [resolved-value (:resolved-value (first value))]
|
||||||
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
||||||
(dwta/toggle-token {:token (first value)
|
(dwta/toggle-token {:token (first value)
|
||||||
:attrs #{attr}
|
:attrs #{attr}
|
||||||
:shape-ids ids})))))
|
:shape-ids ids}))
|
||||||
|
(run! #(do-size-change resolved-value attr) shapes))))))
|
||||||
|
|
||||||
on-proportion-lock-change
|
on-proportion-lock-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@@ -304,6 +315,11 @@
|
|||||||
(run! #(st/emit! (udw/set-shape-proportion-lock % new-lock)) ids))))
|
(run! #(st/emit! (udw/set-shape-proportion-lock % new-lock)) ids))))
|
||||||
|
|
||||||
;; POSITION
|
;; POSITION
|
||||||
|
do-position-change
|
||||||
|
(mf/use-fn
|
||||||
|
(fn [shape' value attr]
|
||||||
|
(st/emit! (udw/update-position (:id shape') {attr value}))))
|
||||||
|
|
||||||
on-position-change
|
on-position-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps ids)
|
(mf/deps ids)
|
||||||
@@ -311,11 +327,21 @@
|
|||||||
(if (or (string? value) (number? value))
|
(if (or (string? value) (number? value))
|
||||||
(do
|
(do
|
||||||
(st/emit! (udw/trigger-bounding-box-cloaking ids))
|
(st/emit! (udw/trigger-bounding-box-cloaking ids))
|
||||||
(st/emit! (udw/update-position ids {attr value})))
|
(run! #(do-position-change %1 value attr) shapes))
|
||||||
|
(do
|
||||||
|
(let [resolved-value (:resolved-value (first value))]
|
||||||
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
||||||
(dwta/toggle-token {:token (first value)
|
(dwta/toggle-token {:token (first value)
|
||||||
:attrs #{attr}
|
:attrs #{attr}
|
||||||
:shape-ids ids})))))
|
:shape-ids ids}))
|
||||||
|
(run! #(do-position-change %1 resolved-value attr) shapes))))))
|
||||||
|
|
||||||
|
;; ROTATION
|
||||||
|
do-rotation-change
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps ids)
|
||||||
|
(fn [value]
|
||||||
|
(st/emit! (udw/increase-rotation ids value))))
|
||||||
|
|
||||||
on-rotation-change
|
on-rotation-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@@ -324,11 +350,14 @@
|
|||||||
(if (or (string? value) (number? value))
|
(if (or (string? value) (number? value))
|
||||||
(do
|
(do
|
||||||
(st/emit! (udw/trigger-bounding-box-cloaking ids))
|
(st/emit! (udw/trigger-bounding-box-cloaking ids))
|
||||||
(st/emit! (udw/increase-rotation ids value)))
|
(run! #(do-rotation-change value) shapes))
|
||||||
|
(do
|
||||||
|
(let [resolved-value (:resolved-value (first value))]
|
||||||
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
(st/emit! (udw/trigger-bounding-box-cloaking ids)
|
||||||
(dwta/toggle-token {:token (first value)
|
(dwta/toggle-token {:token (first value)
|
||||||
:attrs #{:rotation}
|
:attrs #{:rotation}
|
||||||
:shape-ids ids})))))
|
:shape-ids ids}))
|
||||||
|
(run! #(do-rotation-change resolved-value) shapes))))))
|
||||||
|
|
||||||
on-width-change
|
on-width-change
|
||||||
(mf/use-fn (mf/deps on-size-change) #(on-size-change % :width))
|
(mf/use-fn (mf/deps on-size-change) #(on-size-change % :width))
|
||||||
@@ -381,8 +410,7 @@
|
|||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dwt/selected-fit-content))))]
|
(st/emit! (dwt/selected-fit-content))))]
|
||||||
|
|
||||||
[:section {:class (stl/css :element-set)
|
[:div {:class (stl/css :element-set)}
|
||||||
:aria-label "shape-measures-section"}
|
|
||||||
(when (and (options :presets)
|
(when (and (options :presets)
|
||||||
(or (nil? all-types) (= (count all-types) 1)))
|
(or (nil? all-types) (= (count all-types) 1)))
|
||||||
[:div {:class (stl/css :presets)}
|
[:div {:class (stl/css :presets)}
|
||||||
|
|||||||
@@ -176,8 +176,7 @@
|
|||||||
:token token
|
:token token
|
||||||
:shape-ids ids}))))]
|
:shape-ids ids}))))]
|
||||||
|
|
||||||
[:section {:class (stl/css :stroke-section)
|
[:div {:class (stl/css :stroke-section)}
|
||||||
:aria-label "stroke-section"}
|
|
||||||
[:div {:class (stl/css :stroke-title)}
|
[:div {:class (stl/css :stroke-title)}
|
||||||
[:> title-bar* {:collapsable has-strokes?
|
[:> title-bar* {:collapsable has-strokes?
|
||||||
:collapsed (not open?)
|
:collapsed (not open?)
|
||||||
|
|||||||
@@ -9,50 +9,18 @@
|
|||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.types.color :as ctc]
|
[app.common.types.color :as ctc]
|
||||||
[app.common.types.token :as tk]
|
|
||||||
[app.main.data.workspace.tokens.application :as dwta]
|
[app.main.data.workspace.tokens.application :as dwta]
|
||||||
[app.main.features :as features]
|
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.numeric-input :as deprecated-input]
|
[app.main.ui.components.numeric-input :refer [numeric-input*]]
|
||||||
[app.main.ui.components.reorder-handler :refer [reorder-handler*]]
|
[app.main.ui.components.reorder-handler :refer [reorder-handler*]]
|
||||||
[app.main.ui.components.select :refer [select]]
|
[app.main.ui.components.select :refer [select]]
|
||||||
[app.main.ui.context :as muc]
|
|
||||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||||
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
|
|
||||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
|
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
|
||||||
[app.main.ui.hooks :as h]
|
[app.main.ui.hooks :as h]
|
||||||
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]]
|
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc numeric-input-wrapper*
|
|
||||||
{::mf/private true}
|
|
||||||
[{:keys [values name applied-tokens align on-detach] :rest props}]
|
|
||||||
(let [tokens (mf/use-ctx muc/active-tokens-by-type)
|
|
||||||
tokens (mf/with-memo [tokens name]
|
|
||||||
(delay
|
|
||||||
(-> (deref tokens)
|
|
||||||
(select-keys (get tk/tokens-by-input name))
|
|
||||||
(not-empty))))
|
|
||||||
|
|
||||||
on-detach-attr (mf/use-fn
|
|
||||||
(mf/deps on-detach name)
|
|
||||||
#(on-detach % name))
|
|
||||||
|
|
||||||
applied-token (get applied-tokens name)
|
|
||||||
|
|
||||||
props (mf/spread-props props
|
|
||||||
{:placeholder (if (= :multiple values)
|
|
||||||
(tr "settings.multiple")
|
|
||||||
"--")
|
|
||||||
:applied-token applied-token
|
|
||||||
:tokens (if (delay? tokens) @tokens tokens)
|
|
||||||
:align align
|
|
||||||
:on-detach on-detach-attr
|
|
||||||
:name name
|
|
||||||
:value values})]
|
|
||||||
[:> numeric-input* props]))
|
|
||||||
|
|
||||||
(mf/defc stroke-row*
|
(mf/defc stroke-row*
|
||||||
[{:keys [index
|
[{:keys [index
|
||||||
stroke
|
stroke
|
||||||
@@ -77,10 +45,7 @@
|
|||||||
select-on-focus
|
select-on-focus
|
||||||
ids]}]
|
ids]}]
|
||||||
|
|
||||||
(let [token-numeric-inputs
|
(let [on-drop
|
||||||
(features/use-feature "tokens/numeric-input")
|
|
||||||
|
|
||||||
on-drop
|
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps on-reorder index)
|
(mf/deps on-reorder index)
|
||||||
(fn [relative-pos data]
|
(fn [relative-pos data]
|
||||||
@@ -123,13 +88,7 @@
|
|||||||
on-width-change
|
on-width-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps index on-stroke-width-change)
|
(mf/deps index on-stroke-width-change)
|
||||||
(fn [value]
|
#(on-stroke-width-change index %))
|
||||||
(if (or (string? value) (int? value))
|
|
||||||
(on-stroke-width-change index value)
|
|
||||||
(do
|
|
||||||
(st/emit! (dwta/toggle-token {:token (first value)
|
|
||||||
:attrs #{:stroke-width}
|
|
||||||
:shape-ids ids}))))))
|
|
||||||
|
|
||||||
stroke-alignment (or (:stroke-alignment stroke) :center)
|
stroke-alignment (or (:stroke-alignment stroke) :center)
|
||||||
|
|
||||||
@@ -190,12 +149,6 @@
|
|||||||
(fn [token]
|
(fn [token]
|
||||||
(on-detach-token token #{:stroke-color})))
|
(on-detach-token token #{:stroke-color})))
|
||||||
|
|
||||||
on-detach-token-width
|
|
||||||
(mf/use-fn
|
|
||||||
(mf/deps on-detach-token)
|
|
||||||
(fn [token]
|
|
||||||
(on-detach-token (first token) #{:stroke-width})))
|
|
||||||
|
|
||||||
stroke-caps-options
|
stroke-caps-options
|
||||||
[{:value nil :label (tr "workspace.options.stroke-cap.none")}
|
[{:value nil :label (tr "workspace.options.stroke-cap.none")}
|
||||||
:separator
|
:separator
|
||||||
@@ -216,8 +169,7 @@
|
|||||||
[:div {:class (stl/css-case
|
[:div {:class (stl/css-case
|
||||||
:stroke-data true
|
:stroke-data true
|
||||||
:dnd-over-top (= (:over dprops) :top)
|
:dnd-over-top (= (:over dprops) :top)
|
||||||
:dnd-over-bot (= (:over dprops) :bot))
|
:dnd-over-bot (= (:over dprops) :bot))}
|
||||||
:aria-label (str "stroke-row-" index)}
|
|
||||||
|
|
||||||
(when (some? on-reorder)
|
(when (some? on-reorder)
|
||||||
[:> reorder-handler* {:ref dref}])
|
[:> reorder-handler* {:ref dref}])
|
||||||
@@ -243,30 +195,17 @@
|
|||||||
|
|
||||||
;; Stroke Width, Alignment & Style
|
;; Stroke Width, Alignment & Style
|
||||||
[:div {:class (stl/css :stroke-options)}
|
[:div {:class (stl/css :stroke-options)}
|
||||||
(if token-numeric-inputs
|
|
||||||
[:> numeric-input-wrapper* {:on-change on-width-change
|
|
||||||
:on-detach on-detach-token-width
|
|
||||||
:icon i/stroke-size
|
|
||||||
:min 0
|
|
||||||
:on-focus on-focus
|
|
||||||
:on-blur on-blur
|
|
||||||
:name :stroke-width
|
|
||||||
:class (stl/css :numeric-input-wrapper)
|
|
||||||
:property (tr "workspace.options.stroke-width")
|
|
||||||
:applied-tokens applied-tokens
|
|
||||||
:values stroke-width}]
|
|
||||||
|
|
||||||
[:div {:class (stl/css :stroke-width-input)
|
[:div {:class (stl/css :stroke-width-input)
|
||||||
:title (tr "workspace.options.stroke-width")}
|
:title (tr "workspace.options.stroke-width")}
|
||||||
[:> icon* {:icon-id i/stroke-size
|
[:> icon* {:icon-id i/stroke-size
|
||||||
:size "s"}]
|
:size "s"}]
|
||||||
[:> deprecated-input/numeric-input* {:value stroke-width
|
[:> numeric-input* {:value stroke-width
|
||||||
:min 0
|
:min 0
|
||||||
:placeholder (tr "settings.multiple")
|
:placeholder (tr "settings.multiple")
|
||||||
:on-change on-width-change
|
:on-change on-width-change
|
||||||
:on-focus on-focus
|
:on-focus on-focus
|
||||||
:select-on-focus select-on-focus
|
:select-on-focus select-on-focus
|
||||||
:on-blur on-blur}]])
|
:on-blur on-blur}]]
|
||||||
|
|
||||||
[:div {:class (stl/css :stroke-alignment-select)
|
[:div {:class (stl/css :stroke-alignment-select)
|
||||||
:data-testid "stroke.alignment"}
|
:data-testid "stroke.alignment"}
|
||||||
|
|||||||
@@ -45,11 +45,6 @@
|
|||||||
padding-inline-start: var(--sp-xs);
|
padding-inline-start: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.numeric-input-wrapper {
|
|
||||||
grid-column: span 2;
|
|
||||||
--dropdown-width: var(--7-columns-dropdown-width);
|
|
||||||
}
|
|
||||||
|
|
||||||
.stroke-alignment-select {
|
.stroke-alignment-select {
|
||||||
grid-column: span 3;
|
grid-column: span 3;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
[app.main.data.workspace.shortcuts]
|
[app.main.data.workspace.shortcuts]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.search-bar :refer [search-bar*]]
|
[app.main.ui.components.search-bar :refer [search-bar*]]
|
||||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
|
||||||
[app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]]
|
[app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]]
|
||||||
|
[app.main.ui.ds.product.panel-title :refer [panel-title*]]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :refer [tr]]
|
[app.util.i18n :refer [tr]]
|
||||||
[app.util.strings :refer [matches-search]]
|
[app.util.strings :refer [matches-search]]
|
||||||
@@ -487,13 +487,9 @@
|
|||||||
(dom/focus! (dom/get-element "shortcut-search")))
|
(dom/focus! (dom/get-element "shortcut-search")))
|
||||||
|
|
||||||
[:div {:class (dm/str class " " (stl/css :shortcuts))}
|
[:div {:class (dm/str class " " (stl/css :shortcuts))}
|
||||||
[:div {:class (stl/css :shortcuts-header)}
|
[:> panel-title* {:class (stl/css :shortcuts-title)
|
||||||
[:div {:class (stl/css :shortcuts-title)} (tr "shortcuts.title")]
|
:text (tr "shortcuts.title")
|
||||||
[:> icon-button* {:variant "ghost"
|
:on-close close-fn}]
|
||||||
:icon i/close
|
|
||||||
:class (stl/css :shortcuts-close-button)
|
|
||||||
:on-click close-fn
|
|
||||||
:aria-label (tr "labels.close")}]]
|
|
||||||
|
|
||||||
[:div {:class (stl/css :search-field)}
|
[:div {:class (stl/css :search-field)}
|
||||||
[:> search-bar* {:on-change on-search-term-change-2
|
[:> search-bar* {:on-change on-search-term-change-2
|
||||||
|
|||||||
@@ -18,27 +18,8 @@
|
|||||||
margin: deprecated.$s-16 deprecated.$s-12 deprecated.$s-4 deprecated.$s-12;
|
margin: deprecated.$s-16 deprecated.$s-12 deprecated.$s-4 deprecated.$s-12;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcuts-header {
|
|
||||||
@include deprecated.flexCenter;
|
|
||||||
@include deprecated.uppercaseTitleTipography;
|
|
||||||
position: relative;
|
|
||||||
height: deprecated.$s-32;
|
|
||||||
padding: deprecated.$s-2 deprecated.$s-2 deprecated.$s-2 0;
|
|
||||||
margin: deprecated.$s-4 deprecated.$s-4 0 deprecated.$s-4;
|
|
||||||
border-radius: deprecated.$br-6;
|
|
||||||
background-color: var(--panel-title-background-color);
|
|
||||||
|
|
||||||
.shortcuts-title {
|
.shortcuts-title {
|
||||||
@include deprecated.flexCenter;
|
margin: var(--sp-s) var(--sp-s) 0 var(--sp-s);
|
||||||
flex-grow: 1;
|
|
||||||
color: var(--title-foreground-color-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortcuts-close-button {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.section {
|
.section {
|
||||||
|
|||||||
@@ -223,7 +223,7 @@
|
|||||||
gap-items (all-or-separate-actions {:attribute-labels {:column-gap "Column Gap"
|
gap-items (all-or-separate-actions {:attribute-labels {:column-gap "Column Gap"
|
||||||
:row-gap "Row Gap"}
|
:row-gap "Row Gap"}
|
||||||
:hint (tr "workspace.tokens.gaps")
|
:hint (tr "workspace.tokens.gaps")
|
||||||
:on-update-shape dwta/update-layout-gap}
|
:on-update-shape dwta/update-layout-spacing}
|
||||||
context-data)]
|
context-data)]
|
||||||
(->> (concat
|
(->> (concat
|
||||||
gap-items
|
gap-items
|
||||||
@@ -239,7 +239,7 @@
|
|||||||
(all-or-separate-actions {:attribute-labels {:width "Width"
|
(all-or-separate-actions {:attribute-labels {:width "Width"
|
||||||
:height "Height"}
|
:height "Height"}
|
||||||
:hint (tr "workspace.tokens.size")
|
:hint (tr "workspace.tokens.size")
|
||||||
:on-update-shape dwta/use-dimensions-token}
|
:on-update-shape dwta/update-shape-dimensions}
|
||||||
context-data)
|
context-data)
|
||||||
[:separator]
|
[:separator]
|
||||||
(all-or-separate-actions {:attribute-labels {:layout-item-min-w "Min Width"
|
(all-or-separate-actions {:attribute-labels {:layout-item-min-w "Min Width"
|
||||||
|
|||||||
@@ -140,6 +140,9 @@
|
|||||||
error
|
error
|
||||||
(get-in @form [:errors input-name])
|
(get-in @form [:errors input-name])
|
||||||
|
|
||||||
|
extra-error
|
||||||
|
(get-in @form [:extra-errors input-name])
|
||||||
|
|
||||||
value
|
value
|
||||||
(get-in @form [:data input-name] "")
|
(get-in @form [:data input-name] "")
|
||||||
|
|
||||||
@@ -247,9 +250,14 @@
|
|||||||
:hint-type (:type hint)})
|
:hint-type (:type hint)})
|
||||||
|
|
||||||
props
|
props
|
||||||
(if (and error touched?)
|
(cond
|
||||||
|
(and error touched?)
|
||||||
(mf/spread-props props {:hint-type "error"
|
(mf/spread-props props {:hint-type "error"
|
||||||
:hint-message (:message error)})
|
:hint-message (:message error)})
|
||||||
|
(and extra-error touched?)
|
||||||
|
(mf/spread-props props {:hint-type "error"
|
||||||
|
:hint-message (:message extra-error)})
|
||||||
|
:else
|
||||||
props)]
|
props)]
|
||||||
|
|
||||||
(mf/with-effect [resolve-stream tokens token input-name]
|
(mf/with-effect [resolve-stream tokens token input-name]
|
||||||
|
|||||||
@@ -236,12 +236,14 @@
|
|||||||
(on-composite-input-change form field value false))
|
(on-composite-input-change form field value false))
|
||||||
([form field value trim?]
|
([form field value trim?]
|
||||||
(letfn [(clean-errors [errors]
|
(letfn [(clean-errors [errors]
|
||||||
(-> errors
|
(some-> errors
|
||||||
(dissoc field)
|
(update :value #(when (map? %) (dissoc % field)))
|
||||||
|
(update :value #(when (seq %) %))
|
||||||
(not-empty)))]
|
(not-empty)))]
|
||||||
(swap! form (fn [state]
|
(swap! form (fn [state]
|
||||||
(-> state
|
(-> state
|
||||||
(assoc-in [:data :value field] (if trim? (str/trim value) value))
|
(assoc-in [:data :value field] (if trim? (str/trim value) value))
|
||||||
|
(assoc-in [:touched :value field] true)
|
||||||
(update :errors clean-errors)
|
(update :errors clean-errors)
|
||||||
(update :extra-errors clean-errors)))))))
|
(update :extra-errors clean-errors)))))))
|
||||||
|
|
||||||
@@ -257,6 +259,9 @@
|
|||||||
value
|
value
|
||||||
(get-in @form [:data :value input-name] "")
|
(get-in @form [:data :value input-name] "")
|
||||||
|
|
||||||
|
touched?
|
||||||
|
(get-in @form [:touched :value input-name])
|
||||||
|
|
||||||
resolve-stream
|
resolve-stream
|
||||||
(mf/with-memo [token]
|
(mf/with-memo [token]
|
||||||
(if-let [value (get-in token [:value input-name])]
|
(if-let [value (get-in token [:value input-name])]
|
||||||
@@ -284,7 +289,7 @@
|
|||||||
:hint-message (:message hint)
|
:hint-message (:message hint)
|
||||||
:hint-type (:type hint)})
|
:hint-type (:type hint)})
|
||||||
props
|
props
|
||||||
(if error
|
(if (and touched? error)
|
||||||
(mf/spread-props props {:hint-type "error"
|
(mf/spread-props props {:hint-type "error"
|
||||||
:hint-message (:message error)})
|
:hint-message (:message error)})
|
||||||
props)
|
props)
|
||||||
@@ -332,6 +337,7 @@
|
|||||||
message (tr "workspace.tokens.resolved-value" (or resolved-value value))]
|
message (tr "workspace.tokens.resolved-value" (or resolved-value value))]
|
||||||
(swap! form update :errors dissoc :value)
|
(swap! form update :errors dissoc :value)
|
||||||
(swap! form update :extra-errors dissoc :value)
|
(swap! form update :extra-errors dissoc :value)
|
||||||
|
(swap! form update :async-errors dissoc :reference)
|
||||||
(if (= input-value (str resolved-value))
|
(if (= input-value (str resolved-value))
|
||||||
(reset! hint* {})
|
(reset! hint* {})
|
||||||
(reset! hint* {:message message :type "hint"})))))))]
|
(reset! hint* {:message message :type "hint"})))))))]
|
||||||
|
|||||||
@@ -23,21 +23,19 @@
|
|||||||
(let [token-type
|
(let [token-type
|
||||||
(or (:type token) token-type)
|
(or (:type token) token-type)
|
||||||
|
|
||||||
tokens-in-selected-set
|
|
||||||
(mf/deref refs/workspace-all-tokens-in-selected-set)
|
|
||||||
|
|
||||||
token-path
|
token-path
|
||||||
(mf/with-memo [token]
|
(mf/with-memo [token]
|
||||||
(cft/token-name->path (:name token)))
|
(cft/token-name->path (:name token)))
|
||||||
|
|
||||||
tokens-tree-in-selected-set
|
all-tokens (mf/deref refs/workspace-all-tokens-map)
|
||||||
(mf/with-memo [token-path tokens-in-selected-set]
|
|
||||||
(-> (ctob/tokens-tree tokens-in-selected-set)
|
all-tokens
|
||||||
|
(mf/with-memo [token-path all-tokens]
|
||||||
|
(-> (ctob/tokens-tree all-tokens)
|
||||||
(d/dissoc-in token-path)))
|
(d/dissoc-in token-path)))
|
||||||
props
|
props
|
||||||
(mf/spread-props props {:token-type token-type
|
(mf/spread-props props {:token-type token-type
|
||||||
:tokens-tree-in-selected-set tokens-tree-in-selected-set
|
:all-token-tree all-tokens
|
||||||
:tokens-in-selected-set tokens-in-selected-set
|
|
||||||
:token token})
|
:token token})
|
||||||
text-case-props (mf/spread-props props {:input-value-placeholder (tr "workspace.tokens.text-case-value-enter")})
|
text-case-props (mf/spread-props props {:input-value-placeholder (tr "workspace.tokens.text-case-value-enter")})
|
||||||
text-decoration-props (mf/spread-props props {:input-value-placeholder (tr "workspace.tokens.text-decoration-value-enter")})
|
text-decoration-props (mf/spread-props props {:input-value-placeholder (tr "workspace.tokens.text-decoration-value-enter")})
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
[app.main.data.helpers :as dh]
|
[app.main.data.helpers :as dh]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.workspace.tokens.application :as dwta]
|
[app.main.data.workspace.tokens.application :as dwta]
|
||||||
|
[app.main.data.workspace.tokens.errors :as wte]
|
||||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||||
[app.main.data.workspace.tokens.propagation :as dwtp]
|
[app.main.data.workspace.tokens.propagation :as dwtp]
|
||||||
[app.main.data.workspace.tokens.remapping :as remap]
|
[app.main.data.workspace.tokens.remapping :as remap]
|
||||||
@@ -88,14 +89,13 @@
|
|||||||
action
|
action
|
||||||
is-create
|
is-create
|
||||||
selected-token-set-id
|
selected-token-set-id
|
||||||
tokens-tree-in-selected-set
|
all-token-tree
|
||||||
token-type
|
token-type
|
||||||
make-schema
|
make-schema
|
||||||
input-component
|
input-component
|
||||||
initial
|
initial
|
||||||
type
|
type
|
||||||
value-subfield
|
value-subfield
|
||||||
tokens-in-selected-set
|
|
||||||
input-value-placeholder] :as props}]
|
input-value-placeholder] :as props}]
|
||||||
|
|
||||||
(let [make-schema (or make-schema default-make-schema)
|
(let [make-schema (or make-schema default-make-schema)
|
||||||
@@ -105,13 +105,6 @@
|
|||||||
active-tab* (mf/use-state #(if (cft/is-reference? token) :reference :composite))
|
active-tab* (mf/use-state #(if (cft/is-reference? token) :reference :composite))
|
||||||
active-tab (deref active-tab*)
|
active-tab (deref active-tab*)
|
||||||
|
|
||||||
on-toggle-tab
|
|
||||||
(mf/use-fn
|
|
||||||
(mf/deps)
|
|
||||||
(fn [new-tab]
|
|
||||||
(let [new-tab (keyword new-tab)]
|
|
||||||
(reset! active-tab* new-tab))))
|
|
||||||
|
|
||||||
token
|
token
|
||||||
(mf/with-memo [token]
|
(mf/with-memo [token]
|
||||||
(or token {:type token-type}))
|
(or token {:type token-type}))
|
||||||
@@ -124,6 +117,9 @@
|
|||||||
tokens
|
tokens
|
||||||
(mf/deref refs/workspace-active-theme-sets-tokens)
|
(mf/deref refs/workspace-active-theme-sets-tokens)
|
||||||
|
|
||||||
|
tokens-in-selected-set
|
||||||
|
(mf/deref refs/workspace-all-tokens-in-selected-set)
|
||||||
|
|
||||||
tokens
|
tokens
|
||||||
(mf/with-memo [tokens tokens-in-selected-set token]
|
(mf/with-memo [tokens tokens-in-selected-set token]
|
||||||
;; Ensure that the resolved value uses the currently editing token
|
;; Ensure that the resolved value uses the currently editing token
|
||||||
@@ -134,8 +130,8 @@
|
|||||||
(assoc (:name token) token)))
|
(assoc (:name token) token)))
|
||||||
|
|
||||||
schema
|
schema
|
||||||
(mf/with-memo [tokens-tree-in-selected-set active-tab]
|
(mf/with-memo [all-token-tree active-tab]
|
||||||
(make-schema tokens-tree-in-selected-set active-tab))
|
(make-schema all-token-tree active-tab))
|
||||||
|
|
||||||
initial
|
initial
|
||||||
(mf/with-memo [token]
|
(mf/with-memo [token]
|
||||||
@@ -148,6 +144,17 @@
|
|||||||
(fm/use-form :schema schema
|
(fm/use-form :schema schema
|
||||||
:initial initial)
|
:initial initial)
|
||||||
|
|
||||||
|
on-toggle-tab
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps form)
|
||||||
|
(fn [new-tab]
|
||||||
|
(let [new-tab (keyword new-tab)]
|
||||||
|
(if (= new-tab :reference)
|
||||||
|
(swap! form assoc-in [:async-errors :reference]
|
||||||
|
{:message "Need valid reference"})
|
||||||
|
(swap! form update :async-errors dissoc :reference))
|
||||||
|
(reset! active-tab* new-tab))))
|
||||||
|
|
||||||
on-cancel
|
on-cancel
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [e]
|
(fn [e]
|
||||||
@@ -224,7 +231,12 @@
|
|||||||
:description description}))
|
:description description}))
|
||||||
(dwtl/toggle-token-path path)
|
(dwtl/toggle-token-path path)
|
||||||
(dwtp/propagate-workspace-tokens)
|
(dwtp/propagate-workspace-tokens)
|
||||||
(modal/hide!))))))))))]
|
(modal/hide!)))))
|
||||||
|
;; WORKAROUND: display validation errors in the form instead of crashing
|
||||||
|
(fn [{:keys [errors]}]
|
||||||
|
(let [error-messages (wte/humanize-errors errors)
|
||||||
|
error-message (first error-messages)]
|
||||||
|
(swap! form assoc-in [:extra-errors :value] {:message error-message}))))))))]
|
||||||
|
|
||||||
[:> fc/form* {:class (stl/css :form-wrapper)
|
[:> fc/form* {:class (stl/css :form-wrapper)
|
||||||
:form form
|
:form form
|
||||||
|
|||||||
@@ -291,6 +291,7 @@
|
|||||||
[:color {:optional true} [:maybe :string]]
|
[:color {:optional true} [:maybe :string]]
|
||||||
[:color-result {:optional true} ::sm/any]
|
[:color-result {:optional true} ::sm/any]
|
||||||
[:inset {:optional true} [:maybe :boolean]]]]]
|
[:inset {:optional true} [:maybe :boolean]]]]]
|
||||||
|
|
||||||
(if (= active-tab :reference)
|
(if (= active-tab :reference)
|
||||||
[:reference {:optional false} ::sm/text]
|
[:reference {:optional false} ::sm/text]
|
||||||
[:reference {:optional true} [:maybe :string]])]]
|
[:reference {:optional true} [:maybe :string]])]]
|
||||||
|
|||||||
@@ -228,7 +228,7 @@
|
|||||||
:class (stl/css :main-toolbar-options-button)
|
:class (stl/css :main-toolbar-options-button)
|
||||||
:icon i/bug
|
:icon i/bug
|
||||||
:aria-pressed (contains? layout :debug-panel)
|
:aria-pressed (contains? layout :debug-panel)
|
||||||
:aria-label "Debugging tool"
|
:aria-label (tr "workspace.toolbar.debug")
|
||||||
:tooltip-placement "bottom"
|
:tooltip-placement "bottom"
|
||||||
:on-click toggle-debug-panel}]])]]
|
:on-click toggle-debug-panel}]])]]
|
||||||
|
|
||||||
|
|||||||
@@ -1185,7 +1185,6 @@
|
|||||||
{:cmd :export-shapes
|
{:cmd :export-shapes
|
||||||
:profile-id (:profile-id @st/state)
|
:profile-id (:profile-id @st/state)
|
||||||
:wait true
|
:wait true
|
||||||
:skip-children (:skip-children value false)
|
|
||||||
:exports [{:file-id file-id
|
:exports [{:file-id file-id
|
||||||
:page-id page-id
|
:page-id page-id
|
||||||
:object-id id
|
:object-id id
|
||||||
|
|||||||
@@ -114,7 +114,7 @@
|
|||||||
|
|
||||||
(defn- load
|
(defn- load
|
||||||
[locale]
|
[locale]
|
||||||
(let [path (str "./translation." locale ".js?version=" (:full cf/version))]
|
(let [path (str "./translation." locale ".js?version=" cf/version-tag)]
|
||||||
(->> (mod/import path)
|
(->> (mod/import path)
|
||||||
(p/fmap (fn [result] (unchecked-get result "default")))
|
(p/fmap (fn [result] (unchecked-get result "default")))
|
||||||
(p/fnly (fn [data cause]
|
(p/fnly (fn [data cause]
|
||||||
|
|||||||
@@ -260,7 +260,7 @@
|
|||||||
events [(dwta/apply-token {:shape-ids [(:id rect-1)]
|
events [(dwta/apply-token {:shape-ids [(:id rect-1)]
|
||||||
:attributes #{:width :height}
|
:attributes #{:width :height}
|
||||||
:token (toht/get-token file "dimensions.sm")
|
:token (toht/get-token file "dimensions.sm")
|
||||||
:on-update-shape dwta/use-dimensions-token})]]
|
:on-update-shape dwta/update-shape-dimensions})]]
|
||||||
(tohs/run-store-async
|
(tohs/run-store-async
|
||||||
store done events
|
store done events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
@@ -333,7 +333,7 @@
|
|||||||
events [(dwta/apply-token {:shape-ids [(:id rect-1)]
|
events [(dwta/apply-token {:shape-ids [(:id rect-1)]
|
||||||
:attributes #{:width :height}
|
:attributes #{:width :height}
|
||||||
:token (toht/get-token file "sizing.sm")
|
:token (toht/get-token file "sizing.sm")
|
||||||
:on-update-shape dwta/use-dimensions-token})]]
|
:on-update-shape dwta/update-shape-dimensions})]]
|
||||||
(tohs/run-store-async
|
(tohs/run-store-async
|
||||||
store done events
|
store done events
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
|
|||||||
@@ -5476,6 +5476,10 @@ msgstr "Delete row and shapes"
|
|||||||
msgid "workspace.context-menu.grid-track.row.duplicate"
|
msgid "workspace.context-menu.grid-track.row.duplicate"
|
||||||
msgstr "Duplicate row"
|
msgstr "Duplicate row"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/debug.cljs:37
|
||||||
|
msgid "workspace.debug.title"
|
||||||
|
msgstr "Debugging tools"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/sidebar/layers.cljs:512
|
#: src/app/main/ui/workspace/sidebar/layers.cljs:512
|
||||||
msgid "workspace.focus.focus-mode"
|
msgid "workspace.focus.focus-mode"
|
||||||
msgstr "Focus mode"
|
msgstr "Focus mode"
|
||||||
@@ -8421,6 +8425,10 @@ msgstr "Comments (%s)"
|
|||||||
msgid "workspace.toolbar.curve"
|
msgid "workspace.toolbar.curve"
|
||||||
msgstr "Curve (%s)"
|
msgstr "Curve (%s)"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/top_toolbar.cljs:231
|
||||||
|
msgid "workspace.toolbar.debug"
|
||||||
|
msgstr "Debugging tools"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/top_toolbar.cljs:172
|
#: src/app/main/ui/workspace/top_toolbar.cljs:172
|
||||||
msgid "workspace.toolbar.ellipse"
|
msgid "workspace.toolbar.ellipse"
|
||||||
msgstr "Ellipse (%s)"
|
msgstr "Ellipse (%s)"
|
||||||
|
|||||||
@@ -5461,6 +5461,10 @@ msgstr "Borrar fila con el contenido"
|
|||||||
msgid "workspace.context-menu.grid-track.row.duplicate"
|
msgid "workspace.context-menu.grid-track.row.duplicate"
|
||||||
msgstr "Duplicar fila"
|
msgstr "Duplicar fila"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/sidebar/debug.cljs:37
|
||||||
|
msgid "workspace.debug.title"
|
||||||
|
msgstr "Herramientas de depuración"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/sidebar/layers.cljs:512
|
#: src/app/main/ui/workspace/sidebar/layers.cljs:512
|
||||||
msgid "workspace.focus.focus-mode"
|
msgid "workspace.focus.focus-mode"
|
||||||
msgstr "Modo foco"
|
msgstr "Modo foco"
|
||||||
@@ -7965,7 +7969,7 @@ msgstr "Line height (multiplicador, px o %) o {alias}"
|
|||||||
|
|
||||||
#: src/app/main/data/workspace/tokens/errors.cljs:57
|
#: src/app/main/data/workspace/tokens/errors.cljs:57
|
||||||
msgid "workspace.tokens.missing-references"
|
msgid "workspace.tokens.missing-references"
|
||||||
msgstr "Referéncias de tokens no encontradas:"
|
msgstr "Referencias de tokens no encontradas: "
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/tokens/management/token_pill.cljs:123
|
#: src/app/main/ui/workspace/tokens/management/token_pill.cljs:123
|
||||||
msgid "workspace.tokens.more-options"
|
msgid "workspace.tokens.more-options"
|
||||||
@@ -8282,6 +8286,10 @@ msgstr "Comentarios (%s)"
|
|||||||
msgid "workspace.toolbar.curve"
|
msgid "workspace.toolbar.curve"
|
||||||
msgstr "Curva (%s)"
|
msgstr "Curva (%s)"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/top_toolbar.cljs:231
|
||||||
|
msgid "workspace.toolbar.debug"
|
||||||
|
msgstr "Herramientas de depuración"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/top_toolbar.cljs:172
|
#: src/app/main/ui/workspace/top_toolbar.cljs:172
|
||||||
msgid "workspace.toolbar.ellipse"
|
msgid "workspace.toolbar.ellipse"
|
||||||
msgstr "Elipse (%s)"
|
msgstr "Elipse (%s)"
|
||||||
|
|||||||
4
plugins/wrangle-penpot-plugins-api-doc.toml
Normal file
4
plugins/wrangle-penpot-plugins-api-doc.toml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
name = "penpot-plugins-api-doc"
|
||||||
|
compatibility_date = "2025-01-01"
|
||||||
|
|
||||||
|
assets = { directory = "dist/doc" }
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
export CURRENT_VERSION=${CURRENT_VERSION:-develop};
|
export VERSION_TAG=${VERSION:-develop};
|
||||||
|
|
||||||
if [ "$NODE_ENV" = "production" ]; then
|
if [ "$NODE_ENV" = "production" ]; then
|
||||||
export BUILD_MODE="release";
|
export BUILD_MODE="release";
|
||||||
@@ -81,7 +81,7 @@ function copy_artifacts {
|
|||||||
cp target/wasm32-unknown-emscripten/$BUILD_MODE/render_wasm.js $DEST/$BUILD_NAME.js;
|
cp target/wasm32-unknown-emscripten/$BUILD_MODE/render_wasm.js $DEST/$BUILD_NAME.js;
|
||||||
cp target/wasm32-unknown-emscripten/$BUILD_MODE/render_wasm.wasm $DEST/$BUILD_NAME.wasm;
|
cp target/wasm32-unknown-emscripten/$BUILD_MODE/render_wasm.wasm $DEST/$BUILD_NAME.wasm;
|
||||||
|
|
||||||
sed -i "s/render_wasm.wasm/$BUILD_NAME.wasm?version=$CURRENT_VERSION/g" $DEST/$BUILD_NAME.js;
|
sed -i "s/render_wasm.wasm/$BUILD_NAME.wasm?version=$VERSION_TAG/g" $DEST/$BUILD_NAME.js;
|
||||||
|
|
||||||
yarn esbuild target/wasm32-unknown-emscripten/$BUILD_MODE/render_wasm.js \
|
yarn esbuild target/wasm32-unknown-emscripten/$BUILD_MODE/render_wasm.js \
|
||||||
--log-level=error \
|
--log-level=error \
|
||||||
|
|||||||
@@ -284,6 +284,7 @@ pub extern "C" fn set_view_end() {
|
|||||||
performance::end_measure!("set_view_end::clear_tile_index");
|
performance::end_measure!("set_view_end::clear_tile_index");
|
||||||
performance::end_timed_log!("clear_tile_index", _clear_start);
|
performance::end_timed_log!("clear_tile_index", _clear_start);
|
||||||
}
|
}
|
||||||
|
state.render_state.sync_cached_viewbox();
|
||||||
performance::end_measure!("set_view_end");
|
performance::end_measure!("set_view_end");
|
||||||
performance::end_timed_log!("set_view_end", _end_start);
|
performance::end_timed_log!("set_view_end", _end_start);
|
||||||
#[cfg(feature = "profile-macros")]
|
#[cfg(feature = "profile-macros")]
|
||||||
|
|||||||
@@ -1136,6 +1136,7 @@ impl RenderState {
|
|||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let _start = performance::begin_timed_log!("start_render_loop");
|
let _start = performance::begin_timed_log!("start_render_loop");
|
||||||
let scale = self.get_scale();
|
let scale = self.get_scale();
|
||||||
|
|
||||||
self.tile_viewbox.update(self.viewbox, scale);
|
self.tile_viewbox.update(self.viewbox, scale);
|
||||||
|
|
||||||
self.focus_mode.reset();
|
self.focus_mode.reset();
|
||||||
@@ -2292,6 +2293,10 @@ impl RenderState {
|
|||||||
(self.viewbox.zoom - self.cached_viewbox.zoom).abs() > f32::EPSILON
|
(self.viewbox.zoom - self.cached_viewbox.zoom).abs() > f32::EPSILON
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sync_cached_viewbox(&mut self) {
|
||||||
|
self.cached_viewbox = self.viewbox;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mark_touched(&mut self, uuid: Uuid) {
|
pub fn mark_touched(&mut self, uuid: Uuid) {
|
||||||
self.touched_ids.insert(uuid);
|
self.touched_ids.insert(uuid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1529,6 +1529,7 @@ impl Shape {
|
|||||||
|| !self.transform.is_identity()
|
|| !self.transform.is_identity()
|
||||||
|| !math::is_close_to(self.rotation, 0.0)
|
|| !math::is_close_to(self.rotation, 0.0)
|
||||||
|| matches!(self.shape_type, Type::Group(_) | Type::Frame(_))
|
|| matches!(self.shape_type, Type::Group(_) | Type::Frame(_))
|
||||||
|
|| matches!(self.shape_type, Type::Text(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count_visible_inner_strokes(&self) -> usize {
|
pub fn count_visible_inner_strokes(&self) -> usize {
|
||||||
|
|||||||
@@ -100,6 +100,16 @@ impl<'a> State<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_render_loop(&mut self, timestamp: i32) -> Result<(), String> {
|
pub fn start_render_loop(&mut self, timestamp: i32) -> Result<(), String> {
|
||||||
|
// If zoom changed, we MUST rebuild the tile index before using it.
|
||||||
|
// Otherwise, the index will have tiles from the old zoom level, causing visible
|
||||||
|
// tiles to appear empty. This can happen if start_render_loop() is called before
|
||||||
|
// set_view_end() finishes rebuilding the index, or if set_view_end() hasn't been
|
||||||
|
// called yet.
|
||||||
|
let zoom_changed = self.render_state.zoom_changed();
|
||||||
|
if zoom_changed {
|
||||||
|
self.rebuild_tiles_shallow();
|
||||||
|
}
|
||||||
|
|
||||||
self.render_state
|
self.render_state
|
||||||
.start_render_loop(None, &self.shapes, timestamp, false)?;
|
.start_render_loop(None, &self.shapes, timestamp, false)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user