Merge remote-tracking branch 'origin/staging' into staging-render

This commit is contained in:
Andrey Antukh
2025-12-04 11:06:48 +01:00
75 changed files with 730 additions and 231 deletions

1
.gitignore vendored
View File

@@ -80,3 +80,4 @@ node_modules
/playwright/.cache/
/render-wasm/target/
/**/.yarn/*
/.pnpm-store

View File

@@ -61,6 +61,7 @@ example. It's still usable as before, we just removed the example.
### :heart: Community contributions (Thank you!)
- Ensure consistent snap behavior across all zoom levels [Github #7774](https://github.com/penpot/penpot/pull/7774) by [@Tokytome](https://github.com/Tokytome)
- Fix crash in token grid view due to tooltip validation (by @dfelinto) [Github #7887](https://github.com/penpot/penpot/pull/7887)
### :sparkles: New features & Enhancements
@@ -88,6 +89,9 @@ example. It's still usable as before, we just removed the example.
- Fix input confirmation behavior is not uniform [Taiga #12294](https://tree.taiga.io/project/penpot/issue/12294)
- Fix copy/pasting application/transit+json [Taiga #12721](https://tree.taiga.io/project/penpot/issue/12721)
- Fix problem with plugins content attribute [Plugins #209](https://github.com/penpot/penpot-plugins/issues/209)
- Fix U and E icon displayed in project list [Taiga #12806](https://tree.taiga.io/project/penpot/issue/12806)
- Fix unpublish library modal not scrolling a long file list [Taiga #12285](https://tree.taiga.io/project/penpot/issue/12285)
- Fix incorrect interaction betwen hower and scroll on assets sidebar [Taiga #12389](https://tree.taiga.io/project/penpot/issue/12389)
## 2.11.1

View File

@@ -3,6 +3,7 @@
export PENPOT_MANAGEMENT_API_KEY=super-secret-management-api-key
export PENPOT_SECRET_KEY=super-secret-devenv-key
export PENPOT_HOST=devenv
export PENPOT_PUBLIC_URI=https://localhost:3449
export PENPOT_FLAGS="\
$PENPOT_FLAGS \

View File

@@ -106,17 +106,17 @@
(let [content-part (MimeBodyPart.)
alternative-mpart (MimeMultipart. "alternative")]
(when-let [content (get body "text/plain")]
(let [text-part (MimeBodyPart.)]
(.setText text-part ^String content ^String charset)
(.addBodyPart alternative-mpart text-part)))
(when-let [content (get body "text/html")]
(let [html-part (MimeBodyPart.)]
(.setContent html-part ^String content
(str "text/html; charset=" charset))
(.addBodyPart alternative-mpart html-part)))
(when-let [content (get body "text/plain")]
(let [text-part (MimeBodyPart.)]
(.setText text-part ^String content ^String charset)
(.addBodyPart alternative-mpart text-part)))
(.setContent content-part alternative-mpart)
(.addBodyPart mixed-mpart content-part))

View File

@@ -79,18 +79,6 @@
(remove #(contains? reserved-props (key %))))
props))
(defn event-from-rpc-params
"Create a base event skeleton with pre-filled some important
data that can be extracted from RPC params object"
[params]
(let [context {:external-session-id (::rpc/external-session-id params)
:external-event-origin (::rpc/external-event-origin params)
:triggered-by (::rpc/handler-name params)}]
{::type "action"
::profile-id (::rpc/profile-id params)
::ip-addr (::rpc/ip-addr params)
::context (d/without-nils context)}))
(defn get-external-session-id
[request]
(when-let [session-id (yreq/get-header request "x-external-session-id")]
@@ -99,13 +87,24 @@
(str/blank? session-id))
session-id)))
(defn- get-external-event-origin
(defn- get-client-event-origin
[request]
(when-let [origin (yreq/get-header request "x-event-origin")]
(when-not (or (> (count origin) 256)
(= origin "null")
(when-not (or (= origin "null")
(str/blank? origin))
origin)))
(str/prune origin 200))))
(defn get-client-user-agent
[request]
(when-let [user-agent (yreq/get-header request "user-agent")]
(str/prune user-agent 500)))
(defn- get-client-version
[request]
(when-let [origin (yreq/get-header request "x-frontend-version")]
(when-not (or (= origin "null")
(str/blank? origin))
(str/prune origin 100))))
;; --- SPECS
@@ -134,6 +133,33 @@
(def ^:private check-event
(sm/check-fn schema:event))
(defn- prepare-context-from-request
[request]
(let [client-event-origin (get-client-event-origin request)
client-version (get-client-version request)
client-user-agent (get-client-user-agent request)
session-id (get-external-session-id request)
token-id (::actoken/id request)]
(d/without-nils
{:external-session-id session-id
:access-token-id (some-> token-id str)
:client-event-origin client-event-origin
:client-user-agent client-user-agent
:client-version client-version
:version (:full cf/version)})))
(defn event-from-rpc-params
"Create a base event skeleton with pre-filled some important
data that can be extracted from RPC params object"
[params]
(let [context (some-> params meta ::http/request prepare-context-from-request)
event {::type "action"
::profile-id (or (::rpc/profile-id params) uuid/zero)
::ip-addr (::rpc/ip-addr params)}]
(cond-> event
(some? context)
(assoc ::context context))))
(defn prepare-event
[cfg mdata params result]
(let [resultm (meta result)
@@ -148,18 +174,10 @@
(merge (::props resultm))
(dissoc :profile-id)
(dissoc :type)))
(clean-props))
token-id (::actoken/id request)
context (-> (::context resultm)
(assoc :external-session-id
(get-external-session-id request))
(assoc :external-event-origin
(get-external-event-origin request))
(assoc :access-token-id (some-> token-id str))
(d/without-nils))
context (merge (::context resultm)
(prepare-context-from-request request))
ip-addr (inet/parse-request request)]
{::type (or (::type resultm)

View File

@@ -101,6 +101,38 @@ RUN set -eux; \
corepack enable; \
rm -rf /tmp/nodejs.tar.gz;
################################################################################
## CADDYSERVER SETUP
################################################################################
FROM base AS setup-caddy
ENV CADDY_VERSION=2.10.2
RUN set -eux; \
ARCH="$(dpkg --print-architecture)"; \
case "${ARCH}" in \
aarch64|arm64) \
BINARY_URL="https://github.com/caddyserver/caddy/releases/download/v${CADDY_VERSION}/caddy_${CADDY_VERSION}_linux_arm64.tar.gz"; \
;; \
amd64|x86_64) \
BINARY_URL="https://github.com/caddyserver/caddy/releases/download/v${CADDY_VERSION}/caddy_${CADDY_VERSION}_linux_amd64.tar.gz"; \
;; \
*) \
echo "Unsupported arch: ${ARCH}"; \
exit 1; \
;; \
esac; \
curl -LfsSo /tmp/caddy.tar.gz ${BINARY_URL}; \
mkdir -p /tmp/caddy; \
cd /tmp/caddy; \
tar -xf /tmp/caddy.tar.gz; \
chown -R root /tmp/caddy; \
mv /tmp/caddy/caddy /usr/bin/; \
rm -rf /tmp/caddy.tar.gz; \
rm -rf /tmp/caddy;
################################################################################
## JVM SETUP
################################################################################
@@ -393,6 +425,7 @@ COPY --from=setup-utils /opt/utils /opt/utils
COPY --from=setup-rust /opt/cargo /opt/cargo
COPY --from=setup-rust /opt/rustup /opt/rustup
COPY --from=setup-rust /opt/emsdk /opt/emsdk
COPY --from=setup-caddy /usr/bin/caddy /usr/bin/caddy
COPY files/nginx.conf /etc/nginx/nginx.conf
COPY files/nginx-mime.types /etc/nginx/mime.types
@@ -403,6 +436,9 @@ COPY files/vimrc /root/.vimrc
COPY files/tmux.conf /root/.tmux.conf
COPY files/sudoers /etc/sudoers
COPY files/Caddyfile /home/
COPY files/selfsigned.crt /home/
COPY files/selfsigned.key /home/
COPY files/start-tmux.sh /home/start-tmux.sh
COPY files/start-tmux-back.sh /home/start-tmux-back.sh
COPY files/entrypoint.sh /home/entrypoint.sh

View File

@@ -33,6 +33,8 @@ services:
- 3447:3447
- 3448:3448
- 3449:3449
- 3449:3449/udp
- 3450:3450
- 6006:6006
- 6060:6060
- 6061:6061

View File

@@ -0,0 +1,12 @@
{
auto_https off
}
localhost:3449 {
reverse_proxy localhost:4449
tls /home/selfsigned.crt /home/selfsigned.key
}
http://localhost:3450 {
reverse_proxy localhost:4449
}

View File

@@ -2,4 +2,5 @@
set -e
nginx
tail -f /dev/null
caddy start -c /home/Caddyfile
tail -f /dev/null;

View File

@@ -12,7 +12,7 @@ http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 0;
keepalive_timeout 100;
types_hash_max_size 2048;
server_tokens off;
@@ -55,7 +55,7 @@ http {
proxy_cache_key "$host$request_uri";
server {
listen 3449 default_server;
listen 4449 default_server;
server_name _;
client_max_body_size 300M;
@@ -231,7 +231,6 @@ http {
}
add_header Cache-Control "no-store";
add_header Connection close always;
# This header is what we need to use on prod
# add_header Cache-Control "public, must-revalidate, max-age=0";
try_files $uri /index.html$is_args$args /index.html =404;

View File

@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDuzCCAqOgAwIBAgIUa3THJQSn1+ErK65g1jDL0tjUkBYwDQYJKoZIhvcNAQEL
BQAwXzELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBUxvY2FsMQ4wDAYDVQQHDAVMb2Nh
bDEOMAwGA1UECgwFTG9jYWwxDDAKBgNVBAsMA0RldjESMBAGA1UEAwwJbG9jYWxo
b3N0MB4XDTI1MTIwMjA4MjUyM1oXDTI2MTIwMjA4MjUyM1owXzELMAkGA1UEBhMC
VVMxDjAMBgNVBAgMBUxvY2FsMQ4wDAYDVQQHDAVMb2NhbDEOMAwGA1UECgwFTG9j
YWwxDDAKBgNVBAsMA0RldjESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyVIlfpIPE+QyL/q7IQOilEA7wEOZ6wbsh2Fr
59H1gSLFvgoCxI6RVUkQ/MFRnw/r1ZbAqRpc2xAl5a9Ml14q20Zlj6dAHsWX6O2J
EwNsD18dQmX3BncnjV3yCZM2iQcMFKuXG4KQNdIQNNvdIgtlrHYp0ohS9s3XC7cj
KxNrm/pW9EAXfn9AYDd/qER090L2E4ipP9m/5l3MjinNc4l2kpH9rLOgb79H0RLt
PK3/KP8ErZhAvzdmDBAdM5Z5K37b+TfB/kSVNUKL6qyw5CCjlShERLhBNprlnRfz
tHNIQ1RHq3qJJN19ZnJrLqICuQ5ztvj7hBDiOSV0LnmyKgXr6wIDAQABo28wbTAd
BgNVHQ4EFgQUPL8WGf6z/wB8TimJBx1zybsIeikwHwYDVR0jBBgwFoAUPL8WGf6z
/wB8TimJBx1zybsIeikwDwYDVR0TAQH/BAUwAwEB/zAaBgNVHREEEzARgglsb2Nh
bGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggEBACMMVyR3kbNxnzuUc2lahKH4
cPXVWOsvCvnDtjzm41XmKjUJTbtjn3p5d/ZmLbZ4zzIQULfWXO3XG/HevkvVo0g6
6pJXTXc6C6ZhFG0rIYMcPPzmGmalDV5n+lUaCVx5XbFFxvRQ7893auwhRATdwGs+
xiMyYbE2w9otKqyDItmJZJ5nW6vmXJ42YHxlXF18u9U88xqtOSMd5xZahbsmw7Gg
A4/o4TPoAX5QfA306sL443WaczsF7bmsTf9qcYa/3xxQkP5Seyqx8ePWpS22qysE
jG6XPpymxb6sb2mVaFBAzhEMb/eBvE9nRAopxmB7uV4TbqC51K/U3uo6jFX4Jbw=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDJUiV+kg8T5DIv
+rshA6KUQDvAQ5nrBuyHYWvn0fWBIsW+CgLEjpFVSRD8wVGfD+vVlsCpGlzbECXl
r0yXXirbRmWPp0AexZfo7YkTA2wPXx1CZfcGdyeNXfIJkzaJBwwUq5cbgpA10hA0
290iC2WsdinSiFL2zdcLtyMrE2ub+lb0QBd+f0BgN3+oRHT3QvYTiKk/2b/mXcyO
Kc1ziXaSkf2ss6Bvv0fREu08rf8o/wStmEC/N2YMEB0zlnkrftv5N8H+RJU1Qovq
rLDkIKOVKEREuEE2muWdF/O0c0hDVEereokk3X1mcmsuogK5DnO2+PuEEOI5JXQu
ebIqBevrAgMBAAECggEABqtE+LNn8nW9v98jcc2IBjc2g4D5yVJaZYWxqGVJJ7T6
Lfhw7Qf4AoZAHM9en9FMM7Ahw7hO2SboynoLJHyHGOp1FNQqiJptFNdBkjKr0rqI
4pk0HK+3zLQO/4gz50gne0vP3qZtlorV5Jpf8e/Et3jWm9XOQcTB2e6AKL4k827B
dv4Tld+/7PoZVXjahfrUWuIZr5mzyF1eUkD8sPOpdr3HJxSueqsOMjbG8XMRqCQ+
5eCWWSW5yPQlMr7M7cXM+a0k73Xn1sKl7fP3/9byji25zxGUaMu5RA1kw0Oqseid
RXuRxGphGZgnx1aFxDAPg3FtmGch7/Cc6WfqboOL0QKBgQD4GZO1gGaE8cg4lvuo
ZUX2YJu6UJuNOmuhfvG3ui4WO9PHy3btc2q+3kutSuBcyIjhi+qbXasBcX/QOOJF
udyTZc5PopNkJojS4JdXAZCiu5sKI3lp4DIt9qNISlXGgrJgdxGUO+DzarBctXdn
BSwXFw5hcjJjl7wsPGQl1tBTQwKBgQDPuz5MEM5ZeUe9CT5sQDq/ld0u4aL5AHmx
aaA2gzDgd9l2R5wHX6wLzjoVWXOmeqaYzJopt2JN4iXrtbjWkyePgZeZMyWoyJ/v
clW9bi8HM9f9EpPr7czSj9sLUnsjd9cuTD+JuXK//jRGbRpw7r7nWtLHImjj6d2v
APZRq0v2OQKBgBcESG/OObSbubeGSlKVEqiIzem7ELNJeDLDVCl3XE8zvbILbj0Z
OA39EYhCKg5xjEFgeaNwTS0VGoZ2wIc3dv81sq4wpvvjl035CBFKU+DFBt0p7Vml
MwKQnxVV0B9agLHyWe8mnvf2LeZr72ffUvfRa8QelA4pRYvVDnV0OF+BAoGAW6rM
+tQPuvwB5DFIEozlX9XKHP4E5MyI5vktceDCmMtKcx92gup9CVif2Pv4ROaqzZK8
FNyPzL6W7UTrpASb2H/fXgNsAudFbGyP2V/d8Ne34D1qeRoe4GwKxRxIqoYftpZ/
E096i66pcsqCeINiSsWRbb6JesmgwbEzAScOBkECgYEA6O/Dibc9PaqRpaiE6Qut
S3W/Rr1Pd1jbN4rOVI2TFCgMJQmc6jOdq2fCntR9acsa8HPx+djOlXTUBPKBZ/Ae
p8umRdXVWcNMnwWVWHt7tsEuR/gYkxQ5xjXeS1VDPnEre9+EaevMBuVs8HdRsKQO
uzvNGeAFEfqwIqn7CFQ+ndU=
-----END PRIVATE KEY-----

View File

@@ -10,19 +10,19 @@ desc: Begin with the Penpot user guide! Get quickstarts, shortcuts, and tutorial
<li>
<a href="/user-guide/account-teams/your-account">
<h2>Your account →</h2>
<p>Ways to start with Penpot</p>
<p>Access your account settings and manage personal access tokens</p>
</a>
</li>
<li>
<a href="/user-guide/account-teams/teams">
<h2>Teams →</h2>
<p>Info of interest about Penpot</p>
<p>Create and manage your teams</p>
</a>
</li>
<li>
<a href="/user-guide/account-teams/comments/">
<h2>Comments →</h2>
<p>Info of interest about Penpot</p>
<p>Give and receive feedback right over your designs</p>
</a>
</li>
</ul>

View File

@@ -10,31 +10,31 @@ desc: Begin with the Penpot user guide! Get quickstarts, shortcuts, and tutorial
<li>
<a href="/user-guide/design-systems/assets">
<h2>Assets →</h2>
<p>Ways to start with Penpot</p>
<p>Store elements and styles to easily reuse them</p>
</a>
</li>
<li>
<a href="/user-guide/design-systems/libraries">
<h2>Libraries →</h2>
<p>Info of interest about Penpot</p>
<p>Organize and manage your stored elements with Libraries</p>
</a>
</li>
<li>
<a href="/user-guide/design-systems/components">
<h2>Components →</h2>
<p>Speed your design workflow</p>
<p>Speed your design workflow with reusable components</p>
</a>
</li>
<li>
<a href="/user-guide/design-systems/variants">
<h2>Variants →</h2>
<p>Info of interest about Penpot</p>
<p>Group components into a single, customizable one</p>
</a>
</li>
<li>
<a href="/user-guide/design-systems/design-tokens">
<h2>Design Tokens →</h2>
<p>Info of interest about Penpot</p>
<p>Synchronize visual elements across your designs</p>
</a>
</li>
</ul>

View File

@@ -5,7 +5,7 @@ desc: Use Penpot's libraries for reusable design elements! Learn to create, mana
---
<h1 id="libraries">Libraries</h1>
<p class="main-paragraph">Libraries may include components, graphics, colors and typographies. Learn how to create and manage them to better organize the pieces of your designs and speed your workflow.</p>
<p class="main-paragraph">Libraries may include components, colors and typographies. Learn how to create and manage them to better organize the pieces of your designs and speed your workflow.</p>
<h3 id="file-libraries">File libraries</h3>
<p>Each file has its own file library which is where the assets that belong to this file are stored.</p>

View File

@@ -10,31 +10,31 @@ desc: Begin with the Penpot user guide! Get quickstarts, shortcuts, and tutorial
<li>
<a href="/user-guide/designing/workspace-basics">
<h2>Workspace basics →</h2>
<p>Workspace basics</p>
<p>Get to know the Workspace, where designs are created</p>
</a>
</li>
<li>
<a href="/user-guide/designing/layers">
<h2>Layers →</h2>
<p>Info of interest about Penpot</p>
<p>Objects available in Penpot and how to get the most of them</p>
</a>
</li>
<li>
<a href="/user-guide/designing/color-stroke/">
<h2>Color & Strokes→</h2>
<p>Info of interest about Penpot</p>
<p>Styling options available for each layer</p>
</a>
</li>
<li>
<a href="/user-guide/designing/text-typo">
<h2>Text & Typography→</h2>
<p>Info of interest about Penpot</p>
<p>Styling text content & using custom fonts</p>
</a>
</li>
<li>
<a href="/user-guide/designing/flexible-layouts">
<h2>Flexible layouts →</h2>
<p>Info of interest about Penpot</p>
<p>Create designs that adapt automatically</p>
</a>
</li>
</ul>

View File

@@ -10,13 +10,13 @@ desc: Begin with the Penpot user guide! Get quickstarts, shortcuts, and tutorial
<li>
<a href="/user-guide/export-import/export-import-files/">
<h2>Export/Import Penpot files →</h2>
<p>Ways to start with Penpot</p>
<p>How to export and import your Penpot files</p>
</a>
</li>
<li>
<a href="/user-guide/export-import/exporting-layers/">
<h2>Exporting layers →</h2>
<p>Exporting layers</p>
<p>How to export elements from your design into different file formats</p>
</a>
</li>
</ul>

View File

@@ -16,7 +16,7 @@ desc: Begin with the Penpot user guide! Get quickstarts, shortcuts, and tutorial
<li>
<a href="/user-guide/first-steps/the-interface">
<h2>Interface tour →</h2>
<p>Info of interest about Penpot</p>
<p>Take a tour of Penpot's main areas</p>
</a>
</li>
<li>
@@ -28,7 +28,7 @@ desc: Begin with the Penpot user guide! Get quickstarts, shortcuts, and tutorial
<li>
<a href="/user-guide/first-steps/info">
<h2>Tutorials & info →</h2>
<p>Info of interest about Penpot</p>
<p>Useful resources to better understand Penpot</p>
</a>
</li>
</ul>

View File

@@ -22,49 +22,49 @@ eleventyNavigation:
<li>
<a href="/user-guide/designing/layers/">
<h2>Layers</h2>
<p>Ways to start with Penpot</p>
<p>Objects available in Penpot and how to get the most of them</p>
</a>
</li>
<li>
<a href="/user-guide/designing/flexible-layouts/">
<h2>Flexible layouts</h2>
<p>Create designs that adapt automatically.</p>
<p>Create designs that adapt automatically</p>
</a>
</li>
<li>
<a href="/user-guide/design-systems/components/">
<h2>Components</h2>
<p>Ways to start with Penpot</p>
<p>Speed your design workflow with reusable components</p>
</a>
</li>
<li>
<a href="/user-guide/design-systems/variants/">
<h2>Variants</h2>
<p>Penpot's main areas and features</p>
<p>Group components into a single, customizable one</p>
</a>
</li>
<li>
<a href="/user-guide/design-systems/design-tokens/">
<h2>Design Tokens</h2>
<p>Penpot's main areas and features</p>
<p>Synchronize visual elements across your designs</p>
</a>
</li>
<li>
<a href="/user-guide/dev-tools/#inspect-design">
<h2>Inspect design</h2>
<p>Ways to start with Penpot</p>
<p>Get production-ready code</p>
</a>
</li>
<li>
<a href="/user-guide/prototyping-testing/prototyping/">
<h2>Prototyping</h2>
<p>Ways to start with Penpot</p>
<p>Build interactive prototypes to mimic your product behaviour</p>
</a>
</li>
<li>
<a href="/user-guide/design-systems/libraries/">
<h2>Libraries</h2>
<p>Ways to start with Penpot</p>
<p>Organize and manage your stored elements with Libraries</p>
</a>
</li>
</ul>

View File

@@ -10,13 +10,13 @@ desc: Begin with the Penpot user guide! Get quickstarts, shortcuts, and tutorial
<li>
<a href="/user-guide/prototyping-testing/prototyping">
<h2>Prototyping →</h2>
<p>Ways to start with Penpot</p>
<p>Build interactive prototypes to mimic your product behaviour</p>
</a>
</li>
<li>
<a href="/user-guide/prototyping-testing/testing-view-mode">
<h2>Testing: View mode →</h2>
<p>Info of interest about Penpot</p>
<p>Test your designs and play the interactions</p>
</a>
</li>
</ul>

View File

@@ -18,4 +18,15 @@ cp ../.yarnrc.yml target/;
cp yarn.lock target/;
cp package.json target/;
cat <<EOF | tee target/setup
#/usr/bin/env bash
set -e;
corepack enable;
corepack install;
yarn install
yarn run playwright install chromium;
EOF
chmod +x target/setup;
sed -i -re "s/\%version\%/$CURRENT_VERSION/g" ./target/app.js;

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

View File

@@ -67,7 +67,7 @@
[]
(let [uagent (new ua/UAParser)]
(merge
{:app-version (:full cf/version)
{:version (:full cf/version)
:locale @i18n/locale}
(let [browser (.getBrowser uagent)]
{:browser (obj/get browser "name")

View File

@@ -20,7 +20,9 @@
[app.common.path-names :as cpn]
[app.common.transit :as t]
[app.common.types.component :as ctc]
[app.common.types.components-list :as ctkl]
[app.common.types.shape :as cts]
[app.common.types.variant :as ctv]
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.comments :as dcmt]
@@ -551,7 +553,6 @@
component-id (:component-id shape)
undo-id (js/Symbol)]
(when valid?
(if (ctc/is-variant-container? shape)
;; Rename the full variant when it is a variant container
@@ -566,6 +567,43 @@
(dwl/rename-component component-id clean-name))
(dwu/commit-undo-transaction undo-id))))))))))
(defn rename-shape-or-variant
([id name]
(rename-shape-or-variant nil nil id name))
([file-id page-id id name]
(ptk/reify ::rename-shape-or-variant
ptk/WatchEvent
(watch [_ state _]
(let [file-id (d/nilv file-id (:current-file-id state))
page-id (d/nilv page-id (:current-page-id state))
file-data (dsh/lookup-file-data state file-id)
shape
(-> (dsh/lookup-page-objects state file-id page-id)
(get id))
is-variant? (ctc/is-variant? shape)
variant-id (when is-variant? (:variant-id shape))
variant-name (when is-variant? (:variant-name shape))
component-id (:component-id shape)
component (ctkl/get-component file-data (:component-id shape))
variant-properties (:variant-properties component)]
(cond
(and variant-name (ctv/valid-properties-formula? name))
(rx/of (dwva/update-properties-names-and-values
component-id variant-id variant-properties (ctv/properties-formula->map name))
(dwva/remove-empty-properties variant-id)
(dwva/update-error component-id))
variant-name
(rx/of (dwva/update-properties-names-and-values
component-id variant-id variant-properties {})
(dwva/remove-empty-properties variant-id)
(dwva/update-error component-id name))
:else
(rx/of (end-rename-shape id name))))))))
;; --- Update Selected Shapes attrs
(defn update-selected-shapes

View File

@@ -128,14 +128,16 @@
related-components (cfv/find-variant-components data objects variant-id)
props (-> related-components last :variant-properties)
prop-name (-> props (nth pos) :name)
valid-pos? (> (count props) pos)
prop-name (when valid-pos? (-> props (nth pos) :name))
changes (-> (pcb/empty-changes it page-id)
(pcb/with-objects objects)
(pcb/with-library-data data)
(clvp/generate-update-property-name variant-id pos new-name))
changes (when valid-pos?
(-> (pcb/empty-changes it page-id)
(pcb/with-objects objects)
(pcb/with-library-data data)
(clvp/generate-update-property-name variant-id pos new-name)))
undo-id (js/Symbol)]
(when (not= prop-name new-name)
(when (and valid-pos? (not= prop-name new-name))
(rx/of
(dwu/start-undo-transaction undo-id)
(dch/commit-changes changes)

View File

@@ -14,6 +14,7 @@
[app.main.ui.components.dropdown :refer [dropdown-content*]]
[app.main.ui.icons :as deprecated-icon]
[app.util.dom :as dom]
[app.util.globals :as ug]
[app.util.i18n :as i18n :refer [tr]]
[app.util.keyboard :as kbd]
[app.util.timers :as tm]
@@ -53,14 +54,13 @@
(def ^:private valid-option?
(sm/lazy-validator schema:option))
(mf/defc context-menu*
[{:keys [show on-close options selectable selected
(mf/defc context-menu-inner*
[{:keys [on-close options selectable selected
top left fixed min-width origin width]
:as props}]
(assert (every? valid-option? options) "expected valid options")
(assert (fn? on-close) "missing `on-close` prop")
(assert (boolean? show) "missing `show` prop")
(assert (vector? options) "missing `options` prop")
(let [width (d/nilv width "initial")
@@ -80,14 +80,15 @@
offset-x (get state :offset-x)
offset-y (get state :offset-y)
levels (get state :levels)
internal-id (mf/use-id)
on-local-close
(mf/use-fn
(mf/deps on-close)
(fn []
(swap! state* assoc :levels [{:parent nil
:options options}])
(on-close)))
(swap! state* assoc :levels [{:parent nil :options options}])
(when (fn? on-close)
(on-close))))
props
(mf/spread-props props {:on-close on-local-close})
@@ -216,11 +217,22 @@
(swap! state* assoc :levels [{:parent nil
:options options}]))
(mf/with-effect [internal-id]
(ug/dispatch! (ug/event "penpot:context-menu:open" #js {:id internal-id})))
(mf/with-effect [internal-id on-local-close]
(letfn [(on-event [event]
(when-let [detail (unchecked-get event "detail")]
(when (not= internal-id (unchecked-get detail "id"))
(on-local-close event))))]
(ug/listen "penpot:context-menu:open" on-event)
(partial ug/unlisten "penpot:context-menu:open" on-event)))
(mf/with-effect [ids]
(tm/schedule-on-idle
#(dom/focus! (dom/get-element (first ids)))))
(when (and show (some? levels))
(when (some? levels)
[:> dropdown-content* props
(let [level (peek levels)
options (:options level)
@@ -229,7 +241,7 @@
[:div {:class (stl/css-case
:is-selectable selectable
:context-menu true
:is-open show
:is-open true
:fixed fixed)
:style {:top (+ top offset-y)
:left (+ left offset-x)}
@@ -241,7 +253,7 @@
:role "menu"
:ref check-menu-offscreen}
(when-let [parent (:parent level)]
(when parent
[:*
[:li {:id "go-back-sub-option"
:class (stl/css :context-menu-item)
@@ -256,7 +268,7 @@
[:li {:class (stl/css :separator)}]])
(for [[index option] (d/enumerate (:options level))]
(for [[index option] (d/enumerate options)]
(let [name (:name option)
id (:id option)
sub-options (:options option)
@@ -297,3 +309,12 @@
:data-testid id}
name
[:span {:class (stl/css :submenu-icon)} deprecated-icon/arrow]])]))))]])])))
(mf/defc context-menu*
{::mf/private true}
[{:keys [show] :as props}]
(assert (boolean? show) "expected `show` prop to be a boolean")
(when ^boolean show
[:> context-menu-inner* props]))

View File

@@ -151,14 +151,16 @@
(mf/defc menu-team-icon*
[{:keys [subscription-type]}]
[:span {:class (stl/css :subscription-icon)
:title (if (= subscription-type "unlimited")
(tr "subscription.dashboard.power-up.unlimited-plan")
(tr "subscription.dashboard.power-up.enterprise-plan"))
:data-testid "subscription-icon"}
(case subscription-type
"unlimited" i/character-u
"enterprise" i/character-e)])
[:span {:class (stl/css :subscription-icon-wrapper)}
[:> icon* {:icon-id (case subscription-type
"unlimited" i/character-u
"enterprise" i/character-e)
:class (stl/css :subscription-icon)
:size "s"
:title (if (= subscription-type "unlimited")
(tr "subscription.dashboard.power-up.unlimited-plan")
(tr "subscription.dashboard.power-up.enterprise-plan"))
:data-testid "subscription-icon"}]])
(mf/defc main-menu-power-up*
[{:keys [close-sub-menu]}]

View File

@@ -144,20 +144,20 @@
padding: 0;
}
.subscription-icon {
@extend .button-icon;
.subscription-icon-wrapper {
display: flex;
justify-content: center;
align-items: center;
background: var(--color-background-primary);
stroke: var(--color-foreground-secondary);
border-radius: 6px;
border-radius: $br-6;
border: 1.75px solid var(--color-foreground-secondary);
stroke-width: 2.25px;
width: var(--sp-xl);
height: var(--sp-xl);
block-size: var(--sp-xl);
inline-size: var(--sp-xl);
}
svg {
block-size: var(--sp-m);
inline-size: var(--sp-m);
}
.subscription-icon {
stroke: var(--color-foreground-secondary);
stroke-width: 2.25px;
}
.menu-item {

View File

@@ -106,14 +106,14 @@
(when (not= 0 count-libraries)
(if (pos? (count references))
[:*
[:div
(when (and (string? scd-msg) (not= scd-msg ""))
[:h3 {:class (stl/css :modal-scd-msg)} scd-msg])
[:ul {:class (stl/css :element-list)}
(for [[file-id file-name] references]
[:li {:class (stl/css :list-item)
:key (dm/str file-id)}
[:span "- " file-name]])]]
(when (and (string? scd-msg) (not= scd-msg ""))
[:p {:class (stl/css :modal-scd-msg)} scd-msg])
[:ul {:class (stl/css :element-list)}
(for [[file-id file-name] references]
[:li {:class (stl/css :list-item)
:key (dm/str file-id)}
[:span "- " file-name]])]
(when (and (string? hint) (not= hint ""))
[:> context-notification* {:level :info
:appearance :ghost}

View File

@@ -4,7 +4,8 @@
//
// Copyright (c) KALEIDOS INC
@use "refactor/common-refactor.scss" as deprecated;
@use "refactor/basic-rules.scss" as *;
@use "ds/typography.scss" as t;
.modal-overlay {
@extend .modal-overlay-base;
@@ -15,14 +16,19 @@
.modal-container {
@extend .modal-container-base;
display: grid;
gap: var(--sp-xxl);
grid-template-rows: auto minmax(0, 1fr) auto;
}
.modal-header {
margin-bottom: deprecated.$s-24;
.list-wrapper {
display: grid;
grid-template-rows: auto 1fr auto;
max-height: 100%;
}
.modal-title {
@include deprecated.headlineMediumTypography;
@include t.use-typography("headline-medium");
color: var(--modal-title-foreground-color);
}
@@ -31,13 +37,16 @@
}
.modal-content {
@include deprecated.bodySmallTypography;
margin-bottom: deprecated.$s-24;
@include t.use-typography("body-small");
display: grid;
gap: var(--sp-s);
}
.element-list {
@include deprecated.bodyLargeTypography;
@include t.use-typography("body-large");
color: var(--modal-text-foreground-color);
overflow-y: scroll;
margin-block: 0;
}
.action-buttons {
@@ -55,10 +64,14 @@
}
}
.modal-scd-msg {
margin-block: 0;
}
.modal-scd-msg,
.modal-subtitle,
.modal-msg {
@include deprecated.bodyLargeTypography;
@include t.use-typography("body-large");
color: var(--modal-text-foreground-color);
line-height: 1.5;
}

View File

@@ -173,7 +173,7 @@
[:id {:optional true} :string]
[:offset {:optional true} :int]
[:delay {:optional true} :int]
[:content [:or fn? :string]]
[:content [:or fn? :string map?]]
[:placement {:optional true}
[:maybe [:enum "top" "bottom" "left" "right" "top-right" "bottom-right" "bottom-left" "top-left"]]]])

View File

@@ -14,7 +14,6 @@
padding-bottom: deprecated.$s-16;
overflow-y: auto;
overflow-x: hidden;
scrollbar-gutter: stable;
padding-inline: var(--sp-m);
}

View File

@@ -30,8 +30,8 @@
.tool-windows {
block-size: 100%;
display: flex;
flex-direction: column;
display: grid;
grid-template-rows: auto 1fr;
gap: var(--sp-s);
}
@@ -150,7 +150,6 @@
}
.inspect-content {
flex: 1;
overflow: hidden;
}
@@ -158,6 +157,5 @@
--tabs-nav-padding-inline-start: 0;
--tabs-nav-padding-inline-end: var(--sp-m);
block-size: calc(100vh - px2rem(200)); // TODO: Fix this hardcoded value
overflow: auto;
}

View File

@@ -0,0 +1,11 @@
// 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/_utils.scss" as *;
.styles-tab {
block-size: calc(100vh - px2rem(200)); // TODO: Fix this hardcoded value
}

View File

@@ -6,6 +6,15 @@
@use "ds/typography.scss" as *;
// TODO: this must be a custom property in the design system
:global(.light) {
--low-emphasis-background: #fafafa;
}
:global(.default) {
--low-emphasis-background: #121214;
}
.style-box {
--title-gap: var(--sp-xs);
--title-padding: var(--sp-s);
@@ -13,12 +22,9 @@
--arrow-color: var(--color-foreground-secondary);
--box-border-color: var(--color-background-primary);
// TODO: this must be a custom property in the design system
--lowEmphasis-background: #121214;
padding-block: var(--sp-s);
padding-inline: var(--sp-m);
background-color: var(--lowEmphasis-background);
background-color: var(--low-emphasis-background);
border-block-end: 2px solid var(--box-border-color);
}

View File

@@ -30,6 +30,7 @@
[app.main.ui.releases.v2-1]
[app.main.ui.releases.v2-10]
[app.main.ui.releases.v2-11]
[app.main.ui.releases.v2-12]
[app.main.ui.releases.v2-2]
[app.main.ui.releases.v2-3]
[app.main.ui.releases.v2-4]
@@ -102,4 +103,4 @@
(defmethod rc/render-release-notes "0.0"
[params]
(rc/render-release-notes (assoc params :version "2.11")))
(rc/render-release-notes (assoc params :version "2.12")))

View File

@@ -0,0 +1,162 @@
;; 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.releases.v2-12
(:require-macros [app.main.style :as stl])
(:require
[app.common.data.macros :as dm]
[app.main.ui.releases.common :as c]
[rumext.v2 :as mf]))
(defmethod c/render-release-notes "2.12"
[{:keys [slide klass next finish navigate version]}]
(mf/html
(case slide
:start
[:div {:class (stl/css-case :modal-overlay true)}
[:div.animated {:class klass}
[:div {:class (stl/css :modal-container)}
[:img {:src "images/features/2.12-slide-0.jpg"
:class (stl/css :start-image)
:border "0"
:alt "Penpot 2.12 is here!"}]
[:div {:class (stl/css :modal-content)}
[:div {:class (stl/css :modal-header)}
[:h1 {:class (stl/css :modal-title)}
"Whats new in Penpot?"]
[:div {:class (stl/css :version-tag)}
(dm/str "Version " version)]]
[:div {:class (stl/css :features-block)}
[:span {:class (stl/css :feature-title)}
"Better tokens visibility and more!"]
[:p {:class (stl/css :feature-content)}
"This release focuses on making your everyday workflow feel clearer, faster and more intuitive. Tokens are now easier to see and apply, appearing directly where you work and giving the designs better context during code inspection. Variants gain a more natural flow thanks to simple boolean toggles that remove friction when switching states. And PDF export becomes more flexible, letting you choose exactly which boards to share so your files match the story you want to tell."]
[:p {:class (stl/css :feature-content)}
"Together, these enhancements bring greater control and fluidity to your entire design process."]
[:p {:class (stl/css :feature-content)}
"Lets dive in!"]]
[:div {:class (stl/css :navigation)}
[:button {:class (stl/css :next-btn)
:on-click next} "Continue"]]]]]]
0
[:div {:class (stl/css-case :modal-overlay true)}
[:div.animated {:class klass}
[:div {:class (stl/css :modal-container)}
[:img {:src "images/features/2.12-tokens-sidebar.gif"
:class (stl/css :start-image)
:border "0"
:alt "Better tokens visibility"}]
[:div {:class (stl/css :modal-content)}
[:div {:class (stl/css :modal-header)}
[:h1 {:class (stl/css :modal-title)}
"Better tokens visibility"]]
[:div {:class (stl/css :feature)}
[:p {:class (stl/css :feature-content)}
"Design systems should be both powerful and effortless to use. This release brings tokens closer to where you work, making them easier to apply and easier to understand."]
[:span {:class (stl/css :feature-title)}
"Apply color tokens right from the sidebar"]
[:p {:class (stl/css :feature-content)}
"Your color tokens now appear directly in the properties sidebar, making it faster to apply or unapply tokens from the design tab. No more digging: now you can use tokens within your design flow."]
[:span {:class (stl/css :feature-title)}
"See token names in the Inspect panel"]
[:p {:class (stl/css :feature-content)}
"Developers now get a clearer context during handoff. The Inspect panel shows the actual token used in your design, in a similar way to how styles are displayed. This small detail reduces ambiguity, aligns everyone on the same language, and strengthens collaboration across the team."]]
[:div {:class (stl/css :navigation)}
[:& c/navigation-bullets
{:slide slide
:navigate navigate
:total 3}]
[:button {:on-click next
:class (stl/css :next-btn)} "Continue"]]]]]]
1
[:div {:class (stl/css-case :modal-overlay true)}
[:div.animated {:class klass}
[:div {:class (stl/css :modal-container)}
[:img {:src "images/features/2.12-variants.gif"
:class (stl/css :start-image)
:border "0"
:alt "Simpler boolean variants"}]
[:div {:class (stl/css :modal-content)}
[:div {:class (stl/css :modal-header)}
[:h1 {:class (stl/css :modal-title)}
"Simpler boolean variants"]]
[:div {:class (stl/css :feature)}
[:p {:class (stl/css :feature-content)}
"Variants are central to building flexible, scalable components. With this release, boolean properties become far easier to work with."]
[:span {:class (stl/css :feature-title)}
"A simple toggle for boolean values"]
[:p {:class (stl/css :feature-content)}
"Binary states now use a clean toggle, to be able to switch visually, instead of a dropdown. This makes adjusting component states more intuitive and speeds up working with multiple instances."]
[:p {:class (stl/css :feature-content)}
"Its a subtle improvement, but it removes friction you feel hundreds of times a week, and makes component work flow more naturally."]]
[:div {:class (stl/css :navigation)}
[:& c/navigation-bullets
{:slide slide
:navigate navigate
:total 3}]
[:button {:on-click next
:class (stl/css :next-btn)} "Continue"]]]]]]
2
[:div {:class (stl/css-case :modal-overlay true)}
[:div.animated {:class klass}
[:div {:class (stl/css :modal-container)}
[:img {:src "images/features/2.12-export-pdf.gif"
:class (stl/css :start-image)
:border "0"
:alt "Smarter PDF export"}]
[:div {:class (stl/css :modal-content)}
[:div {:class (stl/css :modal-header)}
[:h1 {:class (stl/css :modal-title)}
"Smarter PDF export"]]
[:div {:class (stl/css :feature)}
[:p {:class (stl/css :feature-content)}
"Exporting your work is now more precise and flexible."]
[:span {:class (stl/css :feature-title)}
"Select specific boards when exporting"]
[:p {:class (stl/css :feature-content)}
"Youre now in control of which boards make it into your PDF. Share just the final screens, just a flow, just the workshop materials. This streamlined export flow adapts to the way real teams work: share the story you want to tell, with exactly the boards you need."]]
[:div {:class (stl/css :navigation)}
[:& c/navigation-bullets
{:slide slide
:navigate navigate
:total 3}]
[:button {:on-click finish
:class (stl/css :next-btn)} "Let's go"]]]]]])))

View File

@@ -0,0 +1,102 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) KALEIDOS INC
@use "refactor/common-refactor.scss" as deprecated;
.modal-overlay {
@extend .modal-overlay-base;
}
.modal-container {
display: grid;
grid-template-columns: deprecated.$s-324 1fr;
height: deprecated.$s-500;
width: deprecated.$s-888;
border-radius: deprecated.$br-8;
background-color: var(--modal-background-color);
border: deprecated.$s-2 solid var(--modal-border-color);
}
.start-image {
width: deprecated.$s-324;
border-radius: deprecated.$br-8 0 0 deprecated.$br-8;
}
.modal-content {
padding: deprecated.$s-40;
display: grid;
grid-template-rows: auto 1fr deprecated.$s-32;
gap: deprecated.$s-24;
a {
color: var(--button-primary-background-color-rest);
}
}
.modal-header {
display: grid;
gap: deprecated.$s-8;
}
.version-tag {
@include deprecated.flexCenter;
@include deprecated.headlineSmallTypography;
height: deprecated.$s-32;
width: deprecated.$s-96;
background-color: var(--communication-tag-background-color);
color: var(--communication-tag-foreground-color);
border-radius: deprecated.$br-8;
}
.modal-title {
@include deprecated.headlineLargeTypography;
color: var(--modal-title-foreground-color);
}
.features-block {
display: flex;
flex-direction: column;
gap: deprecated.$s-16;
width: deprecated.$s-440;
}
.feature {
display: flex;
flex-direction: column;
gap: deprecated.$s-8;
}
.feature-title {
@include deprecated.bodyLargeTypography;
color: var(--modal-title-foreground-color);
}
.feature-content {
@include deprecated.bodyMediumTypography;
margin: 0;
color: var(--modal-text-foreground-color);
}
.feature-list {
@include deprecated.bodyMediumTypography;
color: var(--modal-text-foreground-color);
list-style: disc;
display: grid;
gap: deprecated.$s-8;
}
.navigation {
width: 100%;
display: grid;
grid-template-areas: "bullets button";
}
.next-btn {
@extend .button-primary;
width: deprecated.$s-100;
justify-self: flex-end;
grid-area: button;
}

View File

@@ -56,9 +56,8 @@
(update file :data dissoc :pages-index))
refs/file))
(mf/defc assets-local-library
{::mf/wrap [mf/memo]
::mf/wrap-props false}
(mf/defc assets-local-library*
{::mf/private true}
[{:keys [filters]}]
(let [file (mf/deref ref:local-library)]
[:> file-library*
@@ -68,7 +67,7 @@
:filters filters}]))
(defn- toggle-values
[v [a b]]
[v a b]
(if (= v a) b a))
(mf/defc assets-toolbox*
@@ -97,7 +96,7 @@
(mf/use-fn
(mf/deps ordering)
(fn []
(let [new-value (toggle-values ordering [:asc :desc])]
(let [new-value (toggle-values ordering :asc :desc)]
(swap! filters* assoc :ordering new-value)
(dwa/set-current-assets-ordering! new-value))))
@@ -105,7 +104,7 @@
(mf/use-fn
(mf/deps list-style)
(fn []
(let [new-value (toggle-values list-style [:thumbs :list])]
(let [new-value (toggle-values list-style :thumbs :list)]
(swap! filters* assoc :list-style new-value)
(dwa/set-current-assets-list-style! new-value))))
@@ -209,5 +208,5 @@
[:& (mf/provider cmm/assets-toggle-ordering) {:value toggle-ordering}
[:& (mf/provider cmm/assets-toggle-list-style) {:value toggle-list-style}
[:*
[:& assets-local-library {:filters filters}]
[:> assets-local-library* {:filters filters}]
[:> assets-libraries* {:filters filters}]]]]]]))

View File

@@ -15,7 +15,7 @@
cursor: pointer;
.title-menu {
display: block;
visibility: visible;
}
}
}
@@ -25,7 +25,7 @@
}
.title-menu {
display: none;
visibility: hidden;
}
.group-title {

View File

@@ -11,7 +11,6 @@
[app.common.data.macros :as dm]
[app.common.types.variant :as ctv]
[app.main.data.workspace :as dw]
[app.main.data.workspace.variants :as dwv]
[app.main.store :as st]
[app.util.debug :as dbg]
[app.util.dom :as dom]
@@ -69,15 +68,7 @@
name (str/trim (dom/get-value name-input))]
(on-stop-edit)
(reset! edition* false)
(if variant-name
(if (ctv/valid-properties-formula? name)
(st/emit! (dwv/update-properties-names-and-values component-id variant-id variant-properties (ctv/properties-formula->map name))
(dwv/remove-empty-properties variant-id)
(dwv/update-error component-id))
(st/emit! (dwv/update-properties-names-and-values component-id variant-id variant-properties {})
(dwv/remove-empty-properties variant-id)
(dwv/update-error component-id name)))
(st/emit! (dw/end-rename-shape shape-id name))))))
(st/emit! (dw/rename-shape-or-variant shape-id name)))))
cancel-edit
(mf/use-fn

View File

@@ -687,7 +687,7 @@
(str/upper (tr "workspace.assets.local-library"))
(dm/get-in libraries [current-library-id :name]))
current-lib-data (mf/with-memo [libraries]
current-lib-data (mf/with-memo [libraries current-library-id]
(get-in libraries [current-library-id :data]))
current-lib-counts (mf/with-memo [current-lib-data]

View File

@@ -149,9 +149,9 @@
canvas-ref (mf/use-ref nil)
;; VARS
disable-paste (mf/use-var false)
in-viewport? (mf/use-var false)
;; STATE REFS
disable-paste-ref (mf/use-ref false)
in-viewport-ref (mf/use-ref false)
;; STREAMS
move-stream (mf/use-memo #(rx/subject))
@@ -210,10 +210,10 @@
on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? path-editing? grid-editing?
path-drawing? create-comment? space? panning z? read-only?)
on-pointer-up (actions/on-pointer-up disable-paste)
on-pointer-up (actions/on-pointer-up disable-paste-ref)
on-pointer-enter (actions/on-pointer-enter in-viewport?)
on-pointer-leave (actions/on-pointer-leave in-viewport?)
on-pointer-enter (actions/on-pointer-enter in-viewport-ref)
on-pointer-leave (actions/on-pointer-leave in-viewport-ref)
on-pointer-move (actions/on-pointer-move move-stream)
on-move-selected (actions/on-move-selected hover hover-ids selected space? z? read-only?)
on-menu-selected (actions/on-menu-selected hover hover-ids selected read-only?)
@@ -304,7 +304,7 @@
#(st/emit!
(dwv/add-new-variant (:id first-shape))))]
(hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool path-drawing?)
(hooks/setup-dom-events zoom disable-paste-ref in-viewport-ref read-only? drawing-tool path-drawing?)
(hooks/setup-viewport-size vport viewport-ref)
(hooks/setup-cursor cursor alt? mod? space? panning drawing-tool path-drawing? path-editing? z? read-only?)
(hooks/setup-keyboard alt? mod? space? z? shift?)

View File

@@ -266,7 +266,7 @@
(st/emit! (dw/show-shape-context-menu {:position position :hover-ids @hover-ids})))))))
(defn on-pointer-up
[disable-paste]
[disable-paste-ref]
(mf/use-callback
(fn [event]
(dom/stop-propagation event)
@@ -291,21 +291,19 @@
(dom/prevent-default event)
;; We store this so in Firefox the middle button won't do a paste of the content
(reset! disable-paste true)
(ts/schedule #(reset! disable-paste false)))
(mf/set-ref-val! disable-paste-ref true)
(ts/schedule #(mf/set-ref-val! disable-paste-ref false)))
(st/emit! (dw/finish-panning)
(dw/finish-zooming))))))
(defn on-pointer-enter [in-viewport?]
(mf/use-callback
(fn []
(reset! in-viewport? true))))
(defn on-pointer-enter
[in-viewport-ref]
(mf/use-fn #(mf/set-ref-val! in-viewport-ref true)))
(defn on-pointer-leave [in-viewport?]
(mf/use-callback
(fn []
(reset! in-viewport? false))))
(defn on-pointer-leave
[in-viewport-ref]
(mf/use-fn #(mf/set-ref-val! in-viewport-ref false)))
(defn on-key-down []
(mf/use-callback
@@ -524,15 +522,22 @@
:blobs (seq files)}]
(st/emit! (dwm/upload-media-workspace params))))))))
(def ^:private invalid-paste-targets
#{"INPUT" "TEXTAREA"})
(defn on-paste
[disable-paste in-viewport? read-only?]
[disable-paste-ref in-viewport-ref read-only?]
(mf/use-fn
(mf/deps read-only?)
(fn [event]
;; We disable the paste just after mouse-up of a middle button so
;; when panning won't paste the content into the workspace
(let [tag-name (-> event dom/get-target dom/get-tag-name)]
(when (and (not (#{"INPUT" "TEXTAREA"} tag-name))
(not @disable-paste)
;; We disable the paste when: 1. just after mouse-up of a middle
;; button (so when panning won't paste the content into the
;; workspace); 2. when we paste content in an input on the
;; sidebar
(let [tag-name (-> event dom/get-target dom/get-tag-name)
disable-paste? (mf/ref-val disable-paste-ref)
in-viewport? (mf/ref-val in-viewport-ref)]
(when (and (not (contains? invalid-paste-targets tag-name))
(not disable-paste?)
(not read-only?))
(st/emit! (dw/paste-from-event event @in-viewport?)))))))
(st/emit! (dw/paste-from-event event in-viewport?)))))))

View File

@@ -42,11 +42,12 @@
[rumext.v2 :as mf])
(:import goog.events.EventType))
(defn setup-dom-events [zoom disable-paste in-viewport? workspace-read-only? drawing-tool drawing-path?]
(defn setup-dom-events
[zoom disable-paste-ref in-viewport-ref workspace-read-only? drawing-tool drawing-path?]
(let [on-key-down (actions/on-key-down)
on-key-up (actions/on-key-up)
on-mouse-wheel (actions/on-mouse-wheel zoom)
on-paste (actions/on-paste disable-paste in-viewport? workspace-read-only?)
on-paste (actions/on-paste disable-paste-ref in-viewport-ref workspace-read-only?)
on-pointer-down (mf/use-fn
(mf/deps drawing-tool drawing-path?)
(fn [e]
@@ -56,27 +57,27 @@
(st/emit! (dwe/clear-edition-mode))))))
on-blur (mf/use-fn #(st/emit! (mse/->BlurEvent)))]
(mf/use-effect
(mf/deps drawing-tool drawing-path?)
(fn []
(let [keys [(events/listen js/window EventType.POINTERDOWN on-pointer-down)]]
(fn []
(doseq [key keys]
(events/unlistenByKey key))))))
(mf/with-effect [drawing-tool drawing-path?]
(let [key (events/listen js/window EventType.POINTERDOWN on-pointer-down)]
(mf/use-layout-effect
(mf/deps on-key-down on-key-up on-mouse-wheel on-paste workspace-read-only?)
(fn []
(let [keys [(events/listen js/document EventType.KEYDOWN on-key-down)
(events/listen js/document EventType.KEYUP on-key-up)
;; bind with passive=false to allow the event to be cancelled
;; https://stackoverflow.com/a/57582286/3219895
(events/listen js/window EventType.WHEEL on-mouse-wheel #js {:passive false})
(events/listen js/window EventType.PASTE on-paste)
(events/listen js/window EventType.BLUR on-blur)]]
(fn []
(doseq [key keys]
(events/unlistenByKey key))))))))
;; We need to disable workspace paste when we on comments
(if (= drawing-tool :comments)
(mf/set-ref-val! disable-paste-ref true)
(mf/set-ref-val! disable-paste-ref false))
#(events/unlistenByKey key)))
(mf/with-layout-effect [on-key-down on-key-up on-mouse-wheel on-paste workspace-read-only?]
(let [keys [(events/listen js/document EventType.KEYDOWN on-key-down)
(events/listen js/document EventType.KEYUP on-key-up)
;; bind with passive=false to allow the event to be cancelled
;; https://stackoverflow.com/a/57582286/3219895
(events/listen js/window EventType.WHEEL on-mouse-wheel #js {:passive false})
(events/listen js/window EventType.PASTE on-paste)
(events/listen js/window EventType.BLUR on-blur)]]
(fn []
(doseq [key keys]
(events/unlistenByKey key)))))))
(defn setup-viewport-size [vport viewport-ref]
(mf/with-effect [vport]

View File

@@ -138,9 +138,9 @@
canvas-ref (mf/use-ref nil)
text-editor-ref (mf/use-ref nil)
;; VARS
disable-paste (mf/use-var false)
in-viewport? (mf/use-var false)
;; STATE REFS
disable-paste-ref (mf/use-ref false)
in-viewport-ref (mf/use-ref false)
;; STREAMS
move-stream (mf/use-memo #(rx/subject))
@@ -200,10 +200,10 @@
on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? path-editing? grid-editing?
path-drawing? create-comment? space? panning z? read-only?)
on-pointer-up (actions/on-pointer-up disable-paste)
on-pointer-up (actions/on-pointer-up disable-paste-ref)
on-pointer-enter (actions/on-pointer-enter in-viewport?)
on-pointer-leave (actions/on-pointer-leave in-viewport?)
on-pointer-enter (actions/on-pointer-enter in-viewport-ref)
on-pointer-leave (actions/on-pointer-leave in-viewport-ref)
on-pointer-move (actions/on-pointer-move move-stream)
on-move-selected (actions/on-move-selected hover hover-ids selected space? z? read-only?)
on-menu-selected (actions/on-menu-selected hover hover-ids selected read-only?)
@@ -345,7 +345,7 @@
(wasm.api/show-grid @hover-top-frame-id)
(wasm.api/clear-grid))))
(hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool path-drawing?)
(hooks/setup-dom-events zoom disable-paste-ref in-viewport-ref read-only? drawing-tool path-drawing?)
(hooks/setup-viewport-size vport viewport-ref)
(hooks/setup-cursor cursor alt? mod? space? panning drawing-tool path-drawing? path-editing? z? read-only?)
(hooks/setup-keyboard alt? mod? space? z? shift?)

View File

@@ -901,10 +901,10 @@
(fn [pos value]
(cond
(not (nat-int? pos))
(u/display-not-valid :pos pos)
(u/display-not-valid :pos (str pos))
(not (string? name))
(u/display-not-valid :name name)
(not (string? value))
(u/display-not-valid :name value)
:else
(st/emit!

View File

@@ -218,7 +218,7 @@
(u/display-not-valid :name value)
:else
(st/emit! (dw/end-rename-shape id value)))))}
(st/emit! (dw/rename-shape-or-variant file-id page-id id value)))))}
:blocked
{:this true

View File

@@ -57,10 +57,11 @@
(= (dom/get-tag-name target) "INPUT")]
;; ignore when pasting into an editable control
(when-not (or content-editable? is-input?)
(if-not (or content-editable? is-input?)
(-> event
(dom/event->browser-event)
(from-clipboard-event options))))))
(from-clipboard-event options))
(rx/empty)))))
(defn from-drop-event
"Get clipboard stream from drop event"

View File

@@ -35,14 +35,26 @@ goog.scope(function () {
};
}
self.event = function(...args) {
return new CustomEvent(...args);
self.event = function(name, detail) {
const options = {};
if (detail !== undefined) {
options.detail = detail;
}
return new CustomEvent(name, options);
};
self.dispatch_BANG_ = function(...args) {
self.document.dispatchEvent(...args);
};
self.listen = function(...args) {
self.document.addEventListener(...args);
};
self.unlisten = function(...args) {
self.document.removeEventListener(...args);
}
self.window = (function () {
if (typeof goog.global.window !== "undefined") {
return goog.global.window;

View File

@@ -392,7 +392,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"els fitxers amb biblioteques compartides sinclouran a lexportació, "
"Els fitxers amb biblioteques compartides sinclouran a lexportació, "
"mantenint la vinculació."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -542,7 +542,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"soubory se sdílenými knihovnami budou zahrnuty do exportu, čímž se zachová "
"Soubory se sdílenými knihovnami budou zahrnuty do exportu, čímž se zachová "
"jejich propojení."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -576,7 +576,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"files with shared libraries will be included in the export, maintaining "
"Files with shared libraries will be included in the export, maintaining "
"their linkage."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -585,7 +585,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"ficheros con librerias compartidas se inclurán en el paquete de exportación "
"Ficheros con librerias compartidas se inclurán en el paquete de exportación "
"y mantendrán los enlaces."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -370,7 +370,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"partekatutako liburutegiak dituzten fitxategiak esportazio paketean sartuko "
"Partekatutako liburutegiak dituzten fitxategiak esportazio paketean sartuko "
"dira eta loturak mantenduko dituzte."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -368,7 +368,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"os ficheiros con bibliotecas compartidas incluiranse na exportación "
"Os ficheiros con bibliotecas compartidas incluiranse na exportación "
"mantendo os vínculos."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -430,7 +430,7 @@ msgstr "za ka iya fitar da kundi daya ko fiye ta hanyar tura taska. \"me \"*?"
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr "manhajar tura kundi ta kunshi fitarwa, tattali mahaxarsu."
msgstr "Manhajar tura kundi ta kunshi fitarwa, tattali mahaxarsu."
#: src/app/main/ui/exports/files.cljs:165
msgid "dashboard.export.options.all.title"

View File

@@ -541,7 +541,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"datoteke sa zajedničkim bibliotekama bit će uključene u izvoz, održavajući "
"Datoteke sa zajedničkim bibliotekama bit će uključene u izvoz, održavajući "
"njihovu poveznicu."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -573,7 +573,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr "berkas dengan pustaka bersama akan dimasukkan dalam hasil ekspor."
msgstr "Berkas dengan pustaka bersama akan dimasukkan dalam hasil ekspor."
#: src/app/main/ui/exports/files.cljs:165
msgid "dashboard.export.options.all.title"

View File

@@ -346,7 +346,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"failai su bendromis bibliotekomis bus įtraukti į eksportą, išlaikant jų "
"Failai su bendromis bibliotekomis bus įtraukti į eksportą, išlaikant jų "
"susiejimą."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -584,7 +584,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"izguvē tiks iekļautas datnes ar koplietojamām bibliotēkām, saglabājot to "
"Izguvē tiks iekļautas datnes ar koplietojamām bibliotēkām, saglabājot to "
"sasaisti."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -438,7 +438,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"fail dengan perpustakaan kongsi akan disertakan dalam eksport, mengekalkan "
"Fail dengan perpustakaan kongsi akan disertakan dalam eksport, mengekalkan "
"hubungannya."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -372,7 +372,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"pliki z bibliotekami współdzielonymi zostaną uwzględnione w eksporcie, z "
"Pliki z bibliotekami współdzielonymi zostaną uwzględnione w eksporcie, z "
"zachowaniem ich powiązania."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -581,7 +581,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"arquivos com bibliotecas compartilhadas serão incluídos na exportação, "
"Arquivos com bibliotecas compartilhadas serão incluídos na exportação, "
"mantendo seu vínculo."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -555,7 +555,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"ficheiros com bibliotecas partilhadas serão incluídos na exportação, "
"Ficheiros com bibliotecas partilhadas serão incluídos na exportação, "
"mantendo as ligações."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -590,7 +590,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"fișierele cu biblioteci partajate vor fi incluse în export, menținându-le "
"Fișierele cu biblioteci partajate vor fi incluse în export, menținându-le "
"legătura."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -491,7 +491,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"датотеке са дељеним библиотекама ће бити укључене у извоз, одржавајући "
"Датотеке са дељеним библиотекама ће бити укључене у извоз, одржавајући "
"њихову повезаност."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -582,7 +582,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"filer med delade bibliotek kommer att ingå i exporten, bibehåller deras "
"Filer med delade bibliotek kommer att ingå i exporten, bibehåller deras "
"koppling."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -583,7 +583,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"paylaşılan kütüphanelere sahip dosyalar, bağlantılarını koruyarak dışarı "
"Paylaşılan kütüphanelere sahip dosyalar, bağlantılarını koruyarak dışarı "
"aktarmaya dahil edilecek."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -577,7 +577,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message"
msgstr ""
"файли з спільними бібліотеками буде додано до експорту зі збереженням "
"Файли з спільними бібліотеками буде додано до експорту зі збереженням "
"зв'язків між ними."
#: src/app/main/ui/exports/files.cljs:165

View File

@@ -19,7 +19,7 @@ set -e
ARCH=$(uname -m)
if [[ "$ARCH" == "x86_64" || "$ARCH" == "i386" || "$ARCH" == "i686" ]]; then
if [[ "$ARCH" == "x86_64" || "$ARCH" == "amd64" || "$ARCH" == "i386" || "$ARCH" == "i686" ]]; then
ARCH="amd64"
elif [[ "$ARCH" == "aarch64" || "$ARCH" == "arm64" ]]; then
ARCH="arm64"

View File

@@ -2,7 +2,7 @@
set -ex
cljfmt --parallel=true \
cljfmt --parallel=true fix \
common/src/ \
common/test/ \
frontend/src/ \