mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 11:18:36 +00:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
01d68ec09b
27
.opencode/agents/commiter.md
Normal file
27
.opencode/agents/commiter.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
name: commiter
|
||||||
|
description: Git commit assistant following CONTRIBUTING.md commit rules
|
||||||
|
mode: primary
|
||||||
|
---
|
||||||
|
|
||||||
|
Role: You are responsible for creating git commits for Penpot and must follow
|
||||||
|
the repository commit-format rules exactly.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
* Read `CONTRIBUTING.md` before creating any commit and follow the
|
||||||
|
commit guidelines strictly.
|
||||||
|
* Use commit messages in the form `:emoji: <imperative subject>`.
|
||||||
|
* Keep the subject capitalized, concise, 70 characters or fewer, and
|
||||||
|
without a trailing period.
|
||||||
|
* Keep the description (commit body) with maximum line length of 80
|
||||||
|
characters. Use manual line breaks to wrap text before it exceeds
|
||||||
|
this limit.
|
||||||
|
* Separate the subject from the body with a blank line.
|
||||||
|
* Write a clear and concise body when needed.
|
||||||
|
* Use `git commit -s` so the commit includes the required
|
||||||
|
`Signed-off-by` line.
|
||||||
|
* Do not guess or hallucinate git author information (Name or
|
||||||
|
Email). Never include the `--author` flag in git commands unless
|
||||||
|
specifically instructed by the user for a unique case; assume the
|
||||||
|
local environment is already configured.
|
||||||
30
AGENTS.md
30
AGENTS.md
@ -32,6 +32,36 @@ precision while maintaining a strong focus on maintainability and performance.
|
|||||||
5. When searching code, prefer `ripgrep` (`rg`) over `grep` — it respects
|
5. When searching code, prefer `ripgrep` (`rg`) over `grep` — it respects
|
||||||
`.gitignore` by default.
|
`.gitignore` by default.
|
||||||
|
|
||||||
|
## GitHub Operations
|
||||||
|
|
||||||
|
To obtain the list of repository members/collaborators:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gh api repos/:owner/:repo/collaborators --paginate --jq '.[].login'
|
||||||
|
```
|
||||||
|
|
||||||
|
To obtain the list of open PRs authored by members:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
MEMBERS=$(gh api repos/:owner/:repo/collaborators --paginate --jq '.[].login' | tr '\n' '|' | sed 's/|$//')
|
||||||
|
gh pr list --state open --limit 200 --json author,title,number | jq -r --arg members "$MEMBERS" '
|
||||||
|
($members | split("|")) as $m |
|
||||||
|
.[] | select(.author.login as $a | $m | index($a)) |
|
||||||
|
"\(.number)\t\(.author.login)\t\(.title)"
|
||||||
|
'
|
||||||
|
```
|
||||||
|
|
||||||
|
To obtain the list of open PRs from external contributors (non-members):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
MEMBERS=$(gh api repos/:owner/:repo/collaborators --paginate --jq '.[].login' | tr '\n' '|' | sed 's/|$//')
|
||||||
|
gh pr list --state open --limit 200 --json author,title,number | jq -r --arg members "$MEMBERS" '
|
||||||
|
($members | split("|")) as $m |
|
||||||
|
.[] | select(.author.login as $a | $m | index($a) | not) |
|
||||||
|
"\(.number)\t\(.author.login)\t\(.title)"
|
||||||
|
'
|
||||||
|
```
|
||||||
|
|
||||||
## Architecture Overview
|
## Architecture Overview
|
||||||
|
|
||||||
Penpot is an open-source design tool composed of several modules:
|
Penpot is an open-source design tool composed of several modules:
|
||||||
|
|||||||
@ -109,6 +109,7 @@
|
|||||||
- Fix dashboard navigation tabs overlap with projects content when scrolling [Taiga #13962](https://tree.taiga.io/project/penpot/issue/13962)
|
- Fix dashboard navigation tabs overlap with projects content when scrolling [Taiga #13962](https://tree.taiga.io/project/penpot/issue/13962)
|
||||||
- Fix text editor v1 focus [Taiga #13961](https://tree.taiga.io/project/penpot/issue/13961)
|
- Fix text editor v1 focus [Taiga #13961](https://tree.taiga.io/project/penpot/issue/13961)
|
||||||
- Fix color dropdown option update [Taiga #14035](https://tree.taiga.io/project/penpot/issue/14035)
|
- Fix color dropdown option update [Taiga #14035](https://tree.taiga.io/project/penpot/issue/14035)
|
||||||
|
- Fix themes modal height [Taiga #14046](https://tree.taiga.io/project/penpot/issue/14046)
|
||||||
|
|
||||||
|
|
||||||
## 2.15.0 (Unreleased)
|
## 2.15.0 (Unreleased)
|
||||||
@ -160,6 +161,7 @@
|
|||||||
- Fix wrong `mapcat` call in `collect-main-shapes`
|
- Fix wrong `mapcat` call in `collect-main-shapes`
|
||||||
- Fix stale accumulator in `get-children-in-instance` recursion
|
- Fix stale accumulator in `get-children-in-instance` recursion
|
||||||
- Fix typo `:podition` in swap-shapes grid cell
|
- Fix typo `:podition` in swap-shapes grid cell
|
||||||
|
- Fix multiple selection on shapes with token applied to stroke color
|
||||||
|
|
||||||
|
|
||||||
## 2.14.2
|
## 2.14.2
|
||||||
|
|||||||
@ -40,8 +40,8 @@
|
|||||||
[promesa.util :as pu]
|
[promesa.util :as pu]
|
||||||
[yetti.adapter :as yt])
|
[yetti.adapter :as yt])
|
||||||
(:import
|
(:import
|
||||||
com.github.luben.zstd.ZstdIOException
|
|
||||||
com.github.luben.zstd.ZstdInputStream
|
com.github.luben.zstd.ZstdInputStream
|
||||||
|
com.github.luben.zstd.ZstdIOException
|
||||||
com.github.luben.zstd.ZstdOutputStream
|
com.github.luben.zstd.ZstdOutputStream
|
||||||
java.io.DataInputStream
|
java.io.DataInputStream
|
||||||
java.io.DataOutputStream
|
java.io.DataOutputStream
|
||||||
|
|||||||
@ -36,11 +36,11 @@
|
|||||||
java.sql.Connection
|
java.sql.Connection
|
||||||
java.sql.PreparedStatement
|
java.sql.PreparedStatement
|
||||||
java.sql.Savepoint
|
java.sql.Savepoint
|
||||||
org.postgresql.PGConnection
|
|
||||||
org.postgresql.geometric.PGpoint
|
org.postgresql.geometric.PGpoint
|
||||||
org.postgresql.jdbc.PgArray
|
org.postgresql.jdbc.PgArray
|
||||||
org.postgresql.largeobject.LargeObject
|
org.postgresql.largeobject.LargeObject
|
||||||
org.postgresql.largeobject.LargeObjectManager
|
org.postgresql.largeobject.LargeObjectManager
|
||||||
|
org.postgresql.PGConnection
|
||||||
org.postgresql.util.PGInterval
|
org.postgresql.util.PGInterval
|
||||||
org.postgresql.util.PGobject))
|
org.postgresql.util.PGobject))
|
||||||
|
|
||||||
|
|||||||
@ -22,13 +22,13 @@
|
|||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[integrant.core :as ig])
|
[integrant.core :as ig])
|
||||||
(:import
|
(:import
|
||||||
jakarta.mail.Message$RecipientType
|
|
||||||
jakarta.mail.Session
|
|
||||||
jakarta.mail.Transport
|
|
||||||
jakarta.mail.internet.InternetAddress
|
jakarta.mail.internet.InternetAddress
|
||||||
jakarta.mail.internet.MimeBodyPart
|
jakarta.mail.internet.MimeBodyPart
|
||||||
jakarta.mail.internet.MimeMessage
|
jakarta.mail.internet.MimeMessage
|
||||||
jakarta.mail.internet.MimeMultipart
|
jakarta.mail.internet.MimeMultipart
|
||||||
|
jakarta.mail.Message$RecipientType
|
||||||
|
jakarta.mail.Session
|
||||||
|
jakarta.mail.Transport
|
||||||
java.util.Properties))
|
java.util.Properties))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|||||||
@ -31,8 +31,8 @@
|
|||||||
(:import
|
(:import
|
||||||
clojure.lang.XMLHandler
|
clojure.lang.XMLHandler
|
||||||
java.io.InputStream
|
java.io.InputStream
|
||||||
javax.xml.XMLConstants
|
|
||||||
javax.xml.parsers.SAXParserFactory
|
javax.xml.parsers.SAXParserFactory
|
||||||
|
javax.xml.XMLConstants
|
||||||
org.apache.commons.io.IOUtils
|
org.apache.commons.io.IOUtils
|
||||||
org.im4java.core.ConvertCmd
|
org.im4java.core.ConvertCmd
|
||||||
org.im4java.core.IMOperation))
|
org.im4java.core.IMOperation))
|
||||||
|
|||||||
@ -15,16 +15,16 @@
|
|||||||
io.prometheus.client.CollectorRegistry
|
io.prometheus.client.CollectorRegistry
|
||||||
io.prometheus.client.Counter
|
io.prometheus.client.Counter
|
||||||
io.prometheus.client.Counter$Child
|
io.prometheus.client.Counter$Child
|
||||||
|
io.prometheus.client.exporter.common.TextFormat
|
||||||
io.prometheus.client.Gauge
|
io.prometheus.client.Gauge
|
||||||
io.prometheus.client.Gauge$Child
|
io.prometheus.client.Gauge$Child
|
||||||
io.prometheus.client.Histogram
|
io.prometheus.client.Histogram
|
||||||
io.prometheus.client.Histogram$Child
|
io.prometheus.client.Histogram$Child
|
||||||
|
io.prometheus.client.hotspot.DefaultExports
|
||||||
io.prometheus.client.SimpleCollector
|
io.prometheus.client.SimpleCollector
|
||||||
io.prometheus.client.Summary
|
io.prometheus.client.Summary
|
||||||
io.prometheus.client.Summary$Builder
|
io.prometheus.client.Summary$Builder
|
||||||
io.prometheus.client.Summary$Child
|
io.prometheus.client.Summary$Child
|
||||||
io.prometheus.client.exporter.common.TextFormat
|
|
||||||
io.prometheus.client.hotspot.DefaultExports
|
|
||||||
java.io.StringWriter))
|
java.io.StringWriter))
|
||||||
|
|
||||||
(set! *warn-on-reflection* true)
|
(set! *warn-on-reflection* true)
|
||||||
|
|||||||
@ -24,28 +24,28 @@
|
|||||||
[integrant.core :as ig])
|
[integrant.core :as ig])
|
||||||
(:import
|
(:import
|
||||||
clojure.lang.MapEntry
|
clojure.lang.MapEntry
|
||||||
io.lettuce.core.KeyValue
|
|
||||||
io.lettuce.core.RedisClient
|
|
||||||
io.lettuce.core.RedisCommandInterruptedException
|
|
||||||
io.lettuce.core.RedisCommandTimeoutException
|
|
||||||
io.lettuce.core.RedisException
|
|
||||||
io.lettuce.core.RedisURI
|
|
||||||
io.lettuce.core.ScriptOutputType
|
|
||||||
io.lettuce.core.SetArgs
|
|
||||||
io.lettuce.core.api.StatefulRedisConnection
|
io.lettuce.core.api.StatefulRedisConnection
|
||||||
io.lettuce.core.api.sync.RedisCommands
|
io.lettuce.core.api.sync.RedisCommands
|
||||||
io.lettuce.core.api.sync.RedisScriptingCommands
|
io.lettuce.core.api.sync.RedisScriptingCommands
|
||||||
io.lettuce.core.codec.RedisCodec
|
io.lettuce.core.codec.RedisCodec
|
||||||
io.lettuce.core.codec.StringCodec
|
io.lettuce.core.codec.StringCodec
|
||||||
|
io.lettuce.core.KeyValue
|
||||||
|
io.lettuce.core.pubsub.api.sync.RedisPubSubCommands
|
||||||
io.lettuce.core.pubsub.RedisPubSubListener
|
io.lettuce.core.pubsub.RedisPubSubListener
|
||||||
io.lettuce.core.pubsub.StatefulRedisPubSubConnection
|
io.lettuce.core.pubsub.StatefulRedisPubSubConnection
|
||||||
io.lettuce.core.pubsub.api.sync.RedisPubSubCommands
|
io.lettuce.core.RedisClient
|
||||||
|
io.lettuce.core.RedisCommandInterruptedException
|
||||||
|
io.lettuce.core.RedisCommandTimeoutException
|
||||||
|
io.lettuce.core.RedisException
|
||||||
|
io.lettuce.core.RedisURI
|
||||||
io.lettuce.core.resource.ClientResources
|
io.lettuce.core.resource.ClientResources
|
||||||
io.lettuce.core.resource.DefaultClientResources
|
io.lettuce.core.resource.DefaultClientResources
|
||||||
|
io.lettuce.core.ScriptOutputType
|
||||||
|
io.lettuce.core.SetArgs
|
||||||
io.netty.channel.nio.NioEventLoopGroup
|
io.netty.channel.nio.NioEventLoopGroup
|
||||||
|
io.netty.util.concurrent.EventExecutorGroup
|
||||||
io.netty.util.HashedWheelTimer
|
io.netty.util.HashedWheelTimer
|
||||||
io.netty.util.Timer
|
io.netty.util.Timer
|
||||||
io.netty.util.concurrent.EventExecutorGroup
|
|
||||||
java.lang.AutoCloseable
|
java.lang.AutoCloseable
|
||||||
java.time.Duration))
|
java.time.Duration))
|
||||||
|
|
||||||
|
|||||||
@ -30,21 +30,18 @@
|
|||||||
java.nio.file.Path
|
java.nio.file.Path
|
||||||
java.time.Duration
|
java.time.Duration
|
||||||
java.util.Collection
|
java.util.Collection
|
||||||
java.util.Optional
|
|
||||||
java.util.concurrent.atomic.AtomicLong
|
java.util.concurrent.atomic.AtomicLong
|
||||||
|
java.util.Optional
|
||||||
org.reactivestreams.Subscriber
|
org.reactivestreams.Subscriber
|
||||||
software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider
|
software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider
|
||||||
software.amazon.awssdk.core.ResponseBytes
|
|
||||||
software.amazon.awssdk.core.async.AsyncRequestBody
|
software.amazon.awssdk.core.async.AsyncRequestBody
|
||||||
software.amazon.awssdk.core.async.AsyncResponseTransformer
|
software.amazon.awssdk.core.async.AsyncResponseTransformer
|
||||||
software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody
|
software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody
|
||||||
software.amazon.awssdk.core.client.config.ClientAsyncConfiguration
|
software.amazon.awssdk.core.client.config.ClientAsyncConfiguration
|
||||||
|
software.amazon.awssdk.core.ResponseBytes
|
||||||
software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient
|
software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient
|
||||||
software.amazon.awssdk.http.nio.netty.SdkEventLoopGroup
|
software.amazon.awssdk.http.nio.netty.SdkEventLoopGroup
|
||||||
software.amazon.awssdk.regions.Region
|
software.amazon.awssdk.regions.Region
|
||||||
software.amazon.awssdk.services.s3.S3AsyncClient
|
|
||||||
software.amazon.awssdk.services.s3.S3AsyncClientBuilder
|
|
||||||
software.amazon.awssdk.services.s3.S3Configuration
|
|
||||||
software.amazon.awssdk.services.s3.model.Delete
|
software.amazon.awssdk.services.s3.model.Delete
|
||||||
software.amazon.awssdk.services.s3.model.DeleteObjectRequest
|
software.amazon.awssdk.services.s3.model.DeleteObjectRequest
|
||||||
software.amazon.awssdk.services.s3.model.DeleteObjectsRequest
|
software.amazon.awssdk.services.s3.model.DeleteObjectsRequest
|
||||||
@ -54,9 +51,12 @@
|
|||||||
software.amazon.awssdk.services.s3.model.ObjectIdentifier
|
software.amazon.awssdk.services.s3.model.ObjectIdentifier
|
||||||
software.amazon.awssdk.services.s3.model.PutObjectRequest
|
software.amazon.awssdk.services.s3.model.PutObjectRequest
|
||||||
software.amazon.awssdk.services.s3.model.S3Error
|
software.amazon.awssdk.services.s3.model.S3Error
|
||||||
software.amazon.awssdk.services.s3.presigner.S3Presigner
|
|
||||||
software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest
|
software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest
|
||||||
software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest))
|
software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest
|
||||||
|
software.amazon.awssdk.services.s3.presigner.S3Presigner
|
||||||
|
software.amazon.awssdk.services.s3.S3AsyncClient
|
||||||
|
software.amazon.awssdk.services.s3.S3AsyncClientBuilder
|
||||||
|
software.amazon.awssdk.services.s3.S3Configuration))
|
||||||
|
|
||||||
(def ^:private max-retries
|
(def ^:private max-retries
|
||||||
"A maximum number of retries on internal operations"
|
"A maximum number of retries on internal operations"
|
||||||
|
|||||||
@ -17,11 +17,11 @@
|
|||||||
java.util.List
|
java.util.List
|
||||||
linked.map.LinkedMap
|
linked.map.LinkedMap
|
||||||
linked.set.LinkedSet
|
linked.set.LinkedSet
|
||||||
|
org.fressian.handlers.ReadHandler
|
||||||
|
org.fressian.handlers.WriteHandler
|
||||||
org.fressian.Reader
|
org.fressian.Reader
|
||||||
org.fressian.StreamingWriter
|
org.fressian.StreamingWriter
|
||||||
org.fressian.Writer
|
org.fressian.Writer))
|
||||||
org.fressian.handlers.ReadHandler
|
|
||||||
org.fressian.handlers.WriteHandler))
|
|
||||||
|
|
||||||
(set! *warn-on-reflection* true)
|
(set! *warn-on-reflection* true)
|
||||||
|
|
||||||
|
|||||||
@ -8,11 +8,11 @@
|
|||||||
(:refer-clojure :exclude [get])
|
(:refer-clojure :exclude [get])
|
||||||
(:import
|
(:import
|
||||||
java.lang.AutoCloseable
|
java.lang.AutoCloseable
|
||||||
|
org.apache.commons.pool2.impl.DefaultPooledObject
|
||||||
|
org.apache.commons.pool2.impl.SoftReferenceObjectPool
|
||||||
org.apache.commons.pool2.ObjectPool
|
org.apache.commons.pool2.ObjectPool
|
||||||
org.apache.commons.pool2.PooledObject
|
org.apache.commons.pool2.PooledObject
|
||||||
org.apache.commons.pool2.PooledObjectFactory
|
org.apache.commons.pool2.PooledObjectFactory))
|
||||||
org.apache.commons.pool2.impl.DefaultPooledObject
|
|
||||||
org.apache.commons.pool2.impl.SoftReferenceObjectPool))
|
|
||||||
|
|
||||||
(defn pool?
|
(defn pool?
|
||||||
[o]
|
[o]
|
||||||
|
|||||||
@ -32,7 +32,7 @@ RUN set -ex; \
|
|||||||
|
|
||||||
FROM base AS setup-node
|
FROM base AS setup-node
|
||||||
|
|
||||||
ENV NODE_VERSION=v22.22.0 \
|
ENV NODE_VERSION=v24.15.0 \
|
||||||
PATH=/opt/node/bin:$PATH
|
PATH=/opt/node/bin:$PATH
|
||||||
|
|
||||||
RUN set -eux; \
|
RUN set -eux; \
|
||||||
@ -67,7 +67,7 @@ RUN set -eux; \
|
|||||||
|
|
||||||
FROM base AS setup-caddy
|
FROM base AS setup-caddy
|
||||||
|
|
||||||
ENV CADDY_VERSION=2.10.2
|
ENV CADDY_VERSION=2.11.2
|
||||||
|
|
||||||
RUN set -eux; \
|
RUN set -eux; \
|
||||||
ARCH="$(dpkg --print-architecture)"; \
|
ARCH="$(dpkg --print-architecture)"; \
|
||||||
@ -99,18 +99,18 @@ RUN set -eux; \
|
|||||||
FROM base AS setup-jvm
|
FROM base AS setup-jvm
|
||||||
|
|
||||||
# https://clojure.org/releases/tools
|
# https://clojure.org/releases/tools
|
||||||
ENV CLOJURE_VERSION=1.12.4.1602
|
ENV CLOJURE_VERSION=1.12.4.1618
|
||||||
|
|
||||||
RUN set -eux; \
|
RUN set -eux; \
|
||||||
ARCH="$(dpkg --print-architecture)"; \
|
ARCH="$(dpkg --print-architecture)"; \
|
||||||
case "${ARCH}" in \
|
case "${ARCH}" in \
|
||||||
aarch64|arm64) \
|
aarch64|arm64) \
|
||||||
ESUM='9903c6b19183a33725ca1dfdae5b72400c9d00995c76fafc4a0d31c5152f33f7'; \
|
ESUM='cc1b459dc442d7422b46a3b5fe52acaea54879fa7913e29a05650cef54687f5f'; \
|
||||||
BINARY_URL='https://cdn.azul.com/zulu/bin/zulu25.32.21-ca-jdk25.0.2-linux_aarch64.tar.gz'; \
|
BINARY_URL='https://cdn.azul.com/zulu/bin/zulu26.30.11-ca-jdk26.0.1-linux_aarch64.tar.gz'; \
|
||||||
;; \
|
;; \
|
||||||
amd64|x86_64) \
|
amd64|x86_64) \
|
||||||
ESUM='946ad9766d98fc6ab495a1a120072197db54997f6925fb96680f1ecd5591db4e'; \
|
ESUM='7d6663ea8d4298df65de065e32f9f449745ff607d30ba5d13777cb92e9d4613d'; \
|
||||||
BINARY_URL='https://cdn.azul.com/zulu/bin/zulu25.32.21-ca-jdk25.0.2-linux_x64.tar.gz'; \
|
BINARY_URL='https://cdn.azul.com/zulu/bin/zulu26.30.11-ca-jdk26.0.1-linux_x64.tar.gz'; \
|
||||||
;; \
|
;; \
|
||||||
*) \
|
*) \
|
||||||
echo "Unsupported arch: ${ARCH}"; \
|
echo "Unsupported arch: ${ARCH}"; \
|
||||||
@ -181,10 +181,10 @@ RUN set -eux; \
|
|||||||
|
|
||||||
FROM base AS setup-utils
|
FROM base AS setup-utils
|
||||||
|
|
||||||
ENV CLJKONDO_VERSION=2026.01.19 \
|
ENV CLJKONDO_VERSION=2026.04.15 \
|
||||||
BABASHKA_VERSION=1.12.208 \
|
BABASHKA_VERSION=1.12.208 \
|
||||||
CLJFMT_VERSION=0.15.6 \
|
CLJFMT_VERSION=0.16.4 \
|
||||||
PIXI_VERSION=0.63.2
|
PIXI_VERSION=0.67.2
|
||||||
|
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
ARCH="$(dpkg --print-architecture)"; \
|
ARCH="$(dpkg --print-architecture)"; \
|
||||||
|
|||||||
@ -31,9 +31,10 @@
|
|||||||
.project-tree {
|
.project-tree {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
min-width: 0;
|
||||||
height: deprecated.$s-32;
|
height: deprecated.$s-32;
|
||||||
min-height: deprecated.$s-32;
|
min-height: deprecated.$s-32;
|
||||||
max-width: calc(100% - deprecated.$s-64);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-name,
|
.project-name,
|
||||||
|
|||||||
@ -49,16 +49,16 @@
|
|||||||
• :prop → the property type (:fill, :stroke, :shadow, etc.)
|
• :prop → the property type (:fill, :stroke, :shadow, etc.)
|
||||||
• :shape-id → the UUID of the shape using this color
|
• :shape-id → the UUID of the shape using this color
|
||||||
• :index → index of the color in the shape's fill/stroke list
|
• :index → index of the color in the shape's fill/stroke list
|
||||||
|
|
||||||
Example of groups:
|
Example of groups:
|
||||||
{
|
{
|
||||||
{:color \"#9f2929\", :opacity 0.3, :token-name \"asd2\" :has-token-applied true}
|
{:color \"#9f2929\", :opacity 0.3, :token-name \"asd2\" :has-token-applied true}
|
||||||
[{:prop :fill, :shape-id #uuid \"d0231035-25c9-80d5-8006-eae4c3dff32e\", :index 0}]
|
[{:prop :fill, :shape-id #uuid \"d0231035-25c9-80d5-8006-eae4c3dff32e\", :index 0}]
|
||||||
|
|
||||||
{:color \"#1b54b6\", :opacity 1}
|
{:color \"#1b54b6\", :opacity 1}
|
||||||
[{:prop :fill, :shape-id #uuid \"aab34f9a-98c1-801a-8006-eae5e8236f1b\", :index 0}]
|
[{:prop :fill, :shape-id #uuid \"aab34f9a-98c1-801a-8006-eae5e8236f1b\", :index 0}]
|
||||||
}
|
}
|
||||||
|
|
||||||
This structure allows fast lookups of all shapes using the same visual color,
|
This structure allows fast lookups of all shapes using the same visual color,
|
||||||
regardless of whether it comes from local fills, strokes or shadow-colors."
|
regardless of whether it comes from local fills, strokes or shadow-colors."
|
||||||
|
|
||||||
@ -106,12 +106,11 @@
|
|||||||
open? (deref open*)
|
open? (deref open*)
|
||||||
|
|
||||||
has-colors? (or (some? (seq colors)) (some? (seq library-colors)))
|
has-colors? (or (some? (seq colors)) (some? (seq library-colors)))
|
||||||
|
|
||||||
toggle-content (mf/use-fn #(swap! open* not))
|
toggle-content (mf/use-fn #(swap! open* not))
|
||||||
|
|
||||||
expand-lib-color (mf/use-state false)
|
expand-lib-color (mf/use-state false)
|
||||||
expand-color (mf/use-state false)
|
expand-color (mf/use-state false)
|
||||||
expand-token-color (mf/use-state false)
|
expand-token-color (mf/use-state false)
|
||||||
|
|
||||||
;; TODO: Review if this is still necessary.
|
;; TODO: Review if this is still necessary.
|
||||||
prev-colors-ref (mf/use-ref nil)
|
prev-colors-ref (mf/use-ref nil)
|
||||||
|
|||||||
@ -203,7 +203,9 @@
|
|||||||
[:div {:class (stl/css-case :stroke-content true
|
[:div {:class (stl/css-case :stroke-content true
|
||||||
:stroke-content-empty (not has-strokes?))}
|
:stroke-content-empty (not has-strokes?))}
|
||||||
(cond
|
(cond
|
||||||
(= :multiple strokes)
|
(or (= :multiple (:stroke-color applied-tokens))
|
||||||
|
(= :multiple (:stroke-width applied-tokens))
|
||||||
|
(= :multiple strokes))
|
||||||
[:div {:class (stl/css :stroke-multiple)}
|
[:div {:class (stl/css :stroke-multiple)}
|
||||||
[:div {:class (stl/css :stroke-multiple-label)}
|
[:div {:class (stl/css :stroke-multiple-label)}
|
||||||
(tr "settings.multiple")]
|
(tr "settings.multiple")]
|
||||||
|
|||||||
@ -71,12 +71,13 @@
|
|||||||
[{:keys [active-tokens applied-token-name color on-swatch-click-token detach-token open-modal-from-token]}]
|
[{:keys [active-tokens applied-token-name color on-swatch-click-token detach-token open-modal-from-token]}]
|
||||||
(let [;; `active-tokens` may be provided as a `delay` (lazy computation).
|
(let [;; `active-tokens` may be provided as a `delay` (lazy computation).
|
||||||
;; In that case we must deref it (`@active-tokens`) to force evaluation
|
;; In that case we must deref it (`@active-tokens`) to force evaluation
|
||||||
;; and obtain the actual value. If it’s already realized (not a delay),
|
;; and obtain the actual value. If it's already realized (not a delay),
|
||||||
;; we just use it directly.
|
;; we just use it directly.
|
||||||
active-tokens (if (delay? active-tokens)
|
active-tokens (if (delay? active-tokens)
|
||||||
@active-tokens
|
@active-tokens
|
||||||
active-tokens)
|
active-tokens)
|
||||||
|
|
||||||
|
|
||||||
active-color-tokens (:color active-tokens)
|
active-color-tokens (:color active-tokens)
|
||||||
|
|
||||||
token (some #(when (= (:name %) applied-token-name) %) active-color-tokens)
|
token (some #(when (= (:name %) applied-token-name) %) active-color-tokens)
|
||||||
@ -351,6 +352,10 @@
|
|||||||
:dnd-over-top (= (:over dprops) :top)
|
:dnd-over-top (= (:over dprops) :top)
|
||||||
:dnd-over-bot (= (:over dprops) :bot))]
|
:dnd-over-bot (= (:over dprops) :bot))]
|
||||||
|
|
||||||
|
(when (= applied-token :multiple)
|
||||||
|
;; (js/console.trace "color-row*")
|
||||||
|
(prn "color-row*" index color applied-token))
|
||||||
|
|
||||||
(mf/with-effect [color prev-color disable-picker]
|
(mf/with-effect [color prev-color disable-picker]
|
||||||
(when (and (not disable-picker) (not= prev-color color))
|
(when (and (not disable-picker) (not= prev-color color))
|
||||||
(modal/update-props! :colorpicker {:data (parse-color color)})))
|
(modal/update-props! :colorpicker {:data (parse-color color)})))
|
||||||
|
|||||||
@ -205,6 +205,8 @@
|
|||||||
(when (some? on-reorder)
|
(when (some? on-reorder)
|
||||||
[:> reorder-handler* {:ref dref}])
|
[:> reorder-handler* {:ref dref}])
|
||||||
|
|
||||||
|
(prn "stroke-row*" applied-tokens)
|
||||||
|
|
||||||
;; Stroke Color
|
;; Stroke Color
|
||||||
;; FIXME: memorize stroke color
|
;; FIXME: memorize stroke color
|
||||||
[:div {:class (stl/css :stroke-color-actions)}
|
[:div {:class (stl/css :stroke-color-actions)}
|
||||||
|
|||||||
@ -98,11 +98,13 @@
|
|||||||
on-delete
|
on-delete
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps id)
|
(mf/deps id)
|
||||||
#(st/emit! (modal/show
|
(fn [event]
|
||||||
{:type :confirm
|
(dom/stop-propagation event)
|
||||||
:title (tr "modals.delete-page.title")
|
(st/emit! (modal/show
|
||||||
:message (tr "modals.delete-page.body")
|
{:type :confirm
|
||||||
:on-accept delete-fn})))
|
:title (tr "modals.delete-page.title")
|
||||||
|
:message (tr "modals.delete-page.body")
|
||||||
|
:on-accept delete-fn}))))
|
||||||
|
|
||||||
on-double-click
|
on-double-click
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
|||||||
@ -4,19 +4,36 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) KALEIDOS INC
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
@use "ds/_utils.scss" as *;
|
||||||
@use "ds/_sizes.scss" as *;
|
@use "ds/_sizes.scss" as *;
|
||||||
@use "refactor/common-refactor.scss" as deprecated;
|
@use "ds/_borders.scss" as *;
|
||||||
|
@use "ds/mixins.scss" as *;
|
||||||
|
@use "ds/z-index.scss" as *;
|
||||||
|
|
||||||
.modal-overlay {
|
.modal-overlay {
|
||||||
@extend %modal-overlay-base;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: fixed;
|
||||||
|
inset-inline-start: 0;
|
||||||
|
inset-block-start: 0;
|
||||||
|
block-size: 100%;
|
||||||
|
inline-size: 100%;
|
||||||
|
z-index: var(--z-index-set);
|
||||||
|
background-color: var(--color-overlay-default);
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-dialog {
|
.modal-dialog {
|
||||||
@extend %modal-container-base;
|
position: relative;
|
||||||
|
inline-size: 100%;
|
||||||
width: 100%;
|
min-inline-size: $sz-364;
|
||||||
max-width: deprecated.$s-512;
|
min-block-size: $sz-192;
|
||||||
max-height: unset;
|
max-inline-size: $sz-512;
|
||||||
|
max-block-size: calc(100dvh - #{px2rem(192)});
|
||||||
|
padding: var(--sp-xxxl);
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: $b-2 solid var(--color-background-quaternary);
|
||||||
|
background-color: var(--color-background-primary);
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,14 +42,15 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: deprecated.$s-12;
|
gap: var(--sp-m);
|
||||||
padding: deprecated.$s-72 0;
|
padding-block: px2rem(72);
|
||||||
|
padding-inline: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.themes-modal-wrapper {
|
.themes-modal-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: deprecated.$s-16;
|
gap: var(--sp-l);
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-theme-form {
|
.edit-theme-form {
|
||||||
@ -52,10 +70,10 @@
|
|||||||
border: none;
|
border: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
color: var(--color-foreground-secondary);
|
color: var(--color-foreground-secondary);
|
||||||
width: fit-content;
|
inline-size: fit-content;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto auto;
|
grid-template-columns: auto auto;
|
||||||
gap: deprecated.$s-4;
|
gap: var(--sp-xs);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
@ -66,9 +84,9 @@
|
|||||||
|
|
||||||
.button-footer {
|
.button-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-left: auto;
|
margin-inline-start: auto;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: deprecated.$s-6;
|
gap: px2rem(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-theme-footer {
|
.edit-theme-footer {
|
||||||
@ -97,18 +115,19 @@
|
|||||||
.create-theme-wrapper {
|
.create-theme-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: deprecated.$s-24;
|
gap: var(--sp-xxl);
|
||||||
}
|
}
|
||||||
|
|
||||||
.close-btn {
|
.close-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: deprecated.$s-8;
|
inset-block-start: var(--sp-s);
|
||||||
right: deprecated.$s-6;
|
inset-inline-end: px2rem(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-group-label {
|
.theme-group-label {
|
||||||
color: var(--color-foreground-secondary);
|
color: var(--color-foreground-secondary);
|
||||||
margin: 0 0 deprecated.$s-12 0;
|
margin-block: 0 var(--sp-m);
|
||||||
|
margin-inline: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +135,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
gap: deprecated.$s-4;
|
gap: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-title-icon {
|
.group-title-icon {
|
||||||
@ -124,35 +143,36 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.group-title-name {
|
.group-title-name {
|
||||||
flex-grow: 1;
|
@include textEllipsis;
|
||||||
|
|
||||||
@include deprecated.text-ellipsis;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-group-rows-wrapper {
|
.theme-group-rows-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: deprecated.$s-6;
|
gap: px2rem(6);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-group-wrapper {
|
.theme-group-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-block-start: deprecated.$s-6;
|
margin-block-start: px2rem(6);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
gap: deprecated.$s-32;
|
gap: var(--sp-xxxl);
|
||||||
|
max-block-size: calc(100dvh - #{px2rem(448)});
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-row {
|
.theme-row {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: deprecated.$s-16;
|
gap: var(--sp-l);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-name-row {
|
.theme-name-row {
|
||||||
@include deprecated.text-ellipsis;
|
@include textEllipsis;
|
||||||
|
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
@ -164,13 +184,13 @@
|
|||||||
.theme-actions-row {
|
.theme-actions-row {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: deprecated.$s-6;
|
gap: px2rem(6);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sets-count-button {
|
.sets-count-button {
|
||||||
padding: deprecated.$s-6;
|
padding: px2rem(6);
|
||||||
padding-left: deprecated.$s-12;
|
padding-inline-start: var(--sp-m);
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-wrapper {
|
.label-wrapper {
|
||||||
@ -183,32 +203,32 @@
|
|||||||
.edit-theme-wrapper {
|
.edit-theme-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: deprecated.$s-24;
|
gap: var(--sp-xxl);
|
||||||
inline-size: 100%;
|
inline-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sets-list-wrapper {
|
.sets-list-wrapper {
|
||||||
border: deprecated.$s-1 solid color-mix(in hsl, var(--color-foreground-secondary) 30%, transparent);
|
border: $b-1 solid color-mix(in hsl, var(--color-foreground-secondary) 30%, transparent);
|
||||||
border-radius: deprecated.$s-8;
|
border-radius: $br-8;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
max-height: deprecated.$s-452;
|
max-block-size: px2rem(452);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sets-count-empty-button {
|
.sets-count-empty-button {
|
||||||
text-transform: lowercase;
|
text-transform: lowercase;
|
||||||
padding: deprecated.$s-6;
|
padding: px2rem(6);
|
||||||
padding-left: deprecated.$s-12;
|
padding-inline-start: var(--sp-m);
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-input-wrapper {
|
.group-input-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: deprecated.$s-4;
|
gap: var(--sp-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-theme-inputs-wrapper {
|
.edit-theme-inputs-wrapper {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 0.6fr 1fr;
|
grid-template-columns: 0.6fr 1fr;
|
||||||
gap: deprecated.$s-12;
|
gap: var(--sp-m);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -309,9 +309,6 @@
|
|||||||
(let [el (dom/get-element "app")]
|
(let [el (dom/get-element "app")]
|
||||||
(mf/create-root el)))
|
(mf/create-root el)))
|
||||||
|
|
||||||
(declare ^:private render-single-object)
|
|
||||||
(declare ^:private render-components)
|
|
||||||
(declare ^:private render-objects)
|
|
||||||
|
|
||||||
(defn- parse-params
|
(defn- parse-params
|
||||||
[loc]
|
[loc]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user