diff --git a/CHANGES.md b/CHANGES.md
index 2f0dbac7d3..5631282a05 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -11,6 +11,7 @@
### :sparkles: New features
- New gradients UI with multi-stop support.
+- Shareable link pointing to an specific board.
### :bug: Bugs fixed
@@ -46,6 +47,8 @@
### :bug: Bugs fixed
- Fix problem with some texts desynchronization [Taiga #9379](https://tree.taiga.io/project/penpot/issue/9379)
+- Fix problem with reoder grid layers [#5446](https://github.com/penpot/penpot/issues/5446)
+- Fix problem with swap component style [#9542](https://tree.taiga.io/project/penpot/issue/9542)
## 2.3.3
diff --git a/backend/resources/app/email/comment-mention/en.html b/backend/resources/app/email/comment-mention/en.html
new file mode 100644
index 0000000000..fa45cab25e
--- /dev/null
+++ b/backend/resources/app/email/comment-mention/en.html
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+ Hello {{name|abbreviate:25}}!
+ |
+
+
+ |
+
+ {{ source-user }} has mentioned you on a comment at "{{ comment-reference }}".
+ |
+
+
+ |
+
+ {{ comment-content }}
+
+ |
+
+
+ |
+
+ |
+
+
+ |
+
+ The Penpot team.
+ |
+
+
+
+
+ |
+
+
+
+
+
+ {% include "app/email/includes/footer.html" %}
+
+
+
+
+
diff --git a/backend/resources/app/email/comment-mention/en.subj b/backend/resources/app/email/comment-mention/en.subj
new file mode 100644
index 0000000000..c3f027d5d5
--- /dev/null
+++ b/backend/resources/app/email/comment-mention/en.subj
@@ -0,0 +1 @@
+Mentioned in comment
diff --git a/backend/resources/app/email/comment-mention/en.txt b/backend/resources/app/email/comment-mention/en.txt
new file mode 100644
index 0000000000..32a15a4d58
--- /dev/null
+++ b/backend/resources/app/email/comment-mention/en.txt
@@ -0,0 +1,13 @@
+Hello {{name|abbreviate:25}}!
+
+{{ source-user }} has mentioned you on a comment at "{{ comment-reference }}".
+
+--
+
+{{ comment-content }}
+
+--
+
+{{ comment-url }}
+
+The Penpot team.
diff --git a/backend/resources/app/email/comment-notification/en.html b/backend/resources/app/email/comment-notification/en.html
new file mode 100644
index 0000000000..595c6b53da
--- /dev/null
+++ b/backend/resources/app/email/comment-notification/en.html
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+ Hello {{name|abbreviate:25}}!
+ |
+
+
+ |
+
+ {{ source-user }} has commented at "{{ comment-reference }}".
+ |
+
+
+ |
+
+ {{ comment-content }}
+
+ |
+
+
+ |
+
+ |
+
+
+ |
+
+ The Penpot team.
+ |
+
+
+
+
+ |
+
+
+
+
+
+ {% include "app/email/includes/footer.html" %}
+
+
+
+
+
diff --git a/backend/resources/app/email/comment-notification/en.subj b/backend/resources/app/email/comment-notification/en.subj
new file mode 100644
index 0000000000..94a261f310
--- /dev/null
+++ b/backend/resources/app/email/comment-notification/en.subj
@@ -0,0 +1 @@
+New comment
diff --git a/backend/resources/app/email/comment-notification/en.txt b/backend/resources/app/email/comment-notification/en.txt
new file mode 100644
index 0000000000..166ffc14bb
--- /dev/null
+++ b/backend/resources/app/email/comment-notification/en.txt
@@ -0,0 +1,13 @@
+Hello {{name|abbreviate:25}}!
+
+{{ source-user }} has commented at "{{ comment-reference }}".
+
+--
+
+{{ comment-content }}
+
+--
+
+{{ comment-url }}
+
+The Penpot team.
diff --git a/backend/resources/app/email/comment-thread/en.html b/backend/resources/app/email/comment-thread/en.html
new file mode 100644
index 0000000000..8676a35291
--- /dev/null
+++ b/backend/resources/app/email/comment-thread/en.html
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+ Hello {{name|abbreviate:25}}!
+ |
+
+
+ |
+
+ {{ source-user }} has created a comment in a thread you've been mentioned at "{{ comment-reference }}".
+ |
+
+
+ |
+
+ {{ comment-content }}
+
+ |
+
+
+ |
+
+ |
+
+
+ |
+
+ The Penpot team.
+ |
+
+
+
+
+ |
+
+
+
+
+
+ {% include "app/email/includes/footer.html" %}
+
+
+
+
+
diff --git a/backend/resources/app/email/comment-thread/en.subj b/backend/resources/app/email/comment-thread/en.subj
new file mode 100644
index 0000000000..5477605728
--- /dev/null
+++ b/backend/resources/app/email/comment-thread/en.subj
@@ -0,0 +1 @@
+New response in comment
diff --git a/backend/resources/app/email/comment-thread/en.txt b/backend/resources/app/email/comment-thread/en.txt
new file mode 100644
index 0000000000..52d79de54c
--- /dev/null
+++ b/backend/resources/app/email/comment-thread/en.txt
@@ -0,0 +1,13 @@
+Hello {{name|abbreviate:25}}!
+
+{{ source-user }} has created a comment in a thread you've been mentioned at "{{ comment-reference }}".
+
+--
+
+{{ comment-content }}
+
+--
+
+{{ comment-url }}
+
+The Penpot team.
diff --git a/backend/src/app/email.clj b/backend/src/app/email.clj
index 5bcf741f1c..75365fe75c 100644
--- a/backend/src/app/email.clj
+++ b/backend/src/app/email.clj
@@ -449,6 +449,45 @@
:id ::request-team-access
:schema schema:request-team-access))
+(def ^:private schema:comment-mention
+ [:map
+ [:name ::sm/text]
+ [:source-user ::sm/text]
+ [:comment-reference ::sm/text]
+ [:comment-content ::sm/text]
+ [:comment-url ::sm/text]])
+
+(def comment-mention
+ (template-factory
+ :id ::comment-mention
+ :schema schema:comment-mention))
+
+(def ^:private schema:comment-thread
+ [:map
+ [:name ::sm/text]
+ [:source-user ::sm/text]
+ [:comment-reference ::sm/text]
+ [:comment-content ::sm/text]
+ [:comment-url ::sm/text]])
+
+(def comment-thread
+ (template-factory
+ :id ::comment-thread
+ :schema schema:comment-thread))
+
+(def ^:private schema:comment-notification
+ [:map
+ [:name ::sm/text]
+ [:source-user ::sm/text]
+ [:comment-reference ::sm/text]
+ [:comment-content ::sm/text]
+ [:comment-url ::sm/text]])
+
+(def comment-notification
+ (template-factory
+ :id ::comment-notification
+ :schema schema:comment-notification))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; BOUNCE/COMPLAINS HELPERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/backend/src/app/migrations.clj b/backend/src/app/migrations.clj
index 566095a19e..cefa94b65c 100644
--- a/backend/src/app/migrations.clj
+++ b/backend/src/app/migrations.clj
@@ -426,7 +426,10 @@
:fn (mg/resource "app/migrations/sql/0134-mod-file-change-table.sql")}
{:name "0135-mod-team-invitation-table.sql"
- :fn (mg/resource "app/migrations/sql/0135-mod-team-invitation-table.sql")}])
+ :fn (mg/resource "app/migrations/sql/0135-mod-team-invitation-table.sql")}
+
+ {:name "0136-mod-comments-mentions.sql"
+ :fn (mg/resource "app/migrations/sql/0136-mod-comments-mentions.sql")}])
(defn apply-migrations!
[pool name migrations]
diff --git a/backend/src/app/migrations/sql/0136-mod-comments-mentions.sql b/backend/src/app/migrations/sql/0136-mod-comments-mentions.sql
new file mode 100644
index 0000000000..f5a8cf9f0e
--- /dev/null
+++ b/backend/src/app/migrations/sql/0136-mod-comments-mentions.sql
@@ -0,0 +1,3 @@
+ALTER TABLE comment ADD COLUMN mentions uuid[] NULL DEFAULT '{}';
+
+ALTER TABLE comment_thread ADD COLUMN mentions uuid[] NULL DEFAULT '{}';
diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj
index 062436dbe6..cf9db7762f 100644
--- a/backend/src/app/rpc/commands/auth.clj
+++ b/backend/src/app/rpc/commands/auth.clj
@@ -273,7 +273,8 @@
(merge {:viewed-tutorial? false
:viewed-walkthrough? false
:nudge {:big 10 :small 1}
- :v2-info-shown true})
+ :v2-info-shown true
+ :release-notes-viewed (:main cf/version)})
(db/tjson))
password (or (:password params) "!")
diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj
index fafecd8b87..f649f577b5 100644
--- a/backend/src/app/rpc/commands/comments.clj
+++ b/backend/src/app/rpc/commands/comments.clj
@@ -6,40 +6,165 @@
(ns app.rpc.commands.comments
(:require
+ [app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.exceptions :as ex]
[app.common.geom.point :as gpt]
[app.common.schema :as sm]
+ [app.common.uri :as uri]
[app.common.uuid :as uuid]
+ [app.config :as cf]
[app.db :as db]
[app.db.sql :as sql]
+ [app.email :as eml]
[app.features.fdata :as feat.fdata]
[app.loggers.audit :as-alias audit]
[app.loggers.webhooks :as-alias webhooks]
[app.rpc :as-alias rpc]
[app.rpc.commands.files :as files]
+ [app.rpc.commands.profile :as profile]
[app.rpc.commands.teams :as teams]
[app.rpc.doc :as-alias doc]
[app.rpc.quotes :as quotes]
[app.rpc.retry :as rtry]
[app.util.pointer-map :as pmap]
[app.util.services :as sv]
- [app.util.time :as dt]))
+ [app.util.time :as dt]
+ [clojure.set :as set]
+ [cuerdas.core :as str]))
;; --- GENERAL PURPOSE INTERNAL HELPERS
+(def r-mentions-split #"@\[[^\]]*\]\([^\)]*\)")
+(def r-mentions #"@\[([^\]]*)\]\(([^\)]*)\)")
+
+(defn- format-comment
+ [{:keys [content]}]
+ (->> (d/interleave-all
+ (str/split content r-mentions-split)
+ (->> (re-seq r-mentions content)
+ (map (fn [[_ user _]] user))))
+ (str/join "")))
+
+(defn- format-comment-url
+ [{:keys [team-id file-id page-id]}]
+ (str/ffmt "%/#/workspace?%"
+ (cf/get :public-uri)
+ (uri/map->query-string
+ {:file-id file-id
+ :page-id page-id
+ :team-id team-id})))
+
+(defn- format-comment-ref
+ [{:keys [seqn]} {:keys [file-name page-name]}]
+ (str/ffmt "#%, %, %" seqn file-name page-name))
+
+(defn get-team-users
+ [conn team-id]
+ (->> (teams/get-users+props conn team-id)
+ (map profile/decode-row)
+ (d/index-by :id)))
+
+(defn- resolve-profile-name
+ [conn profile-id]
+ (-> (db/get conn :profile {:id profile-id}
+ {::sql/columns [:fullname]})
+ (get :fullname)))
+
+(defn- notification-email?
+ [profile-id owner-id props]
+ (if (= profile-id owner-id)
+ (not= :none (-> props :notifications :email-comments))
+ (= :all (-> props :notifications :email-comments))))
+
+(defn- mention-email?
+ [props]
+ (not= :none (-> props :notifications :email-comments)))
+
+(defn send-comment-emails!
+ [conn {:keys [profile-id team-id] :as params} comment thread]
+
+ (let [team-users (get-team-users conn team-id)
+ source-user (resolve-profile-name conn profile-id)
+
+ comment-reference (format-comment-ref thread params)
+ comment-content (format-comment comment)
+ comment-url (format-comment-url params)
+
+ ;; Users mentioned in this comment
+ comment-mentions
+ (-> (:mentions comment)
+ (set/difference #{profile-id}))
+
+ ;; Users mentioned in this thread
+ thread-mentions
+ (-> (:mentions thread)
+ ;; Remove the mentions in the thread because we're already sending a
+ ;; notification
+ (set/difference comment-mentions)
+ (disj profile-id))
+
+ ;; All users
+ notificate-users-ids
+ (-> (set (keys team-users))
+ (set/difference comment-mentions)
+ (set/difference thread-mentions)
+ (disj profile-id))]
+
+ (doseq [mention comment-mentions]
+ (let [{:keys [fullname email props]} (get team-users mention)]
+ (when (mention-email? props)
+ (eml/send!
+ {::eml/conn conn
+ ::eml/factory eml/comment-mention
+ :to email
+ :name fullname
+ :source-user source-user
+ :comment-reference comment-reference
+ :comment-content comment-content
+ :comment-url comment-url}))))
+
+ ;; Send to the thread users
+ (doseq [mention thread-mentions]
+ (let [{:keys [fullname email props]} (get team-users mention)]
+ (when (mention-email? props)
+ (eml/send!
+ {::eml/conn conn
+ ::eml/factory eml/comment-thread
+ :to email
+ :name fullname
+ :source-user source-user
+ :comment-reference comment-reference
+ :comment-content comment-content
+ :comment-url comment-url}))))
+
+ ;; Send to users with the "all" flag activated
+ (doseq [user-id notificate-users-ids]
+ (let [{:keys [id fullname email props]} (get team-users user-id)]
+ (when (notification-email? id (:owner-id thread) props)
+ (eml/send!
+ {::eml/conn conn
+ ::eml/factory eml/comment-notification
+ :to email
+ :name fullname
+ :source-user source-user
+ :comment-reference comment-reference
+ :comment-content comment-content
+ :comment-url comment-url}))))))
+
(defn- decode-row
- [{:keys [participants position] :as row}]
+ [{:keys [participants position mentions] :as row}]
(cond-> row
(db/pgpoint? position) (assoc :position (db/decode-pgpoint position))
- (db/pgobject? participants) (assoc :participants (db/decode-transit-pgobject participants))))
+ (db/pgobject? participants) (assoc :participants (db/decode-transit-pgobject participants))
+ (db/pgarray? mentions) (assoc :mentions (db/decode-pgarray mentions #{}))))
(def xf-decode-row
(map decode-row))
-(def ^:privateqpage-name
+(def ^:private
sql:get-file
- "select f.id, f.modified_at, f.revn, f.features,
+ "select f.id, f.modified_at, f.revn, f.features, f.name,
f.project_id, p.team_id, f.data
from file as f
join project as p on (p.id = f.project_id)
@@ -91,7 +216,7 @@
(defn upsert-comment-thread-status!
([conn profile-id thread-id]
- (upsert-comment-thread-status! conn profile-id thread-id (dt/now)))
+ (upsert-comment-thread-status! conn profile-id thread-id (dt/in-future "1s")))
([conn profile-id thread-id mod-at]
(db/exec-one! conn [sql:upsert-comment-thread-status thread-id profile-id mod-at mod-at])))
@@ -116,36 +241,38 @@
{::doc/added "1.15"
::sm/params schema:get-comment-threads}
[cfg {:keys [::rpc/profile-id file-id share-id] :as params}]
-
(db/run! cfg (fn [{:keys [::db/conn]}]
(files/check-comment-permissions! conn profile-id file-id share-id)
(get-comment-threads conn profile-id file-id))))
(def ^:private sql:comment-threads
- "select distinct on (ct.id)
+ "SELECT DISTINCT ON (ct.id)
ct.*,
- f.name as file_name,
- f.project_id as project_id,
- first_value(c.content) over w as content,
- (select count(1)
- from comment as c
- where c.thread_id = ct.id) as count_comments,
- (select count(1)
- from comment as c
- where c.thread_id = ct.id
- and c.created_at >= coalesce(cts.modified_at, ct.created_at)) as count_unread_comments
- from comment_thread as ct
- inner join comment as c on (c.thread_id = ct.id)
- inner join file as f on (f.id = ct.file_id)
- left join comment_thread_status as cts
- on (cts.thread_id = ct.id and
- cts.profile_id = ?)
- where ct.file_id = ?
- window w as (partition by c.thread_id order by c.created_at asc)")
+ p.team_id AS team_id,
+ f.name AS file_name,
+ f.project_id AS project_id,
+ first_value(c.content) OVER w AS content,
+ (SELECT count(1)
+ FROM comment AS c
+ WHERE c.thread_id = ct.id) AS count_comments,
+ (SELECT count(1)
+ FROM comment AS c
+ WHERE c.thread_id = ct.id
+ AND c.created_at >= coalesce(cts.modified_at, ct.created_at)) AS count_unread_comments
+ FROM comment_thread AS ct
+ INNER JOIN comment AS c ON (c.thread_id = ct.id)
+ INNER JOIN file AS f ON (f.id = ct.file_id)
+ INNER JOIN project AS p ON (p.id = f.project_id)
+ LEFT JOIN comment_thread_status AS cts ON (cts.thread_id = ct.id AND cts.profile_id = ?)
+ WINDOW w AS (PARTITION BY c.thread_id ORDER BY c.created_at ASC)")
+
+(def ^:private sql:comment-threads-by-file-id
+ (str "WITH threads AS (" sql:comment-threads ")"
+ "SELECT * FROM threads WHERE file_id = ?"))
(defn- get-comment-threads
[conn profile-id file-id]
- (->> (db/exec! conn [sql:comment-threads profile-id file-id])
+ (->> (db/exec! conn [sql:comment-threads-by-file-id profile-id file-id])
(into [] xf-decode-row)))
;; --- COMMAND: Get Unread Comment Threads
@@ -161,41 +288,41 @@
{::doc/added "1.15"
::sm/params schema:get-unread-comment-threads}
[cfg {:keys [::rpc/profile-id team-id] :as params}]
- (db/run! cfg (fn [{:keys [::db/conn]}]
- (teams/check-read-permissions! conn profile-id team-id)
- (get-unread-comment-threads conn profile-id team-id))))
+ (db/run!
+ cfg
+ (fn [{:keys [::db/conn]}]
+ (teams/check-read-permissions! conn profile-id team-id)
+ (get-unread-comment-threads conn profile-id team-id))))
-(def sql:comment-threads-by-team
- "select distinct on (ct.id)
- ct.*,
- f.name as file_name,
- f.project_id as project_id,
- first_value(c.content) over w as content,
- (select count(1)
- from comment as c
- where c.thread_id = ct.id) as count_comments,
- (select count(1)
- from comment as c
- where c.thread_id = ct.id
- and c.created_at >= coalesce(cts.modified_at, ct.created_at)) as count_unread_comments
- from comment_thread as ct
- inner join comment as c on (c.thread_id = ct.id)
- inner join file as f on (f.id = ct.file_id)
- inner join project as p on (p.id = f.project_id)
- left join comment_thread_status as cts
- on (cts.thread_id = ct.id and
- cts.profile_id = ?)
- where p.team_id = ?
- window w as (partition by c.thread_id order by c.created_at asc)")
+(def sql:unread-all-comment-threads-by-team
+ (str "WITH threads AS (" sql:comment-threads ")"
+ "SELECT * FROM threads WHERE count_unread_comments > 0 AND team_id = ?"))
-(def sql:unread-comment-threads-by-team
- (str "with threads as (" sql:comment-threads-by-team ")"
- "select * from threads where count_unread_comments > 0"))
+;; The partial configuration will retrieve only comments created by the user and
+;; threads that have a mention to the user.
+(def sql:unread-partial-comment-threads-by-team
+ (str "WITH threads AS (" sql:comment-threads ")"
+ "SELECT * FROM threads
+ WHERE count_unread_comments > 0
+ AND team_id = ?
+ AND (owner_id = ? OR ? = ANY(mentions))"))
(defn- get-unread-comment-threads
[conn profile-id team-id]
- (->> (db/exec! conn [sql:unread-comment-threads-by-team profile-id team-id])
- (into [] xf-decode-row)))
+ (let [profile (-> (db/get conn :profile {:id profile-id})
+ (profile/decode-row))
+ notify (or (-> profile :props :notifications :dashboard-comments) :all)]
+
+ (case notify
+ :all
+ (->> (db/exec! conn [sql:unread-all-comment-threads-by-team profile-id team-id])
+ (into [] xf-decode-row))
+
+ :partial
+ (->> (db/exec! conn [sql:unread-partial-comment-threads-by-team profile-id team-id profile-id profile-id])
+ (into [] xf-decode-row))
+
+ [])))
;; --- COMMAND: Get Single Comment Thread
@@ -212,9 +339,9 @@
[cfg {:keys [::rpc/profile-id file-id id share-id] :as params}]
(db/run! cfg (fn [{:keys [::db/conn]}]
(files/check-comment-permissions! conn profile-id file-id share-id)
- (let [sql (str "with threads as (" sql:comment-threads ")"
- "select * from threads where id = ?")]
- (-> (db/exec-one! conn [sql profile-id file-id id])
+ (let [sql (str "WITH threads AS (" sql:comment-threads ")"
+ "SELECT * FROM threads WHERE id = ? AND file_id = ?")]
+ (-> (db/exec-one! conn [sql profile-id id file-id])
(decode-row))))))
;; --- COMMAND: Retrieve Comments
@@ -300,7 +427,8 @@
[:content [:string {:max 750}]]
[:page-id ::sm/uuid]
[:frame-id ::sm/uuid]
- [:share-id {:optional true} [:maybe ::sm/uuid]]])
+ [:share-id {:optional true} [:maybe ::sm/uuid]]
+ [:mentions {:optional true} [:vector ::sm/uuid]]])
(sv/defmethod ::create-comment-thread
{::doc/added "1.15"
@@ -308,11 +436,10 @@
::rtry/enabled true
::rtry/when rtry/conflict-exception?
::sm/params schema:create-comment-thread}
- [cfg {:keys [::rpc/profile-id ::rpc/request-at file-id page-id share-id position content frame-id]}]
+ [cfg {:keys [::rpc/profile-id ::rpc/request-at file-id page-id share-id mentions position content frame-id]}]
(files/check-comment-permissions! cfg profile-id file-id share-id)
- (let [{:keys [team-id project-id page-name]} (get-file cfg file-id page-id)]
-
+ (let [{:keys [team-id project-id page-name name]} (get-file cfg file-id page-id)]
(-> cfg
(assoc ::quotes/profile-id profile-id)
(assoc ::quotes/team-id team-id)
@@ -324,18 +451,23 @@
(let [params {:created-at request-at
:profile-id profile-id
:file-id file-id
+ :file-name name
:page-id page-id
:page-name page-name
:position position
:content content
- :frame-id frame-id}
- thread (db/tx-run! cfg create-comment-thread params)]
+ :frame-id frame-id
+ :team-id team-id
+ :project-id project-id
+ :mentions mentions}
+ thread (-> (db/tx-run! cfg create-comment-thread params)
+ (decode-row))]
(vary-meta thread assoc ::audit/props thread))))
(defn- create-comment-thread
[{:keys [::db/conn] :as cfg}
- {:keys [profile-id file-id page-id page-name created-at position content frame-id]}]
+ {:keys [profile-id file-id page-id page-name created-at position content mentions frame-id] :as params}]
(let [;; NOTE: we take the next seq number from a separate query
;; because we need to lock the file for avoid race conditions
@@ -348,25 +480,29 @@
seqn (get-next-seqn conn file-id)
thread-id (uuid/next)
- thread (db/insert! conn :comment-thread
- {:id thread-id
- :file-id file-id
- :owner-id profile-id
- :participants (db/tjson #{profile-id})
- :page-name page-name
- :page-id page-id
- :created-at created-at
- :modified-at created-at
- :seqn seqn
- :position (db/pgpoint position)
- :frame-id frame-id})
- comment (db/insert! conn :comment
- {:id (uuid/next)
- :thread-id thread-id
- :owner-id profile-id
- :created-at created-at
- :modified-at created-at
- :content content})]
+ thread (-> (db/insert! conn :comment-thread
+ {:id thread-id
+ :file-id file-id
+ :owner-id profile-id
+ :participants (db/tjson #{profile-id})
+ :page-name page-name
+ :page-id page-id
+ :created-at created-at
+ :modified-at created-at
+ :seqn seqn
+ :position (db/pgpoint position)
+ :frame-id frame-id
+ :mentions (db/encode-pgarray mentions conn "uuid")})
+ (decode-row))
+ comment (-> (db/insert! conn :comment
+ {:id (uuid/next)
+ :thread-id thread-id
+ :owner-id profile-id
+ :created-at created-at
+ :modified-at created-at
+ :mentions (db/encode-pgarray mentions conn "uuid")
+ :content content})
+ (decode-row))]
;; Make the current thread as read.
(upsert-comment-thread-status! conn profile-id thread-id created-at)
@@ -377,8 +513,11 @@
{:id file-id}
{::db/return-keys false})
+ ;; Send mentions emails
+ (send-comment-emails! conn params comment thread)
+
(-> thread
- (select-keys [:id :file-id :page-id])
+ (select-keys [:id :file-id :page-id :mentions])
(assoc :comment-id (:id comment)))))
;; --- COMMAND: Update Comment Thread Status
@@ -391,12 +530,12 @@
(sv/defmethod ::update-comment-thread-status
{::doc/added "1.15"
- ::sm/params schema:update-comment-thread-status}
- [cfg {:keys [::rpc/profile-id id share-id]}]
- (db/tx-run! cfg (fn [{:keys [::db/conn]}]
- (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
- (files/check-comment-permissions! conn profile-id file-id share-id)
- (upsert-comment-thread-status! conn profile-id id)))))
+ ::sm/params schema:update-comment-thread-status
+ ::db/transaction true}
+ [{:keys [::db/conn]} {:keys [::rpc/profile-id id share-id]}]
+ (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
+ (files/check-comment-permissions! conn profile-id file-id share-id)
+ (upsert-comment-thread-status! conn profile-id id)))
;; --- COMMAND: Update Comment Thread
@@ -409,16 +548,15 @@
(sv/defmethod ::update-comment-thread
{::doc/added "1.15"
- ::sm/params schema:update-comment-thread}
- [cfg {:keys [::rpc/profile-id id is-resolved share-id]}]
- (db/tx-run! cfg (fn [{:keys [::db/conn]}]
- (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
- (files/check-comment-permissions! conn profile-id file-id share-id)
- (db/update! conn :comment-thread
- {:is-resolved is-resolved}
- {:id id})
- nil))))
-
+ ::sm/params schema:update-comment-thread
+ ::db/transaction true}
+ [{:keys [::db/conn]} {:keys [::rpc/profile-id id is-resolved share-id]}]
+ (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
+ (files/check-comment-permissions! conn profile-id file-id share-id)
+ (db/update! conn :comment-thread
+ {:is-resolved is-resolved}
+ {:id id})
+ nil))
;; --- COMMAND: Add Comment
@@ -429,56 +567,74 @@
[:map {:title "create-comment"}
[:thread-id ::sm/uuid]
[:content [:string {:max 250}]]
- [:share-id {:optional true} [:maybe ::sm/uuid]]])
+ [:share-id {:optional true} [:maybe ::sm/uuid]]
+ [:mentions {:optional true} [:vector ::sm/uuid]]])
(sv/defmethod ::create-comment
{::doc/added "1.15"
::webhooks/event? true
- ::sm/params schema:create-comment}
- [cfg {:keys [::rpc/profile-id ::rpc/request-at thread-id share-id content]}]
- (db/tx-run! cfg
- (fn [{:keys [::db/conn] :as cfg}]
- (let [{:keys [file-id page-id] :as thread} (get-comment-thread conn thread-id ::sql/for-update true)
- {:keys [team-id project-id page-name] :as file} (get-file cfg file-id page-id)]
+ ::sm/params schema:create-comment
+ ::db/transaction true}
+ [{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id ::rpc/request-at thread-id share-id content mentions]}]
+ (let [{:keys [file-id page-id] :as thread} (get-comment-thread conn thread-id ::sql/for-update true)
+ {file-name :name :keys [team-id project-id page-name] :as file} (get-file cfg file-id page-id)]
- (files/check-comment-permissions! conn profile-id file-id share-id)
- (quotes/check! cfg {::quotes/id ::quotes/comments-per-file
- ::quotes/profile-id profile-id
- ::quotes/team-id team-id
- ::quotes/project-id project-id
- ::quotes/file-id file-id})
+ (files/check-comment-permissions! conn profile-id file-id share-id)
+ (quotes/check! cfg {::quotes/id ::quotes/comments-per-file
+ ::quotes/profile-id profile-id
+ ::quotes/team-id team-id
+ ::quotes/project-id project-id
+ ::quotes/file-id file-id})
- ;; Update the page-name cached attribute on comment thread table.
- (when (not= page-name (:page-name thread))
- (db/update! conn :comment-thread
- {:page-name page-name}
- {:id thread-id}))
+ ;; Update the page-name cached attribute on comment thread table.
+ (when (not= page-name (:page-name thread))
+ (db/update! conn :comment-thread
+ {:page-name page-name}
+ {:id thread-id}))
- (let [comment (db/insert! conn :comment
- {:id (uuid/next)
- :created-at request-at
- :modified-at request-at
- :thread-id thread-id
- :owner-id profile-id
- :content content})
- props {:file-id file-id
- :share-id nil}]
+ (let [comment (-> (db/insert!
+ conn :comment
+ {:id (uuid/next)
+ :created-at request-at
+ :modified-at request-at
+ :thread-id thread-id
+ :owner-id profile-id
+ :content content
+ :mentions
+ (-> mentions
+ (set)
+ (db/encode-pgarray conn "uuid"))})
+ (decode-row))
+ props {:file-id file-id
+ :share-id nil}]
- ;; Update thread modified-at attribute and assoc the current
- ;; profile to the participant set.
- (db/update! conn :comment-thread
- {:modified-at request-at
- :participants (-> (:participants thread #{})
- (conj profile-id)
- (db/tjson))}
- {:id thread-id})
+ ;; Update thread modified-at attribute and assoc the current
+ ;; profile to the participant set.
+ (db/update! conn :comment-thread
+ {:modified-at request-at
+ :participants (-> (:participants thread #{})
+ (conj profile-id)
+ (db/tjson))
+ :mentions (-> (:mentions thread)
+ (set)
+ (into mentions)
+ (db/encode-pgarray conn "uuid"))}
+ {:id thread-id})
- ;; Update the current profile status in relation to the
- ;; current thread.
- (upsert-comment-thread-status! conn profile-id thread-id request-at)
+ ;; Update the current profile status in relation to the
+ ;; current thread.
+ (upsert-comment-thread-status! conn profile-id thread-id)
- (vary-meta comment assoc ::audit/props props))))))
+ (let [params {:project-id project-id
+ :profile-id profile-id
+ :team-id team-id
+ :file-id (:file-id thread)
+ :page-id (:page-id thread)
+ :file-name file-name
+ :page-name page-name}]
+ (send-comment-emails! conn params comment thread))
+ (vary-meta comment assoc ::audit/props props))))
;; --- COMMAND: Update Comment
@@ -487,35 +643,42 @@
[:map {:title "update-comment"}
[:id ::sm/uuid]
[:content [:string {:max 250}]]
- [:share-id {:optional true} [:maybe ::sm/uuid]]])
+ [:share-id {:optional true} [:maybe ::sm/uuid]]
+ [:mentions {:optional true} [:vector ::sm/uuid]]])
+;; TODO Check if there are new mentions, if there are send the new emails.
(sv/defmethod ::update-comment
{::doc/added "1.15"
- ::sm/params schema:update-comment}
- [cfg {:keys [::rpc/profile-id ::rpc/request-at id share-id content]}]
- (db/tx-run! cfg
- (fn [{:keys [::db/conn] :as cfg}]
- (let [{:keys [thread-id owner-id] :as comment} (get-comment conn id ::sql/for-update true)
- {:keys [file-id page-id] :as thread} (get-comment-thread conn thread-id ::sql/for-update true)]
+ ::sm/params schema:update-comment
+ ::db/transaction true}
+ [{:keys [::db/conn] :as cfg} {:keys [::rpc/profile-id ::rpc/request-at id share-id content mentions]}]
+ (let [{:keys [thread-id owner-id] :as comment} (get-comment conn id ::sql/for-update true)
+ {:keys [file-id page-id] :as thread} (get-comment-thread conn thread-id ::sql/for-update true)]
- (files/check-comment-permissions! conn profile-id file-id share-id)
+ (files/check-comment-permissions! conn profile-id file-id share-id)
- ;; Don't allow edit comments to not owners
- (when-not (= owner-id profile-id)
- (ex/raise :type :validation
- :code :not-allowed))
+ ;; Don't allow edit comments to not owners
+ (when-not (= owner-id profile-id)
+ (ex/raise :type :validation
+ :code :not-allowed))
- (let [{:keys [page-name]} (get-file cfg file-id page-id)]
- (db/update! conn :comment
- {:content content
- :modified-at request-at}
- {:id id})
+ (let [{:keys [page-name]} (get-file cfg file-id page-id)]
+ (db/update! conn :comment
+ {:content content
+ :modified-at request-at
+ :mentions (db/encode-pgarray mentions conn "uuid")}
+ {:id id})
- (db/update! conn :comment-thread
- {:modified-at request-at
- :page-name page-name}
- {:id thread-id})
- nil)))))
+ (db/update! conn :comment-thread
+ {:modified-at request-at
+ :page-name page-name
+ :mentions
+ (-> (:mentions thread)
+ (set)
+ (into mentions)
+ (db/encode-pgarray conn "uuid"))}
+ {:id thread-id})
+ nil)))
;; --- COMMAND: Delete Comment Thread
@@ -527,17 +690,17 @@
(sv/defmethod ::delete-comment-thread
{::doc/added "1.15"
- ::sm/params schema:delete-comment-thread}
- [cfg {:keys [::rpc/profile-id id share-id]}]
- (db/tx-run! cfg (fn [{:keys [::db/conn]}]
- (let [{:keys [owner-id file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
- (files/check-comment-permissions! conn profile-id file-id share-id)
- (when-not (= owner-id profile-id)
- (ex/raise :type :validation
- :code :not-allowed))
+ ::sm/params schema:delete-comment-thread
+ ::db/transaction true}
+ [{:keys [::db/conn]} {:keys [::rpc/profile-id id share-id]}]
+ (let [{:keys [owner-id file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
+ (files/check-comment-permissions! conn profile-id file-id share-id)
+ (when-not (= owner-id profile-id)
+ (ex/raise :type :validation
+ :code :not-allowed))
- (db/delete! conn :comment-thread {:id id})
- nil))))
+ (db/delete! conn :comment-thread {:id id})
+ nil))
;; --- COMMAND: Delete comment
@@ -549,17 +712,17 @@
(sv/defmethod ::delete-comment
{::doc/added "1.15"
- ::sm/params schema:delete-comment}
- [cfg {:keys [::rpc/profile-id id share-id]}]
- (db/tx-run! cfg (fn [{:keys [::db/conn]}]
- (let [{:keys [owner-id thread-id] :as comment} (get-comment conn id ::sql/for-update true)
- {:keys [file-id] :as thread} (get-comment-thread conn thread-id)]
- (files/check-comment-permissions! conn profile-id file-id share-id)
- (when-not (= owner-id profile-id)
- (ex/raise :type :validation
- :code :not-allowed))
- (db/delete! conn :comment {:id id})
- nil))))
+ ::sm/params schema:delete-comment
+ ::db/transaction true}
+ [{:keys [::db/conn]} {:keys [::rpc/profile-id id share-id]}]
+ (let [{:keys [owner-id thread-id] :as comment} (get-comment conn id ::sql/for-update true)
+ {:keys [file-id] :as thread} (get-comment-thread conn thread-id)]
+ (files/check-comment-permissions! conn profile-id file-id share-id)
+ (when-not (= owner-id profile-id)
+ (ex/raise :type :validation
+ :code :not-allowed))
+ (db/delete! conn :comment {:id id})
+ nil))
;; --- COMMAND: Update comment thread position
@@ -573,17 +736,17 @@
(sv/defmethod ::update-comment-thread-position
{::doc/added "1.15"
- ::sm/params schema:update-comment-thread-position}
- [cfg {:keys [::rpc/profile-id ::rpc/request-at id position frame-id share-id]}]
- (db/tx-run! cfg (fn [{:keys [::db/conn]}]
- (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
- (files/check-comment-permissions! conn profile-id file-id share-id)
- (db/update! conn :comment-thread
- {:modified-at request-at
- :position (db/pgpoint position)
- :frame-id frame-id}
- {:id (:id thread)})
- nil))))
+ ::sm/params schema:update-comment-thread-position
+ ::db/transaction true}
+ [{:keys [::db/conn]} {:keys [::rpc/profile-id ::rpc/request-at id position frame-id share-id]}]
+ (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
+ (files/check-comment-permissions! conn profile-id file-id share-id)
+ (db/update! conn :comment-thread
+ {:modified-at request-at
+ :position (db/pgpoint position)
+ :frame-id frame-id}
+ {:id (:id thread)})
+ nil))
;; --- COMMAND: Update comment frame
@@ -596,13 +759,13 @@
(sv/defmethod ::update-comment-thread-frame
{::doc/added "1.15"
- ::sm/params schema:update-comment-thread-frame}
- [cfg {:keys [::rpc/profile-id ::rpc/request-at id frame-id share-id]}]
- (db/tx-run! cfg (fn [{:keys [::db/conn]}]
- (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
- (files/check-comment-permissions! conn profile-id file-id share-id)
- (db/update! conn :comment-thread
- {:modified-at request-at
- :frame-id frame-id}
- {:id id})
- nil))))
+ ::sm/params schema:update-comment-thread-frame
+ ::db/transaction true}
+ [{:keys [::db/conn]} {:keys [::rpc/profile-id ::rpc/request-at id frame-id share-id]}]
+ (let [{:keys [file-id] :as thread} (get-comment-thread conn id ::sql/for-update true)]
+ (files/check-comment-permissions! conn profile-id file-id share-id)
+ (db/update! conn :comment-thread
+ {:modified-at request-at
+ :frame-id frame-id}
+ {:id id})
+ nil))
diff --git a/backend/src/app/rpc/commands/files_thumbnails.clj b/backend/src/app/rpc/commands/files_thumbnails.clj
index eb7bf3c169..c3a5cb5d47 100644
--- a/backend/src/app/rpc/commands/files_thumbnails.clj
+++ b/backend/src/app/rpc/commands/files_thumbnails.clj
@@ -402,7 +402,10 @@
[cfg {:keys [::rpc/profile-id file-id] :as params}]
(db/tx-run! cfg (fn [{:keys [::db/conn] :as cfg}]
- (files/check-edition-permissions! conn profile-id file-id)
+ ;; TODO For now we check read permissions instead of write,
+ ;; to allow viewer users to update thumbnails. We might
+ ;; review this approach on the future.
+ (files/check-read-permissions! conn profile-id file-id)
(when-not (db/read-only? conn)
(let [media (create-file-thumbnail! cfg params)]
{:uri (files/resolve-public-uri (:id media))
diff --git a/backend/src/app/rpc/commands/profile.clj b/backend/src/app/rpc/commands/profile.clj
index 7c7ca33399..7760c96b5f 100644
--- a/backend/src/app/rpc/commands/profile.clj
+++ b/backend/src/app/rpc/commands/profile.clj
@@ -41,6 +41,12 @@
(declare strip-private-attrs)
(declare verify-password)
+(def schema:props-notifications
+ [:map {:title "props-notifications"}
+ [:dashboard-comments [::sm/one-of #{:all :partial :none}]]
+ [:email-comments [::sm/one-of #{:all :partial :none}]]
+ [:email-invites [::sm/one-of #{:all :none}]]])
+
(def schema:props
[:map {:title "ProfileProps"}
[:plugins {:optional true} schema:plugin-registry]
@@ -51,7 +57,8 @@
[:v2-info-shown {:optional true} ::sm/boolean]
[:welcome-file-id {:optional true} [:maybe ::sm/boolean]]
[:release-notes-viewed {:optional true}
- [::sm/text {:max 100}]]])
+ [::sm/text {:max 100}]]
+ [:notifications {:optional true} schema:props-notifications]])
(def schema:profile
[:map {:title "Profile"}
@@ -200,6 +207,44 @@
{:id id})
nil))
+
+;; --- MUTATION: Update notifications
+
+(def ^:private
+ schema:update-profile-notifications
+ [:map {:title "update-profile-notifications"}
+ [:dashboard-comments [::sm/one-of #{:all :partial :none}]]
+ [:email-comments [::sm/one-of #{:all :partial :none}]]
+ [:email-invites [::sm/one-of #{:all :none}]]])
+
+(declare update-notifications!)
+
+(sv/defmethod ::update-profile-notifications
+ {::doc/added "2.4.0"
+ ::sm/params schema:update-profile-notifications
+ ::climit/id :auth/global}
+ [cfg {:keys [::rpc/profile-id] :as params}]
+ (db/tx-run! cfg update-notifications! (assoc params :profile-id profile-id)))
+
+(defn- update-notifications!
+ [{:keys [::db/conn] :as cfg} {:keys [profile-id dashboard-comments email-comments email-invites]}]
+ (let [profile (get-profile conn profile-id)
+
+ notifications
+ {:dashboard-comments dashboard-comments
+ :email-comments email-comments
+ :email-invites email-invites}]
+
+ (db/update!
+ conn :profile
+ {:props
+ (-> (:props profile)
+ (assoc :notifications notifications)
+ (db/tjson))}
+ {:id (:id profile)})
+
+ nil))
+
;; --- MUTATION: Update Photo
(declare upload-photo)
diff --git a/backend/src/app/rpc/commands/teams.clj b/backend/src/app/rpc/commands/teams.clj
index f111b11846..7e4d0c2610 100644
--- a/backend/src/app/rpc/commands/teams.clj
+++ b/backend/src/app/rpc/commands/teams.clj
@@ -286,18 +286,18 @@
;; implemented in UI)
(def sql:team-users
- "select pf.id, pf.fullname, pf.photo_id
+ "select pf.id, pf.fullname, pf.photo_id, pf.email
from profile as pf
inner join team_profile_rel as tpr on (tpr.profile_id = pf.id)
where tpr.team_id = ?
union
- select pf.id, pf.fullname, pf.photo_id
+ select pf.id, pf.fullname, pf.photo_id, pf.email
from profile as pf
inner join project_profile_rel as ppr on (ppr.profile_id = pf.id)
inner join project as p on (ppr.project_id = p.id)
where p.team_id = ?
union
- select pf.id, pf.fullname, pf.photo_id
+ select pf.id, pf.fullname, pf.photo_id, pf.email
from profile as pf
inner join file_profile_rel as fpr on (fpr.profile_id = pf.id)
inner join file as f on (fpr.file_id = f.id)
@@ -308,6 +308,30 @@
[conn team-id]
(db/exec! conn [sql:team-users team-id team-id team-id]))
+;; Get the users but add the props property
+(def sql:team-users+props
+ "select pf.id, pf.fullname, pf.photo_id, pf.email, pf.props
+ from profile as pf
+ inner join team_profile_rel as tpr on (tpr.profile_id = pf.id)
+ where tpr.team_id = ?
+ union
+ select pf.id, pf.fullname, pf.photo_id, pf.email, pf.props
+ from profile as pf
+ inner join project_profile_rel as ppr on (ppr.profile_id = pf.id)
+ inner join project as p on (ppr.project_id = p.id)
+ where p.team_id = ?
+ union
+ select pf.id, pf.fullname, pf.photo_id, pf.email, pf.props
+ from profile as pf
+ inner join file_profile_rel as fpr on (fpr.profile_id = pf.id)
+ inner join file as f on (fpr.file_id = f.id)
+ inner join project as p on (f.project_id = p.id)
+ where p.team_id = ?")
+
+(defn get-users+props
+ [conn team-id]
+ (db/exec! conn [sql:team-users+props team-id team-id team-id]))
+
(def sql:get-team-by-file
"SELECT t.*
FROM team AS t
diff --git a/backend/src/app/rpc/commands/verify_token.clj b/backend/src/app/rpc/commands/verify_token.clj
index d725ceda2e..27679536ef 100644
--- a/backend/src/app/rpc/commands/verify_token.clj
+++ b/backend/src/app/rpc/commands/verify_token.clj
@@ -166,23 +166,26 @@
;; invited team.
(let [props {:team-id (:team-id claims)
:role (:role claims)
- :invitation-id (:id invitation)}
+ :invitation-id (:id invitation)}]
- accept-invitation-event
- (-> (audit/event-from-rpc-params params)
- (assoc ::audit/name "accept-team-invitation")
- (assoc ::audit/props props))
+ (audit/submit!
+ cfg
+ (-> (audit/event-from-rpc-params params)
+ (assoc ::audit/name "accept-team-invitation")
+ (assoc ::audit/props props)))
- accept-invitation-from-event
- (-> (audit/event-from-rpc-params params)
- (assoc ::audit/profile-id (:created-by invitation))
- (assoc ::audit/name "accept-team-invitation-from")
- (assoc ::audit/props (assoc props
- :profile-id (:id profile)
- :email (:email profile))))]
-
- (audit/submit! cfg accept-invitation-event)
- (audit/submit! cfg accept-invitation-from-event)
+ ;; NOTE: Backward compatibility; old invitations can
+ ;; have the `created-by` to be nil; so in this case we
+ ;; don't submit this event to the audit-log
+ (when-let [created-by (:created-by invitation)]
+ (audit/submit!
+ cfg
+ (-> (audit/event-from-rpc-params params)
+ (assoc ::audit/profile-id created-by)
+ (assoc ::audit/name "accept-team-invitation-from")
+ (assoc ::audit/props (assoc props
+ :profile-id (:id profile)
+ :email (:email profile))))))
(accept-invitation cfg claims invitation profile)
(assoc claims :state :created))
diff --git a/backend/src/app/rpc/commands/viewer.clj b/backend/src/app/rpc/commands/viewer.clj
index 641d564af6..b258420ee1 100644
--- a/backend/src/app/rpc/commands/viewer.clj
+++ b/backend/src/app/rpc/commands/viewer.clj
@@ -12,7 +12,6 @@
[app.config :as cf]
[app.db :as db]
[app.rpc :as-alias rpc]
- [app.rpc.commands.comments :as comments]
[app.rpc.commands.files :as files]
[app.rpc.commands.teams :as teams]
[app.rpc.cond :as-alias cond]
@@ -38,10 +37,10 @@
team (-> (db/get conn :team {:id (:team-id project)})
(teams/decode-row))
- members (into #{} (->> (teams/get-team-members conn (:team-id project))
- (map :id)))
+ members (teams/get-team-members conn (:team-id project))
+ member-ids (into #{} (map :id) members)
- perms (assoc perms :in-team (contains? members profile-id))
+ perms (assoc perms :in-team (contains? member-ids profile-id))
_ (-> (cfeat/get-team-enabled-features cf/flags team)
(cfeat/check-client-features! (:features params))
@@ -55,7 +54,6 @@
(update :data select-keys [:id :options :pages :pages-index :components]))
libs (files/get-file-libraries conn file-id)
- users (comments/get-file-comments-users conn file-id profile-id)
links (->> (db/query conn :share-link {:file-id file-id})
(mapv (fn [row]
(-> row
@@ -71,7 +69,7 @@
{:team-id (:id team)
:deleted-at nil})]
- {:users users
+ {:users members
:fonts fonts
:project project
:share-links links
diff --git a/backend/test/backend_tests/rpc_comment_test.clj b/backend/test/backend_tests/rpc_comment_test.clj
index 9e0f864742..d500352b3f 100644
--- a/backend/test/backend_tests/rpc_comment_test.clj
+++ b/backend/test/backend_tests/rpc_comment_test.clj
@@ -177,7 +177,7 @@
;; (th/print-result! out)
(t/is (th/success? out))
(let [[thread :as result] (:result out)]
- (t/is (= 1 (count result)))))
+ (t/is (= 0 (count result)))))
(let [data {::th/type :update-comment-thread-status
::rpc/profile-id (:id profile-1)
diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc
index 0f59271f85..2465a9e98a 100644
--- a/common/src/app/common/data.cljc
+++ b/common/src/app/common/data.cljc
@@ -653,6 +653,28 @@
(into new-elems)
(into (drop index coll))))
+(defn interleave-all
+ "Like interleave, but stops when the longest seq is done, instead of the shortest."
+ ([] ())
+ ([c1] (lazy-seq c1))
+ ([c1 c2]
+ (lazy-seq
+ (let [s1 (seq c1) s2 (seq c2)]
+ (cond
+ ;; Interleave as it
+ (and s1 s2)
+ (cons (first s1)
+ (cons (first s2)
+ (interleave-all (rest s1) (rest s2))))
+ ;; s2 is empty, we return s1
+ s1 s1
+ ;; s1 is empty
+ s2 s2))))
+ ([c1 c2 & colls]
+ (lazy-seq
+ (let [ss (filter identity (map seq (conj colls c2 c1)))]
+ (c/concat (map first ss) (apply interleave-all (map rest ss)))))))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Data Parsing / Conversion
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/common/src/app/common/logic/shapes.cljc b/common/src/app/common/logic/shapes.cljc
index a3dee69609..2d9dd4464e 100644
--- a/common/src/app/common/logic/shapes.cljc
+++ b/common/src/app/common/logic/shapes.cljc
@@ -304,7 +304,9 @@
(->> ids
(mapcat #(ctn/get-child-heads objects %))
(map :id)))
- cell (or cell (ctl/get-cell-by-index parent to-index))]
+
+ index-cell-data (when to-index (ctl/get-cell-by-index parent to-index))
+ cell (or cell (and index-cell-data [(:row index-cell-data) (:column index-cell-data)]))]
(-> changes
(pcb/with-page-id page-id)
diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc
index 1101fd55ac..84a8f0000b 100644
--- a/common/src/app/common/types/shape/layout.cljc
+++ b/common/src/app/common/types/shape/layout.cljc
@@ -1479,7 +1479,7 @@
(defn get-cell-by-index
[parent to-index]
(let [cells (get-cells parent {:sort? true :remove-empty? true})
- to-index (- (count cells) to-index)]
+ to-index (- (count cells) to-index 1)]
(nth cells to-index nil)))
(defn add-children-to-index
diff --git a/docker/devenv/files/nginx.conf b/docker/devenv/files/nginx.conf
index 961b3a4fb4..1777f8a88e 100644
--- a/docker/devenv/files/nginx.conf
+++ b/docker/devenv/files/nginx.conf
@@ -90,6 +90,7 @@ http {
proxy_hide_header x-amz-meta-server-side-encryption;
proxy_hide_header x-amz-server-side-encryption;
proxy_pass $redirect_uri;
+ proxy_ssl_server_name on;
add_header x-internal-redirect "$redirect_uri";
add_header x-cache-control "$redirect_cache_control";
diff --git a/docker/images/files/nginx.conf b/docker/images/files/nginx.conf
index ee2f641750..e03f7ef0b2 100644
--- a/docker/images/files/nginx.conf
+++ b/docker/images/files/nginx.conf
@@ -92,6 +92,7 @@ http {
proxy_hide_header x-amz-request-id;
proxy_hide_header x-amz-meta-server-side-encryption;
proxy_hide_header x-amz-server-side-encryption;
+ proxy_ssl_server_name on;
proxy_pass $redirect_uri;
add_header x-internal-redirect "$redirect_uri";
diff --git a/docs/plugins/deployment.md b/docs/plugins/deployment.md
index 5b8951dd6b..a225d0a58f 100644
--- a/docs/plugins/deployment.md
+++ b/docs/plugins/deployment.md
@@ -216,3 +216,9 @@ Success! - Published to example-plugin-penpot.surge.sh
```
5. Done!
+
+## 3.5. Submitting to Penpot
+
+To make your finished plugin available in our catalog, submit in on the [plugin submission page](https://penpot.app/penpothub/plugins/create-plugin). Once it becomes available any Penpot user will be able to install and use it.
+
+
diff --git a/docs/technical-guide/developer/ui.md b/docs/technical-guide/developer/ui.md
index fbcf300ca8..db958e2cd6 100644
--- a/docs/technical-guide/developer/ui.md
+++ b/docs/technical-guide/developer/ui.md
@@ -84,7 +84,7 @@ However, we might want to control the aspect of the icons, or limit which icons
[{:keys [icon children] :rest props}]
(assert (or (nil? icon) (contains? valid-icon-list icon) "expected valid icon id"))
[:> "button" props
- (when icon [:> icon* {:id icon :size "m"}])
+ (when icon [:> icon* {:icon-id icon :size "m"}])
children])
```
@@ -160,7 +160,7 @@ Nested styles for DOM elements that are not instantiated by our component should
[{:keys [icon children class] :rest props}]
(let [props (mf/spread-props props {:class (stl/css :button)})]
[:> "button" props
- (when icon [:> icon* {:id icon :size "m"}])
+ (when icon [:> icon* {:icon-id icon :size "m"}])
[:span {:class (stl/css :label-wrapper)} children]]))
;; later in code
diff --git a/docs/user-guide/workspace-basics/index.njk b/docs/user-guide/workspace-basics/index.njk
index dfb5bee2a4..09fb5a07e8 100644
--- a/docs/user-guide/workspace-basics/index.njk
+++ b/docs/user-guide/workspace-basics/index.njk
@@ -250,11 +250,6 @@ geometric structure. In Penpot there are three types of guides:
Navigate actions
To navigate through the actions press Ctrl/⌘ + Z to go backwards and Ctrl/⌘ + Shift/⇧ + Z to go forward.
You can also press any item of the actions list to get to this specific state.
-
-
-
Comments allow the team to have one priceless conversation getting and providing feedback right over the designs and prototypes.
diff --git a/frontend/deps.edn b/frontend/deps.edn
index 8febd1edd0..a64a3d5ba1 100644
--- a/frontend/deps.edn
+++ b/frontend/deps.edn
@@ -9,8 +9,8 @@
funcool/okulary {:mvn/version "2022.04.11-16"}
funcool/potok2
- {:git/tag "v2.1"
- :git/sha "84c97b9"
+ {:git/tag "v2.2"
+ :git/sha "0f7e15a"
:git/url "https://github.com/funcool/potok.git"
:exclusions [funcool/beicon2]}
@@ -20,8 +20,8 @@
:git/url "https://github.com/funcool/beicon.git"}
funcool/rumext
- {:git/tag "v2.15"
- :git/sha "28783a7"
+ {:git/tag "v2.18"
+ :git/sha "b6e8f45"
:git/url "https://github.com/funcool/rumext.git"}
instaparse/instaparse {:mvn/version "1.5.0"}
diff --git a/frontend/externs/main.txt b/frontend/externs/main.txt
new file mode 100644
index 0000000000..cb9613622a
--- /dev/null
+++ b/frontend/externs/main.txt
@@ -0,0 +1,3392 @@
+a
+b
+c
+d
+e
+f
+g
+h
+i
+j
+k
+l
+m
+n
+o
+p
+q
+r
+s
+t
+u
+v
+w
+x
+y
+z
+A
+B
+C
+D
+E
+F
+G
+H
+I
+J
+K
+L
+M
+N
+O
+P
+Q
+R
+S
+T
+U
+V
+W
+X
+Y
+Z
+$
+aa
+ab
+ac
+ad
+ae
+af
+ag
+ah
+ai
+aj
+ak
+al
+am
+an
+ao
+ap
+aq
+ar
+as
+at
+au
+av
+aw
+ax
+ay
+az
+aA
+aB
+aC
+aD
+aE
+aF
+aG
+aH
+aI
+aJ
+aK
+aL
+aM
+aN
+aO
+aP
+aQ
+aR
+aS
+aT
+aU
+aV
+aW
+aX
+aY
+aZ
+a$
+a0
+a1
+a2
+a3
+a4
+a5
+a6
+a7
+a8
+a9
+ba
+bb
+bc
+bd
+be
+bf
+bg
+bh
+bi
+bj
+bk
+bl
+bm
+bn
+bo
+bp
+bq
+br
+bs
+bt
+bu
+bv
+bw
+bx
+by
+bz
+bA
+bB
+bC
+bD
+bE
+bF
+bG
+bH
+bI
+bJ
+bK
+bL
+bM
+bN
+bO
+bP
+bQ
+bR
+bS
+bT
+bU
+bV
+bW
+bX
+bY
+bZ
+b$
+b0
+b1
+b2
+b3
+b4
+b5
+b6
+b7
+b8
+b9
+ca
+cb
+cc
+cd
+ce
+cf
+cg
+ch
+ci
+cj
+ck
+cl
+cm
+cn
+co
+cp
+cq
+cr
+cs
+ct
+cu
+cv
+cw
+cx
+cy
+cz
+cA
+cB
+cC
+cD
+cE
+cF
+cG
+cH
+cI
+cJ
+cK
+cL
+cM
+cN
+cO
+cP
+cQ
+cR
+cS
+cT
+cU
+cV
+cW
+cX
+cY
+cZ
+c$
+c0
+c1
+c2
+c3
+c4
+c5
+c6
+c7
+c8
+c9
+da
+db
+dc
+dd
+de
+df
+dg
+dh
+di
+dj
+dk
+dl
+dm
+dn
+do
+dp
+dq
+dr
+ds
+dt
+du
+dv
+dw
+dx
+dy
+dz
+dA
+dB
+dC
+dD
+dE
+dF
+dG
+dH
+dI
+dJ
+dK
+dL
+dM
+dN
+dO
+dP
+dQ
+dR
+dS
+dT
+dU
+dV
+dW
+dX
+dY
+dZ
+d$
+d0
+d1
+d2
+d3
+d4
+d5
+d6
+d7
+d8
+d9
+ea
+eb
+ec
+ed
+ee
+ef
+eg
+eh
+ei
+ej
+ek
+el
+em
+en
+eo
+ep
+eq
+er
+es
+et
+eu
+ev
+ew
+ex
+ey
+ez
+eA
+eB
+eC
+eD
+eE
+eF
+eG
+eH
+eI
+eJ
+eK
+eL
+eM
+eN
+eO
+eP
+eQ
+eR
+eS
+eT
+eU
+eV
+eW
+eX
+eY
+eZ
+e$
+e0
+e1
+e2
+e3
+e4
+e5
+e6
+e7
+e8
+e9
+fa
+fb
+fc
+fd
+fe
+ff
+fg
+fh
+fi
+fj
+fk
+fl
+fm
+fn
+fo
+fp
+fq
+fr
+fs
+ft
+fu
+fv
+fw
+fx
+fy
+fz
+fA
+fB
+fC
+fD
+fE
+fF
+fG
+fH
+fI
+fJ
+fK
+fL
+fM
+fN
+fO
+fP
+fQ
+fR
+fS
+fT
+fU
+fV
+fW
+fX
+fY
+fZ
+f$
+f0
+f1
+f2
+f3
+f4
+f5
+f6
+f7
+f8
+f9
+ga
+gb
+gc
+gd
+ge
+gf
+gg
+gh
+gi
+gj
+gk
+gl
+gm
+gn
+go
+gp
+gq
+gr
+gs
+gt
+gu
+gv
+gw
+gx
+gy
+gz
+gA
+gB
+gC
+gD
+gE
+gF
+gG
+gH
+gI
+gJ
+gK
+gL
+gM
+gN
+gO
+gP
+gQ
+gR
+gS
+gT
+gU
+gV
+gW
+gX
+gY
+gZ
+g$
+g0
+g1
+g2
+g3
+g4
+g5
+g6
+g7
+g8
+g9
+ha
+hb
+hc
+hd
+he
+hf
+hg
+hh
+hi
+hj
+hk
+hl
+hm
+hn
+ho
+hp
+hq
+hr
+hs
+ht
+hu
+hv
+hw
+hx
+hy
+hz
+hA
+hB
+hC
+hD
+hE
+hF
+hG
+hH
+hI
+hJ
+hK
+hL
+hM
+hN
+hO
+hP
+hQ
+hR
+hS
+hT
+hU
+hV
+hW
+hX
+hY
+hZ
+h$
+h0
+h1
+h2
+h3
+h4
+h5
+h6
+h7
+h8
+h9
+ia
+ib
+ic
+id
+ie
+if
+ig
+ih
+ii
+ij
+ik
+il
+im
+in
+io
+ip
+iq
+ir
+is
+it
+iu
+iv
+iw
+ix
+iy
+iz
+iA
+iB
+iC
+iD
+iE
+iF
+iG
+iH
+iI
+iJ
+iK
+iL
+iM
+iN
+iO
+iP
+iQ
+iR
+iS
+iT
+iU
+iV
+iW
+iX
+iY
+iZ
+i$
+i0
+i1
+i2
+i3
+i4
+i5
+i6
+i7
+i8
+i9
+ja
+jb
+jc
+jd
+je
+jf
+jg
+jh
+ji
+jj
+jk
+jl
+jm
+jn
+jo
+jp
+jq
+jr
+js
+jt
+ju
+jv
+jw
+jx
+jy
+jz
+jA
+jB
+jC
+jD
+jE
+jF
+jG
+jH
+jI
+jJ
+jK
+jL
+jM
+jN
+jO
+jP
+jQ
+jR
+jS
+jT
+jU
+jV
+jW
+jX
+jY
+jZ
+j$
+j0
+j1
+j2
+j3
+j4
+j5
+j6
+j7
+j8
+j9
+ka
+kb
+kc
+kd
+ke
+kf
+kg
+kh
+ki
+kj
+kk
+kl
+km
+kn
+ko
+kp
+kq
+kr
+ks
+kt
+ku
+kv
+kw
+kx
+ky
+kz
+kA
+kB
+kC
+kD
+kE
+kF
+kG
+kH
+kI
+kJ
+kK
+kL
+kM
+kN
+kO
+kP
+kQ
+kR
+kS
+kT
+kU
+kV
+kW
+kX
+kY
+kZ
+k$
+k0
+k1
+k2
+k3
+k4
+k5
+k6
+k7
+k8
+k9
+la
+lb
+lc
+ld
+le
+lf
+lg
+lh
+li
+lj
+lk
+ll
+lm
+ln
+lo
+lp
+lq
+lr
+ls
+lt
+lu
+lv
+lw
+lx
+ly
+lz
+lA
+lB
+lC
+lD
+lE
+lF
+lG
+lH
+lI
+lJ
+lK
+lL
+lM
+lN
+lO
+lP
+lQ
+lR
+lS
+lT
+lU
+lV
+lW
+lX
+lY
+lZ
+l$
+l0
+l1
+l2
+l3
+l4
+l5
+l6
+l7
+l8
+l9
+ma
+mb
+mc
+md
+me
+mf
+mg
+mh
+mi
+mj
+mk
+ml
+mm
+mn
+mo
+mp
+mq
+mr
+ms
+mt
+mu
+mv
+mw
+mx
+my
+mz
+mA
+mB
+mC
+mD
+mE
+mF
+mG
+mH
+mI
+mJ
+mK
+mL
+mM
+mN
+mO
+mP
+mQ
+mR
+mS
+mT
+mU
+mV
+mW
+mX
+mY
+mZ
+m$
+m0
+m1
+m2
+m3
+m4
+m5
+m6
+m7
+m8
+m9
+na
+nb
+nc
+nd
+ne
+nf
+ng
+nh
+ni
+nj
+nk
+nl
+nm
+nn
+no
+np
+nq
+nr
+ns
+nt
+nu
+nv
+nw
+nx
+ny
+nz
+nA
+nB
+nC
+nD
+nE
+nF
+nG
+nH
+nI
+nJ
+nK
+nL
+nM
+nN
+nO
+nP
+nQ
+nR
+nS
+nT
+nU
+nV
+nW
+nX
+nY
+nZ
+n$
+n0
+n1
+n2
+n3
+n4
+n5
+n6
+n7
+n8
+n9
+oa
+ob
+oc
+od
+oe
+of
+og
+oh
+oi
+oj
+ok
+ol
+om
+on
+oo
+op
+oq
+or
+os
+ot
+ou
+ov
+ow
+ox
+oy
+oz
+oA
+oB
+oC
+oD
+oE
+oF
+oG
+oH
+oI
+oJ
+oK
+oL
+oM
+oN
+oO
+oP
+oQ
+oR
+oS
+oT
+oU
+oV
+oW
+oX
+oY
+oZ
+o$
+o0
+o1
+o2
+o3
+o4
+o5
+o6
+o7
+o8
+o9
+pa
+pb
+pc
+pd
+pe
+pf
+pg
+ph
+pi
+pj
+pk
+pl
+pm
+pn
+po
+pp
+pq
+pr
+ps
+pt
+pu
+pv
+pw
+px
+py
+pz
+pA
+pB
+pC
+pD
+pE
+pF
+pG
+pH
+pI
+pJ
+pK
+pL
+pM
+pN
+pO
+pP
+pQ
+pR
+pS
+pT
+pU
+pV
+pW
+pX
+pY
+pZ
+p$
+p0
+p1
+p2
+p3
+p4
+p5
+p6
+p7
+p8
+p9
+qa
+qb
+qc
+qd
+qe
+qf
+qg
+qh
+qi
+qj
+qk
+ql
+qm
+qn
+qo
+qp
+qq
+qr
+qs
+qt
+qu
+qv
+qw
+qx
+qy
+qz
+qA
+qB
+qC
+qD
+qE
+qF
+qG
+qH
+qI
+qJ
+qK
+qL
+qM
+qN
+qO
+qP
+qQ
+qR
+qS
+qT
+qU
+qV
+qW
+qX
+qY
+qZ
+q$
+q0
+q1
+q2
+q3
+q4
+q5
+q6
+q7
+q8
+q9
+ra
+rb
+rc
+rd
+re
+rf
+rg
+rh
+ri
+rj
+rk
+rl
+rm
+rn
+ro
+rp
+rq
+rr
+rs
+rt
+ru
+rv
+rw
+rx
+ry
+rz
+rA
+rB
+rC
+rD
+rE
+rF
+rG
+rH
+rI
+rJ
+rK
+rL
+rM
+rN
+rO
+rP
+rQ
+rR
+rS
+rT
+rU
+rV
+rW
+rX
+rY
+rZ
+r$
+r0
+r1
+r2
+r3
+r4
+r5
+r6
+r7
+r8
+r9
+sa
+sb
+sc
+sd
+se
+sf
+sg
+sh
+si
+sj
+sk
+sl
+sm
+sn
+so
+sp
+sq
+sr
+ss
+st
+su
+sv
+sw
+sx
+sy
+sz
+sA
+sB
+sC
+sD
+sE
+sF
+sG
+sH
+sI
+sJ
+sK
+sL
+sM
+sN
+sO
+sP
+sQ
+sR
+sS
+sT
+sU
+sV
+sW
+sX
+sY
+sZ
+s$
+s0
+s1
+s2
+s3
+s4
+s5
+s6
+s7
+s8
+s9
+ta
+tb
+tc
+td
+te
+tf
+tg
+th
+ti
+tj
+tk
+tl
+tm
+tn
+to
+tp
+tq
+tr
+ts
+tt
+tu
+tv
+tw
+tx
+ty
+tz
+tA
+tB
+tC
+tD
+tE
+tF
+tG
+tH
+tI
+tJ
+tK
+tL
+tM
+tN
+tO
+tP
+tQ
+tR
+tS
+tT
+tU
+tV
+tW
+tX
+tY
+tZ
+t$
+t0
+t1
+t2
+t3
+t4
+t5
+t6
+t7
+t8
+t9
+ua
+ub
+uc
+ud
+ue
+uf
+ug
+uh
+ui
+uj
+uk
+ul
+um
+un
+uo
+up
+uq
+ur
+us
+ut
+uu
+uv
+uw
+ux
+uy
+uz
+uA
+uB
+uC
+uD
+uE
+uF
+uG
+uH
+uI
+uJ
+uK
+uL
+uM
+uN
+uO
+uP
+uQ
+uR
+uS
+uT
+uU
+uV
+uW
+uX
+uY
+uZ
+u$
+u0
+u1
+u2
+u3
+u4
+u5
+u6
+u7
+u8
+u9
+va
+vb
+vc
+vd
+ve
+vf
+vg
+vh
+vi
+vj
+vk
+vl
+vm
+vn
+vo
+vp
+vq
+vr
+vs
+vt
+vu
+vv
+vw
+vx
+vy
+vz
+vA
+vB
+vC
+vD
+vE
+vF
+vG
+vH
+vI
+vJ
+vK
+vL
+vM
+vN
+vO
+vP
+vQ
+vR
+vS
+vT
+vU
+vV
+vW
+vX
+vY
+vZ
+v$
+v0
+v1
+v2
+v3
+v4
+v5
+v6
+v7
+v8
+v9
+wa
+wb
+wc
+wd
+we
+wf
+wg
+wh
+wi
+wj
+wk
+wl
+wm
+wn
+wo
+wp
+wq
+wr
+ws
+wt
+wu
+wv
+ww
+wx
+wy
+wz
+wA
+wB
+wC
+wD
+wE
+wF
+wG
+wH
+wI
+wJ
+wK
+wL
+wM
+wN
+wO
+wP
+wQ
+wR
+wS
+wT
+wU
+wV
+wW
+wX
+wY
+wZ
+w$
+w0
+w1
+w2
+w3
+w4
+w5
+w6
+w7
+w8
+w9
+xa
+xb
+xc
+xd
+xe
+xf
+xg
+xh
+xi
+xj
+xk
+xl
+xm
+xn
+xo
+xp
+xq
+xr
+xs
+xt
+xu
+xv
+xw
+xx
+xy
+xz
+xA
+xB
+xC
+xD
+xE
+xF
+xG
+xH
+xI
+xJ
+xK
+xL
+xM
+xN
+xO
+xP
+xQ
+xR
+xS
+xT
+xU
+xV
+xW
+xX
+xY
+xZ
+x$
+x0
+x1
+x2
+x3
+x4
+x5
+x6
+x7
+x8
+x9
+ya
+yb
+yc
+yd
+ye
+yf
+yg
+yh
+yi
+yj
+yk
+yl
+ym
+yn
+yo
+yp
+yq
+yr
+ys
+yt
+yu
+yv
+yw
+yx
+yy
+yz
+yA
+yB
+yC
+yD
+yE
+yF
+yG
+yH
+yI
+yJ
+yK
+yL
+yM
+yN
+yO
+yP
+yQ
+yR
+yS
+yT
+yU
+yV
+yW
+yX
+yY
+yZ
+y$
+y0
+y1
+y2
+y3
+y4
+y5
+y6
+y7
+y8
+y9
+za
+zb
+zc
+zd
+ze
+zf
+zg
+zh
+zi
+zj
+zk
+zl
+zm
+zn
+zo
+zp
+zq
+zr
+zs
+zt
+zu
+zv
+zw
+zx
+zy
+zz
+zA
+zB
+zC
+zD
+zE
+zF
+zG
+zH
+zI
+zJ
+zK
+zL
+zM
+zN
+zO
+zP
+zQ
+zR
+zS
+zT
+zU
+zV
+zW
+zX
+zY
+zZ
+z$
+z0
+z1
+z2
+z3
+z4
+z5
+z6
+z7
+z8
+z9
+Aa
+Ab
+Ac
+Ad
+Ae
+Af
+Ag
+Ah
+Ai
+Aj
+Ak
+Al
+Am
+An
+Ao
+Ap
+Aq
+Ar
+As
+At
+Au
+Av
+Aw
+Ax
+Ay
+Az
+AA
+AB
+AC
+AD
+AE
+AF
+AG
+AH
+AI
+AJ
+AK
+AL
+AM
+AN
+AO
+AP
+AQ
+AR
+AS
+AT
+AU
+AV
+AW
+AX
+AY
+AZ
+A$
+A0
+A1
+A2
+A3
+A4
+A5
+A6
+A7
+A8
+A9
+Ba
+Bb
+Bc
+Bd
+Be
+Bf
+Bg
+Bh
+Bi
+Bj
+Bk
+Bl
+Bm
+Bn
+Bo
+Bp
+Bq
+Br
+Bs
+Bt
+Bu
+Bv
+Bw
+Bx
+By
+Bz
+BA
+BB
+BC
+BD
+BE
+BF
+BG
+BH
+BI
+BJ
+BK
+BL
+BM
+BN
+BO
+BP
+BQ
+BR
+BS
+BT
+BU
+BV
+BW
+BX
+BY
+BZ
+B$
+B0
+B1
+B2
+B3
+B4
+B5
+B6
+B7
+B8
+B9
+Ca
+Cb
+Cc
+Cd
+Ce
+Cf
+Cg
+Ch
+Ci
+Cj
+Ck
+Cl
+Cm
+Cn
+Co
+Cp
+Cq
+Cr
+Cs
+Ct
+Cu
+Cv
+Cw
+Cx
+Cy
+Cz
+CA
+CB
+CC
+CD
+CE
+CF
+CG
+CH
+CI
+CJ
+CK
+CL
+CM
+CN
+CO
+CP
+CQ
+CR
+CS
+CT
+CU
+CV
+CW
+CX
+CY
+CZ
+C$
+C0
+C1
+C2
+C3
+C4
+C5
+C6
+C7
+C8
+C9
+Da
+Db
+Dc
+Dd
+De
+Df
+Dg
+Dh
+Di
+Dj
+Dk
+Dl
+Dm
+Dn
+Do
+Dp
+Dq
+Dr
+Ds
+Dt
+Du
+Dv
+Dw
+Dx
+Dy
+Dz
+DA
+DB
+DC
+DD
+DE
+DF
+DG
+DH
+DI
+DJ
+DK
+DL
+DM
+DN
+DO
+DP
+DQ
+DR
+DS
+DT
+DU
+DV
+DW
+DX
+DY
+DZ
+D$
+D0
+D1
+D2
+D3
+D4
+D5
+D6
+D7
+D8
+D9
+Ea
+Eb
+Ec
+Ed
+Ee
+Ef
+Eg
+Eh
+Ei
+Ej
+Ek
+El
+Em
+En
+Eo
+Ep
+Eq
+Er
+Es
+Et
+Eu
+Ev
+Ew
+Ex
+Ey
+Ez
+EA
+EB
+EC
+ED
+EE
+EF
+EG
+EH
+EI
+EJ
+EK
+EL
+EM
+EN
+EO
+EP
+EQ
+ER
+ES
+ET
+EU
+EV
+EW
+EX
+EY
+EZ
+E$
+E0
+E1
+E2
+E3
+E4
+E5
+E6
+E7
+E8
+E9
+Fa
+Fb
+Fc
+Fd
+Fe
+Ff
+Fg
+Fh
+Fi
+Fj
+Fk
+Fl
+Fm
+Fn
+Fo
+Fp
+Fq
+Fr
+Fs
+Ft
+Fu
+Fv
+Fw
+Fx
+Fy
+Fz
+FA
+FB
+FC
+FD
+FE
+FF
+FG
+FH
+FI
+FJ
+FK
+FL
+FM
+FN
+FO
+FP
+FQ
+FR
+FS
+FT
+FU
+FV
+FW
+FX
+FY
+FZ
+F$
+F0
+F1
+F2
+F3
+F4
+F5
+F6
+F7
+F8
+F9
+Ga
+Gb
+Gc
+Gd
+Ge
+Gf
+Gg
+Gh
+Gi
+Gj
+Gk
+Gl
+Gm
+Gn
+Go
+Gp
+Gq
+Gr
+Gs
+Gt
+Gu
+Gv
+Gw
+Gx
+Gy
+Gz
+GA
+GB
+GC
+GD
+GE
+GF
+GG
+GH
+GI
+GJ
+GK
+GL
+GM
+GN
+GO
+GP
+GQ
+GR
+GS
+GT
+GU
+GV
+GW
+GX
+GY
+GZ
+G$
+G0
+G1
+G2
+G3
+G4
+G5
+G6
+G7
+G8
+G9
+Ha
+Hb
+Hc
+Hd
+He
+Hf
+Hg
+Hh
+Hi
+Hj
+Hk
+Hl
+Hm
+Hn
+Ho
+Hp
+Hq
+Hr
+Hs
+Ht
+Hu
+Hv
+Hw
+Hx
+Hy
+Hz
+HA
+HB
+HC
+HD
+HE
+HF
+HG
+HH
+HI
+HJ
+HK
+HL
+HM
+HN
+HO
+HP
+HQ
+HR
+HS
+HT
+HU
+HV
+HW
+HX
+HY
+HZ
+H$
+H0
+H1
+H2
+H3
+H4
+H5
+H6
+H7
+H8
+H9
+Ia
+Ib
+Ic
+Id
+Ie
+If
+Ig
+Ih
+Ii
+Ij
+Ik
+Il
+Im
+In
+Io
+Ip
+Iq
+Ir
+Is
+It
+Iu
+Iv
+Iw
+Ix
+Iy
+Iz
+IA
+IB
+IC
+ID
+IE
+IF
+IG
+IH
+II
+IJ
+IK
+IL
+IM
+IN
+IO
+IP
+IQ
+IR
+IS
+IT
+IU
+IV
+IW
+IX
+IY
+IZ
+I$
+I0
+I1
+I2
+I3
+I4
+I5
+I6
+I7
+I8
+I9
+Ja
+Jb
+Jc
+Jd
+Je
+Jf
+Jg
+Jh
+Ji
+Jj
+Jk
+Jl
+Jm
+Jn
+Jo
+Jp
+Jq
+Jr
+Js
+Jt
+Ju
+Jv
+Jw
+Jx
+Jy
+Jz
+JA
+JB
+JC
+JD
+JE
+JF
+JG
+JH
+JI
+JJ
+JK
+JL
+JM
+JN
+JO
+JP
+JQ
+JR
+JS
+JT
+JU
+JV
+JW
+JX
+JY
+JZ
+J$
+J0
+J1
+J2
+J3
+J4
+J5
+J6
+J7
+J8
+J9
+Ka
+Kb
+Kc
+Kd
+Ke
+Kf
+Kg
+Kh
+Ki
+Kj
+Kk
+Kl
+Km
+Kn
+Ko
+Kp
+Kq
+Kr
+Ks
+Kt
+Ku
+Kv
+Kw
+Kx
+Ky
+Kz
+KA
+KB
+KC
+KD
+KE
+KF
+KG
+KH
+KI
+KJ
+KK
+KL
+KM
+KN
+KO
+KP
+KQ
+KR
+KS
+KT
+KU
+KV
+KW
+KX
+KY
+KZ
+K$
+K0
+K1
+K2
+K3
+K4
+K5
+K6
+K7
+K8
+K9
+La
+Lb
+Lc
+Ld
+Le
+Lf
+Lg
+Lh
+Li
+Lj
+Lk
+Ll
+Lm
+Ln
+Lo
+Lp
+Lq
+Lr
+Ls
+Lt
+Lu
+Lv
+Lw
+Lx
+Ly
+Lz
+LA
+LB
+LC
+LD
+LE
+LF
+LG
+LH
+LI
+LJ
+LK
+LL
+LM
+LN
+LO
+LP
+LQ
+LR
+LS
+LT
+LU
+LV
+LW
+LX
+LY
+LZ
+L$
+L0
+L1
+L2
+L3
+L4
+L5
+L6
+L7
+L8
+L9
+Ma
+Mb
+Mc
+Md
+Me
+Mf
+Mg
+Mh
+Mi
+Mj
+Mk
+Ml
+Mm
+Mn
+Mo
+Mp
+Mq
+Mr
+Ms
+Mt
+Mu
+Mv
+Mw
+Mx
+My
+Mz
+MA
+MB
+MC
+MD
+ME
+MF
+MG
+MH
+MI
+MJ
+MK
+ML
+MM
+MN
+MO
+MP
+MQ
+MR
+MS
+MT
+MU
+MV
+MW
+MX
+MY
+MZ
+M$
+M0
+M1
+M2
+M3
+M4
+M5
+M6
+M7
+M8
+M9
+Na
+Nb
+Nc
+Nd
+Ne
+Nf
+Ng
+Nh
+Ni
+Nj
+Nk
+Nl
+Nm
+Nn
+No
+Np
+Nq
+Nr
+Ns
+Nt
+Nu
+Nv
+Nw
+Nx
+Ny
+Nz
+NA
+NB
+NC
+ND
+NE
+NF
+NG
+NH
+NI
+NJ
+NK
+NL
+NM
+NN
+NO
+NP
+NQ
+NR
+NS
+NT
+NU
+NV
+NW
+NX
+NY
+NZ
+N$
+N0
+N1
+N2
+N3
+N4
+N5
+N6
+N7
+N8
+N9
+Oa
+Ob
+Oc
+Od
+Oe
+Of
+Og
+Oh
+Oi
+Oj
+Ok
+Ol
+Om
+On
+Oo
+Op
+Oq
+Or
+Os
+Ot
+Ou
+Ov
+Ow
+Ox
+Oy
+Oz
+OA
+OB
+OC
+OD
+OE
+OF
+OG
+OH
+OI
+OJ
+OK
+OL
+OM
+ON
+OO
+OP
+OQ
+OR
+OS
+OT
+OU
+OV
+OW
+OX
+OY
+OZ
+O$
+O0
+O1
+O2
+O3
+O4
+O5
+O6
+O7
+O8
+O9
+Pa
+Pb
+Pc
+Pd
+Pe
+Pf
+Pg
+Ph
+Pi
+Pj
+Pk
+Pl
+Pm
+Pn
+Po
+Pp
+Pq
+Pr
+Ps
+Pt
+Pu
+Pv
+Pw
+Px
+Py
+Pz
+PA
+PB
+PC
+PD
+PE
+PF
+PG
+PH
+PI
+PJ
+PK
+PL
+PM
+PN
+PO
+PP
+PQ
+PR
+PS
+PT
+PU
+PV
+PW
+PX
+PY
+PZ
+P$
+P0
+P1
+P2
+P3
+P4
+P5
+P6
+P7
+P8
+P9
+Qa
+Qb
+Qc
+Qd
+Qe
+Qf
+Qg
+Qh
+Qi
+Qj
+Qk
+Ql
+Qm
+Qn
+Qo
+Qp
+Qq
+Qr
+Qs
+Qt
+Qu
+Qv
+Qw
+Qx
+Qy
+Qz
+QA
+QB
+QC
+QD
+QE
+QF
+QG
+QH
+QI
+QJ
+QK
+QL
+QM
+QN
+QO
+QP
+QQ
+QR
+QS
+QT
+QU
+QV
+QW
+QX
+QY
+QZ
+Q$
+Q0
+Q1
+Q2
+Q3
+Q4
+Q5
+Q6
+Q7
+Q8
+Q9
+Ra
+Rb
+Rc
+Rd
+Re
+Rf
+Rg
+Rh
+Ri
+Rj
+Rk
+Rl
+Rm
+Rn
+Ro
+Rp
+Rq
+Rr
+Rs
+Rt
+Ru
+Rv
+Rw
+Rx
+Ry
+Rz
+RA
+RB
+RC
+RD
+RE
+RF
+RG
+RH
+RI
+RJ
+RK
+RL
+RM
+RN
+RO
+RP
+RQ
+RR
+RS
+RT
+RU
+RV
+RW
+RX
+RY
+RZ
+R$
+R0
+R1
+R2
+R3
+R4
+R5
+R6
+R7
+R8
+R9
+Sa
+Sb
+Sc
+Sd
+Se
+Sf
+Sg
+Sh
+Si
+Sj
+Sk
+Sl
+Sm
+Sn
+So
+Sp
+Sq
+Sr
+Ss
+St
+Su
+Sv
+Sw
+Sx
+Sy
+Sz
+SA
+SB
+SC
+SD
+SE
+SF
+SG
+SH
+SI
+SJ
+SK
+SL
+SM
+SN
+SO
+SP
+SQ
+SR
+SS
+ST
+SU
+SV
+SW
+SX
+SY
+SZ
+S$
+S0
+S1
+S2
+S3
+S4
+S5
+S6
+S7
+S8
+S9
+Ta
+Tb
+Tc
+Td
+Te
+Tf
+Tg
+Th
+Ti
+Tj
+Tk
+Tl
+Tm
+Tn
+To
+Tp
+Tq
+Tr
+Ts
+Tt
+Tu
+Tv
+Tw
+Tx
+Ty
+Tz
+TA
+TB
+TC
+TD
+TE
+TF
+TG
+TH
+TI
+TJ
+TK
+TL
+TM
+TN
+TO
+TP
+TQ
+TR
+TS
+TT
+TU
+TV
+TW
+TX
+TY
+TZ
+T$
+T0
+T1
+T2
+T3
+T4
+T5
+T6
+T7
+T8
+T9
+Ua
+Ub
+Uc
+Ud
+Ue
+Uf
+Ug
+Uh
+Ui
+Uj
+Uk
+Ul
+Um
+Un
+Uo
+Up
+Uq
+Ur
+Us
+Ut
+Uu
+Uv
+Uw
+Ux
+Uy
+Uz
+UA
+UB
+UC
+UD
+UE
+UF
+UG
+UH
+UI
+UJ
+UK
+UL
+UM
+UN
+UO
+UP
+UQ
+UR
+US
+UT
+UU
+UV
+UW
+UX
+UY
+UZ
+U$
+U0
+U1
+U2
+U3
+U4
+U5
+U6
+U7
+U8
+U9
+Va
+Vb
+Vc
+Vd
+Ve
+Vf
+Vg
+Vh
+Vi
+Vj
+Vk
+Vl
+Vm
+Vn
+Vo
+Vp
+Vq
+Vr
+Vs
+Vt
+Vu
+Vv
+Vw
+Vx
+Vy
+Vz
+VA
+VB
+VC
+VD
+VE
+VF
+VG
+VH
+VI
+VJ
+VK
+VL
+VM
+VN
+VO
+VP
+VQ
+VR
+VS
+VT
+VU
+VV
+VW
+VX
+VY
+VZ
+V$
+V0
+V1
+V2
+V3
+V4
+V5
+V6
+V7
+V8
+V9
+Wa
+Wb
+Wc
+Wd
+We
+Wf
+Wg
+Wh
+Wi
+Wj
+Wk
+Wl
+Wm
+Wn
+Wo
+Wp
+Wq
+Wr
+Ws
+Wt
+Wu
+Wv
+Ww
+Wx
+Wy
+Wz
+WA
+WB
+WC
+WD
+WE
+WF
+WG
+WH
+WI
+WJ
+WK
+WL
+WM
+WN
+WO
+WP
+WQ
+WR
+WS
+WT
+WU
+WV
+WW
+WX
+WY
+WZ
+W$
+W0
+W1
+W2
+W3
+W4
+W5
+W6
+W7
+W8
+W9
+Xa
+Xb
+Xc
+Xd
+Xe
+Xf
+Xg
+Xh
+Xi
+Xj
+Xk
+Xl
+Xm
+Xn
+Xo
+Xp
+Xq
+Xr
+Xs
+Xt
+Xu
+Xv
+Xw
+Xx
+Xy
+Xz
+XA
+XB
+XC
+XD
+XE
+XF
+XG
+XH
+XI
+XJ
+XK
+XL
+XM
+XN
+XO
+XP
+XQ
+XR
+XS
+XT
+XU
+XV
+XW
+XX
+XY
+XZ
+X$
+X0
+X1
+X2
+X3
+X4
+X5
+X6
+X7
+X8
+X9
+Ya
+Yb
+Yc
+Yd
+Ye
+Yf
+Yg
+Yh
+Yi
+Yj
+Yk
+Yl
+Ym
+Yn
+Yo
+Yp
+Yq
+Yr
+Ys
+Yt
+Yu
+Yv
+Yw
+Yx
+Yy
+Yz
+YA
+YB
+YC
+YD
+YE
+YF
+YG
+YH
+YI
+YJ
+YK
+YL
+YM
+YN
+YO
+YP
+YQ
+YR
+YS
+YT
+YU
+YV
+YW
+YX
+YY
+YZ
+Y$
+Y0
+Y1
+Y2
+Y3
+Y4
+Y5
+Y6
+Y7
+Y8
+Y9
+Za
+Zb
+Zc
+Zd
+Ze
+Zf
+Zg
+Zh
+Zi
+Zj
+Zk
+Zl
+Zm
+Zn
+Zo
+Zp
+Zq
+Zr
+Zs
+Zt
+Zu
+Zv
+Zw
+Zx
+Zy
+Zz
+ZA
+ZB
+ZC
+ZD
+ZE
+ZF
+ZG
+ZH
+ZI
+ZJ
+ZK
+ZL
+ZM
+ZN
+ZO
+ZP
+ZQ
+ZR
+ZS
+ZT
+ZU
+ZV
+ZW
+ZX
+ZY
+ZZ
+Z$
+Z0
+Z1
+Z2
+Z3
+Z4
+Z5
+Z6
+Z7
+Z8
+Z9
+$a
+$b
+$c
+$d
+$e
+$f
+$g
+$h
+$i
+$j
+$k
+$l
+$m
+$n
+$o
+$p
+$q
+$r
+$s
+$t
+$u
+$v
+$w
+$x
+$y
+$z
+$A
+$B
+$C
+$D
+$E
+$F
+$G
+$H
+$I
+$J
+$K
+$L
+$M
+$N
+$O
+$P
+$Q
+$R
+$S
+$T
+$U
+$V
+$W
+$X
+$Y
+$Z
+$$
+$0
+$1
+$2
+$3
+$4
+$5
+$6
+$7
+$8
+$9
diff --git a/frontend/externs/worker.txt b/frontend/externs/worker.txt
new file mode 120000
index 0000000000..f446a60e65
--- /dev/null
+++ b/frontend/externs/worker.txt
@@ -0,0 +1 @@
+main.txt
\ No newline at end of file
diff --git a/frontend/playwright/ui/pages/ViewerPage.js b/frontend/playwright/ui/pages/ViewerPage.js
index 311c0c45ff..7a2a96bcef 100644
--- a/frontend/playwright/ui/pages/ViewerPage.js
+++ b/frontend/playwright/ui/pages/ViewerPage.js
@@ -104,8 +104,7 @@ export class ViewerPage extends BaseWebSocketPage {
async showCommentsThread(number, clickOptions = {}) {
await this.page
- .getByTestId("floating-thread-bubble")
- .filter({ hasText: number.toString() })
+ .getByTestId(`floating-thread-bubble-${number.toString()}`)
.click(clickOptions);
}
diff --git a/frontend/playwright/ui/specs/viewer-comments.spec.js b/frontend/playwright/ui/specs/viewer-comments.spec.js
index 4ed32135a3..5e923ef6ae 100644
--- a/frontend/playwright/ui/specs/viewer-comments.spec.js
+++ b/frontend/playwright/ui/specs/viewer-comments.spec.js
@@ -19,12 +19,8 @@ test("Comment is shown with scroll and valid position", async ({ page }) => {
});
await viewer.showComments();
await viewer.showCommentsThread(1);
- await expect(
- viewer.page.getByRole("textbox", { name: "Reply" }),
- ).toBeVisible();
+ await expect(viewer.page.getByRole("textbox")).toBeVisible();
await viewer.showCommentsThread(1);
await viewer.showCommentsThread(2);
- await expect(
- viewer.page.getByRole("textbox", { name: "Reply" }),
- ).toBeVisible();
+ await expect(viewer.page.getByRole("textbox")).toBeVisible();
});
diff --git a/frontend/resources/images/icons/at.svg b/frontend/resources/images/icons/at.svg
new file mode 100644
index 0000000000..72e5ff01db
--- /dev/null
+++ b/frontend/resources/images/icons/at.svg
@@ -0,0 +1 @@
+
diff --git a/frontend/resources/styles/common/refactor/basic-rules.scss b/frontend/resources/styles/common/refactor/basic-rules.scss
index 5096ecd6a5..8b43750ab2 100644
--- a/frontend/resources/styles/common/refactor/basic-rules.scss
+++ b/frontend/resources/styles/common/refactor/basic-rules.scss
@@ -810,28 +810,6 @@
}
}
-.comment-bubbles {
- @include bodySmallTypography;
- @include flexCenter;
- height: $s-32;
- width: $s-32;
- border-radius: $br-circle;
- background-color: var(--comment-bullet-background-color-rest);
- border: $s-1 solid var(--comment-bullet-border-color-rest);
- color: var(--comment-bullet-foreground-color-rest);
-}
-
-.resolved-comment-bubble {
- background-color: var(--comment-bullet-background-color-resolved);
- border: $s-1 solid var(--comment-bullet-border-color-resolved);
- color: var(--comment-bullet-foreground-color-resolved);
-}
-.unread-comment-bubble {
- background-color: var(--comment-bullet-background-color-unread);
- border: $s-1 solid var(--comment-bullet-border-color-unread);
- color: var(--comment-bullet-foreground-color-unread);
-}
-
// SELECTS AND DROPDOWNS
.menu-dropdown {
@include menuShadow;
diff --git a/frontend/src/app/config.cljs b/frontend/src/app/config.cljs
index f481303bb8..37d28e0541 100644
--- a/frontend/src/app/config.cljs
+++ b/frontend/src/app/config.cljs
@@ -143,6 +143,11 @@
(let [f (obj/get global "externalSessionId")]
(when (fn? f) (f))))
+(defn external-context-info
+ []
+ (let [f (obj/get global "externalContextInfo")]
+ (when (fn? f) (f))))
+
;; --- Helper Functions
(defn ^boolean check-browser? [candidate]
diff --git a/frontend/src/app/main/data/auth.cljs b/frontend/src/app/main/data/auth.cljs
index c1ba640b51..740946b24a 100644
--- a/frontend/src/app/main/data/auth.cljs
+++ b/frontend/src/app/main/data/auth.cljs
@@ -39,24 +39,26 @@
accepting invitation, or third party auth signup or singin."
[{:keys [props] :as profile}]
(letfn [(get-redirect-events [teams]
- (if-let [redirect-href (:login-redirect storage/session)]
- (binding [storage/*sync* true]
- (swap! storage/session dissoc :login-redirect)
- (if (= redirect-href (rt/get-current-href))
- (rx/of (rt/reload true))
- (rx/of (rt/nav-raw :href redirect-href))))
- (if-let [file-id (get props :welcome-file-id)]
- (rx/of (dcm/go-to-workspace
- :file-id file-id
- :team-id (:default-team-id profile))
- (dp/update-profile-props {:welcome-file-id nil}))
+ (if-let [token (:invitation-token profile)]
+ (rx/of (rt/nav :auth-verify-token {:token token}))
+ (if-let [redirect-href (:login-redirect storage/session)]
+ (binding [storage/*sync* true]
+ (swap! storage/session dissoc :login-redirect)
+ (if (= redirect-href (rt/get-current-href))
+ (rx/of (rt/reload true))
+ (rx/of (rt/nav-raw :href redirect-href))))
+ (if-let [file-id (get props :welcome-file-id)]
+ (rx/of (dcm/go-to-workspace
+ :file-id file-id
+ :team-id (:default-team-id profile))
+ (dp/update-profile-props {:welcome-file-id nil}))
- (let [teams (into #{} (map :id) teams)
- team-id (dtm/get-last-team-id)
- team-id (if (and team-id (contains? teams team-id))
- team-id
- (:default-team-id profile))]
- (rx/of (dcm/go-to-dashboard-recent {:team-id team-id}))))))]
+ (let [teams (into #{} (map :id) teams)
+ team-id (dtm/get-last-team-id)
+ team-id (if (and team-id (contains? teams team-id))
+ team-id
+ (:default-team-id profile))]
+ (rx/of (dcm/go-to-dashboard-recent {:team-id team-id})))))))]
(ptk/reify ::logged-in
ev/Event
diff --git a/frontend/src/app/main/data/comments.cljs b/frontend/src/app/main/data/comments.cljs
index 3dc86b5a33..73d8a4c0fc 100644
--- a/frontend/src/app/main/data/comments.cljs
+++ b/frontend/src/app/main/data/comments.cljs
@@ -25,7 +25,7 @@
[:file-id ::sm/uuid]
[:project-id ::sm/uuid]
[:owner-id ::sm/uuid]
- [:page-name :string]
+ [:page-name {:optional true} :string]
[:file-name :string]
[:seqn :int]
[:content :string]
@@ -55,6 +55,19 @@
(declare retrieve-comment-threads)
(declare refresh-comment-thread)
+(def r-mentions #"@\[([^\]]*)\]\(([^\)]*)\)")
+
+(defn extract-mentions
+ "Retrieves the mentions in the content as an array of uuids"
+ [content]
+ (->> (re-seq r-mentions content)
+ (mapv (fn [[_ _ id]] (uuid/uuid id)))))
+
+(defn update-mentions
+ "Updates the params object with the mentiosn"
+ [{:keys [content] :as props}]
+ (assoc props :mentions (extract-mentions content)))
+
(defn created-thread-on-workspace
([params]
(created-thread-on-workspace params true))
@@ -103,7 +116,9 @@
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
frame-id (ctst/get-frame-id-by-position objects (:position params))
- params (assoc params :frame-id frame-id)]
+ params (-> params
+ (update-mentions)
+ (assoc :frame-id frame-id))]
(->> (rp/cmd! :create-comment-thread params)
(rx/mapcat #(rp/cmd! :get-comment-thread {:file-id (:file-id %) :id (:id %)}))
(rx/tap on-thread-created)
@@ -156,7 +171,9 @@
(watch [_ state _]
(let [share-id (-> state :viewer-local :share-id)
frame-id (:frame-id params)
- params (assoc params :share-id share-id :frame-id frame-id)]
+ params (-> params
+ (update-mentions)
+ (assoc :share-id share-id :frame-id frame-id))]
(->> (rp/cmd! :create-comment-thread params)
(rx/mapcat #(rp/cmd! :get-comment-thread {:file-id (:file-id %) :id (:id %) :share-id share-id}))
(rx/map created-thread-on-viewer)
@@ -228,9 +245,15 @@
(watch [_ state _]
(let [share-id (-> state :viewer-local :share-id)
created (fn [comment state]
- (update-in state [:comments (:id thread)] assoc (:id comment) comment))]
+ (update-in state [:comments (:id thread)] assoc (:id comment) comment))
+
+ params
+ (-> {:thread-id (:id thread)
+ :content content
+ :share-id share-id}
+ (update-mentions))]
(rx/concat
- (->> (rp/cmd! :create-comment {:thread-id (:id thread) :content content :share-id share-id})
+ (->> (rp/cmd! :create-comment params)
(rx/map (fn [comment] (partial created comment)))
(rx/catch (fn [{:keys [type code] :as cause}]
(if (and (= type :restriction)
@@ -260,8 +283,10 @@
ptk/WatchEvent
(watch [_ state _]
(let [file-id (:current-file-id state)
- share-id (-> state :viewer-local :share-id)]
- (->> (rp/cmd! :update-comment {:id id :content content :share-id share-id})
+ share-id (-> state :viewer-local :share-id)
+ params (-> {:id id :content content :share-id share-id}
+ (update-mentions))]
+ (->> (rp/cmd! :update-comment params)
(rx/catch #(rx/throw {:type :comment-error}))
(rx/map #(retrieve-comment-threads file-id)))))))
@@ -502,11 +527,11 @@
(d/update-in-when [:comments-local :draft] merge data)))))
(defn toggle-comment-options
- [comment]
+ [comment-id]
(ptk/reify ::toggle-comment-options
ptk/UpdateEvent
(update [_ state]
- (update-in state [:comments-local :options] #(if (= (:id comment) %) nil (:id comment))))))
+ (update-in state [:comments-local :options] #(if (= comment-id %) nil comment-id)))))
(defn hide-comment-options
[]
@@ -559,7 +584,10 @@
(filter (comp not :is-resolved))
(= :yours mode)
- (filter #(contains? (:participants %) (:id profile))))))
+ (filter #(contains? (:participants %) (:id profile)))
+
+ (= :mentions mode)
+ (filter #(contains? (set (:mentions %)) (:id profile))))))
(defn update-comment-thread-frame
([thread]
diff --git a/frontend/src/app/main/data/common.cljs b/frontend/src/app/main/data/common.cljs
index 925c314677..0036824b14 100644
--- a/frontend/src/app/main/data/common.cljs
+++ b/frontend/src/app/main/data/common.cljs
@@ -307,7 +307,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [team-id (or team-id (:current-team-id state))]
- (rx/of (rt/nav :dashboard-libraries {:team-id team-id}))))))
+ (rx/of (rt/nav :dashboard-fonts {:team-id team-id}))))))
(defn go-to-dashboard-recent
[& {:keys [team-id] :as options}]
@@ -367,14 +367,14 @@
(watch [_ state _]
(let [team-id (or team-id (:current-team-id state))
file-id (or file-id (:current-file-id state))
- ;: FIXME: why not :current-page-id
- page-id (or page-id
+ page-id (or page-id (:current-page-id state)
(dm/get-in state [:workspace-data :pages 0]))
+
params (-> (rt/get-params state)
(assoc :team-id team-id)
(assoc :file-id file-id)
(assoc :page-id page-id)
- (assoc :layout layout)
+ (update :layout #(or layout %))
(d/without-nils))]
(rx/of (rt/nav :workspace params options))))))
diff --git a/frontend/src/app/main/data/dashboard.cljs b/frontend/src/app/main/data/dashboard.cljs
index 49756a5592..54f64e9656 100644
--- a/frontend/src/app/main/data/dashboard.cljs
+++ b/frontend/src/app/main/data/dashboard.cljs
@@ -361,7 +361,7 @@
;; --- EVENT: delete-file
(defn file-deleted
- [_team-id project-id]
+ [project-id]
(ptk/reify ::file-deleted
ptk/UpdateEvent
(update [_ state]
@@ -378,10 +378,9 @@
(d/update-when :recent-files dissoc id)))
ptk/WatchEvent
- (watch [_ state _]
- (let [team-id (uuid/uuid (get-in state [:route :path-params :team-id]))]
- (->> (rp/cmd! :delete-file {:id id})
- (rx/map #(file-deleted team-id project-id)))))))
+ (watch [_ _ _]
+ (->> (rp/cmd! :delete-file {:id id})
+ (rx/map (partial file-deleted project-id))))))
;; --- Rename File
diff --git a/frontend/src/app/main/data/event.cljs b/frontend/src/app/main/data/event.cljs
index ff5250be7e..51d59b6f97 100644
--- a/frontend/src/app/main/data/event.cljs
+++ b/frontend/src/app/main/data/event.cljs
@@ -8,6 +8,7 @@
(:require
["ua-parser-js" :as ua]
[app.common.data :as d]
+ [app.common.json :as json]
[app.common.logging :as l]
[app.config :as cf]
[app.main.repo :as rp]
@@ -93,6 +94,11 @@
data
data))
+(defn add-external-context-info
+ [context]
+ (let [external-context-info (json/->clj (cf/external-context-info))]
+ (merge context external-context-info)))
+
(defn- process-event-by-proto
[event]
(let [data (d/deep-merge (-data event) (meta event))
@@ -102,6 +108,7 @@
(assoc :event-origin (::origin data))
(assoc :event-namespace (namespace type))
(assoc :event-symbol ev-name)
+ (add-external-context-info)
(d/without-nils))
props (-> data d/without-qualified simplify-props)]
@@ -119,6 +126,7 @@
(let [type (::type data "action")
context (-> (::context data)
(assoc :event-origin (::origin data))
+ (add-external-context-info)
(d/without-nils))
props (-> data d/without-qualified simplify-props)]
{:type type
diff --git a/frontend/src/app/main/data/profile.cljs b/frontend/src/app/main/data/profile.cljs
index 6ae1641694..2a22ad57eb 100644
--- a/frontend/src/app/main/data/profile.cljs
+++ b/frontend/src/app/main/data/profile.cljs
@@ -208,7 +208,6 @@
;; Social registered users don't have old-password
[:password-old {:optional true} [:maybe :string]]])
-
(defn update-password
[data]
(dm/assert!
@@ -233,6 +232,32 @@
(rx/empty)))
(rx/ignore))))))
+(def ^:private schema:update-notifications
+ [:map {:title "NotificationsForm"}
+ [:dashboard-comments [::sm/one-of #{:all :partial :none}]]
+ [:email-comments [::sm/one-of #{:all :partial :none}]]
+ [:email-invites [::sm/one-of #{:all :none}]]])
+
+(defn update-notifications
+ [data]
+ (dm/assert!
+ "expected valid parameters"
+ (sm/check schema:update-notifications data))
+
+ (ptk/reify ::update-notifications
+ ev/Event
+ (-data [_] {})
+
+ ptk/WatchEvent
+ (watch [_ _ _]
+ (let [{:keys [on-error on-success]
+ :or {on-error identity
+ on-success identity}} (meta data)]
+ (->> (rp/cmd! :update-profile-notifications data)
+ (rx/tap on-success)
+ (rx/catch #(do (on-error %) (rx/empty)))
+ (rx/ignore))))))
+
(defn update-profile-props
[props]
(ptk/reify ::update-profile-props
diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs
index c289ec5ca9..05353ffdf2 100644
--- a/frontend/src/app/main/data/workspace.cljs
+++ b/frontend/src/app/main/data/workspace.cljs
@@ -254,6 +254,22 @@
(dwsl/initialize-shape-layout)
(fetch-libraries file-id))))))
+(defn zoom-to-frame
+ []
+ (ptk/reify ::zoom-to-frame
+ ptk/WatchEvent
+ (watch [_ state _]
+ (let [params (rt/get-params state)
+ board-id (get params :board-id)
+ board-id (cond
+ (vector? board-id) board-id
+ (string? board-id) [board-id])
+ frames-id (->> board-id
+ (map uuid/uuid)
+ (into (d/ordered-set)))]
+ (rx/of (dws/select-shapes frames-id)
+ dwz/zoom-to-selected-shape)))))
+
(defn- fetch-bundle
"Multi-stage file bundle fetch coordinator"
[file-id]
@@ -290,7 +306,6 @@
:features features
:thumbnails thumbnails})))))
(rx/map bundle-fetched)))
-
(rx/take-until stopper-s))))))
(defn initialize-workspace
@@ -334,6 +349,13 @@
(rx/take 1)
(rx/map #(dwl/go-to-local-component :id component-id))))
+ (when (:board-id rparams)
+ (->> stream
+ (rx/filter (ptk/type? ::workspace-initialized))
+ (rx/observe-on :async)
+ (rx/take 1)
+ (rx/map zoom-to-frame)))
+
(->> stream
(rx/filter dch/commit?)
(rx/map deref)
@@ -1913,6 +1935,13 @@
(update [_ state]
(assoc-in state [:workspace-global :show-distances?] value))))
+(defn copy-link-to-clipboard
+ []
+ (ptk/reify ::copy-link-to-clipboard
+ ptk/WatchEvent
+ (watch [_ _ _]
+ (wapi/write-to-clipboard (rt/get-current-href)))))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Interactions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/frontend/src/app/main/data/workspace/comments.cljs b/frontend/src/app/main/data/workspace/comments.cljs
index d1b250cc1d..1688ec3322 100644
--- a/frontend/src/app/main/data/workspace/comments.cljs
+++ b/frontend/src/app/main/data/workspace/comments.cljs
@@ -151,11 +151,13 @@
(pcb/with-page page)
(pcb/set-comment-thread-position thread))]
- (rx/merge
- (rx/of (dch/commit-changes changes))
- (->> (rp/cmd! :update-comment-thread-position thread)
- (rx/catch #(rx/throw {:type :update-comment-thread-position}))
- (rx/ignore))))))))
+ (rx/concat
+ (rx/merge
+ (rx/of (dch/commit-changes changes))
+ (->> (rp/cmd! :update-comment-thread-position thread)
+ (rx/catch #(rx/throw {:type :update-comment-thread-position}))
+ (rx/ignore)))
+ (rx/of (dcmt/refresh-comment-thread thread))))))))
;; Move comment threads that are inside a frame when that frame is moved"
(defmethod ptk/resolve ::move-frame-comment-threads
diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs
index 7125453b58..2fdd28d01e 100644
--- a/frontend/src/app/main/data/workspace/selection.cljs
+++ b/frontend/src/app/main/data/workspace/selection.cljs
@@ -26,6 +26,7 @@
[app.main.data.workspace.undo :as dwu]
[app.main.data.workspace.zoom :as dwz]
[app.main.refs :as refs]
+ [app.main.router :as rt]
[app.main.streams :as ms]
[app.main.worker :as uw]
[app.util.mouse :as mse]
@@ -138,12 +139,25 @@
ptk/WatchEvent
(watch [_ state _]
- (let [page-id (:current-page-id state)
- objects (wsh/lookup-page-objects state page-id)]
+ (let [page-id (:current-page-id state)
+ objects (wsh/lookup-page-objects state page-id)
+ selected-id (wsh/lookup-selected state)
+ selected (wsh/lookup-shapes state selected-id)
+ frame-ids (map (fn [item] (let [parent (cfh/get-frame objects (:id item))]
+ (:id parent))) selected)
+ params-without-board (-> (rt/get-params state)
+ (dissoc :board-id))
+ params-board (-> (rt/get-params state)
+ (assoc :board-id frame-ids))]
+
(rx/of
(dwc/expand-all-parents [id] objects)
:interrupt
- ::dwsp/interrupt))))))
+ ::dwsp/interrupt)
+
+ (if (some #(= % uuid/zero) frame-ids)
+ (rx/of (rt/nav :workspace params-without-board {::rt/replace true}))
+ (rx/of (rt/nav :workspace params-board {::rt/replace true}))))))))
(defn select-prev-shape
([]
@@ -290,8 +304,11 @@
([check-modal]
(ptk/reify ::deselect-all
ptk/WatchEvent
- (watch [_ _ _]
- (rx/of ::dwsp/interrupt))
+ (watch [_ state _]
+ (let [params-without-board (-> (rt/get-params state)
+ (dissoc :board-id))]
+ (rx/of ::dwsp/interrupt)
+ (rx/of (rt/nav :workspace params-without-board {::rt/replace true}))))
ptk/UpdateEvent
(update [_ state]
diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs
index 40879477ec..3a41175bd3 100644
--- a/frontend/src/app/main/data/workspace/shortcuts.cljs
+++ b/frontend/src/app/main/data/workspace/shortcuts.cljs
@@ -85,6 +85,11 @@
:subsections [:edit]
:fn #(st/emit! (dw/copy-selected))}
+ :copy-link {:tooltip (ds/meta (ds/alt "C"))
+ :command (ds/c-mod "alt+c")
+ :subsections [:edit]
+ :fn #(st/emit! (dw/copy-link-to-clipboard))}
+
:cut {:tooltip (ds/meta "X")
:command (ds/c-mod "x")
:subsections [:edit]
diff --git a/frontend/src/app/main/data/workspace/thumbnails.cljs b/frontend/src/app/main/data/workspace/thumbnails.cljs
index 0d2ef2239f..132db9156a 100644
--- a/frontend/src/app/main/data/workspace/thumbnails.cljs
+++ b/frontend/src/app/main/data/workspace/thumbnails.cljs
@@ -52,6 +52,11 @@
(defonce queue
(q/create find-request (/ 1000 30)))
+(defn clear-queue!
+ []
+ (l/dbg :hint "clearing thumbnail queue")
+ (q/clear! queue))
+
;; This function first renders the HTML calling `render/render-frame` that
;; returns HTML as a string, then we send that data to the iframe rasterizer
;; that returns the image as a Blob. Finally we create a URI for that blob.
diff --git a/frontend/src/app/main/data/workspace/versions.cljs b/frontend/src/app/main/data/workspace/versions.cljs
index 3a8243c63e..250d13deb6 100644
--- a/frontend/src/app/main/data/workspace/versions.cljs
+++ b/frontend/src/app/main/data/workspace/versions.cljs
@@ -12,6 +12,7 @@
[app.main.data.event :as ev]
[app.main.data.persistence :as dwp]
[app.main.data.workspace :as dw]
+ [app.main.data.workspace.thumbnails :as th]
[app.main.refs :as refs]
[app.main.repo :as rp]
[app.util.time :as dt]
@@ -100,19 +101,23 @@
(rx/concat
(rx/of ::dwp/force-persist
(dw/remove-layout-flag :document-history))
-
- ;; FIXME: we should abstract this
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
(rx/filter #(or (nil? %) (= :saved %)))
(rx/take 1)
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id}))
+ (rx/tap #(th/clear-queue!))
(rx/map #(dw/initialize-workspace file-id)))
+ (case origin
+ :version
+ (rx/of (ptk/event ::ev/event {::ev/name "restore-pin-version"}))
- (when-let [name (case origin
- :version "restore-pin-version"
- :snapshot "restore-autosave"
- nil)]
- (rx/of (ptk/event ::ev/event {::ev/name name}))))))))
+ :snapshot
+ (rx/of (ptk/event ::ev/event {::ev/name "restore-autosave"}))
+
+ :plugin
+ (rx/of (ptk/event ::ev/event {::ev/name "restore-version-plugin"}))
+
+ (rx/empty)))))))
(defn delete-version
[id]
diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs
index 88f8383f83..04a099208f 100644
--- a/frontend/src/app/main/refs.cljs
+++ b/frontend/src/app/main/refs.cljs
@@ -267,9 +267,9 @@
(def workspace-page-flows
(l/derived #(-> % :flows not-empty) workspace-page))
-(defn workspace-page-objects-by-id
- [page-id]
- (l/derived #(wsh/lookup-page-objects % page-id) st/state =))
+(defn workspace-page-object-by-id
+ [page-id shape-id]
+ (l/derived #(wsh/lookup-shape % page-id shape-id) st/state =))
;; TODO: Looks like using the `=` comparator can be pretty expensive
;; on large pages, we are using this for some reason?
diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs
index 95f42507b5..ee962d4b6b 100644
--- a/frontend/src/app/main/ui.cljs
+++ b/frontend/src/app/main/ui.cljs
@@ -149,6 +149,7 @@
(let [{:keys [data params]} route
props (get profile :props)
section (get data :name)
+ team (mf/deref refs/team)
show-question-modal?
@@ -166,10 +167,12 @@
(and (contains? cf/flags :onboarding)
(not (:onboarding-viewed props))
(not (contains? props :onboarding-team-id))
- (contains? props :newsletter-updates))
+ (contains? props :newsletter-updates)
+ (:is-default team))
show-release-modal?
(and (contains? cf/flags :onboarding)
+ (not (contains? cf/flags :hide-release-modal))
(:onboarding-viewed props)
(not= (:release-notes-viewed props) (:main cf/version))
(not= "0.0" (:main cf/version)))]
@@ -191,7 +194,8 @@
:settings-password
:settings-options
:settings-feedback
- :settings-access-tokens)
+ :settings-access-tokens
+ :settings-notifications)
[:? [:& settings-page {:route route}]]
:debug-icons-preview
diff --git a/frontend/src/app/main/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs
index e30b259577..10bf80d3b5 100644
--- a/frontend/src/app/main/ui/auth/login.cljs
+++ b/frontend/src/app/main/ui/auth/login.cljs
@@ -120,17 +120,10 @@
:else
(reset! error (tr "errors.generic")))))
- on-success-default
- (mf/use-fn
- (fn [data]
- (when-let [token (:invitation-token data)]
- (st/emit! (rt/nav :auth-verify-token {:token token})))))
-
on-success
(fn [data]
- (if (nil? on-success-callback)
- (on-success-default data)
- (on-success-callback)))
+ (when (fn? on-success-callback)
+ (on-success-callback data)))
on-submit
(mf/use-callback
diff --git a/frontend/src/app/main/ui/comments.cljs b/frontend/src/app/main/ui/comments.cljs
index 643c35d23c..942ee27ac6 100644
--- a/frontend/src/app/main/ui/comments.cljs
+++ b/frontend/src/app/main/ui/comments.cljs
@@ -9,7 +9,10 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
+ [app.common.files.helpers :as cfh]
[app.common.geom.point :as gpt]
+ [app.common.math :as mth]
+ [app.common.uuid :as uuid]
[app.config :as cfg]
[app.main.data.comments :as dcm]
[app.main.data.modal :as modal]
@@ -17,65 +20,380 @@
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]]
+ [app.main.ui.ds.buttons.button :refer [button*]]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
+ [app.main.ui.ds.foundations.assets.icon :refer [icon*]]
+ [app.main.ui.hooks :as h]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[app.util.keyboard :as kbd]
+ [app.util.object :as obj]
[app.util.time :as dt]
+ [app.util.webapi :as wapi]
+ [beicon.v2.core :as rx]
+ [clojure.math :refer [floor]]
[cuerdas.core :as str]
[okulary.core :as l]
[rumext.v2 :as mf]))
(def comments-local-options (l/derived :options refs/comments-local))
-(mf/defc resizing-textarea
+(def mentions-context (mf/create-context nil))
+
+(def r-mentions-split #"@\[[^\]]*\]\([^\)]*\)")
+(def r-mentions #"@\[([^\]]*)\]\(([^\)]*)\)")
+
+
+(defn- parse-comment
+ "Parse a comment into its elements (texts and mentions)"
+ [comment]
+ (d/interleave-all
+ (->> (str/split comment r-mentions-split)
+ (map #(hash-map :type :text :content %)))
+
+ (->> (re-seq r-mentions comment)
+ (map (fn [[_ user id]]
+ {:type :mention
+ :content user
+ :data {:id id}})))))
+
+(defn parse-nodes
+ "Parse the nodes to format a comment"
+ [node]
+ (->> (dom/get-children node)
+ (map
+ (fn [node]
+ (cond
+ (and (instance? js/HTMLElement node) (dom/get-data node "user-id"))
+ (str/ffmt "@[%](%)" (.-textContent node) (dom/get-data node "user-id"))
+
+ :else
+ (.-textContent node))))
+ (str/join "")))
+
+
+(defn create-text-node
+ "Creates a text-only node"
+ ([]
+ (create-text-node ""))
+ ([text]
+ (-> (dom/create-element "span")
+ (dom/set-data! "type" "text")
+ (dom/set-html! (if (empty? text) "" text)))))
+
+(defn create-mention-node
+ "Creates a mention node"
+ [id fullname]
+ (-> (dom/create-element "span")
+ (dom/set-data! "type" "mention")
+ (dom/set-data! "user-id" (dm/str id))
+ (dom/set-data! "fullname" fullname)
+ (obj/set! "textContent" fullname)))
+
+(defn current-text-node
+ "Retrieves the text node and the offset that the cursor is positioned on"
+ [node]
+
+ (let [selection (wapi/get-selection)
+ range (wapi/get-range selection 0)
+ anchor-node (wapi/range-start-container range)
+ anchor-offset (wapi/range-start-offset range)]
+ (when (and node (.contains node anchor-node))
+ (let [span-node
+ (if (instance? js/Text anchor-node)
+ (dom/get-parent anchor-node)
+ anchor-node)
+ container (dom/get-parent span-node)]
+ (when (= node container)
+ [span-node anchor-offset])))))
+
+(defn absolute-offset
+ [node child offset]
+ (loop [nodes (seq (dom/get-children node))
+ acc 0]
+ (if-let [head (first nodes)]
+ (if (= head child)
+ (+ acc offset)
+ (recur (rest nodes) (+ acc (.-length (.-textContent head)))))
+ nil)))
+
+(defn get-prev-node
+ [parent node]
+ (->> (d/with-prev (dom/get-children parent))
+ (d/seek (fn [[it _]] (= node it)))
+ (second)))
+
+;; Component that renders the component content
+(mf/defc comment-content
+ [{:keys [content]}]
+ (let [comment-elements (mf/use-memo (mf/deps content) #(parse-comment content))]
+ (for [[idx {:keys [type content]}] (d/enumerate comment-elements)]
+ (case type
+ [:span
+ {:key idx
+ :class (stl/css-case
+ :comment-text (= type :text)
+ :comment-mention (= type :mention))}
+ content]))))
+
+;; Input text for comments with mentions
+(mf/defc comment-input
{::mf/wrap-props false}
[props]
+
(let [value (d/nilv (unchecked-get props "value") "")
+ prev-value (h/use-previous value)
+
+ local-ref (mf/use-ref nil)
+ mentions-str (mf/use-ctx mentions-context)
+ cur-mention (mf/use-var nil)
+
+ prev-selection (mf/use-var nil)
+
on-focus (unchecked-get props "on-focus")
on-blur (unchecked-get props "on-blur")
placeholder (unchecked-get props "placeholder")
- max-length (unchecked-get props "max-length")
on-change (unchecked-get props "on-change")
on-esc (unchecked-get props "on-esc")
on-ctrl-enter (unchecked-get props "on-ctrl-enter")
+ max-length (unchecked-get props "max-length")
autofocus? (unchecked-get props "autofocus")
- select-on-focus? (unchecked-get props "select-on-focus")
- local-ref (mf/use-ref)
+ init-input
+ (mf/use-callback
+ (fn [node]
+ (mf/set-ref-val! local-ref node)
+ (when node
+ (doseq [{:keys [type content data]} (parse-comment value)]
+ (case type
+ :text (dom/append-child! node (create-text-node content))
+ :mention (dom/append-child! node (create-mention-node (:id data) content))
+ nil)))))
- on-change*
- (mf/use-fn
+ handle-input
+ (mf/use-callback
(mf/deps on-change)
- (fn [event]
- (let [content (dom/get-target-val event)]
- (on-change content))))
+ (fn []
+ (let [node (mf/ref-val local-ref)
+ children (dom/get-children node)]
- on-key-down
+ (doseq [child-node children]
+ ;; Remove nodes that are not span. This can happen if the user copy/pastes
+ (when (not= (.-tagName child-node) "SPAN")
+ (.remove child-node))
+
+ ;; If a node is empty we set the content to "empty"
+ (when (and (= (dom/get-data child-node "type") "text")
+ (empty? (dom/get-text child-node)))
+ (dom/set-html! child-node ""))
+
+ ;; Remove mentions that have been modified
+ (when (and (= (dom/get-data child-node "type") "mention")
+ (not= (dom/get-data child-node "fullname")
+ (dom/get-text child-node)))
+ (.remove child-node)))
+
+ ;; If there are no nodes we need to create an empty node
+ (when (= 0 (.-length children))
+ (dom/append-child! node (create-text-node)))
+
+ (let [new-input (parse-nodes node)]
+ (when (and on-change (<= (count new-input) max-length))
+ (on-change new-input))))))
+
+ handle-select
+ (mf/use-callback
+ (fn []
+ (let [node (mf/ref-val local-ref)
+ selection (wapi/get-selection)
+ range (wapi/get-range selection 0)
+ anchor-node (wapi/range-start-container range)]
+ (when (and (= node anchor-node) (.-collapsed range))
+ (wapi/set-cursor-after! anchor-node)))
+
+ (let [node (mf/ref-val local-ref)
+ [span-node offset] (current-text-node node)
+ [prev-span prev-offset] @prev-selection]
+
+ (reset! prev-selection #js [span-node offset])
+
+ (when (= (dom/get-data span-node "type") "mention")
+ (let [from-offset (absolute-offset node prev-span prev-offset)
+ to-offset (absolute-offset node span-node offset)
+
+ [_ prev next]
+ (->> node
+ (dom/seq-nodes)
+ (d/with-prev-next)
+ (filter (fn [[elem _ _]] (= elem span-node)))
+ (first))]
+
+ (if (> from-offset to-offset)
+ (wapi/set-cursor-after! prev)
+ (wapi/set-cursor-before! next))))
+
+ (when span-node
+ (let [node-text (subs (dom/get-text span-node) 0 offset)
+
+ current-at-symbol
+ (str/last-index-of (subs node-text 0 offset) "@")
+
+ mention-text
+ (subs node-text current-at-symbol)]
+
+ (if (re-matches #"@\w*" mention-text)
+ (do
+ (reset! cur-mention mention-text)
+ (rx/push! mentions-str {:type :display-mentions})
+ (let [mention (subs mention-text 1)]
+ (when (d/not-empty? mention)
+ (rx/push! mentions-str {:type :filter-mentions :data mention}))))
+ (do
+ (reset! cur-mention nil)
+ (rx/push! mentions-str {:type :hide-mentions}))))))))
+
+ handle-focus
+ (mf/use-callback
+ (fn [event]
+ (dom/prevent-default event)
+ (dom/set-css-property! (mf/ref-val local-ref) "--placeholder" "")
+ (when on-focus
+ (on-focus event))))
+
+ handle-blur
+ (mf/use-callback
+ (mf/deps value)
+ (fn [event]
+ (when (empty? value)
+ (let [node (mf/ref-val local-ref)]
+ (dom/set-css-property! node "--placeholder" (dm/str "\"" placeholder "\""))))
+
+ (when on-blur
+ (on-blur event))))
+
+ handle-insert-mention
+ (fn [data]
+ (let [node (mf/ref-val local-ref)
+ [span-node offset] (current-text-node node)]
+ (when span-node
+ (let [node-text
+ (dom/get-text span-node)
+
+ current-at-symbol
+ (or (str/last-index-of (subs node-text 0 offset) "@")
+ (absolute-offset node span-node offset))
+
+ mention
+ (re-find #"@\w*" (subs node-text current-at-symbol))
+
+ prefix
+ (subs node-text 0 current-at-symbol)
+
+ suffix
+ (subs node-text (+ current-at-symbol (count mention)))
+
+ mention-span (create-mention-node (-> data :user :id) (-> data :user :fullname))
+ after-span (create-text-node (dm/str " " suffix))
+ sel (wapi/get-selection)]
+
+ (dom/set-html! span-node (if (empty? prefix) "" prefix))
+ (dom/insert-after! node span-node mention-span)
+ (dom/insert-after! node mention-span after-span)
+ (wapi/set-cursor-after! after-span)
+ (wapi/collapse-end! sel)
+
+ (when on-change
+ (on-change (parse-nodes node)))))))
+
+ handle-key-down
(mf/use-fn
- (mf/deps on-esc on-ctrl-enter on-change*)
+ (mf/deps on-esc on-ctrl-enter handle-select handle-input)
(fn [event]
- (cond
- (and (kbd/esc? event) (fn? on-esc)) (on-esc event)
- (and (kbd/mod? event) (kbd/enter? event) (fn? on-ctrl-enter))
- (do
- (on-change* event)
- (on-ctrl-enter event)))))
+ (handle-select event)
- on-focus*
- (mf/use-fn
- (mf/deps select-on-focus? on-focus)
- (fn [event]
- (when (fn? on-focus)
- (on-focus event))
+ (let [node (mf/ref-val local-ref)
+ [span-node offset] (current-text-node node)]
- (when ^boolean select-on-focus?
- (let [target (dom/get-target event)]
- (dom/select-text! target)
- ;; In webkit browsers the mouseup event will be called after the on-focus causing and unselect
- (.addEventListener target "mouseup" dom/prevent-default #js {:once true})))))]
+ (cond
+ (and @cur-mention (kbd/enter? event))
+ (do (dom/prevent-default event)
+ (dom/stop-propagation event)
+ (rx/push! mentions-str {:type :insert-selected-mention}))
+ (and @cur-mention (kbd/down-arrow? event))
+ (do (dom/prevent-default event)
+ (dom/stop-propagation event)
+ (rx/push! mentions-str {:type :insert-next-mention}))
+
+ (and @cur-mention (kbd/up-arrow? event))
+ (do (dom/prevent-default event)
+ (dom/stop-propagation event)
+ (rx/push! mentions-str {:type :insert-prev-mention}))
+
+ (and @cur-mention (kbd/esc? event))
+ (do (dom/prevent-default event)
+ (dom/stop-propagation event)
+ (rx/push! mentions-str {:type :hide-mentions}))
+
+ (and (kbd/esc? event) (fn? on-esc))
+ (on-esc event)
+
+ (and (kbd/mod? event) (kbd/enter? event) (fn? on-ctrl-enter))
+ (on-ctrl-enter event)
+
+ (kbd/enter? event)
+ (let [sel (wapi/get-selection)
+ range (.getRangeAt sel 0)]
+ (dom/prevent-default event)
+ (dom/stop-propagation event)
+ (let [[span-node offset] (current-text-node node)]
+ (.deleteContents range)
+ (handle-input)
+
+ (when span-node
+ (let [txt (.-textContent span-node)]
+ (dom/set-html! span-node (dm/str (subs txt 0 offset) "\n" (subs txt offset)))
+ (wapi/set-cursor! span-node (inc offset))
+ (handle-input)))))
+
+ (kbd/backspace? event)
+ (let [prev-node (get-prev-node node span-node)]
+ (when (and (some? prev-node)
+ (= "mention" (dom/get-data prev-node "type"))
+ (= offset 1))
+ (dom/prevent-default event)
+ (dom/stop-propagation event)
+ (.remove prev-node)))))))]
+
+ (mf/use-layout-effect
+ (mf/deps autofocus?)
+ (fn []
+ (when autofocus?
+ (dom/focus! (mf/ref-val local-ref)))))
+
+ ;; Creates the handlers for selection
+ (mf/use-effect
+ (mf/deps handle-select)
+ (fn []
+ (let [handle-select* handle-select]
+ (js/document.addEventListener "selectionchange" handle-select*)
+ #(js/document.removeEventListener "selectionchange" handle-select*))))
+
+ ;; Effect to communicate with the mentions panel
+ (mf/use-effect
+ (fn []
+ (when mentions-str
+ (->> mentions-str
+ (rx/subs!
+ (fn [{:keys [type data]}]
+ (case type
+ :insert-mention
+ (handle-insert-mention data)
+
+ nil)))))))
+
+ ;; Auto resize input to display the comment
(mf/use-layout-effect
nil
(fn []
@@ -83,18 +401,219 @@
(set! (.-height (.-style node)) "0")
(set! (.-height (.-style node)) (str (+ 2 (.-scrollHeight node)) "px")))))
- [:textarea {:ref local-ref
- :auto-focus autofocus?
- :on-key-down on-key-down
- :on-focus on-focus*
- :on-blur on-blur
- :value value
- :placeholder placeholder
- :on-change on-change*
- :max-length max-length}]))
+ (mf/use-effect
+ (mf/deps value prev-value)
+ (fn []
+ (let [node (mf/ref-val local-ref)]
+ (cond
+ (and (d/not-empty? prev-value) (empty? value))
+ (do (dom/set-html! node "")
+ (dom/append-child! node (create-text-node))
+ (dom/set-css-property! node "--placeholder" "")
+ (dom/focus! node))
-(mf/defc reply-form
- [{:keys [thread] :as props}]
+ (and (some? node) (empty? value) (not (dom/focus? node)))
+ (dom/set-css-property! node "--placeholder" (dm/str "\"" placeholder "\""))
+
+ (some? node)
+ (dom/set-css-property! node "--placeholder" "")))))
+
+ [:div
+ {:role "textbox"
+ :class (stl/css :comment-input)
+ :content-editable "true"
+ :suppress-content-editable-warning true
+ :on-input handle-input
+ :ref init-input
+ :on-key-down handle-key-down
+ :on-focus handle-focus
+ :on-blur handle-blur}]))
+
+(mf/defc mentions-panel
+ [{:keys [profiles]}]
+
+ (let [mentions-str (mf/use-ctx mentions-context)
+
+ profile (mf/deref refs/profile)
+
+ mention-state
+ (mf/use-state {:display? false
+ :mention-filter ""
+ :selected 0})
+
+ {:keys [display? mention-filter selected]} @mention-state
+
+ mentions-users
+ (mf/use-memo
+ (mf/deps mention-filter)
+ #(->> (vals profiles)
+ (filter
+ (fn [{:keys [id fullname email]}]
+ (and
+ (not= id (:id profile))
+ (or (not mention-filter)
+ (empty? mention-filter)
+ (str/includes? (str/lower fullname) (str/lower mention-filter))
+ (str/includes? (str/lower email) (str/lower mention-filter))))))
+ (take 4)
+ (into [])))
+
+ selected (mth/clamp selected 0 (dec (count mentions-users)))
+
+ handle-click-mention
+ (mf/use-callback
+ (fn [event]
+ (dom/prevent-default event)
+ (dom/stop-propagation event)
+ (let [id (-> (dom/get-current-target event)
+ (dom/get-data "user-id")
+ (uuid/uuid))]
+ (rx/push! mentions-str {:type :insert-mention
+ :data {:user (get profiles id)}}))))]
+
+ (mf/use-effect
+ (mf/deps mentions-users selected)
+ (fn []
+ (let [sub
+ (->> mentions-str
+ (rx/subs!
+ (fn [{:keys [type data]}]
+ (case type
+ ;; Display the mentions dialog
+ :display-mentions
+ (swap! mention-state assoc :display? true)
+
+ ;; Hide mentions
+ :hide-mentions
+ (swap! mention-state assoc :display? false :mention-filter "")
+
+ ;; Filter the metions by some characters
+ :filter-mentions
+ (swap! mention-state assoc :mention-filter data)
+
+ :insert-selected-mention
+ (rx/push! mentions-str {:type :insert-mention
+ :data {:user (get mentions-users selected)}})
+
+ :insert-next-mention
+ (swap! mention-state update :selected #(mth/clamp (inc %) 0 (dec (count mentions-users))))
+
+ :insert-prev-mention
+ (swap! mention-state update :selected #(mth/clamp (dec %) 0 (dec (count mentions-users))))
+
+ ;;
+ nil))))]
+ #(rx/dispose! sub))))
+
+ (when display?
+ [:div {:class (stl/css :comments-mentions-choice)}
+ (if (empty? mentions-users)
+ [:div {:class (stl/css :comments-mentions-empty)}
+ (tr "comments.mentions.not-found" mention-filter)]
+
+ (for [[idx {:keys [id fullname email] :as user}] (d/enumerate mentions-users)]
+ [:div {:key id
+ :on-pointer-down handle-click-mention
+ :data-user-id (dm/str id)
+ :class (stl/css-case :comments-mentions-entry true
+ :is-selected (= selected idx))}
+ [:img {:class (stl/css :comments-mentions-avatar)
+ :src (cfg/resolve-profile-photo-url user)}]
+ [:div {:class (stl/css :comments-mentions-name)} fullname]
+ [:div {:class (stl/css :comments-mentions-email)} email]]))])))
+
+(mf/defc mentions-button
+ []
+ (let [mentions-str (mf/use-ctx mentions-context)
+ display-mentions* (mf/use-state false)
+
+ handle-mouse-down
+ (mf/use-callback
+ (fn [event]
+ (dom/prevent-default event)
+ (dom/stop-propagation event)
+ (rx/push! mentions-str {:type :display-mentions})))]
+
+ (mf/use-effect
+ (fn []
+ (let [sub
+ (rx/subs!
+ (fn [{:keys [type _]}]
+ (case type
+ :display-mentions (reset! display-mentions* true)
+ :hide-mentions (reset! display-mentions* false)
+ nil))
+ mentions-str)]
+ #(rx/dispose! sub))))
+
+ [:> icon-button*
+ {:variant "ghost"
+ :aria-label (tr "labels.options")
+ :on-pointer-down handle-mouse-down
+ :icon-class (stl/css-case :open-mentions-button true
+ :is-toggled @display-mentions*)
+ :icon "at"}]))
+
+(def ^:private schema:comment-avatar
+ [:map
+ [:class {:optional true} :string]
+ [:image :string]
+ [:variant {:optional true}
+ [:maybe [:enum "read" "unread" "solved"]]]])
+
+(mf/defc comment-avatar*
+ {::mf/props :obj
+ ::mf/schema schema:comment-avatar}
+ [{:keys [image variant class] :rest props}]
+ (let [variant (or variant "read")
+ class (dm/str class " " (stl/css-case :avatar true
+ :avatar-read (= variant "read")
+ :avatar-unread (= variant "unread")
+ :avatar-solved (= variant "solved")))
+ props (mf/spread-props props {:class class})]
+ [:> :div props
+ [:img {:src image
+ :class (stl/css :avatar-image)}]
+ [:div {:class (stl/css-case :avatar-mask true
+ :avatar-darken (= variant "solved"))}]]))
+
+(mf/defc comment-info*
+ {::mf/props :obj
+ ::mf/private true}
+ [{:keys [item profile]}]
+ [:*
+ [:div {:class (stl/css :author)}
+ [:> comment-avatar* {:image (cfg/resolve-profile-photo-url profile)
+ :class (stl/css :avatar-lg)
+ :variant (cond (:is-resolved item) "solved"
+ (pos? (:count-unread-comments item)) "unread"
+ :else "read")}]
+ [:div {:class (stl/css :author-identity)}
+ [:div {:class (stl/css :author-fullname)} (:fullname profile)]
+ [:div {:class (stl/css :author-timeago)} (dt/timeago (:modified-at item))]]]
+
+ [:div {:class (stl/css :item)}
+ [:> comment-content {:content (:content item)}]]
+
+ [:div {:class (stl/css :replies)}
+ (let [total-comments (:count-comments item 1)
+ total-replies (dec total-comments)
+ unread-replies (:count-unread-comments item 0)]
+ [:*
+ (when (> total-replies 0)
+ (if (= total-replies 1)
+ [:span {:class (stl/css :replies-total)} (str total-replies " " (tr "labels.reply"))]
+ [:span {:class (stl/css :replies-total)} (str total-replies " " (tr "labels.replies"))]))
+
+ (when (and (> total-replies 0) (> unread-replies 0))
+ (if (= unread-replies 1)
+ [:span {:class (stl/css :replies-unread)} (str unread-replies " " (tr "labels.reply.new"))]
+ [:span {:class (stl/css :replies-unread)} (str unread-replies " " (tr "labels.replies.new"))]))])]])
+
+(mf/defc comment-reply-form*
+ {::mf/props :obj
+ ::mf/private true}
+ [{:keys [thread]}]
(let [show-buttons? (mf/use-state false)
content (mf/use-state "")
@@ -124,39 +643,79 @@
(fn []
(st/emit! (dcm/add-comment thread @content))
(on-cancel)))]
- [:div {:class (stl/css :reply-form)}
- [:& resizing-textarea {:value @content
- :placeholder "Reply"
- :on-blur on-blur
- :on-focus on-focus
- :select-on-focus? false
- :on-ctrl-enter on-submit
- :on-change on-change
- :max-length 750}]
+ [:div {:class (stl/css :form)}
+ [:& comment-input
+ {:value @content
+ :placeholder (tr "labels.reply.thread")
+ :autofocus true
+ :on-blur on-blur
+ :on-focus on-focus
+ :select-on-focus? false
+ :on-ctrl-enter on-submit
+ :on-change on-change
+ :max-length 750}]
(when (or @show-buttons? (seq @content))
- [:div {:class (stl/css :buttons-wrapper)}
- [:input.btn-secondary
- {:type "button"
- :class (stl/css :cancel-btn)
- :value "Cancel"
- :on-click on-cancel}]
- [:input
- {:type "button"
- :class (stl/css-case :post-btn true
- :global/disabled disabled?)
- :value "Post"
- :on-click on-submit
- :disabled disabled?}]])]))
+ [:div {:class (stl/css :form-buttons-wrapper)}
+ [:> mentions-button]
+ [:> button* {:variant "ghost"
+ :on-click on-cancel}
+ (tr "ds.confirm-cancel")]
+ [:> button* {:variant "primary"
+ :on-click on-submit
+ :disabled disabled?}
+ (tr "labels.post")]])]))
-(mf/defc draft-thread
- [{:keys [draft zoom on-cancel on-submit position-modifier]}]
- (let [position (cond-> (:position draft)
- (some? position-modifier)
- (gpt/transform position-modifier))
- content (:content draft)
+(mf/defc comment-edit-form*
+ {::mf/props :obj
+ ::mf/private true}
+ [{:keys [content on-submit on-cancel]}]
+ (let [content (mf/use-state content)
- pos-x (* (:x position) zoom)
- pos-y (* (:y position) zoom)
+ on-change
+ (mf/use-fn
+ #(reset! content %))
+
+ on-submit*
+ (mf/use-fn
+ (mf/deps @content)
+ (fn [] (on-submit @content)))
+
+ disabled? (or (str/blank? @content)
+ (str/empty? @content))]
+
+ [:div {:class (stl/css :form)}
+ [:& comment-input
+ {:value @content
+ :autofocus true
+ :select-on-focus true
+ :select-on-focus? false
+ :on-ctrl-enter on-submit*
+ :on-change on-change
+ :max-length 750}]
+ [:div {:class (stl/css :form-buttons-wrapper)}
+ [:> mentions-button]
+ [:> button* {:variant "ghost"
+ :on-click on-cancel}
+ (tr "ds.confirm-cancel")]
+ [:> button* {:variant "primary"
+ :on-click on-submit*
+ :disabled disabled?}
+ (tr "labels.post")]]]))
+
+(mf/defc comment-floating-thread-draft*
+ {::mf/props :obj}
+ [{:keys [draft zoom on-cancel on-submit position-modifier profiles]}]
+ (let [profile (mf/deref refs/profile)
+
+ mentions-str (mf/use-memo #(rx/subject))
+
+ position (cond-> (:position draft)
+ (some? position-modifier)
+ (gpt/transform position-modifier))
+ content (:content draft)
+
+ pos-x (* (:x position) zoom)
+ pos-y (* (:y position) zoom)
disabled? (or (str/blank? content)
(str/empty? content))
@@ -181,79 +740,116 @@
(mf/deps draft)
(partial on-submit draft))]
- [:*
+ [:& (mf/provider mentions-context) {:value mentions-str}
[:div
- {:class (stl/css :floating-thread-bubble)
+ {:class (stl/css :floating-preview-wrapper)
:data-testid "floating-thread-bubble"
:style {:top (str pos-y "px")
:left (str pos-x "px")}
:on-click dom/stop-propagation}
- "?"]
- [:div {:class (stl/css :thread-content)
+ [:> comment-avatar* {:class (stl/css :avatar-lg)
+ :image (cfg/resolve-profile-photo-url profile)}]]
+ [:div {:class (stl/css :floating-thread-wrapper)
:style {:top (str (- pos-y 24) "px")
:left (str (+ pos-x 28) "px")}
:on-click dom/stop-propagation}
- [:div {:class (stl/css :reply-form)}
- [:& resizing-textarea {:placeholder (tr "labels.write-new-comment")
- :value (or content "")
- :autofocus true
- :select-on-focus? false
- :on-esc on-esc
- :on-change on-change
- :on-ctrl-enter on-submit
- :max-length 750}]
- [:div {:class (stl/css :buttons-wrapper)}
+ [:div {:class (stl/css :form)}
+ [:& comment-input
+ {:placeholder (tr "labels.write-new-comment")
+ :value (or content "")
+ :autofocus true
+ :select-on-focus? false
+ :on-esc on-esc
+ :on-change on-change
+ :on-ctrl-enter on-submit
+ :max-length 750}]
- [:input {:on-click on-esc
- :class (stl/css :cancel-btn)
- :type "button"
- :value "Cancel"}]
+ [:div {:class (stl/css :form-buttons-wrapper)}
+ [:> mentions-button]
+ [:> button* {:variant "ghost"
+ :on-click on-esc}
+ (tr "ds.confirm-cancel")]
+ [:> button* {:variant "primary"
+ :on-click on-submit
+ :disabled disabled?}
+ (tr "labels.post")]]]
- [:input {:on-click on-submit
- :type "button"
- :value "Post"
- :class (stl/css-case :post-btn true
- :global/disabled disabled?)
- :disabled disabled?}]]]]]))
+ [:& mentions-panel {:profiles profiles}]]]))
-(mf/defc edit-form
- [{:keys [content on-submit on-cancel] :as props}]
- (let [content (mf/use-state content)
+(mf/defc comment-floating-thread-header*
+ {::mf/props :obj
+ ::mf/private true}
+ [{:keys [profiles thread origin]}]
+ (let [owner (get profiles (:owner-id thread))
+ profile (mf/deref refs/profile)
+ options (mf/deref comments-local-options)
- on-change
+ toggle-resolved
(mf/use-fn
- #(reset! content %))
+ (mf/deps thread)
+ (fn [event]
+ (dom/stop-propagation event)
+ (st/emit! (dcm/update-comment-thread (update thread :is-resolved not)))))
- on-submit*
+ on-toggle-options
(mf/use-fn
- (mf/deps @content)
- (fn [] (on-submit @content)))
+ (fn [event]
+ (dom/stop-propagation event)
+ (st/emit! (dcm/toggle-comment-options uuid/zero))))
- disabled? (or (str/blank? @content)
- (str/empty? @content))]
+ delete-thread
+ (mf/use-fn
+ (fn []
+ (st/emit! (dcm/close-thread)
+ (if (= origin :viewer)
+ (dcm/delete-comment-thread-on-viewer thread)
+ (dcm/delete-comment-thread-on-workspace thread)))))
- [:div {:class (stl/css :edit-form)}
- [:& resizing-textarea {:value @content
- :autofocus true
- :select-on-focus true
- :select-on-focus? false
- :on-ctrl-enter on-submit*
- :on-change on-change
- :max-length 750}]
- [:div {:class (stl/css :buttons-wrapper)}
- [:input {:type "button"
- :value "Cancel"
- :class (stl/css :cancel-btn)
- :on-click on-cancel}]
- [:input {:type "button"
- :class (stl/css-case :post-btn true
- :global/disabled disabled?)
- :value "Post"
- :on-click on-submit*
- :disabled disabled?}]]]))
+ on-delete-thread
+ (mf/use-fn
+ (fn [event]
+ (dom/stop-propagation event)
+ (st/emit! (dcm/hide-comment-options))
+ (st/emit! (modal/show
+ {:type :confirm
+ :title (tr "modals.delete-comment-thread.title")
+ :message (tr "modals.delete-comment-thread.message")
+ :accept-label (tr "modals.delete-comment-thread.accept")
+ :on-accept delete-thread}))))
-(mf/defc comment-item
- [{:keys [comment thread profiles origin] :as props}]
+ on-hide-options
+ (mf/use-fn
+ (mf/deps options)
+ (fn [event]
+ (dom/stop-propagation event)
+ (st/emit! (dcm/hide-comment-options))))]
+
+ [:*
+ [:div {:class (stl/css :floating-thread-header-left)}
+ (tr "labels.comment") " " [:span {:class (stl/css :grayed-text)} "#" (:seqn thread)]]
+ [:div {:class (stl/css :floating-thread-header-right)}
+ (when (some? thread)
+ [:div {:class (stl/css :checkbox-wrapper)
+ :title (tr "labels.comment.mark-as-solved")
+ :on-click toggle-resolved}
+ [:span {:class (stl/css-case :checkbox true
+ :global/checked (:is-resolved thread))} i/tick]])
+ (when (= (:id profile) (:id owner))
+ [:> icon-button* {:variant "ghost"
+ :aria-label (tr "labels.options")
+ :on-click on-toggle-options
+ :icon "menu"}])]
+ [:& dropdown {:show (= options uuid/zero)
+ :on-close on-hide-options}
+ [:ul {:class (stl/css :dropdown-menu)}
+ [:li {:class (stl/css :dropdown-menu-option)
+ :on-click on-delete-thread}
+ (tr "labels.delete-comment-thread")]]]]))
+
+(mf/defc comment-floating-thread-item*
+ {::mf/props :obj
+ ::mf/private true}
+ [{:keys [comment thread profiles]}]
(let [owner (get profiles (:owner-id comment))
profile (mf/deref refs/profile)
options (mf/deref comments-local-options)
@@ -264,7 +860,7 @@
(mf/deps options)
(fn [event]
(dom/stop-propagation event)
- (st/emit! (dcm/toggle-comment-options comment))))
+ (st/emit! (dcm/toggle-comment-options (:id comment)))))
on-hide-options
(mf/use-fn
@@ -285,24 +881,6 @@
(mf/deps comment)
#(st/emit! (dcm/delete-comment comment)))
- delete-thread
- (mf/use-fn
- (mf/deps thread)
- #(st/emit! (dcm/close-thread)
- (if (= origin :viewer)
- (dcm/delete-comment-thread-on-viewer thread)
- (dcm/delete-comment-thread-on-workspace thread))))
-
- on-delete-thread
- (mf/use-fn
- (mf/deps thread)
- #(st/emit! (modal/show
- {:type :confirm
- :title (tr "modals.delete-comment-thread.title")
- :message (tr "modals.delete-comment-thread.message")
- :accept-label (tr "modals.delete-comment-thread.accept")
- :on-accept delete-thread})))
-
on-submit
(mf/use-fn
(mf/deps comment thread)
@@ -311,29 +889,15 @@
(st/emit! (dcm/update-comment (assoc comment :content content)))))
on-cancel
- (mf/use-fn #(reset! edition? false))
+ (mf/use-fn #(reset! edition? false))]
- toggle-resolved
- (mf/use-fn
- (mf/deps thread)
- (fn [event]
- (dom/stop-propagation event)
- (st/emit! (dcm/update-comment-thread (update thread :is-resolved not)))))]
-
- [:div {:class (stl/css :comment-container)}
- [:div {:class (stl/css :comment)}
+ [:div {:class (stl/css :floating-thread-item-wrapper)}
+ [:div {:class (stl/css :floating-thread-item)}
[:div {:class (stl/css :author)}
- [:div {:class (stl/css :avatar)}
- [:img {:src (cfg/resolve-profile-photo-url owner)}]]
- [:div {:class (stl/css :name)}
- [:div {:class (stl/css :fullname)} (:fullname owner)]
- [:div {:class (stl/css :timeago)} (dt/timeago (:modified-at comment))]]
-
- (when (some? thread)
- [:div {:class (stl/css :options-resolve-wrapper)
- :on-click toggle-resolved}
- [:span {:class (stl/css-case :options-resolve true
- :global/checked (:is-resolved thread))} i/tick]])
+ [:> comment-avatar* {:image (cfg/resolve-profile-photo-url owner)}]
+ [:div {:class (stl/css :author-identity)}
+ [:div {:class (stl/css :author-fullname)} (:fullname owner)]
+ [:div {:class (stl/css :author-timeago)} (dt/timeago (:modified-at comment))]]
(when (= (:id profile) (:id owner))
[:> icon-button* {:variant "ghost"
@@ -341,24 +905,22 @@
:on-click on-toggle-options
:icon "menu"}])]
- [:div {:class (stl/css :content)}
+ [:div {:class (stl/css :item)}
(if @edition?
- [:& edit-form {:content (:content comment)
- :on-submit on-submit
- :on-cancel on-cancel}]
- [:span {:class (stl/css :text)} (:content comment)])]]
+ [:> comment-edit-form* {:content (:content comment)
+ :on-submit on-submit
+ :on-cancel on-cancel}]
+ [:span {:class (stl/css :text)}
+ [:> comment-content {:content (:content comment)}]])]]
[:& dropdown {:show (= options (:id comment))
:on-close on-hide-options}
- [:ul {:class (stl/css :comment-options-dropdown)}
- [:li {:class (stl/css :context-menu-option)
+ [:ul {:class (stl/css :dropdown-menu)}
+ [:li {:class (stl/css :dropdown-menu-option)
:on-click on-edit-clicked}
(tr "labels.edit")]
- (if thread
- [:li {:class (stl/css :context-menu-option)
- :on-click on-delete-thread}
- (tr "labels.delete-comment-thread")]
- [:li {:class (stl/css :context-menu-option)
+ (when-not thread
+ [:li {:class (stl/css :dropdown-menu-option)
:on-click on-delete-comment}
(tr "labels.delete-comment")])]]]))
@@ -370,48 +932,56 @@
(let [viewport (or viewport {:offset-x 0 :offset-y 0 :width 0 :height 0})
base-x (+ (* (:x position) zoom) (:offset-x viewport))
base-y (+ (* (:y position) zoom) (:offset-y viewport))
+
+ x (:x position)
+ y (:y position)
+
w (:width viewport)
h (:height viewport)
+
comment-width 284 ;; TODO: this is the width set via CSS in an outer container…
;; We should probably do this in a different way.
+
orientation-left? (>= (+ base-x comment-width (:x bubble-margin)) w)
- orientation-top? (>= base-y (/ h 2))
+ orientation-top? (>= base-y (/ h 2))
+
h-dir (if orientation-left? :left :right)
- v-dir (if orientation-top? :top :bottom)
- x (:x position)
- y (:y position)]
+ v-dir (if orientation-top? :top :bottom)]
{:x x :y y :h-dir h-dir :v-dir v-dir}))
-(mf/defc thread-comments
- {::mf/wrap [mf/memo]}
+(mf/defc comment-floating-thread*
+ {::mf/props :obj
+ ::mf/wrap [mf/memo]}
[{:keys [thread zoom profiles origin position-modifier viewport]}]
- (let [ref (mf/use-ref)
- thread-id (:id thread)
- thread-pos (:position thread)
+ (let [ref (mf/use-ref)
+ mentions-str (mf/use-memo #(rx/subject))
+ thread-id (:id thread)
+ thread-pos (:position thread)
- base-pos (cond-> thread-pos
- (some? position-modifier)
- (gpt/transform position-modifier))
+ base-pos (cond-> thread-pos
+ (some? position-modifier)
+ (gpt/transform position-modifier))
- max-height (when (some? viewport) (int (* (:height viewport) 0.75)))
- ;; We should probably look for a better way of doing this.
- bubble-margin {:x 24 :y 0}
- pos (offset-position base-pos viewport zoom bubble-margin)
+ max-height (when (some? viewport) (int (* (obj/get viewport "height") 0.75)))
- margin-x (* (:x bubble-margin) (if (= (:h-dir pos) :left) -1 1))
- margin-y (* (:y bubble-margin) (if (= (:v-dir pos) :top) -1 1))
- pos-x (+ (* (:x pos) zoom) margin-x)
- pos-y (- (* (:y pos) zoom) margin-y)
+ ;; We should probably look for a better way of doing this.
+ bubble-margin {:x 24 :y 24}
+ pos (offset-position base-pos viewport zoom bubble-margin)
- comments-ref (mf/with-memo [thread-id]
- (make-comments-ref thread-id))
- comments-map (mf/deref comments-ref)
+ margin-x (* (:x bubble-margin) (if (= (:h-dir pos) :left) -1 1))
+ margin-y (* (:y bubble-margin) (if (= (:v-dir pos) :top) -1 1))
+ pos-x (+ (* (:x pos) zoom) margin-x)
+ pos-y (- (* (:y pos) zoom) margin-y)
- comments (mf/with-memo [comments-map]
- (->> (vals comments-map)
- (sort-by :created-at)))
+ comments-ref (mf/with-memo [thread-id]
+ (make-comments-ref thread-id))
+ comments-map (mf/deref comments-ref)
- comment (first comments)]
+ comments (mf/with-memo [comments-map]
+ (->> (vals comments-map)
+ (sort-by :created-at)))
+
+ first-comment (first comments)]
(mf/with-effect [thread-id]
(st/emit! (dcm/retrieve-comments thread-id)))
@@ -423,158 +993,172 @@
(when-let [node (mf/ref-val ref)]
(dom/scroll-into-view-if-needed! node)))
- (when (some? comment)
- [:div {:class (stl/css-case :thread-content true
- :thread-content-left (= (:h-dir pos) :left)
- :thread-content-top (= (:v-dir pos) :top))
- :id (str "thread-" thread-id)
- :style {:left (str pos-x "px")
- :top (str pos-y "px")
- :max-height max-height}
- :on-click dom/stop-propagation}
+ [:& (mf/provider mentions-context) {:value mentions-str}
+ (when (some? first-comment)
+ [:div {:class (stl/css-case :floating-thread-wrapper true
+ :left (= (:h-dir pos) :left)
+ :top (= (:v-dir pos) :top))
+ :id (str "thread-" thread-id)
+ :style {:left (str pos-x "px")
+ :top (str pos-y "px")
+ :max-height max-height}
+ :on-click dom/stop-propagation}
- [:div {:class (stl/css :comments)}
- [:& comment-item {:comment comment
- :profiles profiles
- :thread thread
- :origin origin}]
- (for [item (rest comments)]
- [:* {:key (dm/str (:id item))}
- [:& comment-item {:comment item
- :profiles profiles
- :origin origin}]])]
- [:& reply-form {:thread thread}]
- [:div {:ref ref}]])))
+ [:div {:class (stl/css :floating-thread-header)}
+ [:> comment-floating-thread-header* {:profiles profiles
+ :thread thread
+ :origin origin}]]
-(defn use-buble
- [zoom {:keys [position frame-id]}]
- (let [dragging-ref (mf/use-ref false)
+ [:div {:class (stl/css :floating-thread-main)}
+ [:> comment-floating-thread-item* {:comment first-comment
+ :profiles profiles
+ :thread thread}]
+ (for [item (rest comments)]
+ [:* {:key (dm/str (:id item))}
+ [:> comment-floating-thread-item* {:comment item
+ :profiles profiles}]])]
+
+ [:> comment-reply-form* {:thread thread}]
+
+ [:& mentions-panel {:profiles profiles}]])]))
+
+(mf/defc comment-floating-bubble*
+ {::mf/props :obj
+ ::mf/wrap [mf/memo]}
+ [{:keys [thread profiles zoom is-open on-click origin position-modifier]}]
+ (let [owner (get profiles (:owner-id thread))
+
+ base-pos (cond-> (:position thread)
+ (some? position-modifier)
+ (gpt/transform position-modifier))
+
+ drag? (mf/use-ref nil)
+ was-open? (mf/use-ref nil)
+
+ dragging-ref (mf/use-ref false)
start-ref (mf/use-ref nil)
- state (mf/use-state {:hover false
+ position (:position thread)
+ frame-id (:frame-id thread)
+
+ state (mf/use-state {:hover? false
+ :grabbing? false
:new-position-x nil
:new-position-y nil
:new-frame-id frame-id})
+ pos-x (floor (* (or (:new-position-x @state) (:x base-pos)) zoom))
+ pos-y (floor (* (or (:new-position-y @state) (:y base-pos)) zoom))
+
on-pointer-down
(mf/use-fn
+ (mf/deps origin was-open? is-open drag?)
(fn [event]
- (dom/capture-pointer event)
- (mf/set-ref-val! dragging-ref true)
- (mf/set-ref-val! start-ref (dom/get-client-position event))))
+ (when (not= origin :viewer)
+ (swap! state assoc :grabbing? true)
+ (mf/set-ref-val! was-open? is-open)
+ (when is-open (st/emit! (dcm/close-thread)))
+ (mf/set-ref-val! drag? false)
+ (dom/stop-propagation event)
+ (dom/capture-pointer event)
+ (mf/set-ref-val! dragging-ref true)
+ (mf/set-ref-val! start-ref (dom/get-client-position event)))))
on-pointer-up
(mf/use-fn
- (mf/deps (select-keys @state [:new-position-x :new-position-y :new-frame-id]))
- (fn [_ thread]
- (when (and
- (some? (:new-position-x @state))
- (some? (:new-position-y @state)))
- (st/emit! (dwcm/update-comment-thread-position thread [(:new-position-x @state) (:new-position-y @state)])))))
-
- on-lost-pointer-capture
- (mf/use-fn
+ (mf/deps origin thread (select-keys @state [:new-position-x :new-position-y :new-frame-id]))
(fn [event]
- (dom/release-pointer event)
- (mf/set-ref-val! dragging-ref false)
- (mf/set-ref-val! start-ref nil)
- (swap! state assoc :new-position-x nil)
- (swap! state assoc :new-position-y nil)))
+ (when (not= origin :viewer)
+ (swap! state assoc :grabbing? false)
+ (dom/stop-propagation event)
+ (dom/release-pointer event)
+ (mf/set-ref-val! dragging-ref false)
+ (mf/set-ref-val! start-ref nil)
+ (when (and
+ (some? (:new-position-x @state))
+ (some? (:new-position-y @state)))
+ (st/emit! (dwcm/update-comment-thread-position thread [(:new-position-x @state)
+ (:new-position-y @state)]))
+ (swap! state assoc
+ :new-position-x nil
+ :new-position-y nil)))))
on-pointer-move
(mf/use-fn
- (mf/deps position zoom)
- (fn [event]
- (when-let [_ (mf/ref-val dragging-ref)]
- (let [start-pt (mf/ref-val start-ref)
- current-pt (dom/get-client-position event)
- delta-x (/ (- (:x current-pt) (:x start-pt)) zoom)
- delta-y (/ (- (:y current-pt) (:y start-pt)) zoom)]
- (swap! state assoc
- :new-position-x (+ (:x position) delta-x)
- :new-position-y (+ (:y position) delta-y))))))]
-
- {:on-pointer-down on-pointer-down
- :on-pointer-up on-pointer-up
- :on-pointer-move on-pointer-move
- :on-lost-pointer-capture on-lost-pointer-capture
- :state state}))
-
-(mf/defc thread-bubble
- {::mf/wrap [mf/memo]}
- [{:keys [thread zoom open? on-click origin position-modifier]}]
- (let [pos (cond-> (:position thread)
- (some? position-modifier)
- (gpt/transform position-modifier))
-
- drag? (mf/use-ref nil)
- was-open? (mf/use-ref nil)
-
- {:keys [on-pointer-down
- on-pointer-up
- on-pointer-move
- state
- on-lost-pointer-capture]} (use-buble zoom thread)
-
- pos-x (* (or (:new-position-x @state) (:x pos)) zoom)
- pos-y (* (or (:new-position-y @state) (:y pos)) zoom)
-
- on-pointer-down*
- (mf/use-fn
- (mf/deps origin was-open? open? drag? on-pointer-down)
- (fn [event]
- (when (not= origin :viewer)
- (mf/set-ref-val! was-open? open?)
- (when open? (st/emit! (dcm/close-thread)))
- (mf/set-ref-val! drag? false)
- (dom/stop-propagation event)
- (on-pointer-down event))))
-
- on-pointer-up*
- (mf/use-fn
- (mf/deps origin thread was-open? drag? on-pointer-up)
- (fn [event]
- (when (not= origin :viewer)
- (dom/stop-propagation event)
- (on-pointer-up event thread)
-
- (when (or (and (mf/ref-val was-open?) (mf/ref-val drag?))
- (and (not (mf/ref-val was-open?)) (not (mf/ref-val drag?))))
- (st/emit! (dcm/open-thread thread))))))
-
- on-pointer-move*
- (mf/use-fn
- (mf/deps origin drag? on-pointer-move)
+ (mf/deps origin drag? position zoom)
(fn [event]
(when (not= origin :viewer)
(mf/set-ref-val! drag? true)
(dom/stop-propagation event)
- (on-pointer-move event))))
+ (when-let [_ (mf/ref-val dragging-ref)]
+ (let [start-pt (mf/ref-val start-ref)
+ current-pt (dom/get-client-position event)
+ delta-x (/ (- (:x current-pt) (:x start-pt)) zoom)
+ delta-y (/ (- (:y current-pt) (:y start-pt)) zoom)]
+ (swap! state assoc
+ :new-position-x (+ (:x position) delta-x)
+ :new-position-y (+ (:y position) delta-y)))))))
+
+ on-pointer-enter
+ (mf/use-fn
+ (mf/deps is-open)
+ (fn [event]
+ (dom/stop-propagation event)
+ (when (false? is-open)
+ (swap! state assoc :hover? true))))
+
+ on-pointer-leave
+ (mf/use-fn
+ (fn [event]
+ (dom/stop-propagation event)
+ (swap! state assoc :hover? false)))
on-click*
(mf/use-fn
- (mf/deps origin thread on-click)
+ (mf/deps origin thread on-click was-open? drag? (select-keys @state [:hover?]))
(fn [event]
(dom/stop-propagation event)
+ (when (or (and (mf/ref-val was-open?) (mf/ref-val drag?))
+ (and (not (mf/ref-val was-open?)) (not (mf/ref-val drag?))))
+ (swap! state assoc :hover? false)
+ (st/emit! (dcm/open-thread thread)))
(when (= origin :viewer)
(on-click thread))))]
+
[:div {:style {:top (str pos-y "px")
:left (str pos-x "px")}
- :on-pointer-down on-pointer-down*
- :on-pointer-up on-pointer-up*
- :on-pointer-move on-pointer-move*
+ :on-pointer-down on-pointer-down
+ :on-pointer-up on-pointer-up
+ :on-pointer-move on-pointer-move
+ :on-pointer-enter on-pointer-enter
+ :on-pointer-leave on-pointer-leave
:on-click on-click*
- :on-lost-pointer-capture on-lost-pointer-capture
- :data-testid "floating-thread-bubble"
- :class (stl/css-case
- :floating-thread-bubble true
- :resolved (:is-resolved thread)
- :unread (pos? (:count-unread-comments thread)))}
- [:span (:seqn thread)]]))
+ :class (stl/css-case :floating-preview-wrapper true
+ :floating-preview-bubble (false? (:hover? @state))
+ :grabbing (true? (:grabbing? @state)))}
-(mf/defc comment-thread
+ (if (:hover? @state)
+ [:div {:class (stl/css :floating-thread-wrapper :floating-preview-displacement)}
+ [:div {:class (stl/css :floating-thread-item-wrapper)}
+ [:div {:class (stl/css :floating-thread-item)}
+ [:> comment-info* {:item thread
+ :profile owner}]]]]
+
+ [:> comment-avatar* {:image (cfg/resolve-profile-photo-url owner)
+ :class (stl/css :avatar-lg)
+ :data-testid (str "floating-thread-bubble-" (:seqn thread))
+ :variant (cond (:is-resolved thread) "solved"
+ (pos? (:count-unread-comments thread)) "unread"
+ :else "read")}])]))
+
+(mf/defc comment-sidebar-thread-item*
+ {::mf/props :obj
+ ::mf/private true}
[{:keys [item profiles on-click]}]
(let [owner (get profiles (:owner-id item))
+
+ frame (mf/deref (refs/workspace-page-object-by-id (:page-id item) (:frame-id item)))
+
on-click*
(mf/use-fn
(mf/deps item)
@@ -584,52 +1168,64 @@
(when (fn? on-click)
(on-click item))))]
- [:div {:class (stl/css :comment)
+ [:div {:class (stl/css :cover)
:on-click on-click*}
- [:div {:class (stl/css :author)}
- [:div {:class (stl/css-case :thread-bubble true
- :resolved (:is-resolved item)
- :unread (pos? (:count-unread-comments item)))}
- (:seqn item)]
- [:div {:class (stl/css :avatar)}
- [:img {:src (cfg/resolve-profile-photo-url owner)}]]
- [:div {:class (stl/css :name)}
- [:div {:class (stl/css :fullname)} (:fullname owner)]
- [:div {:class (stl/css :timeago)} (dt/timeago (:modified-at item))]]]
- [:div {:class (stl/css :content)}
- (:content item)]
- [:div {:class (stl/css :replies)}
- (let [unread (:count-unread-comments item ::none)
- total (:count-comments item 1)]
- [:*
- (when (> total 1)
- (if (= total 2)
- [:span {:class (stl/css :total-replies)} "1 reply"]
- [:span {:class (stl/css :total-replies)} (str (dec total) " replies")]))
+ [:div {:class (stl/css :location)}
+ [:div {:class (stl/css :location-text)}
+ (str "#" (:seqn item))
+ (str " - " (:page-name item))
+ (when (and (some? frame) (not (cfh/root? frame)))
+ (str " - " (:name frame)))]]
- (when (and (> total 1) (> unread 0))
- (if (= unread 1)
- [:span {:class (stl/css :new-replies)} "1 new reply"]
- [:span {:class (stl/css :new-replies)} (str unread " new replies")]))])]]))
+ [:> comment-info* {:item item
+ :profile owner}]]))
-(mf/defc comment-thread-group
+(mf/defc comment-sidebar-thread-group*
+ {::mf/props :obj}
[{:keys [group profiles on-thread-click]}]
- [:div {:class (stl/css :thread-group)}
- (if (:file-name group)
- [:div {:class (stl/css :section-title)
- :title (str (:file-name group) ", " (:page-name group))}
- [:span {:class (stl/css :file-name)} (:file-name group) ", "]
- [:span {:class (stl/css :page-name)} (:page-name group)]]
+ [:div
+ (for [item (:items group)]
+ [:> comment-sidebar-thread-item*
+ {:item item
+ :on-click on-thread-click
+ :profiles profiles
+ :key (:id item)}])])
- [:div {:class (stl/css :section-title)
- :title (:page-name group)}
- [:span {:class (stl/css :icon)} i/document]
- [:span {:class (stl/css :page-name)} (:page-name group)]])
+(mf/defc comment-dashboard-thread-item*
+ {::mf/props :obj
+ ::mf/private true}
+ [{:keys [item profiles on-click]}]
+ (let [owner (get profiles (:owner-id item))
- [:div {:class (stl/css :threads)}
- (for [item (:items group)]
- [:& comment-thread
- {:item item
- :on-click on-thread-click
- :profiles profiles
- :key (:id item)}])]])
+ on-click*
+ (mf/use-fn
+ (mf/deps item)
+ (fn [event]
+ (dom/stop-propagation event)
+ (dom/prevent-default event)
+ (when (fn? on-click)
+ (on-click item))))]
+
+ [:div {:class (stl/css :cover)
+ :on-click on-click*}
+ [:div {:class (stl/css :location)}
+ [:> icon* {:icon-id "comments"
+ :class (stl/css :location-icon)}]
+ [:div {:class (stl/css :location-text)}
+ (str "#" (:seqn item))
+ (str " " (:file-name item))
+ (str ", " (:page-name item))]]
+
+ [:> comment-info* {:item item
+ :profile owner}]]))
+
+(mf/defc comment-dashboard-thread-group*
+ {::mf/props :obj}
+ [{:keys [group profiles on-thread-click]}]
+ [:div
+ (for [item (:items group)]
+ [:> comment-dashboard-thread-item*
+ {:item item
+ :on-click on-thread-click
+ :profiles profiles
+ :key (:id item)}])])
diff --git a/frontend/src/app/main/ui/comments.scss b/frontend/src/app/main/ui/comments.scss
index d90a158ddd..f02df3bd16 100644
--- a/frontend/src/app/main/ui/comments.scss
+++ b/frontend/src/app/main/ui/comments.scss
@@ -6,103 +6,98 @@
@import "refactor/common-refactor.scss";
-// Comment-thread-group
-.thread-group {
- padding: 0 $s-12;
- cursor: pointer;
- border-radius: $br-8;
- padding: $s-8 $s-16;
-
- &:hover {
- background: var(--comment-thread-background-color-hover);
- }
-}
-
-.section-title {
- display: grid;
- grid-template-columns: auto auto;
- @include bodySmallTypography;
- height: $s-32;
- display: flex;
- align-items: center;
- margin-bottom: $s-8;
-}
-
-.file-name {
- @include textEllipsis;
+.grayed-text {
color: var(--comment-subtitle-color);
}
-.page-name {
- @include textEllipsis;
+.location {
color: var(--comment-subtitle-color);
-}
-
-.icon {
display: flex;
align-items: center;
- padding: 0 $s-6 0 $s-4;
- width: $s-24;
- height: $s-32;
- margin-left: $s-6;
- svg {
- @extend .button-icon-small;
- stroke: var(--icon-foreground);
- }
-}
-
-.threads {
- display: flex;
- flex-direction: column;
- gap: $s-24;
-}
-
-// Comment-thread
-.comment {
- @include bodySmallTypography;
- display: flex;
- flex-direction: column;
- gap: $s-12;
-}
-
-.author {
- display: flex;
gap: $s-8;
}
-.thread-bubble {
- @extend .comment-bubbles;
- &.resolved {
- @extend .resolved-comment-bubble;
- }
- &.unread {
- @extend .unread-comment-bubble;
- }
+.location-icon {
+ display: flex;
+}
+
+.location-text {
+ @include textEllipsis;
+}
+
+.author {
+ @include bodySmallTypography;
+ display: flex;
+ align-items: center;
+ gap: $s-8;
+}
+
+.author-identity {
+ flex-grow: 1;
+}
+
+.author-fullname {
+ @include textEllipsis;
+ color: var(--comment-title-color);
+}
+
+.author-timeago {
+ @include textEllipsis;
+ color: var(--comment-subtitle-color);
}
.avatar {
+ position: relative;
+ height: $s-24;
+ width: $s-24;
+ border-radius: $br-circle;
+}
+
+.avatar-lg {
height: $s-32;
width: $s-32;
+}
+
+.avatar-read {
+ border: $s-2 solid var(--color-background-tertiary);
+}
+
+.avatar-unread {
+ border: $s-2 solid var(--color-accent-primary);
+}
+
+.avatar-solved {
+ border: $s-2 solid var(--color-background-tertiary);
+}
+
+.avatar-image {
border-radius: $br-circle;
- img {
- border-radius: $br-circle;
- }
}
-.name {
- flex-grow: 1;
- .fullname {
- @include textEllipsis;
- color: var(--comment-title-color);
- }
- .timeago {
- @include textEllipsis;
- color: var(--comment-subtitle-color);
- }
+.avatar-mask {
+ border-radius: $br-circle;
+ position: absolute;
+ height: 100%;
+ width: 100%;
+ left: 0;
+ top: 0;
}
-.content {
- position: relative;
+.avatar-darken {
+ background: rgba(0, 0, 0, 0.5);
+}
+
+.cover {
+ @include bodySmallTypography;
+ cursor: pointer;
+ display: flex;
+ flex-direction: column;
+ gap: $s-8;
+ padding: $s-20;
+ border-bottom: $s-1 solid var(--color-background-quaternary);
+}
+
+.item {
@include bodySmallTypography;
color: var(--color-foreground-primary);
word-wrap: break-word;
@@ -112,119 +107,128 @@
}
.replies {
+ @include bodySmallTypography;
display: flex;
gap: $s-8;
}
-.total-replies {
+.replies-total {
color: var(--color-foreground-secondary);
}
-.new-replies {
+.replies-unread {
color: var(--color-accent-primary);
}
-// Thread-bubble
-.floating-thread-bubble {
- @extend .comment-bubbles;
+.floating-preview-wrapper {
+ z-index: $z-index-1;
position: absolute;
+ user-select: none;
cursor: pointer;
pointer-events: auto;
transform: translate(calc(-1 * $s-16), calc(-1 * $s-16));
-
- &.resolved {
- @extend .resolved-comment-bubble;
- }
- &.unread {
- @extend .unread-comment-bubble;
- }
}
-// thread-content
-.thread-content {
- position: absolute;
- overflow-y: auto;
- width: $s-284;
- padding: $s-12;
- padding-inline-end: $s-8;
+.floating-preview-bubble {
+ z-index: initial;
+}
+.floating-preview-displacement {
+ margin-left: calc(-1 * ($s-12 + $s-2));
+ margin-top: calc(-1 * ($s-8 + $s-2));
+}
+
+.grabbing {
+ cursor: grabbing;
+}
+
+.floating-thread-wrapper {
+ position: absolute;
+ display: flex;
+ flex-direction: column;
+ gap: $s-12;
+ width: $s-284;
+ padding: $s-8 $s-12 $s-8 $s-12;
pointer-events: auto;
- user-select: text;
border-radius: $br-8;
border: $s-2 solid var(--modal-border-color);
background-color: var(--comment-modal-background-color);
--translate-x: 0%;
--translate-y: 0%;
transform: translate(var(--translate-x), var(--translate-y));
- .comments {
- display: flex;
- flex-direction: column;
- gap: $s-24;
+ &.left {
+ --translate-x: -100%;
+ }
+ &.top {
+ --translate-y: -100%;
}
}
-.thread-content-left {
- --translate-x: -100%;
-}
-.thread-content-top {
- --translate-y: -100%;
-}
-
-// comment-item
-
-.comment-container {
+.floating-thread-header {
position: relative;
- .comment {
- @include bodySmallTypography;
- .author {
- display: flex;
- gap: $s-8;
- .avatar {
- height: $s-32;
- width: $s-32;
- border-radius: $br-circle;
- img {
- border-radius: $br-circle;
- }
- }
- .name {
- flex-grow: 1;
- .fullname {
- @include textEllipsis;
- color: var(--comment-title-color);
- }
- .timeago {
- @include textEllipsis;
- color: var(--comment-subtitle-color);
- }
- }
- .options-resolve-wrapper {
- @include flexCenter;
- width: $s-16;
- height: $s-32;
- .options-resolve {
- @extend .checkbox-icon;
- cursor: pointer;
- }
- }
- }
- }
- .comment-options-dropdown {
- @extend .dropdown-wrapper;
- position: absolute;
- width: fit-content;
- max-width: $s-200;
- right: 0;
- left: unset;
- .context-menu-option {
- @extend .dropdown-element-base;
- }
- }
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ height: $s-32;
}
-// edit-form & reply-form
+.floating-thread-header-left {
+ @include bodySmallTypography;
+ color: var(--color-foreground-primary);
+}
-.edit-form,
-.reply-form {
+.floating-thread-header-right {
+ display: flex;
+ align-items: center;
+}
+
+.floating-thread-main {
+ display: flex;
+ flex-direction: column;
+ gap: $s-16;
+ overflow-y: auto;
+ padding-bottom: $s-16;
+}
+
+.floating-thread-item-wrapper {
+ position: relative;
+}
+
+.floating-thread-item {
+ display: flex;
+ flex-direction: column;
+ gap: $s-8;
+ @include bodySmallTypography;
+}
+
+.checkbox-wrapper {
+ @include flexCenter;
+ width: $s-16;
+ height: $s-24;
+ margin-right: $s-8;
+}
+
+.checkbox {
+ @extend .checkbox-icon;
+}
+
+.dropdown-menu {
+ @extend .dropdown-wrapper;
+ position: absolute;
+ width: fit-content;
+ max-width: $s-200;
+ right: $s-32;
+ top: 0;
+ left: unset;
+}
+
+.dropdown-menu-option {
+ @extend .dropdown-element-base;
+}
+
+.form {
+ display: flex;
+ flex-direction: column;
+ gap: $s-8;
textarea {
@extend .input-element;
@include bodySmallTypography;
@@ -232,8 +236,8 @@
height: 100%;
width: 100%;
max-width: $s-260;
- margin-bottom: $s-8;
padding: $s-8;
+ margin-top: $s-4;
color: var(--input-foreground-color-active);
resize: vertical;
&:focus {
@@ -241,21 +245,119 @@
outline: none;
}
}
- .buttons-wrapper {
- display: flex;
- justify-content: flex-end;
- gap: $s-4;
- .post-btn {
- @extend .button-primary;
- height: $s-32;
- width: $s-92;
- margin-bottom: 0;
- }
- .cancel-btn {
- @extend .button-secondary;
- height: $s-32;
- width: $s-92;
- margin-bottom: 0;
- }
+}
+
+.form-buttons-wrapper {
+ display: grid;
+ grid-template-columns: 1fr auto auto;
+ justify-content: flex-end;
+ gap: $s-8;
+}
+
+.open-mentions-button {
+ cursor: pointer;
+ stroke: none;
+ fill: var(--color-foreground-secondary);
+
+ &.is-toggled {
+ fill: var(--color-accent-primary);
}
}
+
+.comments-mentions-choice {
+ background: var(--color-background-tertiary);
+ border-radius: $s-8;
+ border: none;
+ display: flex;
+ flex-direction: column;
+ left: calc(-1 * $s-2);
+ margin-top: $s-8;
+ overflow: hidden;
+ padding: $s-2;
+ position: absolute;
+ top: 100%;
+ width: calc(100% + $s-4);
+}
+
+.comments-mentions-entry {
+ cursor: pointer;
+ display: grid;
+ grid-template-areas:
+ "avatar name"
+ "avatar email";
+ grid-template-columns: $s-32 1fr;
+ column-gap: $s-8;
+ margin: $s-4 $s-8;
+ padding: 0 $s-4;
+ border-radius: $br-8;
+ border: $s-1 solid transparent;
+
+ &:hover {
+ background: var(--color-background-quaternary);
+ }
+
+ .comments-mentions-avatar {
+ grid-area: avatar;
+ border-radius: 50%;
+ }
+
+ .comments-mentions-name {
+ grid-area: name;
+ font-size: $fs-12;
+ color: var(--color-foreground-primary);
+ }
+
+ .comments-mentions-email {
+ grid-area: email;
+ font-size: $fs-12;
+ color: var(--color-foreground-secondary);
+ }
+
+ &.is-selected {
+ border: 1px solid var(--color-accent-primary-muted);
+ background: var(--color-background-quaternary);
+ }
+}
+
+.comment-input {
+ @include bodySmallTypography;
+ white-space: pre;
+ background: var(--input-background-color);
+ border-radius: $br-8;
+ border: $s-1 solid var(--input-border-color);
+ color: var(--input-foreground-color);
+ height: $s-36;
+ margin-bottom: $s-8;
+ max-width: $s-260;
+ overflow-y: auto;
+ padding: $s-8;
+ resize: vertical;
+ width: 100%;
+
+ &:focus {
+ border: $s-1 solid var(--input-border-color-active);
+ outline: none;
+ }
+
+ [data-type="mention"] {
+ color: var(--color-accent-primary);
+ }
+
+ [data-type="text"] {
+ color: var(--color-foreground-primary);
+ }
+
+ &::before {
+ content: var(--placeholder);
+ }
+}
+
+.comment-mention {
+ color: var(--color-accent-primary);
+}
+
+.comments-mentions-empty {
+ font-size: $fs-12;
+ color: var(--color-foreground-secondary);
+ padding: $s-6 $s-8;
+}
diff --git a/frontend/src/app/main/ui/components/context_menu_a11y.cljs b/frontend/src/app/main/ui/components/context_menu_a11y.cljs
index 04475e7c24..a3f199ebb4 100644
--- a/frontend/src/app/main/ui/components/context_menu_a11y.cljs
+++ b/frontend/src/app/main/ui/components/context_menu_a11y.cljs
@@ -11,7 +11,7 @@
[app.common.data.macros :as dm]
[app.common.schema :as sm]
[app.main.refs :as refs]
- [app.main.ui.components.dropdown :refer [dropdown']]
+ [app.main.ui.components.dropdown :refer [dropdown-content*]]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
@@ -52,8 +52,6 @@
(sm/lazy-validator schema:option))
(mf/defc context-menu*
- {::mf/props :obj}
-
[{:keys [show on-close options selectable selected
top left fixed min-width origin width]
:as props}]
@@ -90,7 +88,7 @@
(on-close)))
props
- (mf/spread props :on-close on-local-close)
+ (mf/spread-props props {:on-close on-local-close})
ids
(mf/with-memo [levels]
@@ -221,7 +219,7 @@
#(dom/focus! (dom/get-element (first ids)))))
(when (and show (some? levels))
- [:> dropdown' props
+ [:> dropdown-content* props
(let [level (peek levels)
options (:options level)
parent (:parent level)]
diff --git a/frontend/src/app/main/ui/components/dropdown.cljs b/frontend/src/app/main/ui/components/dropdown.cljs
index f27662421f..8da3f0b036 100644
--- a/frontend/src/app/main/ui/components/dropdown.cljs
+++ b/frontend/src/app/main/ui/components/dropdown.cljs
@@ -12,17 +12,13 @@
[app.util.keyboard :as kbd]
[app.util.timers :as tm]
[goog.events :as events]
- [goog.object :as gobj]
[rumext.v2 :as mf])
(:import goog.events.EventType))
-(mf/defc dropdown'
- {::mf/wrap-props false}
- [props]
- (let [children (gobj/get props "children")
- on-close (gobj/get props "on-close")
- container-ref (gobj/get props "container")
- listening-ref (mf/use-ref nil)
+(mf/defc dropdown-content*
+ [{:keys [children on-close container]}]
+ (let [listening-ref (mf/use-ref nil)
+ container-ref container
on-click
(fn [event]
@@ -57,10 +53,13 @@
children))
(mf/defc dropdown
- {::mf/wrap-props false}
- [props]
- (assert (fn? (gobj/get props "on-close")) "missing `on-close` prop")
- (assert (boolean? (gobj/get props "show")) "missing `show` prop")
+ {::mf/props :obj}
+ [{:keys [on-close show children container]}]
+ (assert (fn? on-close) "missing `on-close` prop")
+ (assert (boolean? show) "missing `show` prop")
- (when (gobj/get props "show")
- (mf/element dropdown' props)))
+ (when ^boolean show
+ [:> dropdown-content*
+ {:on-close on-close
+ :container container
+ :children children}]))
diff --git a/frontend/src/app/main/ui/components/radio_buttons.cljs b/frontend/src/app/main/ui/components/radio_buttons.cljs
index 17a3fe5942..c51aa6ab47 100644
--- a/frontend/src/app/main/ui/components/radio_buttons.cljs
+++ b/frontend/src/app/main/ui/components/radio_buttons.cljs
@@ -87,10 +87,16 @@
(dom/blur! input))))
context-value
- (mf/spread props
- :on-change on-change'
- :encode-fn encode-fn
- :decode-fn decode-fn)]
+ (mf/spread-object props
+ ;; We pass a special metadata for disable
+ ;; key casing transformation in this
+ ;; concrete case, because this component
+ ;; uses legacy mode and props are in
+ ;; kebab-case style
+ ^{::mf/transform false}
+ {:on-change on-change'
+ :encode-fn encode-fn
+ :decode-fn decode-fn})]
[:& (mf/provider context) {:value context-value}
[:div {:class (dm/str class " " (stl/css :radio-btn-wrapper))
diff --git a/frontend/src/app/main/ui/components/reorder_handler.cljs b/frontend/src/app/main/ui/components/reorder_handler.cljs
index 8f4acfe320..a8df960209 100644
--- a/frontend/src/app/main/ui/components/reorder_handler.cljs
+++ b/frontend/src/app/main/ui/components/reorder_handler.cljs
@@ -16,7 +16,7 @@
[:*
[:div {:ref ref :class (stl/css :reorder)}
[:> icon*
- {:id ic/reorder
+ {:icon-id ic/reorder
:class (stl/css :reorder-icon)
:aria-hidden true}]]
[:hr {:class (stl/css :reorder-separator-top)}]
diff --git a/frontend/src/app/main/ui/dashboard/comments.cljs b/frontend/src/app/main/ui/dashboard/comments.cljs
index c2b77134ae..b0700e735d 100644
--- a/frontend/src/app/main/ui/dashboard/comments.cljs
+++ b/frontend/src/app/main/ui/dashboard/comments.cljs
@@ -14,25 +14,18 @@
[app.main.store :as st]
[app.main.ui.comments :as cmt]
[app.main.ui.components.dropdown :refer [dropdown]]
+ [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.icons :as i]
[app.util.i18n :as i18n :refer [tr]]
- [app.util.keyboard :as kbd]
[potok.v2.core :as ptk]
[rumext.v2 :as mf]))
-
-(def ^:private close-icon
- (i/icon-xref :close (stl/css :close-icon)))
-
(def ^:private comments-icon-svg
(i/icon-xref :comments (stl/css :comments-icon)))
-
-(def ^:private comments-icon-small
- (i/icon-xref :comments (stl/css :comments-icon-small)))
-
-(mf/defc comments-icon
- [{:keys [profile show? on-show-comments]}]
+(mf/defc comments-icon*
+ {::mf/props :obj}
+ [{:keys [profile on-show-comments]}]
(let [threads-map (mf/deref refs/comment-threads)
@@ -41,24 +34,18 @@
(sort-by :modified-at)
(reverse)
(dcm/apply-filters {} profile)
- (dcm/group-threads-by-file-and-page))
-
- handle-keydown
- (mf/use-callback
- (mf/deps on-show-comments)
- (fn [event]
- (when (kbd/enter? event)
- (on-show-comments event))))]
+ (dcm/group-threads-by-file-and-page))]
[:div {:class (stl/css :dashboard-comments-section)}
- [:button {:tab-index "0"
- :on-click on-show-comments
- :on-key-down handle-keydown
- :data-testid "open-comments"
- :class (stl/css-case :comment-button true
- :open show?
- :unread (boolean (seq tgroups)))}
- comments-icon-small]]))
+ [:> icon-button* {:variant "ghost"
+ :tab-index "0"
+ :class (stl/css :comment-button)
+ :data-testid "open-comments"
+ :aria-label (tr "dashboard.notifications.view")
+ :on-click on-show-comments
+ :icon "comments"}
+ (when (seq tgroups)
+ [:div {:class (stl/css :unread)}])]]))
(mf/defc comments-section
[{:keys [profile team show? on-hide-comments]}]
@@ -72,13 +59,6 @@
(dcm/apply-filters {} profile)
(dcm/group-threads-by-file-and-page))
- handle-keydown
- (mf/use-callback
- (mf/deps on-hide-comments)
- (fn [event]
- (when (kbd/enter? event)
- (on-hide-comments event))))
-
on-navigate
(mf/use-callback
(fn [thread]
@@ -101,22 +81,22 @@
[:& dropdown {:show show? :on-close on-hide-comments}
[:div {:class (stl/css :dropdown :comments-section :comment-threads-section)}
[:div {:class (stl/css :header)}
- [:h3 {:class (stl/css :header-title)} (tr "labels.comments")]
- [:button {:class (stl/css :close-btn)
- :tab-index (if show? "0" "-1")
- :on-click on-hide-comments
- :on-key-down handle-keydown}
- close-icon]]
+ [:h3 {:class (stl/css :header-title)} (tr "dashboard.notifications")]
+ [:> icon-button* {:variant "ghost"
+ :tab-index (if show? "0" "-1")
+ :aria-label (tr "labels.close")
+ :on-click on-hide-comments
+ :icon "close"}]]
(if (seq tgroups)
[:div {:class (stl/css :thread-groups)}
- [:& cmt/comment-thread-group
+ [:> cmt/comment-dashboard-thread-group*
{:group (first tgroups)
:on-thread-click on-navigate
:show-file-name true
:profiles profiles}]
(for [tgroup (rest tgroups)]
- [:& cmt/comment-thread-group
+ [:> cmt/comment-dashboard-thread-group*
{:group tgroup
:on-thread-click on-navigate
:show-file-name true
diff --git a/frontend/src/app/main/ui/dashboard/comments.scss b/frontend/src/app/main/ui/dashboard/comments.scss
index af55f6dd17..93070c2f7c 100644
--- a/frontend/src/app/main/ui/dashboard/comments.scss
+++ b/frontend/src/app/main/ui/dashboard/comments.scss
@@ -44,21 +44,16 @@
}
.comment-button {
- @include buttonStyle;
- @include flexCenter;
- border-radius: $br-8;
- height: $s-32;
- width: $s-32;
- --comment-icon-small-foreground-color: var(--icon-foreground);
-
- &.unread,
- &.open {
- --comment-icon-small-foreground-color: var(--icon-foreground-selected);
- }
-
- &:hover {
- background-color: var(--color-background-quaternary);
- --comment-icon-small-foreground-color: var(--icon-foreground-active);
+ position: relative;
+ .unread {
+ position: absolute;
+ width: $s-8;
+ height: $s-8;
+ border: $s-2 solid var(--color-background-tertiary);
+ border-radius: 50%;
+ background: red;
+ top: $s-6;
+ right: $s-6;
}
}
@@ -100,13 +95,3 @@
flex-grow: 1;
text-transform: uppercase;
}
-
-.close-btn {
- @include buttonStyle;
- @include flexCenter;
-}
-
-.close-icon {
- @extend .button-icon;
- stroke: var(--icon-foreground);
-}
diff --git a/frontend/src/app/main/ui/dashboard/fonts.cljs b/frontend/src/app/main/ui/dashboard/fonts.cljs
index 7ae210b5ff..c9cb383fd2 100644
--- a/frontend/src/app/main/ui/dashboard/fonts.cljs
+++ b/frontend/src/app/main/ui/dashboard/fonts.cljs
@@ -11,6 +11,7 @@
[app.common.media :as cm]
[app.main.data.fonts :as df]
[app.main.data.modal :as modal]
+ [app.main.data.notifications :as ntf]
[app.main.repo :as rp]
[app.main.store :as st]
[app.main.ui.components.context-menu-a11y :refer [context-menu*]]
@@ -109,6 +110,8 @@
(swap! uploading* disj id)
(st/emit! (df/add-font font)))
(fn [error]
+ (st/emit! (ntf/error (tr "errors.bad-font" (first (:names item)))))
+ (swap! fonts* dissoc id)
(js/console.log "error" error))))))
on-upload
diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs
index 830d7caad7..2fee696969 100644
--- a/frontend/src/app/main/ui/dashboard/grid.cljs
+++ b/frontend/src/app/main/ui/dashboard/grid.cljs
@@ -189,7 +189,7 @@
[:& bc/color-bullet {:color {:color (:color color)
:id (:id color)
:opacity (:opacity color)}
- :mini? true}]
+ :mini true}]
[:div {:class (stl/css :name-block)}
[:span {:class (stl/css :color-name)} (:name color)]
(when-not (= (:name color) default-name)
@@ -331,6 +331,15 @@
client-position)]
(st/emit! (dd/show-file-menu-with-position file-id position)))))
+ on-context-menu
+ (mf/use-fn
+ (mf/deps is-library-view)
+ (fn [event]
+ (dom/stop-propagation event)
+ (dom/prevent-default event)
+ (when-not is-library-view
+ (on-menu-click event))))
+
edit
(mf/use-fn
(mf/deps file)
@@ -373,7 +382,7 @@
:on-key-down handle-key-down
:on-double-click on-navigate
:on-drag-start on-drag-start
- :on-context-menu on-menu-click}
+ :on-context-menu on-context-menu}
[:div {:class (stl/css :overlay)}]
@@ -392,31 +401,32 @@
[:h3 (:name file)])
[:& grid-item-metadata {:modified-at (:modified-at file)}]]
- [:div {:class (stl/css-case :project-th-actions true :force-display (:menu-open dashboard-local))}
- [:div
- {:class (stl/css :project-th-icon :menu)
- :tab-index "0"
- :ref menu-ref
- :id (str file-id "-action-menu")
- :on-click on-menu-click
- :on-key-down (fn [event]
- (when (kbd/enter? event)
- (dom/stop-propagation event)
- (on-menu-click event)))}
- menu-icon
- (when (and selected? file-menu-open?)
+ (when-not is-library-view
+ [:div {:class (stl/css-case :project-th-actions true :force-display (:menu-open dashboard-local))}
+ [:div
+ {:class (stl/css :project-th-icon :menu)
+ :tab-index "0"
+ :ref menu-ref
+ :id (str file-id "-action-menu")
+ :on-click on-menu-click
+ :on-key-down (fn [event]
+ (when (kbd/enter? event)
+ (dom/stop-propagation event)
+ (on-menu-click event)))}
+ menu-icon
+ (when (and selected? file-menu-open?)
;; When the menu is open we disable events in the dashboard. We need to force pointer events
;; so the menu can be handled
- [:div {:style {:pointer-events "all"}}
- [:> file-menu* {:files (vals selected-files)
- :left (+ 24 (:x (:menu-pos dashboard-local)))
- :top (:y (:menu-pos dashboard-local))
- :can-edit can-edit
- :navigate true
- :on-edit on-edit
- :on-menu-close on-menu-close
- :origin origin
- :parent-id (dm/str file-id "-action-menu")}]])]]]]]))
+ [:div {:style {:pointer-events "all"}}
+ [:> file-menu* {:files (vals selected-files)
+ :left (+ 24 (:x (:menu-pos dashboard-local)))
+ :top (:y (:menu-pos dashboard-local))
+ :can-edit can-edit
+ :navigate true
+ :on-edit on-edit
+ :on-menu-close on-menu-close
+ :origin origin
+ :parent-id (dm/str file-id "-action-menu")}]])]])]]]))
(mf/defc grid
{::mf/props :obj}
diff --git a/frontend/src/app/main/ui/dashboard/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs
index dfb3691d78..a4f3270154 100644
--- a/frontend/src/app/main/ui/dashboard/sidebar.cljs
+++ b/frontend/src/app/main/ui/dashboard/sidebar.cljs
@@ -23,7 +23,7 @@
[app.main.store :as st]
[app.main.ui.components.dropdown-menu :refer [dropdown-menu dropdown-menu-item*]]
[app.main.ui.components.link :refer [link]]
- [app.main.ui.dashboard.comments :refer [comments-icon comments-section]]
+ [app.main.ui.dashboard.comments :refer [comments-icon* comments-section]]
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
[app.main.ui.dashboard.project-menu :refer [project-menu*]]
[app.main.ui.dashboard.team-form]
@@ -1071,9 +1071,8 @@
(tr "labels.logout")]]
(when (and team profile)
- [:& comments-icon
+ [:> comments-icon*
{:profile profile
- :show? show-comments?
:on-show-comments handle-show-comments}])]]))
(mf/defc sidebar*
diff --git a/frontend/src/app/main/ui/dashboard/sidebar.scss b/frontend/src/app/main/ui/dashboard/sidebar.scss
index 65afa269d2..95ad98c32d 100644
--- a/frontend/src/app/main/ui/dashboard/sidebar.scss
+++ b/frontend/src/app/main/ui/dashboard/sidebar.scss
@@ -412,7 +412,7 @@
border: $b-1 solid var(--color-background-quaternary);
border-radius: var(--sp-s);
padding: var(--sp-m);
- margin: var(--sp-m) var(--sp-s) var(--sp-m) var(--sp-m);
+ margin: var(--sp-m);
color: var(--color-foreground-secondary);
cursor: pointer;
}
diff --git a/frontend/src/app/main/ui/dashboard/team.cljs b/frontend/src/app/main/ui/dashboard/team.cljs
index ce2b9b7911..3daefc5d74 100644
--- a/frontend/src/app/main/ui/dashboard/team.cljs
+++ b/frontend/src/app/main/ui/dashboard/team.cljs
@@ -31,7 +31,6 @@
[app.util.i18n :as i18n :refer [tr]]
[beicon.v2.core :as rx]
[cuerdas.core :as str]
- [okulary.core :as l]
[rumext.v2 :as mf]))
(def ^:private arrow-icon
@@ -743,15 +742,12 @@
[:> i18n/tr-html* {:content (tr "labels.no-invitations-hint")
:tag-name "span"}])])
-(def ^:private ref:invitations
- (l/derived :invitations st/state))
-
(mf/defc invitation-section*
{::mf/props :obj
::mf/private true}
[{:keys [team]}]
(let [permissions (get team :permissions)
- invitations (mf/deref ref:invitations)
+ invitations (get team :invitations)
team-id (get team :id)
@@ -957,7 +953,7 @@
[:span {:title (tr "dashboard.webhooks.cant-edit")
:class (stl/css :menu-disabled)}
- [:> icon* {:id "menu"}]])))
+ [:> icon* {:icon-id "menu"}]])))
(mf/defc webhook-item*
{::mf/wrap [mf/memo]
@@ -1037,13 +1033,10 @@
:key (dm/str (:id webhook))
:permissions permissions}])])
-(def ^:private ref:webhooks
- (l/derived :webhooks st/state))
-
(mf/defc webhooks-page*
{::mf/props :obj}
[{:keys [team]}]
- (let [webhooks (mf/deref ref:webhooks)]
+ (let [webhooks (:webhooks team)]
(mf/with-effect [team]
(dom/set-html-title
diff --git a/frontend/src/app/main/ui/ds/buttons/button.cljs b/frontend/src/app/main/ui/ds/buttons/button.cljs
index cfb30409dd..73af4824ee 100644
--- a/frontend/src/app/main/ui/ds/buttons/button.cljs
+++ b/frontend/src/app/main/ui/ds/buttons/button.cljs
@@ -32,5 +32,5 @@
:button-destructive (= variant "destructive")))
props (mf/spread-props props {:class class})]
[:> "button" props
- (when icon [:> icon* {:id icon :size "m"}])
+ (when icon [:> icon* {:icon-id icon :size "m"}])
[:span {:class (stl/css :label-wrapper)} children]]))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/ds/buttons/icon_button.cljs b/frontend/src/app/main/ui/ds/buttons/icon_button.cljs
index 0b45ad2382..88bf48bd13 100644
--- a/frontend/src/app/main/ui/ds/buttons/icon_button.cljs
+++ b/frontend/src/app/main/ui/ds/buttons/icon_button.cljs
@@ -34,4 +34,4 @@
:icon-button-action (= variant "action")
:icon-button-destructive (= variant "destructive")))
props (mf/spread-props props {:class class :title aria-label})]
- [:> "button" props [:> icon* {:id icon :aria-label aria-label :class icon-class}] children]))
+ [:> "button" props [:> icon* {:icon-id icon :aria-label aria-label :class icon-class}] children]))
diff --git a/frontend/src/app/main/ui/ds/controls/combobox.cljs b/frontend/src/app/main/ui/ds/controls/combobox.cljs
index e39efedb1c..5ed27a05eb 100644
--- a/frontend/src/app/main/ui/ds/controls/combobox.cljs
+++ b/frontend/src/app/main/ui/ds/controls/combobox.cljs
@@ -215,7 +215,7 @@
[:span {:class (stl/css-case :combobox-header true
:header-icon (some? icon))}
(when icon
- [:> icon* {:id icon
+ [:> icon* {:icon-id icon
:size "s"
:aria-hidden true}])
[:input {:type "text"
@@ -236,7 +236,7 @@
:aria-controls listbox-id
:class (stl/css :button-toggle-list)
:on-click on-click}
- [:> icon* {:id i/arrow
+ [:> icon* {:icon-id i/arrow
:class (stl/css :arrow)
:size "s"
:aria-hidden true
diff --git a/frontend/src/app/main/ui/ds/controls/input.cljs b/frontend/src/app/main/ui/ds/controls/input.cljs
index 0df0c0c6da..5637b287fd 100644
--- a/frontend/src/app/main/ui/ds/controls/input.cljs
+++ b/frontend/src/app/main/ui/ds/controls/input.cljs
@@ -30,11 +30,11 @@
(let [ref (or ref (mf/use-ref))
type (d/nilv type "text")
props (mf/spread-props props
- :class (stl/css-case
- :input true
- :input-with-icon (some? icon))
- :ref ref
- :type type)
+ {:class (stl/css-case
+ :input true
+ :input-with-icon (some? icon))
+ :ref ref
+ :type type})
on-icon-click
(mf/use-fn
@@ -46,5 +46,5 @@
[:> :span {:class (dm/str class " " (stl/css :container))}
(when (some? icon)
- [:> icon* {:id icon :class (stl/css :icon) :on-click on-icon-click}])
+ [:> icon* {:icon-id icon :class (stl/css :icon) :on-click on-icon-click}])
[:> :input props]]))
diff --git a/frontend/src/app/main/ui/ds/controls/select.cljs b/frontend/src/app/main/ui/ds/controls/select.cljs
index 0d2730ebb6..02e291cfa9 100644
--- a/frontend/src/app/main/ui/ds/controls/select.cljs
+++ b/frontend/src/app/main/ui/ds/controls/select.cljs
@@ -171,12 +171,12 @@
[:span {:class (stl/css-case :select-header true
:header-icon (some? icon))}
(when icon
- [:> icon* {:id icon
+ [:> icon* {:icon-id icon
:size "s"
:aria-hidden true}])
[:span {:class (stl/css :header-label)}
label]]
- [:> icon* {:id i/arrow
+ [:> icon* {:icon-id i/arrow
:class (stl/css :arrow)
:size "s"
:aria-hidden true}]]
diff --git a/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.cljs b/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.cljs
index 16ce0240ac..6173366de5 100644
--- a/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.cljs
+++ b/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.cljs
@@ -31,7 +31,7 @@
(when (some? icon)
[:> icon*
- {:id icon
+ {:icon-id icon
:size "s"
:class (stl/css :option-icon)
:aria-hidden (when label true)
@@ -40,7 +40,7 @@
[:span {:class (stl/css :option-text)} label]
(when selected
[:> icon*
- {:id i/tick
+ {:icon-id i/tick
:size "s"
:class (stl/css :option-check)
:aria-hidden (when label true)}])])
diff --git a/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs b/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs
index 5609a37491..6bd108a5aa 100644
--- a/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs
+++ b/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs
@@ -55,6 +55,7 @@
(def ^:icon-id arrow-right "arrow-right")
(def ^:icon-id arrow-up "arrow-up")
(def ^:icon-id asc-sort "asc-sort")
+(def ^:icon-id at "at")
(def ^:icon-id board "board")
(def ^:icon-id boards-thumbnail "boards-thumbnail")
(def ^:icon-id boolean-difference "boolean-difference")
@@ -287,17 +288,17 @@
(def ^:private schema:icon
[:map
[:class {:optional true} [:maybe :string]]
- [:id [:and :string [:fn #(contains? icon-list %)]]]
+ [:icon-id [:and :string [:fn #(contains? icon-list %)]]]
[:size {:optional true}
[:maybe [:enum "s" "m"]]]])
(mf/defc icon*
{::mf/props :obj
::mf/schema schema:icon}
- [{:keys [id size class] :rest props}]
+ [{:keys [icon-id size class] :rest props}]
(let [class (dm/str (or class "") " " (stl/css :icon))
props (mf/spread-props props {:class class :width icon-size-m :height icon-size-m})
size-px (cond (= size "s") icon-size-s :else icon-size-m)
offset (/ (- icon-size-m size-px) 2)]
[:> "svg" props
- [:use {:href (dm/str "#icon-" id) :width size-px :height size-px :x offset :y offset}]]))
+ [:use {:href (dm/str "#icon-" icon-id) :width size-px :height size-px :x offset :y offset}]]))
diff --git a/frontend/src/app/main/ui/ds/foundations/assets/icon.mdx b/frontend/src/app/main/ui/ds/foundations/assets/icon.mdx
index 140b897a2d..c1184acd51 100644
--- a/frontend/src/app/main/ui/ds/foundations/assets/icon.mdx
+++ b/frontend/src/app/main/ui/ds/foundations/assets/icon.mdx
@@ -47,7 +47,7 @@ Assuming the namespace is required as `i`:
You can now use the icon IDs defined in the namespace:
```clj
-[:> i/icon* {:id i/pin}]
+[:> i/icon* {:icon-id i/pin}]
```
### Customizing colors
@@ -59,7 +59,7 @@ If you need to override this behavior, you can use a `class` in the ``
component and set `color` to whatever value you prefer:
```clj
-[:> i/icon* {:id i/add :class (stl/css :toolbar-icon)}]
+[:> i/icon* {:icon-id i/add :class (stl/css :toolbar-icon)}]
```
```scss
@@ -74,7 +74,7 @@ By default, icons do not have any accessible text attached to them. You should
add an `aria-label` attribute to set a proper text:
```clj
-[:> i/icon* {:id i/add :aria-label (tr "foo.bar")}]
+[:> i/icon* {:icon-id i/add :aria-label (tr "foo.bar")}]
```
## Usage guidelines for design
diff --git a/frontend/src/app/main/ui/ds/layout/tab_switcher.cljs b/frontend/src/app/main/ui/ds/layout/tab_switcher.cljs
index 1228c4c1f0..5871c61d3e 100644
--- a/frontend/src/app/main/ui/ds/layout/tab_switcher.cljs
+++ b/frontend/src/app/main/ui/ds/layout/tab_switcher.cljs
@@ -38,7 +38,7 @@
[:> :button props
(when (some? icon)
[:> icon*
- {:id icon
+ {:icon-id icon
:aria-hidden (when label true)
:aria-label (when (not label) aria-label)}])
(when (string? label)
diff --git a/frontend/src/app/main/ui/ds/storybook.cljs b/frontend/src/app/main/ui/ds/storybook.cljs
index d503f3a8f1..bec97b7b02 100644
--- a/frontend/src/app/main/ui/ds/storybook.cljs
+++ b/frontend/src/app/main/ui/ds/storybook.cljs
@@ -1,4 +1,3 @@
-
;; 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/.
@@ -16,9 +15,9 @@
{::mf/props :obj}
[{:keys [children size style] :rest other}]
(let [class (stl/css :story-grid)
- size (or size 16)
- style (or style {})
- style (mf/spread style :--component-grid-size (dm/str size "px"))
+ size (or size 16)
+ style (or style #js {})
+ style (mf/spread-props style {"--component-grid-size" (dm/str size "px")})
props (mf/spread-props other {:class class :style style})]
[:> "article" props children]))
@@ -41,4 +40,4 @@
[{:keys [children] :rest other}]
(let [class (stl/css :story-grid-row)
props (mf/spread-props other {:class class})]
- [:> "article" props children]))
\ No newline at end of file
+ [:> "article" props children]))
diff --git a/frontend/src/app/main/ui/routes.cljs b/frontend/src/app/main/ui/routes.cljs
index a199056976..5a114cfc6d 100644
--- a/frontend/src/app/main/ui/routes.cljs
+++ b/frontend/src/app/main/ui/routes.cljs
@@ -33,7 +33,8 @@
["/password" :settings-password]
["/feedback" :settings-feedback]
["/options" :settings-options]
- ["/access-tokens" :settings-access-tokens]]
+ ["/access-tokens" :settings-access-tokens]
+ ["/notifications" :settings-notifications]]
["/frame-preview" :frame-preview]
diff --git a/frontend/src/app/main/ui/settings.cljs b/frontend/src/app/main/ui/settings.cljs
index d5192320d8..e66c3f5ad3 100644
--- a/frontend/src/app/main/ui/settings.cljs
+++ b/frontend/src/app/main/ui/settings.cljs
@@ -17,6 +17,7 @@
[app.main.ui.settings.change-email]
[app.main.ui.settings.delete-account]
[app.main.ui.settings.feedback :refer [feedback-page]]
+ [app.main.ui.settings.notifications :refer [notifications-page]]
[app.main.ui.settings.options :refer [options-page]]
[app.main.ui.settings.password :refer [password-page]]
[app.main.ui.settings.profile :refer [profile-page]]
@@ -67,4 +68,7 @@
[:& options-page]
:settings-access-tokens
- [:& access-tokens-page])]]]]))
+ [:& access-tokens-page]
+
+ :settings-notifications
+ [:& notifications-page])]]]]))
diff --git a/frontend/src/app/main/ui/settings/notifications.cljs b/frontend/src/app/main/ui/settings/notifications.cljs
new file mode 100644
index 0000000000..b402b3af88
--- /dev/null
+++ b/frontend/src/app/main/ui/settings/notifications.cljs
@@ -0,0 +1,106 @@
+;; 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.settings.notifications
+ (:require-macros [app.main.style :as stl])
+ (:require
+ [app.common.data :as d]
+ [app.common.schema :as sm]
+ [app.main.data.notifications :as ntf]
+ [app.main.data.profile :as dp]
+ [app.main.refs :as refs]
+ [app.main.store :as st]
+ [app.main.ui.components.forms :as fm]
+ [app.util.dom :as dom]
+ [app.util.i18n :as i18n :refer [tr]]
+ [okulary.core :as l]
+ [rumext.v2 :as mf]))
+
+(def default-notification-settings
+ {:dashboard-comments :all
+ :email-comments :partial
+ :email-invites :all})
+
+(def notification-settings-ref
+ (l/derived
+ (fn [profile]
+ (-> (merge default-notification-settings
+ (-> profile :props :notifications))
+ (d/update-vals d/name)))
+ refs/profile))
+
+(defn- on-error
+ [form _]
+ (reset! form nil)
+ (st/emit! (ntf/error (tr "generic.error"))))
+
+(defn- on-success
+ [_]
+ (st/emit! (ntf/success (tr "dashboard.notifications.notifications-saved"))))
+
+(defn- on-submit
+ [form event]
+ (dom/prevent-default event)
+ (let [params (with-meta (:clean-data @form)
+ {:on-success (partial on-success form)
+ :on-error (partial on-error form)})]
+ (st/emit! (dp/update-notifications params))))
+
+(def ^:private schema:notifications-form
+ [:map {:title "NotificationsForm"}
+ [:dashboard-comments [::sm/one-of #{:all :partial :none}]]
+ [:email-comments [::sm/one-of #{:all :partial :none}]]
+ [:email-invites [::sm/one-of #{:all :partial :none}]]])
+
+(mf/defc notifications-page
+ []
+ (let [settings (mf/deref notification-settings-ref)
+ form (fm/use-form :schema schema:notifications-form
+ :initial settings)]
+ (mf/with-effect []
+ (dom/set-html-title (tr "title.settings.notifications")))
+
+ [:section {:class (stl/css :notifications-page)}
+ [:& fm/form {:class (stl/css :notifications-form)
+ :on-submit on-submit
+ :form form}
+ [:div {:class (stl/css :form-container)}
+ [:h2 (tr "dashboard.settings.notifications.title")]
+ [:h3 (tr "dashboard.settings.notifications.dashboard.title")]
+ [:h4 (tr "dashboard.settings.notifications.dashboard-comments.title")]
+ [:div {:class (stl/css :fields-row)}
+ [:& fm/radio-buttons
+ {:options [{:label (tr "dashboard.settings.notifications.dashboard-comments.all") :value "all"}
+ {:label (tr "dashboard.settings.notifications.dashboard-comments.partial") :value "partial"}
+ {:label (tr "dashboard.settings.notifications.dashboard-comments.none") :value "none"}]
+ :name :dashboard-comments
+ :class (stl/css :radio-btns)}]]
+
+ [:h3 (tr "dashboard.settings.notifications.email.title")]
+ [:h4 (tr "dashboard.settings.notifications.email-comments.title")]
+ [:div {:class (stl/css :fields-row)}
+ [:& fm/radio-buttons
+ {:options [{:label (tr "dashboard.settings.notifications.email-comments.all") :value "all"}
+ {:label (tr "dashboard.settings.notifications.email-comments.partial") :value "partial"}
+ {:label (tr "dashboard.settings.notifications.email-comments.none") :value "none"}]
+ :name :email-comments
+ :class (stl/css :radio-btns)}]]
+
+ [:h4 (tr "dashboard.settings.notifications.email-invites.title")]
+ [:div {:class (stl/css :fields-row)}
+ [:& fm/radio-buttons
+ {:options [{:label (tr "dashboard.settings.notifications.email-invites.all") :value "all"}
+ ;; This type of notifications doesnt't exist yet
+ ;; {:label "Only invites and requests that my response" :value "partial"}
+ {:label (tr "dashboard.settings.notifications.email-invites.none") :value "none"}]
+ :name :email-invites
+ :class (stl/css :radio-btns)}]]
+
+ [:> fm/submit-button*
+ {:label (tr "dashboard.settings.notifications.submit")
+ :data-testid "submit-settings"
+ :class (stl/css :update-btn)}]]]]))
+
diff --git a/frontend/src/app/main/ui/settings/notifications.scss b/frontend/src/app/main/ui/settings/notifications.scss
new file mode 100644
index 0000000000..7e2cd4ae08
--- /dev/null
+++ b/frontend/src/app/main/ui/settings/notifications.scss
@@ -0,0 +1,42 @@
+// 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 "common/refactor/common-refactor.scss" as *;
+@use "./profile" as *;
+
+.update-btn {
+ margin-top: $s-16;
+ @extend .button-primary;
+ height: $s-36;
+}
+
+.notifications-form {
+ width: $s-400;
+}
+
+.notifications-page {
+ display: flex;
+ justify-content: center;
+}
+
+.radio-btns {
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+}
+
+.form-container {
+ h3 {
+ color: var(--color-foreground-secondary);
+ }
+
+ h4 {
+ font-size: $fs-11;
+ color: var(--color-foreground-primary);
+ text-transform: uppercase;
+ margin: $s-12;
+ }
+}
diff --git a/frontend/src/app/main/ui/settings/sidebar.cljs b/frontend/src/app/main/ui/settings/sidebar.cljs
index 8da8bb6a3c..5de595091c 100644
--- a/frontend/src/app/main/ui/settings/sidebar.cljs
+++ b/frontend/src/app/main/ui/settings/sidebar.cljs
@@ -43,6 +43,9 @@
(def ^:private go-settings-access-tokens
#(st/emit! (rt/nav :settings-access-tokens)))
+(def ^:private go-settings-notifications
+ #(st/emit! (rt/nav :settings-notifications)))
+
(defn- show-release-notes
[event]
(let [version (:main cf/version)]
@@ -60,6 +63,7 @@
options? (= section :settings-options)
feedback? (= section :settings-feedback)
access-tokens? (= section :settings-access-tokens)
+ notifications? (= section :settings-notifications)
team-id (or (dtm/get-last-team-id)
(:default-team-id profile))
@@ -89,6 +93,11 @@
:on-click go-settings-password}
[:span {:class (stl/css :element-title)} (tr "labels.password")]]
+ [:li {:class (stl/css-case :current notifications?
+ :settings-item true)
+ :on-click go-settings-notifications}
+ [:span {:class (stl/css :element-title)} (tr "labels.notifications")]]
+
[:li {:class (stl/css-case :current options?
:settings-item true)
:on-click go-settings-options
diff --git a/frontend/src/app/main/ui/static.cljs b/frontend/src/app/main/ui/static.cljs
index ccf8926222..5b77a7b240 100644
--- a/frontend/src/app/main/ui/static.cljs
+++ b/frontend/src/app/main/ui/static.cljs
@@ -47,7 +47,8 @@
:on-click on-nav-root}
[:> raw-svg* {:id "penpot-logo-icon" :class (stl/css :penpot-logo)}]
(when profile-id
- [:div {:class (stl/css :go-back-wrapper)} [:> icon* {:id "arrow" :class (stl/css :back-arrow)}] [:span (tr "not-found.no-permission.go-dashboard")]])]
+ [:div {:class (stl/css :go-back-wrapper)}
+ [:> icon* {:icon-id "arrow" :class (stl/css :back-arrow)}] [:span (tr "not-found.no-permission.go-dashboard")]])]
[:div {:class (stl/css :deco-before)} i/logo-error-screen]
(when-not profile-id
[:button {:class (stl/css :login-header)
diff --git a/frontend/src/app/main/ui/viewer/comments.cljs b/frontend/src/app/main/ui/viewer/comments.cljs
index 2ab261bb30..db9d66c059 100644
--- a/frontend/src/app/main/ui/viewer/comments.cljs
+++ b/frontend/src/app/main/ui/viewer/comments.cljs
@@ -206,26 +206,28 @@
[:div {:class (stl/css :viewer-comments-container)}
[:div {:class (stl/css :threads)}
(for [item threads]
- [:& cmt/thread-bubble
+ [:> cmt/comment-floating-bubble*
{:thread item
+ :profiles users
:position-modifier modifier1
:zoom zoom
:on-click on-bubble-click
- :open? (= (:id item) (:open local))
+ :is-open (= (:id item) (:open local))
:key (:seqn item)
:origin :viewer}])
(when-let [thread (get threads-map open-thread-id)]
- [:& cmt/thread-comments
+ [:> cmt/comment-floating-thread*
{:thread thread
+ :profiles users
:position-modifier modifier1
:viewport {:offset-x 0 :offset-y 0 :width (:width vsize) :height (:height vsize)}
- :profiles users
:zoom zoom}])
(when-let [draft (:draft local)]
- [:& cmt/draft-thread
+ [:> cmt/comment-floating-thread-draft*
{:draft draft
+ :profiles users
:position-modifier modifier1
:on-cancel on-draft-cancel
:on-submit on-draft-submit
diff --git a/frontend/src/app/main/ui/viewer/inspect/attributes/common.cljs b/frontend/src/app/main/ui/viewer/inspect/attributes/common.cljs
index fcc2eb2502..e7d48424a2 100644
--- a/frontend/src/app/main/ui/viewer/inspect/attributes/common.cljs
+++ b/frontend/src/app/main/ui/viewer/inspect/attributes/common.cljs
@@ -70,7 +70,7 @@
[:div {:class (stl/css :bullet-wrapper)
:style #js {"--bullet-size" "16px"}}
[:& cb/color-bullet {:color color
- :mini? true}]]
+ :mini true}]]
[:div {:class (stl/css :format-wrapper)}
[:div {:class (stl/css :image-format)}
@@ -102,7 +102,7 @@
[:div {:class (stl/css :bullet-wrapper)
:style #js {"--bullet-size" "16px"}}
[:& cb/color-bullet {:color color
- :mini? true}]]
+ :mini true}]]
[:div {:class (stl/css :format-wrapper)}
(when-not (and on-change-format (or (:gradient color) image))
diff --git a/frontend/src/app/main/ui/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs
index 67a831f309..325834266b 100644
--- a/frontend/src/app/main/ui/workspace.cljs
+++ b/frontend/src/app/main/ui/workspace.cljs
@@ -29,7 +29,7 @@
[app.main.ui.workspace.plugins]
[app.main.ui.workspace.sidebar :refer [left-sidebar right-sidebar]]
[app.main.ui.workspace.sidebar.collapsable-button :refer [collapsed-button]]
- [app.main.ui.workspace.sidebar.history :refer [history-toolbox]]
+ [app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
[app.main.ui.workspace.tokens.modals]
[app.main.ui.workspace.tokens.modals.themes]
[app.main.ui.workspace.viewport :refer [viewport]]
@@ -100,7 +100,7 @@
(when (dbg/enabled? :history-overlay)
[:div {:class (stl/css :history-debug-overlay)}
[:button {:on-click #(st/emit! dw/reinitialize-undo)} "CLEAR"]
- [:& history-toolbox]])
+ [:> history-toolbox*]])
[:& viewport {:file file
:wlocal wlocal
diff --git a/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs b/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs
index 9d9097d04c..33f98effb7 100644
--- a/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs
+++ b/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs
@@ -44,7 +44,7 @@
:style #js {"--bullet-size" "20px"}}
(for [[i {:keys [color id gradient]}] (map-indexed vector (take 7 colors))]
[:& cb/color-bullet {:key (dm/str "color-" i)
- :mini? true
+ :mini true
:color {:color color :id id :gradient gradient}}])]]]))
[:li {:class (stl/css-case :file-library true
@@ -68,7 +68,7 @@
:style #js {"--bullet-size" "20px"}}
(for [[i color] (map-indexed vector (take 7 (vals file-colors)))]
[:& cb/color-bullet {:key (dm/str "color-" i)
- :mini? true
+ :mini true
:color color}])]]]
[:li {:class (stl/css :recent-colors true
@@ -90,5 +90,5 @@
:style #js {"--bullet-size" "20px"}}
(for [[idx color] (map-indexed vector (take 7 (reverse recent-colors)))]
[:& cb/color-bullet {:key (str "color-" idx)
- :mini? true
+ :mini true
:color color}])]]]]]))
diff --git a/frontend/src/app/main/ui/workspace/comments.cljs b/frontend/src/app/main/ui/workspace/comments.cljs
index 7fa35a9af1..290e3f2999 100644
--- a/frontend/src/app/main/ui/workspace/comments.cljs
+++ b/frontend/src/app/main/ui/workspace/comments.cljs
@@ -63,6 +63,12 @@
:on-click update-mode}
[:span {:class (stl/css :label)} (tr "labels.show-your-comments")]
[:span {:class (stl/css :icon)} i/tick]]
+ [:li {:class (stl/css-case :dropdown-item true
+ :selected (= :mentions cmode))
+ :data-value "mentions"
+ :on-click update-mode}
+ [:span {:class (stl/css :label)} (tr "labels.show-mentions")]
+ [:span {:class (stl/css :icon)} i/tick]]
[:li {:class (stl/css :separator)}]
[:li {:class (stl/css-case :dropdown-item true
:selected (= :pending cshow))
@@ -137,9 +143,11 @@
[:button {:class (stl/css :mode-dropdown-wrapper)
:on-click toggle-mode-selector}
- [:span {:class (stl/css :mode-label)} (case (:mode local)
- (nil :all) (tr "labels.show-all-comments")
- :yours (tr "labels.show-your-comments"))]
+ [:span {:class (stl/css :mode-label)}
+ (case (:mode local)
+ (nil :all) (tr "labels.show-all-comments")
+ :yours (tr "labels.show-your-comments")
+ :mentions (tr "labels.show-mentions"))]
[:div {:class (stl/css :arrow-icon)} i/arrow]]
[:& dropdown {:show options?
@@ -150,12 +158,12 @@
(if (seq tgroups)
[:div {:class (stl/css :thread-groups)}
- [:& cmt/comment-thread-group
+ [:> cmt/comment-sidebar-thread-group*
{:group (first tgroups)
:on-thread-click on-thread-click
:profiles profiles}]
(for [tgroup (rest tgroups)]
- [:& cmt/comment-thread-group
+ [:> cmt/comment-sidebar-thread-group*
{:group tgroup
:on-thread-click on-thread-click
:profiles profiles
diff --git a/frontend/src/app/main/ui/workspace/comments.scss b/frontend/src/app/main/ui/workspace/comments.scss
index 0d9026a782..af3fa9d43c 100644
--- a/frontend/src/app/main/ui/workspace/comments.scss
+++ b/frontend/src/app/main/ui/workspace/comments.scss
@@ -125,7 +125,6 @@
.thread-groups {
display: flex;
flex-direction: column;
- gap: $s-24;
}
.thread-group-placeholder {
diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs
index 6352a3ea74..8e160a564d 100644
--- a/frontend/src/app/main/ui/workspace/context_menu.cljs
+++ b/frontend/src/app/main/ui/workspace/context_menu.cljs
@@ -138,6 +138,8 @@
::mf/private true}
[]
(let [do-copy #(st/emit! (dw/copy-selected))
+ do-copy-link #(st/emit! (dw/copy-link-to-clipboard))
+
do-cut #(st/emit! (dw/copy-selected)
(dw/delete-selected))
do-paste #(st/emit! (dw/paste-from-clipboard))
@@ -146,6 +148,9 @@
[:> menu-entry* {:title (tr "workspace.shape.menu.copy")
:shortcut (sc/get-tooltip :copy)
:on-click do-copy}]
+ [:> menu-entry* {:title (tr "workspace.shape.menu.copy_link")
+ :shortcut (sc/get-tooltip :copy-link)
+ :on-click do-copy-link}]
[:> menu-entry* {:title (tr "workspace.shape.menu.cut")
:shortcut (sc/get-tooltip :cut)
:on-click do-cut}]
@@ -531,7 +536,7 @@
[{:keys [mdata]}]
(let [{:keys [disable-booleans disable-flatten]} mdata
shapes (mf/deref refs/selected-objects)
- props (mf/spread-props
+ props (mf/props
{:shapes shapes
:disable-booleans disable-booleans
:disable-flatten disable-flatten})]
diff --git a/frontend/src/app/main/ui/workspace/right_header.cljs b/frontend/src/app/main/ui/workspace/right_header.cljs
index 32d679fea0..6cb9618e9a 100644
--- a/frontend/src/app/main/ui/workspace/right_header.cljs
+++ b/frontend/src/app/main/ui/workspace/right_header.cljs
@@ -141,8 +141,7 @@
;; --- Header Component
-(mf/defc right-header
- {::mf/wrap-props false}
+(mf/defc right-header*
[{:keys [file layout page-id]}]
(let [file-id (:id file)
diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs
index 80f8a03794..2c86658ec9 100644
--- a/frontend/src/app/main/ui/workspace/sidebar.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar.cljs
@@ -14,21 +14,22 @@
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.context :as muc]
+ [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*]]
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
[app.main.ui.hooks.resize :refer [use-resize-hook]]
[app.main.ui.workspace.comments :refer [comments-sidebar*]]
[app.main.ui.workspace.left-header :refer [left-header]]
- [app.main.ui.workspace.right-header :refer [right-header]]
+ [app.main.ui.workspace.right-header :refer [right-header*]]
[app.main.ui.workspace.sidebar.assets :refer [assets-toolbox]]
[app.main.ui.workspace.sidebar.debug :refer [debug-panel]]
[app.main.ui.workspace.sidebar.debug-shape-info :refer [debug-shape-info]]
- [app.main.ui.workspace.sidebar.history :refer [history-toolbox]]
+ [app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
[app.main.ui.workspace.sidebar.layers :refer [layers-toolbox]]
- [app.main.ui.workspace.sidebar.options :refer [options-toolbox]]
+ [app.main.ui.workspace.sidebar.options :refer [options-toolbox*]]
[app.main.ui.workspace.sidebar.shortcuts :refer [shortcuts-container]]
[app.main.ui.workspace.sidebar.sitemap :refer [sitemap]]
- [app.main.ui.workspace.sidebar.versions :refer [versions-toolbox]]
+ [app.main.ui.workspace.sidebar.versions :refer [versions-toolbox*]]
[app.main.ui.workspace.tokens.sidebar :refer [tokens-sidebar-tab]]
[app.util.debug :as dbg]
[app.util.i18n :refer [tr]]
@@ -43,7 +44,7 @@
;; NOTE: This custom button may be replace by an action button when this variant is designed
[:button {:class (stl/css :collapse-sidebar-button)
:on-click on-click}
- [:& icon* {:id "arrow"
+ [:> icon* {:icon-id "arrow"
:size "s"
:aria-label (tr "workspace.sidebar.collapse")}]])
@@ -188,74 +189,99 @@
is-history? (contains? layout :document-history)
is-inspect? (= section :inspect)
+ dbg-shape-panel? (dbg/enabled? :shape-panel)
+
current-section* (mf/use-state :info)
current-section (deref current-section*)
- can-be-expanded? (or (dbg/enabled? :shape-panel)
- (and (not is-comments?)
- (not is-history?)
- is-inspect?
- (= current-section :code)))
+ can-be-expanded?
+ (or dbg-shape-panel?
+ (and (not is-comments?)
+ (not is-history?)
+ is-inspect?
+ (= current-section :code)))
{:keys [on-pointer-down on-lost-pointer-capture on-pointer-move set-size size]}
(use-resize-hook :code 276 276 768 :x true :right)
- handle-change-section
- (mf/use-callback
+ on-change-section
+ (mf/use-fn
(fn [section]
(reset! current-section* section)))
- handle-expand
- (mf/use-callback
+ on-close-history
+ (mf/use-fn #(st/emit! (dw/remove-layout-flag :document-history)))
+
+ on-expand
+ (mf/use-fn
(mf/deps size)
(fn []
(set-size (if (> size 276) 276 768))))
props
- (mf/spread props
- :on-change-section handle-change-section
- :on-expand handle-expand)
+ (mf/spread-props props
+ {:on-change-section on-change-section
+ :on-expand on-expand})]
- history-tab
- (mf/html
- [:article {:class (stl/css :history-tab)}
- [:& history-toolbox {}]])
+ [:> (mf/provider muc/sidebar) {:value :right}
+ [:aside
+ {:class (stl/css-case :right-settings-bar true
+ :not-expand (not can-be-expanded?)
+ :expanded (> size 276))
- versions-tab
- (mf/html
- [:article {:class (stl/css :versions-tab)}
- [:& versions-toolbox {}]])]
+ :id "right-sidebar-aside"
+ :data-testid "right-sidebar"
+ :data-size (str size)
+ :style {"--width" (if can-be-expanded? (dm/str size "px") "276px")}}
- [:& (mf/provider muc/sidebar) {:value :right}
- [:aside {:class (stl/css-case :right-settings-bar true
- :not-expand (not can-be-expanded?)
- :expanded (> size 276))
-
- :id "right-sidebar-aside"
- :data-testid "right-sidebar"
- :data-size (str size)
- :style #js {"--width" (if can-be-expanded? (dm/str size "px") "276px")}}
(when can-be-expanded?
[:div {:class (stl/css :resize-area)
:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-pointer-move on-pointer-move}])
- [:& right-header {:file file :layout layout :page-id page-id}]
+
+ [:> right-header*
+ {:file file
+ :layout layout
+ :page-id page-id}]
[:div {:class (stl/css :settings-bar-inside)}
(cond
- (dbg/enabled? :shape-panel)
+ dbg-shape-panel?
[:& debug-shape-info]
- (true? is-comments?)
+ is-comments?
[:> comments-sidebar* {}]
- (true? is-history?)
- [:> tab-switcher*
- {:tabs #js [#js {:label (tr "workspace.versions.tab.history") :id "history" :content versions-tab}
- #js {:label (tr "workspace.versions.tab.actions") :id "actions" :content history-tab}]
- :default-selected "history"
- :class (stl/css :left-sidebar-tabs)}]
+ is-history?
+ (let [history-tab
+ (mf/html
+ [:article {:class (stl/css :history-tab)}
+ [:> history-toolbox*]])
+
+ versions-tab
+ (mf/html
+ [:article {:class (stl/css :versions-tab)}
+ [:> versions-toolbox*]])
+
+ button
+ (mf/html
+ [:> icon-button* {:variant "ghost"
+ :aria-label (tr "labels.close")
+ :on-click on-close-history
+ :icon "close"}])]
+
+ [:> tab-switcher*
+ {:tabs [{:label (tr "workspace.versions.tab.history")
+ :id "history"
+ :content versions-tab}
+ {:label (tr "workspace.versions.tab.actions")
+ :id "actions"
+ :content history-tab}]
+ :default-selected "history"
+ :class (stl/css :left-sidebar-tabs)
+ :action-button-position "end"
+ :action-button button}])
:else
- [:> options-toolbox props])]]]))
+ [:> options-toolbox* props])]]]))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
index bd0fa05f61..3af7840fd7 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
@@ -90,6 +90,9 @@
reverse-sort? (= :desc ordering)
num-libs (count (mf/deref refs/libraries))
+ show-templates-02-test?
+ (and (cf/external-feature-flag "templates-02" "test") (zero? num-libs))
+
toggle-ordering
(mf/use-fn
(mf/deps ordering)
@@ -158,8 +161,7 @@
[:article {:class (stl/css :assets-bar)}
[:div {:class (stl/css :assets-header)}
(when-not ^boolean read-only?
- (if (and (cf/external-feature-flag "templates-02" "test")
- (zero? num-libs))
+ (if show-templates-02-test?
[:button {:class (stl/css :add-library-button)
:on-click show-libraries-dialog
:data-testid "libraries"}
@@ -171,31 +173,32 @@
i/library]
(tr "workspace.assets.libraries")]))
- [:div {:class (stl/css :search-wrapper)}
- [:& search-bar {:on-change on-search-term-change
- :value term
- :placeholder (tr "workspace.assets.search")}
- [:button
- {:on-click on-open-menu
- :title (tr "workspace.assets.filter")
- :class (stl/css-case :section-button true
- :opened menu-open?)}
- i/filter-icon]]
- [:> context-menu*
- {:on-close on-menu-close
- :selectable true
- :selected section
- :show menu-open?
- :fixed true
- :min-width true
- :width size
- :top 158
- :left 18
- :options options}]
- [:> icon-button* {:variant "ghost"
- :aria-label (tr "workspace.assets.sort")
- :on-click toggle-ordering
- :icon (if reverse-sort? "asc-sort" "desc-sort")}]]]
+ (when-not show-templates-02-test?
+ [:div {:class (stl/css :search-wrapper)}
+ [:& search-bar {:on-change on-search-term-change
+ :value term
+ :placeholder (tr "workspace.assets.search")}
+ [:button
+ {:on-click on-open-menu
+ :title (tr "workspace.assets.filter")
+ :class (stl/css-case :section-button true
+ :opened menu-open?)}
+ i/filter-icon]]
+ [:> context-menu*
+ {:on-close on-menu-close
+ :selectable true
+ :selected section
+ :show menu-open?
+ :fixed true
+ :min-width true
+ :width size
+ :top 158
+ :left 18
+ :options options}]
+ [:> icon-button* {:variant "ghost"
+ :aria-label (tr "workspace.assets.sort")
+ :on-click toggle-ordering
+ :icon (if reverse-sort? "asc-sort" "desc-sort")}]])]
[:& (mf/provider cmm/assets-filters) {:value filters}
[:& (mf/provider cmm/assets-toggle-ordering) {:value toggle-ordering}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs
index f3dfccfd8d..0738bd6901 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs
@@ -216,7 +216,7 @@
[:div {:class (stl/css :bullet-block)}
[:& cb/color-bullet {:color color
- :mini? true}]]
+ :mini true}]]
(if ^boolean editing?
[:input
diff --git a/frontend/src/app/main/ui/workspace/sidebar/history.cljs b/frontend/src/app/main/ui/workspace/sidebar/history.cljs
index 753c99c3c4..d5eb76bc3d 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/history.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/history.cljs
@@ -320,7 +320,7 @@
(when @show-detail?
[:& history-entry-details {:entry entry}])]))
-(mf/defc history-toolbox
+(mf/defc history-toolbox*
[]
(let [objects (mf/deref refs/workspace-page-objects)
{:keys [items index]} (mf/deref workspace-undo)
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs
index 9dd8d234a2..491b86707f 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs
@@ -43,7 +43,7 @@
[{:keys [selected] :as props}]
(let [pending-selected (mf/use-var selected)
current-selected (mf/use-state selected)
- props (mf/spread props :selected @current-selected)
+ props (mf/spread-object props {:selected @current-selected})
set-selected
(mf/use-memo
diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs
index ebf93ffb88..f8fd19e1a2 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs
@@ -129,9 +129,9 @@
:file-id file-id
:shared-libs shared-libs}])]))
-(mf/defc options-content
+(mf/defc options-content*
{::mf/memo true
- ::mf/props :obj}
+ ::mf/private true}
[{:keys [selected shapes shapes-with-children page-id file-id on-change-section on-expand]}]
(let [objects (mf/deref refs/workspace-page-objects)
permissions (mf/use-ctx ctx/permissions)
@@ -202,20 +202,19 @@
;; selected-objects-with-children are derefed always but they only
;; need on multiple selection in majority of cases
-(mf/defc options-toolbox
- {::mf/memo true
- ::mf/props :obj}
+(mf/defc options-toolbox*
+ {::mf/memo true}
[{:keys [section selected on-change-section on-expand]}]
(let [page-id (mf/use-ctx ctx/current-page-id)
file-id (mf/use-ctx ctx/current-file-id)
shapes (mf/deref refs/selected-objects)
shapes-with-children (mf/deref refs/selected-shapes-with-children)]
- [:& options-content {:shapes shapes
- :selected selected
- :shapes-with-children shapes-with-children
- :file-id file-id
- :page-id page-id
- :section section
- :on-change-section on-change-section
- :on-expand on-expand}]))
+ [:> options-content* {:shapes shapes
+ :selected selected
+ :shapes-with-children shapes-with-children
+ :file-id file-id
+ :page-id page-id
+ :section section
+ :on-change-section on-change-section
+ :on-expand on-expand}]))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.cljs
index 20404b3e6a..7809c85680 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.cljs
@@ -64,7 +64,7 @@
(if (not radius-expanded)
[:div {:class (stl/css :radius-1)
:title (tr "workspace.options.radius")}
- [:> icon* {:id "corner-radius"
+ [:> icon* {:icon-id "corner-radius"
:size "s"
:class (stl/css :icon)}]
[:> numeric-input*
@@ -116,8 +116,7 @@
[:> icon-button* {:class (stl/css-case :selected radius-expanded)
:variant "ghost"
:on-click toggle-radius-mode
- :aria-label (tr "workspace.options.radius")
- :title (if radius-expanded
- (tr "workspace.options.radius.all-corners")
- (tr "workspace.options.radius.single-corners"))
+ :aria-label (if radius-expanded
+ (tr "workspace.options.radius.all-corners")
+ (tr "workspace.options.radius.single-corners"))
:icon "corner-radius"}]]))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss
index aa443fa33e..030d64cacd 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss
+++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss
@@ -402,6 +402,7 @@
.component-swap {
padding-top: $s-12;
+ max-width: $s-248;
}
.component-swap-content {
diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs
index 57cf42d9d8..b1b1a1c7e0 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs
@@ -456,7 +456,7 @@
type (if (= type "multiple") :simple :multiple)]
(on-type-change type))))
- props (mf/spread props {:on-change on-change})]
+ props (mf/spread-object props {:on-change on-change})]
(mf/with-effect []
;; on destroy component
diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
index 681e879f3a..21a5c5fafe 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
@@ -43,8 +43,7 @@
[prop]
(select-margins (= prop :m1) (= prop :m2) (= prop :m3) (= prop :m4)))
-(mf/defc margin-simple
- {::mf/props :obj}
+(mf/defc margin-simple*
[{:keys [value on-change on-blur]}]
(let [m1 (:m1 value)
m2 (:m2 value)
@@ -103,8 +102,7 @@
:nillable true
:value m2}]]]))
-(mf/defc margin-multiple
- {::mf/props :obj}
+(mf/defc margin-multiple*
[{:keys [value on-change on-blur]}]
(let [m1 (:m1 value)
m2 (:m2 value)
@@ -182,14 +180,13 @@
:value m4}]]]))
-(mf/defc margin-section
- {::mf/props :obj
- ::mf/private true
+(mf/defc margin-section*
+ {::mf/private true
::mf/expect-props #{:value :type :on-type-change :on-change}}
[{:keys [type on-type-change] :as props}]
(let [type (d/nilv type :simple)
on-blur (mf/use-fn #(select-margins false false false false))
- props (mf/spread props :on-blur on-blur)
+ props (mf/spread-props props {:on-blur on-blur})
on-type-change'
(mf/use-fn
@@ -206,10 +203,10 @@
[:div {:class (stl/css :inputs-wrapper)}
(cond
(= type :simple)
- [:> margin-simple props]
+ [:> margin-simple* props]
(= type :multiple)
- [:> margin-multiple props])]
+ [:> margin-multiple* props])]
[:button {:class (stl/css-case
:margin-mode true
@@ -500,10 +497,10 @@
(when is-layout-child?
[:div {:class (stl/css :row)}
- [:& margin-section {:value (:layout-item-margin values)
- :type (:layout-item-margin-type values)
- :on-type-change on-margin-type-change
- :on-change on-margin-change}]])
+ [:> margin-section* {:value (:layout-item-margin values)
+ :type (:layout-item-margin-type values)
+ :on-type-change on-margin-type-change
+ :on-change on-margin-change}]])
(when (or (= h-sizing :fill)
(= v-sizing :fill))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs
index f53360fc30..04dfdb89ba 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs
@@ -212,7 +212,7 @@
(nil? color-name) (assoc
:id nil
:file-id nil))
- :mini? true
+ :mini true
:on-click handle-click-color}]]
(cond
;; Rendering a color with ID
diff --git a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs
index dad7ddcf29..70d1b1b68a 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs
@@ -91,6 +91,7 @@
(tr "shortcuts.bring-front")
(tr "shortcuts.clear-undo")
(tr "shortcuts.copy")
+ (tr "shortcuts.copy-link")
(tr "shortcuts.create-component")
(tr "shortcuts.create-new-project")
(tr "shortcuts.cut")
diff --git a/frontend/src/app/main/ui/workspace/sidebar/versions.cljs b/frontend/src/app/main/ui/workspace/sidebar/versions.cljs
index c8d8a55a46..8d893e55ef 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/versions.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/versions.cljs
@@ -226,14 +226,13 @@
:on-click handle-pin-snapshot}
(tr "workspace.versions.button.pin")]]]])]]]))
-(mf/defc versions-toolbox
+(mf/defc versions-toolbox*
[]
(let [profiles (mf/deref refs/profiles)
profile (mf/deref refs/profile)
expanded (mf/use-state #{})
-
{:keys [status data editing]}
(mf/deref versions)
diff --git a/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs b/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs
index e6cb23f38b..b407624957 100644
--- a/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs
+++ b/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs
@@ -90,7 +90,7 @@
:class (stl/css :theme-group-label)
:typography "body-large"}
[:span {:class (stl/css :group-title)}
- [:> icon* {:id "group"}]
+ [:> icon* {:icon-id "group"}]
group]])
[:ul {:class (stl/css :theme-group-rows-wrapper)}
(for [[_ {:keys [group name] :as theme}] themes
@@ -131,7 +131,7 @@
[:div {:class (stl/css :label-wrapper)}
[:> text* {:as "span" :typography "body-medium"}
(tr "workspace.token.num-sets" sets-count)]
- [:> icon* {:id "arrow-right"}]]]
+ [:> icon* {:icon-id "arrow-right"}]]]
[:> button* {:class (stl/css :sets-count-empty-button)
:type "button"
@@ -140,7 +140,7 @@
[:div {:class (stl/css :label-wrapper)}
[:> text* {:as "span" :typography "body-medium"}
(tr "workspace.token.no-sets")]
- [:> icon* {:id "arrow-right"}]]])
+ [:> icon* {:icon-id "arrow-right"}]]])
[:> icon-button* {:on-click delete-theme
:variant "ghost"
@@ -186,7 +186,7 @@
:on-click (fn [e]
(dom/stop-propagation e)
(on-toggle-dropdown))}
- [:> icon* {:id "arrow-down"}]]))}]]
+ [:> icon* {:icon-id "arrow-down"}]]))}]]
[:div {:class (stl/css :group-input-wrapper)}
;; TODO: This span should be remove when labeled-input is updated
[:span {:class (stl/css :labeled-input-label)} "Theme"]
@@ -306,7 +306,7 @@
[:button {:on-click on-back
:class (stl/css :back-btn)
:type "button"}
- [:> icon* {:id ic/arrow-left :aria-hidden true}]
+ [:> icon* {:icon-id ic/arrow-left :aria-hidden true}]
(tr "workspace.token.back-to-themes")]
[:& theme-inputs {:dropdown-open? dropdown-open?
diff --git a/frontend/src/app/main/ui/workspace/tokens/sets.cljs b/frontend/src/app/main/ui/workspace/tokens/sets.cljs
index 127f13c3fa..0c3eb69281 100644
--- a/frontend/src/app/main/ui/workspace/tokens/sets.cljs
+++ b/frontend/src/app/main/ui/workspace/tokens/sets.cljs
@@ -96,9 +96,8 @@
:aria-label (tr "labels.collapse")
:icon (if @collapsed? "arrow-right" "arrow-down")
:variant "action"}]
- [:> icon*
- {:id "group"
- :class (stl/css :icon)}]
+ [:> icon* {:icon-id "group"
+ :class (stl/css :icon)}]
(if editing?'
[:& editing-label
{:default-value label
@@ -139,10 +138,9 @@
:on-click on-click
:on-double-click #(on-edit tree-path)
:on-context-menu on-context-menu}
- [:> icon*
- {:id "document"
- :class (stl/css-case :icon true
- :root-icon (not tree-depth))}]
+ [:> icon* {:icon-id "document"
+ :class (stl/css-case :icon true
+ :root-icon (not tree-depth))}]
(if editing?'
[:& editing-label
{:default-value label
@@ -160,7 +158,7 @@
[:> icon* {:aria-label (tr "workspace.token.select-set")
:class (stl/css :check-icon)
:size "s"
- :id ic/tick}])]])]))
+ :icon-id ic/tick}])]])]))
(mf/defc sets-tree
[{:keys [set-path set-node tree-depth tree-path on-select selected? on-toggle active? editing? on-edit on-edit-reset on-edit-submit]
diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs
index 1579002644..8fcbab4322 100644
--- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs
+++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs
@@ -73,7 +73,7 @@
(wtt/resolved-value-hex theme-token)
(wtt/resolved-value-hex token))]
[:& color-bullet {:color color
- :mini? true}])
+ :mini true}])
name]))
(mf/defc token-section-icon
diff --git a/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs b/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs
index 484c806c5d..85a3e2eeb0 100644
--- a/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs
+++ b/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs
@@ -42,7 +42,7 @@
:is-selected selected?)
:on-click select-theme}
[:> text* {:as "span" :typography "body-small" :class (stl/css :label)} name]
- [:> icon* {:id i/tick
+ [:> icon* {:icon-id i/tick
:aria-hidden true
:class (stl/css-case :check-icon true
:check-icon-visible selected?)}]])]))
@@ -70,7 +70,7 @@
:role "option"
:on-click on-edit-click}
[:> text* {:as "span" :typography "body-small"} (tr "workspace.token.edit-themes")]
- [:> icon* {:id i/arrow-right :aria-hidden true}]]])))
+ [:> icon* {:icon-id i/arrow-right :aria-hidden true}]]])))
(mf/defc theme-select
[{:keys []}]
@@ -108,7 +108,7 @@
:class (stl/css :custom-select)}
[:> text* {:as "span" :typography "body-small" :class (stl/css :current-label)}
current-label]
- [:> icon* {:id i/arrow-down :class (stl/css :dropdown-button) :aria-hidden true}]
+ [:> icon* {:icon-id i/arrow-down :class (stl/css :dropdown-button) :aria-hidden true}]
[:& dropdown {:show is-open?
:on-close on-close-dropdown
:ref dropdown-element*}
diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs
index 8aa9942b83..33f0cc9256 100644
--- a/frontend/src/app/main/ui/workspace/viewport.cljs
+++ b/frontend/src/app/main/ui/workspace/viewport.cljs
@@ -211,7 +211,7 @@
show-outlines? (and (nil? transform)
(not edition)
(not drawing-obj)
- (not (#{:comments :path :curve} drawing-tool)))
+ (not (#{:path :curve} drawing-tool)))
show-pixel-grid? (and (contains? layout :show-pixel-grid)
(>= zoom 8))
diff --git a/frontend/src/app/main/ui/workspace/viewport/comments.cljs b/frontend/src/app/main/ui/workspace/viewport/comments.cljs
index 1b226dcae0..5cc97b5746 100644
--- a/frontend/src/app/main/ui/workspace/viewport/comments.cljs
+++ b/frontend/src/app/main/ui/workspace/viewport/comments.cljs
@@ -75,22 +75,24 @@
[:div {:class (stl/css :threads)
:style {:transform (dm/fmt "translate(%px, %px)" pos-x pos-y)}}
(for [item threads]
- [:& cmt/thread-bubble {:thread item
- :zoom zoom
- :open? (= (:id item) (:open local))
- :key (:seqn item)}])
+ [:> cmt/comment-floating-bubble* {:thread item
+ :profiles profiles
+ :zoom zoom
+ :is-open (= (:id item) (:open local))
+ :key (:seqn item)}])
(when-let [id (:open local)]
(when-let [thread (get threads-map id)]
(when (seq (dcm/apply-filters local profile [thread]))
- [:& cmt/thread-comments {:thread (update-position positions thread)
- :profiles profiles
- :viewport {:offset-x pos-x :offset-y pos-y :width (:width vport) :height (:height vport)}
- :zoom zoom}])))
+ [:> cmt/comment-floating-thread* {:thread (update-position positions thread)
+ :profiles profiles
+ :viewport {:offset-x pos-x :offset-y pos-y :width (:width vport) :height (:height vport)}
+ :zoom zoom}])))
(when-let [draft (:comment drawing)]
- [:& cmt/draft-thread {:draft draft
- :on-cancel on-draft-cancel
- :on-submit on-draft-submit
- :zoom zoom}])]]]))
+ [:> cmt/comment-floating-thread-draft* {:draft draft
+ :profiles profiles
+ :on-cancel on-draft-cancel
+ :on-submit on-draft-submit
+ :zoom zoom}])]]]))
diff --git a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs
index 00ac129443..30964d8697 100644
--- a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs
+++ b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs
@@ -284,8 +284,7 @@
(p/fmap (fn [ready?]
(when ready?
(reset! canvas-init? true)
- (wasm.api/assign-canvas canvas)
- (wasm.api/set-canvas-background background)))))
+ (wasm.api/assign-canvas canvas)))))
(fn []
(wasm.api/clear-canvas))))
@@ -293,15 +292,15 @@
(when @canvas-init?
(wasm.api/resize-viewbox (:width vport) (:height vport))))
- (mf/with-effect [base-objects canvas-init?]
+ (mf/with-effect [base-objects @canvas-init?]
(when @canvas-init?
(wasm.api/set-objects base-objects)))
- (mf/with-effect [preview-blend canvas-init?]
+ (mf/with-effect [preview-blend @canvas-init?]
(when (and @canvas-init? preview-blend)
(wasm.api/request-render)))
- (mf/with-effect [vbox canvas-init?]
+ (mf/with-effect [vbox @canvas-init?]
(when @canvas-init?
(wasm.api/set-view zoom vbox)))
diff --git a/frontend/src/app/plugins/parser.cljs b/frontend/src/app/plugins/parser.cljs
index c58e6f1ea9..4731528abe 100644
--- a/frontend/src/app/plugins/parser.cljs
+++ b/frontend/src/app/plugins/parser.cljs
@@ -340,76 +340,6 @@
(when (some? guides)
(into [] (map parse-frame-guide) guides)))
-;;interface PathCommand {
-;; command:
-;; | 'M' | 'move-to'
-;; | 'Z' | 'close-path'
-;; | 'L' | 'line-to'
-;; | 'H' | 'line-to-horizontal'
-;; | 'V' | 'line-to-vertical'
-;; | 'C' | 'curve-to'
-;; | 'S' | 'smooth-curve-to'
-;; | 'Q' | 'quadratic-bezier-curve-to'
-;; | 'T' | 'smooth-quadratic-bezier-curve-to'
-;; | 'A' | 'elliptical-arc';
-;;
-;; params?: {
-;; x?: number;
-;; y?: number;
-;; c1x: number;
-;; c1y: number;
-;; c2x: number;
-;; c2y: number;
-;; rx?: number;
-;; ry?: number;
-;; xAxisRotation?: number;
-;; largeArcFlag?: boolean;
-;; sweepFlag?: boolean;
-;; };
-;;}
-(defn parse-command-type
- [^string command-type]
- (case command-type
- "M" :move-to
- "Z" :close-path
- "L" :line-to
- "H" :line-to-horizontal
- "V" :line-to-vertical
- "C" :curve-to
- "S" :smooth-curve-to
- "Q" :quadratic-bezier-curve-to
- "T" :smooth-quadratic-bezier-curve-to
- "A" :elliptical-arc
- (parse-keyword command-type)))
-
-(defn parse-command-params
- [^js params]
- (when (some? params)
- (d/without-nils
- {:x (obj/get params "x")
- :y (obj/get params "y")
- :c1x (obj/get params "c1x")
- :c1y (obj/get params "c1y")
- :c2x (obj/get params "c2x")
- :c2y (obj/get params "c2y")
- :rx (obj/get params "rx")
- :ry (obj/get params "ry")
- :x-axis-rotation (obj/get params "xAxisRotation")
- :large-arc-flag (obj/get params "largeArcFlag")
- :sweep-flag (obj/get params "sweepFlag")})))
-
-(defn parse-command
- [^js command]
- (when (some? command)
- (d/without-nils
- {:command (-> (obj/get command "command") parse-command-type)
- :params (-> (obj/get command "params") parse-command-params)})))
-
-(defn parse-path-content
- [^js content]
- (when (some? content)
- (into [] (map parse-command) content)))
-
;; export interface Dissolve {
;; type: 'dissolve';
;; duration: number;
diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs
index 82e07f1de8..a16deb8aaa 100644
--- a/frontend/src/app/plugins/shape.cljs
+++ b/frontend/src/app/plugins/shape.cljs
@@ -15,7 +15,7 @@
[app.common.record :as crc]
[app.common.schema :as sm]
[app.common.spec :as us]
- [app.common.svg.path.legacy-parser2 :as spp]
+ [app.common.svg.path :as path]
[app.common.text :as txt]
[app.common.types.component :as ctk]
[app.common.types.container :as ctn]
@@ -1296,12 +1296,10 @@
(cond-> (or (cfh/path-shape? data) (cfh/bool-shape? data))
(crc/add-properties!
{:name "content"
- :get #(-> % u/proxy->shape :content format/format-path-content)
+ :get #(-> % u/proxy->shape :content upf/format-path)
:set
(fn [_ value]
- (let [content
- (->> (parser/parse-path-content value)
- (spp/simplify-commands))]
+ (let [content (->> (path/parse value))]
(cond
(not (cfh/path-shape? data))
(u/display-not-valid :content-type type)
diff --git a/frontend/src/app/plugins/user.cljs b/frontend/src/app/plugins/user.cljs
index bf2022435b..b8087f6e96 100644
--- a/frontend/src/app/plugins/user.cljs
+++ b/frontend/src/app/plugins/user.cljs
@@ -18,26 +18,24 @@
(defn- add-session-properties
[user-proxy session-id]
- (let [plugin-id (obj/get user-proxy "$plugin")]
- (crc/add-properties!
- user-proxy
- {:name "$plugin" :enumerable false :get (constantly plugin-id)}
- {:name "$session" :enumerable false :get (constantly session-id)}
+ (crc/add-properties!
+ user-proxy
+ {:name "$session" :enumerable false :get (constantly session-id)}
- {:name "id"
- :get (fn [_] (-> (u/locate-profile session-id) :id str))}
+ {:name "id"
+ :get (fn [_] (-> (u/locate-profile session-id) :id str))}
- {:name "name"
- :get (fn [_] (-> (u/locate-profile session-id) :fullname))}
+ {:name "name"
+ :get (fn [_] (-> (u/locate-profile session-id) :fullname))}
- {:name "avatarUrl"
- :get (fn [_] (cfg/resolve-profile-photo-url (u/locate-profile session-id)))}
+ {:name "avatarUrl"
+ :get (fn [_] (cfg/resolve-profile-photo-url (u/locate-profile session-id)))}
- {:name "color"
- :get (fn [_] (-> (u/locate-presence session-id) :color))}
+ {:name "color"
+ :get (fn [_] (-> (u/locate-presence session-id) :color))}
- {:name "sessionId"
- :get (fn [_] (str session-id))})))
+ {:name "sessionId"
+ :get (fn [_] (str session-id))}))
(defn current-user-proxy? [p]
@@ -46,7 +44,8 @@
(defn current-user-proxy
[plugin-id session-id]
(-> (obj/reify {:name "CurrentUserProxy"}
- :$plugin {:enumerable false :get (fn [] plugin-id)})
+ :$plugin
+ {:enumerable false :get (fn [] plugin-id)})
(add-session-properties session-id)))
(defn active-user-proxy? [p]
@@ -55,7 +54,8 @@
(defn active-user-proxy
[plugin-id session-id]
(-> (obj/reify {:name "ActiveUserProxy"}
- :$plugin {:enumerable false :get (fn [] plugin-id)}
+ :$plugin
+ {:enumerable false :get (fn [] plugin-id)}
:position
{:get (fn [] (-> (u/locate-presence session-id) :point format/format-point))}
@@ -66,19 +66,16 @@
(defn- add-user-properties
[user-proxy data]
- (let [plugin-id (obj/get user-proxy "$plugin")]
- (crc/add-properties!
- user-proxy
- {:name "$plugin" :enumerable false :get (constantly plugin-id)}
+ (crc/add-properties!
+ user-proxy
+ {:name "id"
+ :get (fn [_] (-> data :id str))}
- {:name "id"
- :get (fn [_] (-> data :id str))}
+ {:name "name"
+ :get (fn [_] (-> data :fullname))}
- {:name "name"
- :get (fn [_] (-> data :fullname))}
-
- {:name "avatarUrl"
- :get (fn [_] (cfg/resolve-profile-photo-url data))})))
+ {:name "avatarUrl"
+ :get (fn [_] (cfg/resolve-profile-photo-url data))}))
(defn user-proxy
[plugin-id data]
diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs
index 96e045d24d..eb3f38dd34 100644
--- a/frontend/src/app/render_wasm/api.cljs
+++ b/frontend/src/app/render_wasm/api.cljs
@@ -211,6 +211,93 @@
(store-image id))))))
fills))
+(defn- translate-stroke-style
+ [stroke-style]
+ (case stroke-style
+ :dotted 1
+ :dashed 2
+ :mixed 3
+ 0))
+
+(defn- translate-stroke-cap
+ [stroke-cap]
+ (case stroke-cap
+ :line-arrow 1
+ :triangle-arrow 2
+ :square-marker 3
+ :circle-marker 4
+ :diamond-marker 5
+ :round 6
+ :square 7
+ 0))
+
+(defn set-shape-strokes
+ [strokes]
+ (h/call internal-module "_clear_shape_strokes")
+ (keep (fn [stroke]
+ (let [opacity (or (:stroke-opacity stroke) 1.0)
+ color (:stroke-color stroke)
+ gradient (:stroke-color-gradient stroke)
+ image (:stroke-image stroke)
+ width (:stroke-width stroke)
+ align (:stroke-alignment stroke)
+ style (-> stroke :stroke-style translate-stroke-style)
+ cap-start (-> stroke :stroke-cap-start translate-stroke-cap)
+ cap-end (-> stroke :stroke-cap-end translate-stroke-cap)]
+ (case align
+ :inner (h/call internal-module "_add_shape_inner_stroke" width style cap-start cap-end)
+ :outer (h/call internal-module "_add_shape_outer_stroke" width style cap-start cap-end)
+ (h/call internal-module "_add_shape_center_stroke" width style cap-start cap-end))
+
+ (cond
+ (some? gradient)
+ (let [stops (:stops gradient)
+ n-stops (count stops)
+ mem-size (* 5 n-stops)
+ stops-ptr (h/call internal-module "_alloc_bytes" mem-size)
+ heap (gobj/get ^js internal-module "HEAPU8")
+ mem (js/Uint8Array. (.-buffer heap) stops-ptr mem-size)]
+ (if (= (:type gradient) :linear)
+ (h/call internal-module "_add_shape_stroke_linear_fill"
+ (:start-x gradient)
+ (:start-y gradient)
+ (:end-x gradient)
+ (:end-y gradient)
+ opacity)
+ (h/call internal-module "_add_shape_stroke_radial_fill"
+ (:start-x gradient)
+ (:start-y gradient)
+ (:end-x gradient)
+ (:end-y gradient)
+ opacity
+ (:width gradient)))
+ (.set mem (js/Uint8Array. (clj->js (flatten (map (fn [stop]
+ (let [[r g b a] (rgba-bytes-from-hex (:color stop) (:opacity stop))
+ offset (:offset stop)]
+ [r g b a (* 100 offset)]))
+ stops)))))
+ (h/call internal-module "_add_shape_stroke_stops" stops-ptr n-stops))
+
+ (some? image)
+ (let [id (dm/get-prop image :id)
+ buffer (uuid/get-u32 id)
+ cached-image? (h/call internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))]
+ (h/call internal-module "_add_shape_image_stroke"
+ (aget buffer 0)
+ (aget buffer 1)
+ (aget buffer 2)
+ (aget buffer 3)
+ opacity
+ (dm/get-prop image :width)
+ (dm/get-prop image :height))
+ (when (== cached-image? 0)
+ (store-image id)))
+
+ (some? color)
+ (let [rgba (rgba-from-hex color opacity)]
+ (h/call internal-module "_add_shape_stroke_solid_fill" rgba)))))
+ strokes))
+
(defn set-shape-path-content
[content]
(let [buffer (path/content->buffer content)
@@ -280,6 +367,8 @@
transform (dm/get-prop shape :transform)
fills (if (= type :group)
[] (dm/get-prop shape :fills))
+ strokes (if (= type :group)
+ [] (dm/get-prop shape :strokes))
children (dm/get-prop shape :shapes)
blend-mode (dm/get-prop shape :blend-mode)
opacity (dm/get-prop shape :opacity)
@@ -297,8 +386,8 @@
(set-shape-opacity opacity)
(set-shape-hidden hidden)
(when (and (some? content) (= type :path)) (set-shape-path-content content))
- (let [pending-fills (doall (set-shape-fills fills))]
- (recur (inc index) (into pending pending-fills))))
+ (let [pending' (concat (set-shape-fills fills) (set-shape-strokes strokes))]
+ (recur (inc index) (into pending pending'))))
pending))]
(request-render)
(when-let [pending (seq pending)]
diff --git a/frontend/src/app/render_wasm/shape.cljs b/frontend/src/app/render_wasm/shape.cljs
index 582c611039..9be274472e 100644
--- a/frontend/src/app/render_wasm/shape.cljs
+++ b/frontend/src/app/render_wasm/shape.cljs
@@ -117,6 +117,7 @@
:rotation (api/set-shape-rotation v)
:transform (api/set-shape-transform v)
:fills (api/set-shape-fills v)
+ :strokes (api/set-shape-strokes v)
:blend-mode (api/set-shape-blend-mode v)
:opacity (api/set-shape-opacity v)
:hidden (api/set-shape-hidden v)
diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs
index f13553a269..4257e8c36e 100644
--- a/frontend/src/app/util/dom.cljs
+++ b/frontend/src/app/util/dom.cljs
@@ -314,7 +314,8 @@
(defn set-html!
[^js el html]
(when (some? el)
- (set! (.-innerHTML el) html)))
+ (set! (.-innerHTML el) html))
+ el)
(defn append-child!
[^js el child]
@@ -322,6 +323,16 @@
(.appendChild ^js el child))
el)
+(defn insert-after!
+ [^js el ^js ref child]
+ (when (and (some? el) (some? ref))
+ (let [nodes (.-childNodes el)
+ idx (d/index-of-pred nodes #(= ref %))]
+ (if-let [sibnode (unchecked-get nodes (inc idx))]
+ (.insertBefore el child sibnode)
+ (.appendChild ^js el child))))
+ el)
+
(defn remove-child!
[^js el child]
(when (some? el)
@@ -459,6 +470,11 @@
(when (some? node)
(.focus node)))
+(defn focus?
+ [^js node]
+ (and node
+ (= (.-activeElement js/document) node)))
+
(defn blur!
[^js node]
(when (some? node)
@@ -525,7 +541,8 @@
(.setAttribute node property value))
node)
-(defn get-text [^js node]
+(defn get-text
+ [^js node]
(when (some? node)
(.-textContent node)))
@@ -626,7 +643,8 @@
(defn set-data!
[^js node ^string attr value]
(when (some? node)
- (.setAttribute node (dm/str "data-" attr) (dm/str value))))
+ (.setAttribute node (dm/str "data-" attr) (dm/str value)))
+ node)
(defn set-attribute! [^js node ^string attr value]
(when (some? node)
@@ -842,6 +860,11 @@
([^js node deep?]
(.cloneNode node deep?)))
+(defn get-children
+ [node]
+ (when (some? node)
+ (.-children node)))
+
(defn has-children?
[^js node]
(> (-> node .-children .-length) 0))
@@ -861,3 +884,11 @@
ptk/EffectEvent
(effect [_ _ _]
(focus! (get-element name)))))
+
+(defn first-child
+ [^js node]
+ (.. node -firstChild))
+
+(defn last-child
+ [^js node]
+ (.. node -lastChild))
diff --git a/frontend/src/app/util/keyboard.cljs b/frontend/src/app/util/keyboard.cljs
index 5151b2f502..27ff1493a8 100644
--- a/frontend/src/app/util/keyboard.cljs
+++ b/frontend/src/app/util/keyboard.cljs
@@ -90,4 +90,5 @@
(def backspace? (is-key? "Backspace"))
(def home? (is-key? "Home"))
(def tab? (is-key? "Tab"))
+(def delete? (is-key? "Delete"))
diff --git a/frontend/src/app/util/queue.cljs b/frontend/src/app/util/queue.cljs
index 564fd3cda8..4fbc72b302 100644
--- a/frontend/src/app/util/queue.cljs
+++ b/frontend/src/app/util/queue.cljs
@@ -9,6 +9,7 @@
(:require
[app.common.logging :as l]
[app.common.math :as mth]
+ [app.util.object :as obj]
[app.util.time :as t]
[beicon.v2.core :as rx]))
@@ -47,13 +48,14 @@
;; NOTE: Right now there are no cases where we need to cancel a process
;; but if we do, we can use this function
-;; (defn- cancel-process
-;; [queue]
-;; (l/dbg :hint "queue::cancel-process")
-;; (let [timeout (unchecked-get queue "timeout")]
-;; (when (some? timeout)
-;; (js/clearTimeout timeout))
-;; (unchecked-set queue "timeout" nil)))
+(defn- cancel-process!
+ [queue]
+ (l/dbg :hint "queue::cancel-process")
+ (let [timeout (unchecked-get queue "timeout")]
+ (when (some? timeout)
+ (js/clearTimeout timeout))
+ (unchecked-set queue "timeout" nil))
+ queue)
(defn- process
[queue iterations]
@@ -131,3 +133,10 @@
(enqueue-last queue request))))
(rx/to-observable result)))
+
+(defn clear!
+ [queue]
+ (-> queue
+ (cancel-process!)
+ (obj/set! "items" #js [])
+ (obj/set! "time" 0)))
diff --git a/frontend/src/app/util/webapi.cljs b/frontend/src/app/util/webapi.cljs
index 722067fe77..4a280f57ff 100644
--- a/frontend/src/app/util/webapi.cljs
+++ b/frontend/src/app/util/webapi.cljs
@@ -10,6 +10,7 @@
[app.common.data :as d]
[app.common.exceptions :as ex]
[app.common.logging :as log]
+ [app.util.globals :as globals]
[app.util.object :as obj]
[beicon.v2.core :as rx]
[cuerdas.core :as str]
@@ -264,3 +265,103 @@
(catch :default e (reject e))))))
(def empty-png-size (memoize empty-png-size*))
+
+(defn create-range
+ []
+ (let [document globals/document]
+ (.createRange document)))
+
+(defn select-contents!
+ [range node]
+ (when (and range node)
+ (.selectNodeContents range node))
+ range)
+
+(defn select-all-children!
+ [^js selection ^js node]
+ (.selectAllChildren selection node))
+
+(defn get-selection
+ []
+ (when-let [document globals/document]
+ (.getSelection document)))
+
+(defn get-anchor-node
+ [^js selection]
+ (when selection
+ (.-anchorNode selection)))
+
+(defn get-anchor-offset
+ [^js selection]
+ (when selection
+ (.-anchorOffset selection)))
+
+(defn remove-all-ranges!
+ [^js sel]
+ (.removeAllRanges sel)
+ sel)
+
+(defn add-range!
+ [^js sel ^js range]
+ (.addRange sel range)
+ sel)
+
+(defn collapse-end!
+ [^js sel]
+ (.collapseToEnd sel)
+ sel)
+
+(defn set-cursor!
+ ([^js node]
+ (set-cursor! node 0))
+ ([^js node offset]
+ (when node
+ (let [child-nodes (.-childNodes node)
+ sel (get-selection)
+ r (create-range)]
+ (if (= (.-length child-nodes) 0)
+ (do (.setStart r node offset)
+ (.setEnd r node offset)
+ (remove-all-ranges! sel)
+ (add-range! sel r))
+
+ (let [text-node (aget child-nodes 0)]
+ (.setStart r text-node offset)
+ (.setEnd r text-node offset)
+ (remove-all-ranges! sel)
+ (add-range! sel r)))))))
+
+(defn set-cursor-before!
+ [^js node]
+ (set-cursor! node 1))
+
+(defn set-cursor-after!
+ [^js node]
+ (let [child-nodes (.-childNodes node)
+ first-child (aget child-nodes 0)
+ offset (if first-child (.-length first-child) 0)]
+ (set-cursor! node offset)))
+
+(defn get-range
+ [^js selection idx]
+ (.getRangeAt selection idx))
+
+(defn range-start-container
+ [^js range]
+ (when range
+ (.-startContainer range)))
+
+(defn range-start-offset
+ [^js range]
+ (when range
+ (.-startOffset range)))
+
+(defn range-end-container
+ [^js range]
+ (when range
+ (.-endContainer range)))
+
+(defn range-end-offset
+ [^js range]
+ (when range
+ (.-endOffset range)))
diff --git a/frontend/text-editor/src/editor/content/dom/Style.js b/frontend/text-editor/src/editor/content/dom/Style.js
index a4a8837701..b7abe2f8b2 100644
--- a/frontend/text-editor/src/editor/content/dom/Style.js
+++ b/frontend/text-editor/src/editor/content/dom/Style.js
@@ -139,7 +139,7 @@ export function normalizeStyles(node, styleDefaults = getStyleDefaultsDeclaratio
// a --fills CSS variable property.
const fills = styleDeclaration.getPropertyValue("--fills");
const color = styleDeclaration.getPropertyValue("color");
- if (color) {
+ if (color && !fills) {
styleDeclaration.removeProperty("color");
styleDeclaration.setProperty("--fills", getFills(color));
} else {
diff --git a/frontend/translations/de.po b/frontend/translations/de.po
index 106ddc76c2..2a8f833efe 100644
--- a/frontend/translations/de.po
+++ b/frontend/translations/de.po
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
-"PO-Revision-Date: 2024-11-14 11:14+0000\n"
-"Last-Translator: Anonymous \n"
+"PO-Revision-Date: 2024-11-25 20:01+0000\n"
+"Last-Translator: Stas Haas \n"
"Language-Team: German \n"
"Language: de\n"
@@ -6079,3 +6079,88 @@ msgstr "Aktualisieren"
#, unused
msgid "workspace.viewport.click-to-close-path"
msgstr "Klicken Sie, um den Pfad zu schließen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:150
+msgid "workspace.options.fill.add-fill"
+msgstr "Füllfarbe hinzufügen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:302
+msgid "workspace.options.shadow-options.add-shadow"
+msgstr "Schatten hinzufügen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:177, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:315
+msgid "workspace.options.shadow-options.remove-shadow"
+msgstr "Schatten entfernen"
+
+#: src/app/main/ui/dashboard/fonts.cljs:444
+msgid "dashboard.fonts.empty-placeholder-viewer"
+msgstr "Noch keine eigenen Schriftarten vorhanden."
+
+#: src/app/main/ui/dashboard/team.cljs:944
+msgid "dashboard.webhooks.cant-edit"
+msgstr "Sie können nur von Ihnen erstellte Webhooks löschen oder ändern."
+
+#: src/app/main/data/common.cljs:233
+msgid "dashboard.removed-from-team"
+msgstr "Sie sind nicht mehr Teil des Teams “%s“."
+
+#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:271
+msgid "settings.remove-color"
+msgstr "Farbe entfernen"
+
+#: src/app/main/ui/workspace/plugins.cljs:196
+msgid "workspace.plugins.error.manifest"
+msgstr "Das Plugin-Manifest ist falsch."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:32
+msgid "dashboard.empty-placeholder-libraries-title"
+msgstr "Noch keine Bibliotheken vorhanden."
+
+#: src/app/main/data/common.cljs:204
+msgid "dashboard.permissions-change.editor"
+msgstr "Sie sind jetzt ein Redakteur in diesem Team."
+
+#: src/app/main/data/common.cljs:203
+msgid "dashboard.permissions-change.viewer"
+msgstr "Sie sind jetzt ein Zuschauer in diesem Team."
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:153
+msgid "labels.collapse"
+msgstr "Zusammenklappen"
+
+#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:495
+msgid "workspace.assets.colors.add-color"
+msgstr "Farbe hinzufügen"
+
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:532
+msgid "workspace.assets.components.add-component"
+msgstr "Komponente hinzufügen"
+
+#: src/app/main/ui/workspace/right_header.cljs:255
+msgid "workspace.header.share"
+msgstr "Teilen"
+
+#: src/app/main/ui/workspace/libraries.cljs:304
+msgid "workspace.libraries.more-templates-link"
+msgstr "weitere Vorlagen sind hier"
+
+#: src/app/main/ui/comments.cljs:340, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:295, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:324
+msgid "labels.options"
+msgstr "Optionen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1051
+#, unused
+msgid "labels.add"
+msgstr "Hinzufügen"
+
+#: src/app/main/ui/dashboard/files.cljs:186, src/app/main/ui/dashboard/projects.cljs:280
+msgid "dashboard.empty-placeholder-files-title"
+msgstr "Noch keine Dateien vorhanden."
+
+#: src/app/main/data/common.cljs:205
+msgid "dashboard.permissions-change.admin"
+msgstr "Sie sind jetzt ein Admin in diesem Team."
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:149, src/app/main/ui/workspace/sidebar/versions.cljs:288
+msgid "labels.restore"
+msgstr "Wiederherstellen"
diff --git a/frontend/translations/en.po b/frontend/translations/en.po
index 2e3010559d..a69ddf28be 100644
--- a/frontend/translations/en.po
+++ b/frontend/translations/en.po
@@ -170,7 +170,7 @@ msgstr "The open-source solution for design and prototyping."
msgid "auth.terms-and-privacy-agreement"
msgstr "I agree to the [terms of service](%s) and [privacy policy](%s)."
-#: src/app/main/ui/auth/register.cljs:290, src/app/main/ui/dashboard/sidebar.cljs:1022, src/app/main/ui/workspace/main_menu.cljs:154
+#: src/app/main/ui/auth/register.cljs:290, src/app/main/ui/dashboard/sidebar.cljs:1022, src/app/main/ui/workspace/main_menu.cljs:155
msgid "auth.terms-of-service"
msgstr "Terms of service"
@@ -392,22 +392,15 @@ msgstr "The token will expire on %s"
msgid "dashboard.access-tokens.token-will-not-expire"
msgstr "The token has no expiration date"
-#: src/app/main/ui/dashboard/file_menu.cljs:311, src/app/main/ui/workspace/main_menu.cljs:585
+#: src/app/main/ui/dashboard/file_menu.cljs:311, src/app/main/ui/workspace/main_menu.cljs:614
msgid "dashboard.add-shared"
msgstr "Add as Shared Library"
-#: src/app/main/ui/workspace/main_menu.cljs:607
-msgid "dashboard.show-version-history"
-msgstr "Version history"
-
-msgid "dashboard.create-version-menu"
-msgstr "Pin this version"
-
#: src/app/main/ui/settings/profile.cljs:72
msgid "dashboard.change-email"
msgstr "Change email"
-#: src/app/main/data/dashboard.cljs:771, src/app/main/data/dashboard.cljs:991
+#: src/app/main/data/dashboard.cljs:773, src/app/main/data/dashboard.cljs:993
msgid "dashboard.copy-suffix"
msgstr "(copy)"
@@ -415,6 +408,10 @@ msgstr "(copy)"
msgid "dashboard.create-new-team"
msgstr "Create new team"
+#: src/app/main/ui/workspace/main_menu.cljs:623
+msgid "dashboard.create-version-menu"
+msgstr "Pin this version"
+
#: src/app/main/ui/components/context_menu_a11y.cljs:284, src/app/main/ui/dashboard/sidebar.cljs:646
msgid "dashboard.default-team-name"
msgstr "Your Penpot"
@@ -423,11 +420,11 @@ msgstr "Your Penpot"
msgid "dashboard.delete-team"
msgstr "Delete team"
-#: src/app/main/ui/dashboard/file_menu.cljs:318, src/app/main/ui/dashboard/file_menu.cljs:323, src/app/main/ui/workspace/main_menu.cljs:603, src/app/main/ui/workspace/main_menu.cljs:612
+#: src/app/main/ui/dashboard/file_menu.cljs:318, src/app/main/ui/dashboard/file_menu.cljs:323, src/app/main/ui/workspace/main_menu.cljs:650, src/app/main/ui/workspace/main_menu.cljs:659
msgid "dashboard.download-binary-file"
msgstr "Download Penpot file (.penpot)"
-#: src/app/main/ui/dashboard/file_menu.cljs:328, src/app/main/ui/workspace/main_menu.cljs:621
+#: src/app/main/ui/dashboard/file_menu.cljs:328, src/app/main/ui/workspace/main_menu.cljs:668
msgid "dashboard.download-standard-file"
msgstr "Download standard file (.svg + .json)"
@@ -483,11 +480,11 @@ msgstr "No libraries yet."
msgid "dashboard.export-binary-multi"
msgstr "Download %s Penpot files (.penpot)"
-#: src/app/main/ui/workspace/main_menu.cljs:629
+#: src/app/main/ui/workspace/main_menu.cljs:676
msgid "dashboard.export-frames"
msgstr "Export boards as PDF"
-#: src/app/main/ui/exports/assets.cljs:206
+#: src/app/main/ui/exports/assets.cljs:199
msgid "dashboard.export-frames.title"
msgstr "Export as PDF"
@@ -495,29 +492,29 @@ msgstr "Export as PDF"
msgid "dashboard.export-multi"
msgstr "Export Penpot %s files"
-#: src/app/main/ui/exports/assets.cljs:113
+#: src/app/main/ui/exports/assets.cljs:106
msgid "dashboard.export-multiple.selected"
msgstr "%s of %s elements selected"
-#: src/app/main/ui/workspace/main_menu.cljs:591
+#: src/app/main/ui/workspace/main_menu.cljs:638
msgid "dashboard.export-shapes"
msgstr "Export"
-#: src/app/main/ui/exports/assets.cljs:184
+#: src/app/main/ui/exports/assets.cljs:177
msgid "dashboard.export-shapes.how-to"
msgstr ""
"You can add export settings to elements from the design properties (at the "
"bottom of the right sidebar)."
-#: src/app/main/ui/exports/assets.cljs:188
+#: src/app/main/ui/exports/assets.cljs:181
msgid "dashboard.export-shapes.how-to-link"
msgstr "Info how to set exports at Penpot."
-#: src/app/main/ui/exports/assets.cljs:183
+#: src/app/main/ui/exports/assets.cljs:176
msgid "dashboard.export-shapes.no-elements"
msgstr "There are no elements with export settings."
-#: src/app/main/ui/exports/assets.cljs:194
+#: src/app/main/ui/exports/assets.cljs:187
msgid "dashboard.export-shapes.title"
msgstr "Export selection"
@@ -633,7 +630,7 @@ msgstr ""
msgid "dashboard.import"
msgstr "Import Penpot files"
-#: src/app/main/ui/dashboard/import.cljs:288, src/app/worker/import.cljs:843, src/app/worker/import.cljs:846
+#: src/app/main/ui/dashboard/import.cljs:288, src/app/worker/import.cljs:851, src/app/worker/import.cljs:854
msgid "dashboard.import.analyze-error"
msgstr "Oops! We couldn't import this file"
@@ -731,7 +728,7 @@ msgstr "Move to other team"
msgid "dashboard.new-file"
msgstr "+ New File"
-#: src/app/main/data/dashboard.cljs:966, src/app/main/data/dashboard.cljs:1189
+#: src/app/main/data/dashboard.cljs:968, src/app/main/data/dashboard.cljs:1195
msgid "dashboard.new-file-prefix"
msgstr "New File"
@@ -739,7 +736,7 @@ msgstr "New File"
msgid "dashboard.new-project"
msgstr "+ New project"
-#: src/app/main/data/dashboard.cljs:735, src/app/main/data/dashboard.cljs:1192
+#: src/app/main/data/dashboard.cljs:737, src/app/main/data/dashboard.cljs:1198
msgid "dashboard.new-project-prefix"
msgstr "New Project"
@@ -751,6 +748,14 @@ msgstr "No matches found for “%s“"
msgid "dashboard.no-projects-placeholder"
msgstr "Pinned projects will appear here"
+#: src/app/main/ui/dashboard/comments.cljs
+msgid "dashboard.notifications"
+msgstr "Notifications"
+
+#: src/app/main/ui/dashboard/comments.cljs
+msgid "dashboard.notifications.view"
+msgstr "View notifications"
+
#: src/app/main/ui/auth/verify_token.cljs:32
msgid "dashboard.notifications.email-changed-successfully"
msgstr "Your email address has been updated successfully"
@@ -779,19 +784,19 @@ msgstr "Options"
msgid "dashboard.password-change"
msgstr "Change password"
-#: src/app/main/data/common.cljs:205
+#: src/app/main/data/common.cljs:202
msgid "dashboard.permissions-change.admin"
msgstr "You are now an admin on this team."
-#: src/app/main/data/common.cljs:204
+#: src/app/main/data/common.cljs:201
msgid "dashboard.permissions-change.editor"
msgstr "You are now an editor on this team."
-#: src/app/main/data/common.cljs:206
+#: src/app/main/data/common.cljs:203
msgid "dashboard.permissions-change.owner"
msgstr "You are now owner on this team."
-#: src/app/main/data/common.cljs:203
+#: src/app/main/data/common.cljs:200
msgid "dashboard.permissions-change.viewer"
msgstr "You are now a viewer on this team."
@@ -812,7 +817,7 @@ msgstr "Want to remove your account?"
msgid "dashboard.remove-shared"
msgstr "Remove as Shared Library"
-#: src/app/main/data/common.cljs:233
+#: src/app/main/data/common.cljs:235
msgid "dashboard.removed-from-team"
msgstr "You are not part of the team “%s“ anymore."
@@ -840,6 +845,10 @@ msgstr "Select theme"
msgid "dashboard.show-all-files"
msgstr "Show all files"
+#: src/app/main/ui/workspace/main_menu.cljs:630
+msgid "dashboard.show-version-history"
+msgstr "Version history"
+
#: src/app/main/ui/dashboard/file_menu.cljs:101
msgid "dashboard.success-delete-file"
msgid_plural "dashboard.success-delete-file"
@@ -896,7 +905,7 @@ msgstr "Search results"
msgid "dashboard.type-something"
msgstr "Type to search results"
-#: src/app/main/ui/dashboard/file_menu.cljs:308, src/app/main/ui/workspace/main_menu.cljs:578
+#: src/app/main/ui/dashboard/file_menu.cljs:308, src/app/main/ui/workspace/main_menu.cljs:606
msgid "dashboard.unpublish-shared"
msgstr "Unpublish Library"
@@ -1024,7 +1033,7 @@ msgstr "The fonts %s could not be loaded"
msgid "errors.cannot-upload"
msgstr "Cannot upload the media file."
-#: src/app/main/data/workspace.cljs:1672
+#: src/app/main/data/workspace.cljs:1698
msgid "errors.clipboard-not-implemented"
msgstr "Your browser cannot do this operation"
@@ -1480,71 +1489,71 @@ msgstr "Unset"
msgid "inspect.attributes.typography.text-transform.uppercase"
msgstr "Upper Case"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:152
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:157
msgid "inspect.empty.help"
msgstr "If you want to know more about design inspect visit Penpot's help center"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:155
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:160
msgid "inspect.empty.more-info"
msgstr "More info about inspect"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:147
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:152
msgid "inspect.empty.select"
msgstr "Select a shape, board or group to inspect their properties and code"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:100
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:105
msgid "inspect.tabs.code"
msgstr "Code"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:124
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:129
msgid "inspect.tabs.code.selected.circle"
msgstr "Circle"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:125
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:130
msgid "inspect.tabs.code.selected.component"
msgstr "Component"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:126
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:131
msgid "inspect.tabs.code.selected.curve"
msgstr "Curve"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:127
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:132
msgid "inspect.tabs.code.selected.frame"
msgstr "Board"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:128
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:133
msgid "inspect.tabs.code.selected.group"
msgstr "Group"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:129
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:134
msgid "inspect.tabs.code.selected.image"
msgstr "Image"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:130
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:135
msgid "inspect.tabs.code.selected.mask"
msgstr "Mask"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:119
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:124
msgid "inspect.tabs.code.selected.multiple"
msgstr "%s Selected"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:131
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:136
msgid "inspect.tabs.code.selected.path"
msgstr "Path"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:132
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:137
msgid "inspect.tabs.code.selected.rect"
msgstr "Rectangle"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:133
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:138
msgid "inspect.tabs.code.selected.svg-raw"
msgstr "SVG"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:134
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:139
msgid "inspect.tabs.code.selected.text"
msgstr "Text"
-#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:96
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:101
msgid "inspect.tabs.info"
msgstr "Info"
@@ -1553,11 +1562,11 @@ msgstr "Info"
msgid "intersection"
msgstr ""
-#: src/app/main/ui/workspace/main_menu.cljs:162
+#: src/app/main/ui/workspace/main_menu.cljs:163
msgid "label.shortcuts"
msgstr "Shortcuts"
-#: src/app/main/data/common.cljs:93, src/app/main/ui/dashboard/import.cljs:503
+#: src/app/main/data/common.cljs:90, src/app/main/ui/dashboard/import.cljs:503
msgid "labels.accept"
msgstr "Accept"
@@ -1612,7 +1621,7 @@ msgstr ""
msgid "labels.bad-gateway.main-message"
msgstr "Bad Gateway"
-#: src/app/main/data/common.cljs:131, src/app/main/ui/dashboard/change_owner.cljs:68, src/app/main/ui/dashboard/import.cljs:489, src/app/main/ui/dashboard/team.cljs:906, src/app/main/ui/delete_shared.cljs:35, src/app/main/ui/exports/assets.cljs:168, src/app/main/ui/exports/files.cljs:192, src/app/main/ui/settings/access_tokens.cljs:177, src/app/main/ui/viewer/share_link.cljs:205, src/app/main/ui/workspace/sidebar/assets/groups.cljs:145, src/app/main/ui/workspace/tokens/form.cljs:429, src/app/main/ui/workspace/tokens/modals/themes.cljs:203
+#: src/app/main/data/common.cljs:128, src/app/main/ui/dashboard/change_owner.cljs:68, src/app/main/ui/dashboard/import.cljs:489, src/app/main/ui/dashboard/team.cljs:906, src/app/main/ui/delete_shared.cljs:35, src/app/main/ui/exports/assets.cljs:161, src/app/main/ui/exports/files.cljs:192, src/app/main/ui/settings/access_tokens.cljs:177, src/app/main/ui/viewer/share_link.cljs:205, src/app/main/ui/workspace/sidebar/assets/groups.cljs:145, src/app/main/ui/workspace/tokens/form.cljs:431, src/app/main/ui/workspace/tokens/modals/themes.cljs:203
msgid "labels.cancel"
msgstr "Cancel"
@@ -1620,19 +1629,26 @@ msgstr "Cancel"
msgid "labels.canva"
msgstr "Canva"
-#: src/app/main/ui/dashboard/projects.cljs:96, src/app/main/ui/exports/files.cljs:210, src/app/main/ui/settings/access_tokens.cljs:172, src/app/main/ui/viewer/login.cljs:71, src/app/main/ui/viewer/share_link.cljs:176, src/app/main/ui/workspace/comments.cljs:129, src/app/main/ui/workspace/libraries.cljs:538, src/app/main/ui/workspace/sidebar/debug.cljs:40, src/app/main/ui/workspace/sidebar/layers.cljs:299, src/app/main/ui/workspace/tokens/modals/themes.cljs:366, src/app/main/ui/workspace/tokens/modals.cljs:56
+#: src/app/main/ui/dashboard/projects.cljs:96, src/app/main/ui/exports/files.cljs:210, src/app/main/ui/settings/access_tokens.cljs:172, src/app/main/ui/viewer/login.cljs:71, src/app/main/ui/viewer/share_link.cljs:176, src/app/main/ui/workspace/comments.cljs:129, src/app/main/ui/workspace/libraries.cljs:538, src/app/main/ui/workspace/sidebar/debug.cljs:40, src/app/main/ui/workspace/sidebar/layers.cljs:300, src/app/main/ui/workspace/tokens/modals/themes.cljs:366, src/app/main/ui/workspace/tokens/modals.cljs:56
msgid "labels.close"
msgstr "Close"
-#: src/app/main/ui/workspace/tokens/sets.cljs:153
+#: src/app/main/ui/workspace/tokens/sets.cljs:96
msgid "labels.collapse"
msgstr "Collapse"
+msgid "labels.comment"
+msgstr "Comment"
+
+#: src/app/main/ui/comments.cljs:446
+msgid "labels.comment.mark-as-solved"
+msgstr "Mark as solved"
+
#: src/app/main/ui/dashboard/comments.cljs:104, src/app/main/ui/viewer/comments.cljs:70, src/app/main/ui/workspace/comments.cljs:127
msgid "labels.comments"
msgstr "Comments"
-#: src/app/main/ui/dashboard/sidebar.cljs:985, src/app/main/ui/workspace/main_menu.cljs:114
+#: src/app/main/ui/dashboard/sidebar.cljs:985, src/app/main/ui/workspace/main_menu.cljs:115
msgid "labels.community"
msgstr "Community"
@@ -1664,11 +1680,11 @@ msgstr "Kaleidos @2024"
msgid "labels.create"
msgstr "Create"
-#: src/app/main/ui/dashboard/team_form.cljs:101, src/app/main/ui/dashboard/team_form.cljs:121
+#: src/app/main/ui/dashboard/team_form.cljs:103, src/app/main/ui/dashboard/team_form.cljs:123
msgid "labels.create-team"
msgstr "Create new team"
-#: src/app/main/ui/dashboard/team_form.cljs:113
+#: src/app/main/ui/dashboard/team_form.cljs:115
msgid "labels.create-team.placeholder"
msgstr "Enter new team name"
@@ -1680,7 +1696,7 @@ msgstr "Custom fonts"
msgid "labels.dashboard"
msgstr "Dashboard"
-#: src/app/main/ui/dashboard/file_menu.cljs:336, src/app/main/ui/dashboard/fonts.cljs:256, src/app/main/ui/dashboard/fonts.cljs:332, src/app/main/ui/dashboard/fonts.cljs:346, src/app/main/ui/dashboard/project_menu.cljs:114, src/app/main/ui/dashboard/team.cljs:942, src/app/main/ui/settings/access_tokens.cljs:198, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:209, src/app/main/ui/workspace/sidebar/versions.cljs:152, src/app/main/ui/workspace/tokens/form.cljs:425, src/app/main/ui/workspace/tokens/modals/themes.cljs:335, src/app/main/ui/workspace/tokens/sets_context_menu.cljs:44
+#: src/app/main/ui/dashboard/file_menu.cljs:336, src/app/main/ui/dashboard/fonts.cljs:256, src/app/main/ui/dashboard/fonts.cljs:332, src/app/main/ui/dashboard/fonts.cljs:346, src/app/main/ui/dashboard/project_menu.cljs:114, src/app/main/ui/dashboard/team.cljs:942, src/app/main/ui/settings/access_tokens.cljs:198, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:209, src/app/main/ui/workspace/sidebar/versions.cljs:153, src/app/main/ui/workspace/tokens/form.cljs:427, src/app/main/ui/workspace/tokens/modals/themes.cljs:335, src/app/main/ui/workspace/tokens/sets_context_menu.cljs:44
msgid "labels.delete"
msgstr "Delete"
@@ -1716,7 +1732,7 @@ msgstr "Discard"
msgid "labels.drafts"
msgstr "Drafts"
-#: src/app/main/ui/comments.cljs:356, src/app/main/ui/dashboard/fonts.cljs:253, src/app/main/ui/dashboard/team.cljs:940, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:205, src/app/main/ui/workspace/tokens/sidebar.cljs:199
+#: src/app/main/ui/comments.cljs:356, src/app/main/ui/dashboard/fonts.cljs:253, src/app/main/ui/dashboard/team.cljs:940, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:205, src/app/main/ui/workspace/tokens/sidebar.cljs:200
msgid "labels.edit"
msgstr "Edit"
@@ -1736,7 +1752,7 @@ msgstr "Event"
msgid "labels.expired-invitation"
msgstr "Expired"
-#: src/app/main/ui/exports/assets.cljs:177
+#: src/app/main/ui/exports/assets.cljs:170
msgid "labels.export"
msgstr "Export"
@@ -1776,11 +1792,11 @@ msgstr "CEO or Founder"
msgid "labels.freelancer"
msgstr "Freelancer"
-#: src/app/main/ui/dashboard/sidebar.cljs:1015, src/app/main/ui/workspace/main_menu.cljs:146
+#: src/app/main/ui/dashboard/sidebar.cljs:1015, src/app/main/ui/workspace/main_menu.cljs:147
msgid "labels.github-repo"
msgstr "Github repository"
-#: src/app/main/ui/dashboard/sidebar.cljs:1032, src/app/main/ui/settings/sidebar.cljs:113, src/app/main/ui/workspace/main_menu.cljs:175
+#: src/app/main/ui/dashboard/sidebar.cljs:1032, src/app/main/ui/settings/sidebar.cljs:113, src/app/main/ui/workspace/main_menu.cljs:176
msgid "labels.give-feedback"
msgstr "Give feedback"
@@ -1792,7 +1808,7 @@ msgstr "Go back"
msgid "labels.graphic-design"
msgstr "Graphic design"
-#: src/app/main/ui/dashboard/sidebar.cljs:978, src/app/main/ui/workspace/main_menu.cljs:106, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1079, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1104, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1290
+#: src/app/main/ui/dashboard/sidebar.cljs:978, src/app/main/ui/workspace/main_menu.cljs:107, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1079, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1104, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1290
msgid "labels.help-center"
msgstr "Help Center"
@@ -1830,11 +1846,11 @@ msgstr "Invitations"
msgid "labels.language"
msgstr "Language"
-#: src/app/main/ui/dashboard/sidebar.cljs:1008, src/app/main/ui/workspace/main_menu.cljs:138
+#: src/app/main/ui/dashboard/sidebar.cljs:1008, src/app/main/ui/workspace/main_menu.cljs:139
msgid "labels.libraries-and-templates"
msgstr "Libraries & Templates"
-#: src/app/main/ui/auth/verify_token.cljs:97, src/app/main/ui/dashboard/grid.cljs:104, src/app/main/ui/dashboard/grid.cljs:124, src/app/main/ui/dashboard/import.cljs:253, src/app/main/ui/dashboard/placeholder.cljs:52, src/app/main/ui/ds/product/loader.cljs:52, src/app/main/ui/exports/files.cljs:62, src/app/main/ui/viewer.cljs:637, src/app/main/ui/workspace.cljs:129
+#: src/app/main/ui/auth/verify_token.cljs:97, src/app/main/ui/dashboard/grid.cljs:104, src/app/main/ui/dashboard/grid.cljs:124, src/app/main/ui/dashboard/import.cljs:253, src/app/main/ui/dashboard/placeholder.cljs:52, src/app/main/ui/ds/product/loader.cljs:52, src/app/main/ui/exports/files.cljs:62, src/app/main/ui/viewer.cljs:637, src/app/main/ui/workspace.cljs:130
msgid "labels.loading"
msgstr "Loading…"
@@ -1951,6 +1967,10 @@ msgstr "Password"
msgid "labels.pending-invitation"
msgstr "Pending"
+#: src/app/main/ui/comments.cljs:147
+msgid "labels.post"
+msgstr "Post"
+
#: src/app/main/ui/onboarding/questions.cljs:51
msgid "labels.previous"
msgstr "Previous"
@@ -1971,7 +1991,7 @@ msgstr "Profile"
msgid "labels.projects"
msgstr "Projects"
-#: src/app/main/ui/dashboard/sidebar.cljs:998, src/app/main/ui/settings/sidebar.cljs:106, src/app/main/ui/workspace/main_menu.cljs:130
+#: src/app/main/ui/dashboard/sidebar.cljs:998, src/app/main/ui/settings/sidebar.cljs:106, src/app/main/ui/workspace/main_menu.cljs:131
msgid "labels.release-notes"
msgstr "Release notes"
@@ -1989,19 +2009,39 @@ msgstr "Remove"
msgid "labels.remove-member"
msgstr "Remove member"
-#: src/app/main/ui/dashboard/file_menu.cljs:288, src/app/main/ui/dashboard/project_menu.cljs:87, src/app/main/ui/dashboard/sidebar.cljs:539, src/app/main/ui/workspace/sidebar/assets/groups.cljs:153, src/app/main/ui/workspace/sidebar/versions.cljs:146, src/app/main/ui/workspace/tokens/sets_context_menu.cljs:43
+#: src/app/main/ui/dashboard/file_menu.cljs:288, src/app/main/ui/dashboard/project_menu.cljs:87, src/app/main/ui/dashboard/sidebar.cljs:539, src/app/main/ui/workspace/sidebar/assets/groups.cljs:153, src/app/main/ui/workspace/sidebar/versions.cljs:147, src/app/main/ui/workspace/tokens/sets_context_menu.cljs:43
msgid "labels.rename"
msgstr "Rename"
-#: src/app/main/ui/dashboard/team_form.cljs:99
+#: src/app/main/ui/dashboard/team_form.cljs:101
msgid "labels.rename-team"
msgstr "Rename team"
+#: src/app/main/ui/comments.cljs:145
+msgid "labels.reply"
+msgstr "reply"
+
+#: src/app/main/ui/comments.cljs:150
+msgid "labels.reply.new"
+msgstr "new reply"
+
+#: src/app/main/ui/comments.cljs:188
+msgid "labels.reply.thread"
+msgstr "Reply"
+
+#: src/app/main/ui/comments.cljs:146
+msgid "labels.replies"
+msgstr "replies"
+
+#: src/app/main/ui/comments.cljs:151
+msgid "labels.replies.new"
+msgstr "new replies"
+
#: src/app/main/ui/dashboard/team.cljs:681
msgid "labels.resend-invitation"
msgstr "Resend invitation"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:149, src/app/main/ui/workspace/sidebar/versions.cljs:288
+#: src/app/main/ui/workspace/sidebar/versions.cljs:150, src/app/main/ui/workspace/sidebar/versions.cljs:290
msgid "labels.restore"
msgstr "Restore"
@@ -2013,7 +2053,7 @@ msgstr "Retry"
msgid "labels.role"
msgstr "Role"
-#: src/app/main/ui/dashboard/fonts.cljs:382, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:191, src/app/main/ui/workspace/tokens/form.cljs:433
+#: src/app/main/ui/dashboard/fonts.cljs:382, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:191, src/app/main/ui/workspace/tokens/form.cljs:435
msgid "labels.save"
msgstr "Save"
@@ -2045,7 +2085,7 @@ msgstr "We are in programmed maintenance of our systems."
msgid "labels.service-unavailable.main-message"
msgstr "Service Unavailable"
-#: src/app/main/ui/workspace/tokens/sidebar.cljs:229
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:246
msgid "labels.sets"
msgstr "Sets"
@@ -2077,6 +2117,9 @@ msgstr "Show comments list"
msgid "labels.show-your-comments"
msgstr "Show only your comments"
+msgid "labels.show-mentions"
+msgstr "Show only your mentions"
+
#: src/app/main/ui/onboarding/questions.cljs:167
msgid "labels.sketch"
msgstr "Sketch"
@@ -2105,7 +2148,7 @@ msgstr "Team member"
msgid "labels.themes"
msgstr "Themes"
-#: src/app/main/ui/dashboard/sidebar.cljs:992, src/app/main/ui/workspace/main_menu.cljs:122
+#: src/app/main/ui/dashboard/sidebar.cljs:992, src/app/main/ui/workspace/main_menu.cljs:123
msgid "labels.tutorials"
msgstr "Tutorials"
@@ -2117,7 +2160,7 @@ msgstr "Unpublish %s files"
msgid "labels.update"
msgstr "Update"
-#: src/app/main/ui/dashboard/team_form.cljs:120
+#: src/app/main/ui/dashboard/team_form.cljs:122
msgid "labels.update-team"
msgstr "Update team"
@@ -2161,14 +2204,15 @@ msgstr "Your account"
msgid "labels.youtube"
msgstr "YouTube"
-#: src/app/main/ui/workspace/colorpicker.cljs:344, src/app/main/ui/workspace/colorpicker.cljs:345, src/app/main/ui/workspace/colorpicker.cljs:347
+#: src/app/main/ui/workspace/colorpicker.cljs:475, src/app/main/ui/workspace/colorpicker.cljs:476, src/app/main/ui/workspace/colorpicker.cljs:478
msgid "media.choose-image"
msgstr "Choose image"
+#: src/app/main/ui/workspace/colorpicker.cljs:243
msgid "media.gradient"
msgstr "Gradient"
-#: src/app/main/data/workspace/media.cljs:272, src/app/main/ui/components/color_bullet.cljs:32, src/app/main/ui/components/color_bullet.cljs:45, src/app/main/ui/viewer/inspect/attributes/common.cljs:66, src/app/main/ui/workspace/colorpicker.cljs:231, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:240
+#: src/app/main/data/workspace/media.cljs:272, src/app/main/ui/components/color_bullet.cljs:34, src/app/main/ui/components/color_bullet.cljs:47, src/app/main/ui/viewer/inspect/attributes/common.cljs:66, src/app/main/ui/workspace/colorpicker.cljs:245, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:240
msgid "media.image"
msgstr "Image"
@@ -2176,11 +2220,12 @@ msgstr "Image"
msgid "media.image.short"
msgstr "img"
-#: src/app/main/ui/workspace/colorpicker.cljs:337
+#: src/app/main/ui/workspace/colorpicker.cljs:468
msgid "media.keep-aspect-ratio"
msgstr "Keep aspect ratio"
#: src/app/main/ui/workspace/colorpicker.cljs:228
+#, unused
msgid "media.linear"
msgstr "Linear"
@@ -2189,31 +2234,32 @@ msgid "media.loading"
msgstr "Loading image…"
#: src/app/main/ui/workspace/colorpicker.cljs:229
+#, unused
msgid "media.radial"
msgstr "Radial"
-#: src/app/main/ui/workspace/colorpicker.cljs:226
+#: src/app/main/ui/workspace/colorpicker.cljs:241
msgid "media.solid"
msgstr "Solid"
-#: src/app/main/data/common.cljs:130
+#: src/app/main/data/common.cljs:127
msgid "modals.add-shared-confirm-empty.hint"
msgstr ""
"Your library is empty. Once added as Shared Library, the assets you create "
"will be available to be used among the rest of your files. Are you sure you "
"want to publish it?"
-#: src/app/main/data/common.cljs:132
+#: src/app/main/data/common.cljs:129
msgid "modals.add-shared-confirm.accept"
msgstr "Add as Shared Library"
-#: src/app/main/data/common.cljs:130
+#: src/app/main/data/common.cljs:127
msgid "modals.add-shared-confirm.hint"
msgstr ""
"Once added as Shared Library, the assets of this file library will be "
"available to be used among the rest of your files."
-#: src/app/main/data/common.cljs:129
+#: src/app/main/data/common.cljs:126
msgid "modals.add-shared-confirm.message"
msgstr "Add “%s” as Shared Library"
@@ -2380,11 +2426,11 @@ msgstr ""
msgid "modals.delete-font.title"
msgstr "Deleting font"
-#: src/app/main/ui/workspace/context_menu.cljs:533, src/app/main/ui/workspace/sidebar/sitemap.cljs:46
+#: src/app/main/ui/workspace/context_menu.cljs:539, src/app/main/ui/workspace/sidebar/sitemap.cljs:46
msgid "modals.delete-page.body"
msgstr "Are you sure you want to delete this page?"
-#: src/app/main/ui/workspace/context_menu.cljs:532, src/app/main/ui/workspace/sidebar/sitemap.cljs:45
+#: src/app/main/ui/workspace/context_menu.cljs:538, src/app/main/ui/workspace/sidebar/sitemap.cljs:45
msgid "modals.delete-page.title"
msgstr "Delete page"
@@ -2574,7 +2620,7 @@ msgid_plural "modals.move-shared-confirm.title"
msgstr[0] "Move library"
msgstr[1] "Move libraries"
-#: src/app/main/ui/workspace/main_menu.cljs:271, src/app/main/ui/workspace/nudge.cljs:47
+#: src/app/main/ui/workspace/main_menu.cljs:272, src/app/main/ui/workspace/nudge.cljs:47
msgid "modals.nudge-title"
msgstr "Nudge amount"
@@ -2661,21 +2707,21 @@ msgstr ""
msgid "modals.update-remote-component-in-bulk.message"
msgstr "Update components in a shared library"
-#: src/app/main/ui/workspace/sidebar/assets/common.cljs:380
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:384
msgid "modals.update-remote-component.accept"
msgstr "Update"
-#: src/app/main/ui/workspace/sidebar/assets/common.cljs:379
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:383
msgid "modals.update-remote-component.cancel"
msgstr "Cancel"
-#: src/app/main/ui/workspace/sidebar/assets/common.cljs:378
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:382
msgid "modals.update-remote-component.hint"
msgstr ""
"You are about to update a component in a shared library. This may affect "
"other files that use it."
-#: src/app/main/ui/workspace/sidebar/assets/common.cljs:377
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:381
msgid "modals.update-remote-component.message"
msgstr "Update a component in a shared library"
@@ -2779,11 +2825,11 @@ msgstr "To access this file, you can ask the team owner."
msgid "not-found.no-permission.you-can-ask.project"
msgstr "To access this project, you can ask the team owner."
-#: src/app/main/data/common.cljs:90
+#: src/app/main/data/common.cljs:87
msgid "notifications.by-code.maintenance"
msgstr "Maintenance break: we will be down for a short maintenance within 5 minutes."
-#: src/app/main/data/common.cljs:81
+#: src/app/main/data/common.cljs:78
msgid "notifications.by-code.upgrade-version"
msgstr "A new version is available, please refresh the page"
@@ -3155,7 +3201,7 @@ msgstr "Go to login"
msgid "settings.detach"
msgstr "Detach"
-#: src/app/main/ui/viewer/inspect/exports.cljs:155, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:632, src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:137, src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:148, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:204, src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:161, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:470, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:476, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:494, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:500, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:526, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:537, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:554, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:569, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:576, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:312, src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:182, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:378, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:395, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:248, src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:172
+#: src/app/main/ui/viewer/inspect/exports.cljs:147, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:632, src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:137, src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:148, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:196, src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:161, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:470, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:476, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:494, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:500, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:526, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:537, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:554, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:569, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:576, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:312, src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:182, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:378, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:395, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:248, src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:172
msgid "settings.multiple"
msgstr "Mixed"
@@ -3168,19 +3214,19 @@ msgid "settings.select-this-color"
msgstr "Select items using this style"
# SECTIONS
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:414
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:416
msgid "shortcut-section.basics"
msgstr "Basics"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:420
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:422
msgid "shortcut-section.dashboard"
msgstr "Dashboard"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:423
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:425
msgid "shortcut-section.viewer"
msgstr "Viewer"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:417
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:419
msgid "shortcut-section.workspace"
msgstr "Workspace"
@@ -3201,7 +3247,7 @@ msgstr "Generic"
msgid "shortcut-subsection.general-viewer"
msgstr "Generic"
-#: src/app/main/ui/workspace/main_menu.cljs:777, src/app/main/ui/workspace/sidebar/shortcuts.cljs:60
+#: src/app/main/ui/workspace/main_menu.cljs:824, src/app/main/ui/workspace/sidebar/shortcuts.cljs:60
msgid "shortcut-subsection.main-menu"
msgstr "Main menu"
@@ -3338,498 +3384,503 @@ msgid "shortcuts.copy"
msgstr "Copy"
#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:94
+msgid "shortcuts.copy-link"
+msgstr "Copy link to clipboard"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:95
msgid "shortcuts.create-component"
msgstr "Create component"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:95
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:96
msgid "shortcuts.create-new-project"
msgstr "Create new"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:96
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:97
msgid "shortcuts.cut"
msgstr "Cut"
-#: src/app/main/ui/workspace/right_header.cljs:115, src/app/main/ui/workspace/sidebar/shortcuts.cljs:97
+#: src/app/main/ui/workspace/right_header.cljs:115, src/app/main/ui/workspace/sidebar/shortcuts.cljs:98
msgid "shortcuts.decrease-zoom"
msgstr "Zoom out"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:98
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:99
msgid "shortcuts.delete"
msgstr "Delete"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:99
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:100
msgid "shortcuts.delete-node"
msgstr "Delete node"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:100
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:101
msgid "shortcuts.detach-component"
msgstr "Detach component"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:101
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:102
msgid "shortcuts.draw-curve"
msgstr "Curve"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:102
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:103
msgid "shortcuts.draw-ellipse"
msgstr "Ellipse"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:103
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:104
msgid "shortcuts.draw-frame"
msgstr "Board"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:104
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:105
msgid "shortcuts.draw-nodes"
msgstr "Draw path"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:105
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:106
msgid "shortcuts.draw-path"
msgstr "Path"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:106
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:107
msgid "shortcuts.draw-rect"
msgstr "Rectangle"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:107
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:108
msgid "shortcuts.draw-text"
msgstr "Text"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:108
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:109
msgid "shortcuts.duplicate"
msgstr "Duplicate"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:109
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:110
msgid "shortcuts.escape"
msgstr "Cancel"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:110
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:111
msgid "shortcuts.export-shapes"
msgstr "Export shapes"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:111
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:112
msgid "shortcuts.fit-all"
msgstr "Zoom to fit all"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:112
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:113
msgid "shortcuts.flip-horizontal"
msgstr "Flip horizontally"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:113
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:114
msgid "shortcuts.flip-vertical"
msgstr "Flip vertically"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:114
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:115
msgid "shortcuts.font-size-dec"
msgstr "Decrement font size"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:115
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:116
msgid "shortcuts.font-size-inc"
msgstr "Increment font size"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:116
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:117
msgid "shortcuts.go-to-drafts"
msgstr "Go to drafts"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:117
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:118
msgid "shortcuts.go-to-libs"
msgstr "Go to shared libraries"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:118
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:119
msgid "shortcuts.go-to-search"
msgstr "Search"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:119
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:120
msgid "shortcuts.group"
msgstr "Group"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:120
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:121
msgid "shortcuts.h-distribute"
msgstr "Distribute horizontally"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:121
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:122
msgid "shortcuts.hide-ui"
msgstr "Show / Hide UI"
-#: src/app/main/ui/workspace/right_header.cljs:120, src/app/main/ui/workspace/sidebar/shortcuts.cljs:122
+#: src/app/main/ui/workspace/right_header.cljs:120, src/app/main/ui/workspace/sidebar/shortcuts.cljs:123
msgid "shortcuts.increase-zoom"
msgstr "Zoom in"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:123
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:124
msgid "shortcuts.insert-image"
msgstr "Insert image"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:124
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:125
msgid "shortcuts.italic"
msgstr "Toggle italic"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:125
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:126
msgid "shortcuts.join-nodes"
msgstr "Join nodes"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:126
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:127
msgid "shortcuts.letter-spacing-dec"
msgstr "Decrement letter spacing"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:127
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:128
msgid "shortcuts.letter-spacing-inc"
msgstr "Increment letter spacing"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:128
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:129
msgid "shortcuts.line-height-dec"
msgstr "Decrement line height"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:129
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:130
msgid "shortcuts.line-height-inc"
msgstr "Increment line height"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:130
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:131
msgid "shortcuts.line-through"
msgstr "Toggle line through"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:131
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:132
msgid "shortcuts.make-corner"
msgstr "Make corner"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:132
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:133
msgid "shortcuts.make-curve"
msgstr "Make curve"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:133
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:134
msgid "shortcuts.mask"
msgstr "Mask"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:134
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:135
msgid "shortcuts.merge-nodes"
msgstr "Merge nodes"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:135
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:136
msgid "shortcuts.move"
msgstr "Move"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:136
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:137
msgid "shortcuts.move-fast-down"
msgstr "Move down fast"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:137
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:138
msgid "shortcuts.move-fast-left"
msgstr "Move left fast"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:138
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:139
msgid "shortcuts.move-fast-right"
msgstr "Move right fast"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:139
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:140
msgid "shortcuts.move-fast-up"
msgstr "Move up fast"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:140
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:141
msgid "shortcuts.move-nodes"
msgstr "Move node"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:141
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:142
msgid "shortcuts.move-unit-down"
msgstr "Move down"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:142
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:143
msgid "shortcuts.move-unit-left"
msgstr "Move left"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:143
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:144
msgid "shortcuts.move-unit-right"
msgstr "Move right"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:144
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:145
msgid "shortcuts.move-unit-up"
msgstr "Move up"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:145
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:146
msgid "shortcuts.next-frame"
msgstr "Next board"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:516
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:518
msgid "shortcuts.not-found"
msgstr "No shortcuts found"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:146
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:147
msgid "shortcuts.opacity-0"
msgstr "Set opacity to 100%"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:147
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:148
msgid "shortcuts.opacity-1"
msgstr "Set opacity to 10%"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:148
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:149
msgid "shortcuts.opacity-2"
msgstr "Set opacity to 20%"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:149
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:150
msgid "shortcuts.opacity-3"
msgstr "Set opacity to 30%"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:150
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:151
msgid "shortcuts.opacity-4"
msgstr "Set opacity to 40%"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:151
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:152
msgid "shortcuts.opacity-5"
msgstr "Set opacity to 50%"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:152
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:153
msgid "shortcuts.opacity-6"
msgstr "Set opacity to 60%"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:153
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:154
msgid "shortcuts.opacity-7"
msgstr "Set opacity to 70%"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:154
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:155
msgid "shortcuts.opacity-8"
msgstr "Set opacity to 80%"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:155
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:156
msgid "shortcuts.opacity-9"
msgstr "Set opacity to 90%"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:156
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:157
msgid "shortcuts.open-color-picker"
msgstr "Color picker"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:157
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:158
msgid "shortcuts.open-comments"
msgstr "Go to viewer comment section"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:158
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:159
msgid "shortcuts.open-dashboard"
msgstr "Go to dashboard"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:159
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:160
msgid "shortcuts.open-inspect"
msgstr "Go to viewer inspect section"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:160
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:161
msgid "shortcuts.open-interactions"
msgstr "Go to viewer interactions section"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:161
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:162
msgid "shortcuts.open-viewer"
msgstr "Go to viewer interactions section"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:162
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:163
msgid "shortcuts.open-workspace"
msgstr "Go to workspace"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:260
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:262
msgid "shortcuts.or"
msgstr " or "
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:163
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:164
msgid "shortcuts.paste"
msgstr "Paste"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:164
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:165
msgid "shortcuts.prev-frame"
msgstr "Previous board"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:165
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:166
msgid "shortcuts.redo"
msgstr "Redo"
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:167
msgid "shortcuts.rename"
msgstr "Rename"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:166
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:168
msgid "shortcuts.reset-zoom"
msgstr "Reset zoom"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:167
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:169
msgid "shortcuts.scale"
msgstr "Scale"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:168
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:170
msgid "shortcuts.search-placeholder"
msgstr "Search shortcuts"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:169
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:171
msgid "shortcuts.select-all"
msgstr "Select all"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:170
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:172
msgid "shortcuts.select-next"
msgstr "Select next layer"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:171
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:173
msgid "shortcuts.select-parent-layer"
msgstr "Select parent layer"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:172
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:174
msgid "shortcuts.select-prev"
msgstr "Select previous layer"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:173
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:175
msgid "shortcuts.separate-nodes"
msgstr "Separate nodes"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:174
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:176
msgid "shortcuts.show-pixel-grid"
msgstr "Show / Hide pixel grid"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:175
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:177
msgid "shortcuts.show-shortcuts"
msgstr "Show / Hide shortcuts"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:176
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:178
msgid "shortcuts.snap-nodes"
msgstr "Snap to nodes"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:177
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:179
msgid "shortcuts.snap-pixel-grid"
msgstr "Snap to pixel grid"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:178
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:180
msgid "shortcuts.start-editing"
msgstr "Start editing"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:179
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:181
msgid "shortcuts.start-measure"
msgstr "Start measurement"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:180
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:182
msgid "shortcuts.stop-measure"
msgstr "Stop measurement"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:181
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:183
msgid "shortcuts.text-align-center"
msgstr "Align center"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:182
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:184
msgid "shortcuts.text-align-justify"
msgstr "Align justify"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:183
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:185
msgid "shortcuts.text-align-left"
msgstr "Align left"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:184
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:186
msgid "shortcuts.text-align-right"
msgstr "Align right"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:185
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:187
msgid "shortcuts.thumbnail-set"
msgstr "Set thumbnails"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:496, src/app/main/ui/workspace/sidebar/shortcuts.cljs:505
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:498, src/app/main/ui/workspace/sidebar/shortcuts.cljs:507
msgid "shortcuts.title"
msgstr "Keyboard shortcuts"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:186
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:188
msgid "shortcuts.toggle-alignment"
msgstr "Toggle dynamic alignment"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:187
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:189
msgid "shortcuts.toggle-assets"
msgstr "Toggle assets"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:188
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:190
msgid "shortcuts.toggle-colorpalette"
msgstr "Toggle color palette"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:189
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:191
msgid "shortcuts.toggle-focus-mode"
msgstr "Toggle focus mode"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:190
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:192
msgid "shortcuts.toggle-fullscreen"
msgstr "Toggle fullscreen"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:191
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:193
msgid "shortcuts.toggle-guides"
msgstr "Show / Hide guides"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:192
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:194
msgid "shortcuts.toggle-history"
msgstr "Toggle history"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:193
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:195
msgid "shortcuts.toggle-layers"
msgstr "Toggle layers"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:194
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:196
msgid "shortcuts.toggle-layout-flex"
msgstr "Add / Remove flex layout"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:195
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:197
msgid "shortcuts.toggle-layout-grid"
msgstr "Add/remove grid layout"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:196
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:198
msgid "shortcuts.toggle-lock"
msgstr "Lock / Unlock"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:197
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:199
msgid "shortcuts.toggle-lock-size"
msgstr "Lock proportions"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:198
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:200
msgid "shortcuts.toggle-rulers"
msgstr "Show / Hide rulers"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:199
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:201
#, fuzzy
msgid "shortcuts.toggle-rules"
msgstr ""
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:200
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:202
msgid "shortcuts.toggle-snap-guides"
msgstr "Snap to guides"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:201
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:203
msgid "shortcuts.toggle-snap-ruler-guide"
msgstr "Snap to ruler guides"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:202
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:204
msgid "shortcuts.toggle-textpalette"
msgstr "Toggle text palette"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:203
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:205
msgid "shortcuts.toggle-theme"
msgstr "Change theme"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:204
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:206
msgid "shortcuts.toggle-visibility"
msgstr "Show / Hide"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:205
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:207
msgid "shortcuts.toggle-zoom-style"
msgstr "Toggle zoom style"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:206
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:208
msgid "shortcuts.underline"
msgstr "Toggle underline"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:207
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:209
msgid "shortcuts.undo"
msgstr "Undo"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:208
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:210
msgid "shortcuts.ungroup"
msgstr "Ungroup"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:209
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:211
msgid "shortcuts.unmask"
msgstr "Unmask"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:210
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:212
msgid "shortcuts.v-distribute"
msgstr "Distribute vertically"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:211
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:213
msgid "shortcuts.zoom-lense-decrease"
msgstr "Zoom lense decrease"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:212
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:214
msgid "shortcuts.zoom-lense-increase"
msgstr "Zoom lense increase"
-#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:213
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:215
msgid "shortcuts.zoom-selected"
msgstr "Zoom to selected"
@@ -3901,7 +3952,7 @@ msgstr "Webhooks - %s - Penpot"
msgid "title.viewer"
msgstr "%s - View mode - Penpot"
-#: src/app/main/ui/workspace.cljs:198
+#: src/app/main/ui/workspace.cljs:199
msgid "title.workspace"
msgstr "%s - Penpot"
@@ -4008,19 +4059,19 @@ msgstr "Assets"
msgid "workspace.assets.box-filter-all"
msgstr "All assets"
-#: src/app/main/ui/dashboard/grid.cljs:138, src/app/main/ui/dashboard/grid.cljs:170, src/app/main/ui/workspace/sidebar/assets/colors.cljs:487, src/app/main/ui/workspace/sidebar/assets.cljs:147
+#: src/app/main/ui/dashboard/grid.cljs:138, src/app/main/ui/dashboard/grid.cljs:170, src/app/main/ui/workspace/sidebar/assets/colors.cljs:492, src/app/main/ui/workspace/sidebar/assets.cljs:147
msgid "workspace.assets.colors"
msgstr "Colors"
-#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:495
+#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:500
msgid "workspace.assets.colors.add-color"
msgstr "Add color"
-#: src/app/main/ui/dashboard/grid.cljs:134, src/app/main/ui/dashboard/grid.cljs:149, src/app/main/ui/workspace/sidebar/assets/components.cljs:511, src/app/main/ui/workspace/sidebar/assets.cljs:138
+#: src/app/main/ui/dashboard/grid.cljs:134, src/app/main/ui/dashboard/grid.cljs:149, src/app/main/ui/workspace/sidebar/assets/components.cljs:502, src/app/main/ui/workspace/sidebar/assets.cljs:138
msgid "workspace.assets.components"
msgstr "Components"
-#: src/app/main/ui/workspace/sidebar/assets/components.cljs:532
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:523
msgid "workspace.assets.components.add-component"
msgstr "Add component"
@@ -4032,19 +4083,19 @@ msgstr "Create a group"
msgid "workspace.assets.create-group-hint"
msgstr "Your items are going to be named automatically as \"group name / item name\""
-#: src/app/main/ui/workspace/context_menu.cljs:540, src/app/main/ui/workspace/sidebar/assets/colors.cljs:251, src/app/main/ui/workspace/sidebar/assets/components.cljs:576, src/app/main/ui/workspace/sidebar/assets/graphics.cljs:424, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:447
+#: src/app/main/ui/workspace/context_menu.cljs:548, src/app/main/ui/workspace/sidebar/assets/colors.cljs:256, src/app/main/ui/workspace/sidebar/assets/components.cljs:567, src/app/main/ui/workspace/sidebar/assets/graphics.cljs:424, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:460
msgid "workspace.assets.delete"
msgstr "Delete"
-#: src/app/main/ui/workspace/context_menu.cljs:545, src/app/main/ui/workspace/sidebar/assets/components.cljs:571
+#: src/app/main/ui/workspace/context_menu.cljs:553, src/app/main/ui/workspace/sidebar/assets/components.cljs:562
msgid "workspace.assets.duplicate"
msgstr "Duplicate"
-#: src/app/main/ui/workspace/sidebar/assets/components.cljs:570
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:561
msgid "workspace.assets.duplicate-main"
msgstr "Duplicate main"
-#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:247, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:443
+#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:252, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:456
msgid "workspace.assets.edit"
msgstr "Edit"
@@ -4056,11 +4107,11 @@ msgstr "Filter"
msgid "workspace.assets.graphics"
msgstr "Graphics"
-#: src/app/main/ui/workspace/sidebar/assets/components.cljs:527
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:518
msgid "workspace.assets.grid-view"
msgstr "Grid view"
-#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:255, src/app/main/ui/workspace/sidebar/assets/components.cljs:580, src/app/main/ui/workspace/sidebar/assets/graphics.cljs:428, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:452
+#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:260, src/app/main/ui/workspace/sidebar/assets/components.cljs:571, src/app/main/ui/workspace/sidebar/assets/graphics.cljs:428, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:465
msgid "workspace.assets.group"
msgstr "Group"
@@ -4079,19 +4130,19 @@ msgstr "Add library"
msgid "workspace.assets.list-view"
msgstr "List view"
-#: src/app/main/ui/workspace/sidebar/assets/file_library.cljs:62, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:347
+#: src/app/main/ui/workspace/sidebar/assets/file_library.cljs:72, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:347
msgid "workspace.assets.local-library"
msgstr "local library"
-#: src/app/main/ui/workspace/sidebar/assets/file_library.cljs:295
+#: src/app/main/ui/workspace/sidebar/assets/file_library.cljs:304
msgid "workspace.assets.not-found"
msgstr "No assets found"
-#: src/app/main/ui/workspace/sidebar/assets/file_library.cljs:68
+#: src/app/main/ui/workspace/sidebar/assets/file_library.cljs:78
msgid "workspace.assets.open-library"
msgstr "Open library file"
-#: src/app/main/ui/workspace/context_menu.cljs:543, src/app/main/ui/workspace/sidebar/assets/colors.cljs:243, src/app/main/ui/workspace/sidebar/assets/components.cljs:565, src/app/main/ui/workspace/sidebar/assets/graphics.cljs:421, src/app/main/ui/workspace/sidebar/assets/groups.cljs:62, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:438
+#: src/app/main/ui/workspace/context_menu.cljs:551, src/app/main/ui/workspace/sidebar/assets/colors.cljs:248, src/app/main/ui/workspace/sidebar/assets/components.cljs:556, src/app/main/ui/workspace/sidebar/assets/graphics.cljs:421, src/app/main/ui/workspace/sidebar/assets/groups.cljs:62, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:451
msgid "workspace.assets.rename"
msgstr "Rename"
@@ -4125,11 +4176,11 @@ msgstr[1] "%s components"
msgid "workspace.assets.sort"
msgstr "Sort"
-#: src/app/main/ui/dashboard/grid.cljs:142, src/app/main/ui/dashboard/grid.cljs:197, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:400, src/app/main/ui/workspace/sidebar/assets.cljs:151
+#: src/app/main/ui/dashboard/grid.cljs:142, src/app/main/ui/dashboard/grid.cljs:197, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:413, src/app/main/ui/workspace/sidebar/assets.cljs:151
msgid "workspace.assets.typography"
msgstr "Typographies"
-#: src/app/main/ui/workspace/sidebar/assets/typographies.cljs:408
+#: src/app/main/ui/workspace/sidebar/assets/typographies.cljs:421
msgid "workspace.assets.typography.add-typography"
msgstr "Add typography"
@@ -4174,67 +4225,67 @@ msgstr "Text Transform"
msgid "workspace.assets.ungroup"
msgstr "Ungroup"
-#: src/app/main/ui/workspace/context_menu.cljs:648
+#: src/app/main/ui/workspace/context_menu.cljs:656
msgid "workspace.context-menu.grid-cells.area"
msgstr "Create area"
-#: src/app/main/ui/workspace/context_menu.cljs:651
+#: src/app/main/ui/workspace/context_menu.cljs:659
msgid "workspace.context-menu.grid-cells.create-board"
msgstr "Create board"
-#: src/app/main/ui/workspace/context_menu.cljs:643
+#: src/app/main/ui/workspace/context_menu.cljs:651
msgid "workspace.context-menu.grid-cells.merge"
msgstr "Merge cells"
-#: src/app/main/ui/workspace/context_menu.cljs:608
+#: src/app/main/ui/workspace/context_menu.cljs:616
msgid "workspace.context-menu.grid-track.column.add-after"
msgstr "Add 1 column to the right"
-#: src/app/main/ui/workspace/context_menu.cljs:607
+#: src/app/main/ui/workspace/context_menu.cljs:615
msgid "workspace.context-menu.grid-track.column.add-before"
msgstr "Add 1 column to the left"
-#: src/app/main/ui/workspace/context_menu.cljs:609
+#: src/app/main/ui/workspace/context_menu.cljs:617
msgid "workspace.context-menu.grid-track.column.delete"
msgstr "Delete column"
-#: src/app/main/ui/workspace/context_menu.cljs:610
+#: src/app/main/ui/workspace/context_menu.cljs:618
msgid "workspace.context-menu.grid-track.column.delete-shapes"
msgstr "Delete column and shapes"
-#: src/app/main/ui/workspace/context_menu.cljs:606
+#: src/app/main/ui/workspace/context_menu.cljs:614
msgid "workspace.context-menu.grid-track.column.duplicate"
msgstr "Duplicate column"
-#: src/app/main/ui/workspace/context_menu.cljs:615
+#: src/app/main/ui/workspace/context_menu.cljs:623
msgid "workspace.context-menu.grid-track.row.add-after"
msgstr "Add 1 row below"
-#: src/app/main/ui/workspace/context_menu.cljs:614
+#: src/app/main/ui/workspace/context_menu.cljs:622
msgid "workspace.context-menu.grid-track.row.add-before"
msgstr "Add 1 row above"
-#: src/app/main/ui/workspace/context_menu.cljs:616
+#: src/app/main/ui/workspace/context_menu.cljs:624
msgid "workspace.context-menu.grid-track.row.delete"
msgstr "Delete row"
-#: src/app/main/ui/workspace/context_menu.cljs:617
+#: src/app/main/ui/workspace/context_menu.cljs:625
msgid "workspace.context-menu.grid-track.row.delete-shapes"
msgstr "Delete row and shapes"
-#: src/app/main/ui/workspace/context_menu.cljs:613
+#: src/app/main/ui/workspace/context_menu.cljs:621
msgid "workspace.context-menu.grid-track.row.duplicate"
msgstr "Duplicate row"
-#: src/app/main/ui/workspace/sidebar/layers.cljs:527
+#: src/app/main/ui/workspace/sidebar/layers.cljs:528
msgid "workspace.focus.focus-mode"
msgstr "Focus mode"
-#: src/app/main/ui/workspace/context_menu.cljs:298, src/app/main/ui/workspace/context_menu.cljs:567
+#: src/app/main/ui/workspace/context_menu.cljs:304, src/app/main/ui/workspace/context_menu.cljs:575
msgid "workspace.focus.focus-off"
msgstr "Focus off"
-#: src/app/main/ui/workspace/context_menu.cljs:297
+#: src/app/main/ui/workspace/context_menu.cljs:303
msgid "workspace.focus.focus-on"
msgstr "Focus on"
@@ -4250,11 +4301,11 @@ msgstr "Linear gradient"
msgid "workspace.gradients.radial"
msgstr "Radial gradient"
-#: src/app/main/ui/workspace/main_menu.cljs:243
+#: src/app/main/ui/workspace/main_menu.cljs:244
msgid "workspace.header.menu.disable-dynamic-alignment"
msgstr "Disable dynamic alignment"
-#: src/app/main/ui/workspace/main_menu.cljs:197
+#: src/app/main/ui/workspace/main_menu.cljs:198
msgid "workspace.header.menu.disable-scale-content"
msgstr "Disable proportional scale"
@@ -4263,23 +4314,23 @@ msgstr "Disable proportional scale"
msgid "workspace.header.menu.disable-scale-text"
msgstr "Disable scale text"
-#: src/app/main/ui/workspace/main_menu.cljs:228
+#: src/app/main/ui/workspace/main_menu.cljs:229
msgid "workspace.header.menu.disable-snap-guides"
msgstr "Disable snap to guides"
-#: src/app/main/ui/workspace/main_menu.cljs:258
+#: src/app/main/ui/workspace/main_menu.cljs:259
msgid "workspace.header.menu.disable-snap-pixel-grid"
msgstr "Disable snap to pixel"
-#: src/app/main/ui/workspace/main_menu.cljs:212
+#: src/app/main/ui/workspace/main_menu.cljs:213
msgid "workspace.header.menu.disable-snap-ruler-guides"
msgstr "Disable snap to ruler guides"
-#: src/app/main/ui/workspace/main_menu.cljs:244
+#: src/app/main/ui/workspace/main_menu.cljs:245
msgid "workspace.header.menu.enable-dynamic-alignment"
msgstr "Enable dynamic alignment"
-#: src/app/main/ui/workspace/main_menu.cljs:198
+#: src/app/main/ui/workspace/main_menu.cljs:199
msgid "workspace.header.menu.enable-scale-content"
msgstr "Enable proportional scale"
@@ -4288,59 +4339,59 @@ msgstr "Enable proportional scale"
msgid "workspace.header.menu.enable-scale-text"
msgstr "Enable scale text"
-#: src/app/main/ui/workspace/main_menu.cljs:229
+#: src/app/main/ui/workspace/main_menu.cljs:230
msgid "workspace.header.menu.enable-snap-guides"
msgstr "Snap to guides"
-#: src/app/main/ui/workspace/main_menu.cljs:259
+#: src/app/main/ui/workspace/main_menu.cljs:260
msgid "workspace.header.menu.enable-snap-pixel-grid"
msgstr "Enable snap to pixel"
-#: src/app/main/ui/workspace/main_menu.cljs:213
+#: src/app/main/ui/workspace/main_menu.cljs:214
msgid "workspace.header.menu.enable-snap-ruler-guides"
msgstr "Snap to ruler guides"
-#: src/app/main/ui/workspace/main_menu.cljs:388
+#: src/app/main/ui/workspace/main_menu.cljs:389
msgid "workspace.header.menu.hide-artboard-names"
msgstr "Hide board names"
-#: src/app/main/ui/workspace/main_menu.cljs:342
+#: src/app/main/ui/workspace/main_menu.cljs:343
msgid "workspace.header.menu.hide-guides"
msgstr "Hide guides"
-#: src/app/main/ui/workspace/main_menu.cljs:359
+#: src/app/main/ui/workspace/main_menu.cljs:360
msgid "workspace.header.menu.hide-palette"
msgstr "Hide color palette"
-#: src/app/main/ui/workspace/main_menu.cljs:400
+#: src/app/main/ui/workspace/main_menu.cljs:401
msgid "workspace.header.menu.hide-pixel-grid"
msgstr "Hide pixel grid"
-#: src/app/main/ui/workspace/main_menu.cljs:326
+#: src/app/main/ui/workspace/main_menu.cljs:327
msgid "workspace.header.menu.hide-rules"
msgstr "Hide rulers"
-#: src/app/main/ui/workspace/main_menu.cljs:373
+#: src/app/main/ui/workspace/main_menu.cljs:374
msgid "workspace.header.menu.hide-textpalette"
msgstr "Hide fonts palette"
-#: src/app/main/ui/workspace/main_menu.cljs:803
+#: src/app/main/ui/workspace/main_menu.cljs:850
msgid "workspace.header.menu.option.edit"
msgstr "Edit"
-#: src/app/main/ui/workspace/main_menu.cljs:792
+#: src/app/main/ui/workspace/main_menu.cljs:839
msgid "workspace.header.menu.option.file"
msgstr "File"
-#: src/app/main/ui/workspace/main_menu.cljs:849
+#: src/app/main/ui/workspace/main_menu.cljs:896
msgid "workspace.header.menu.option.help-info"
msgstr "Help & info"
-#: src/app/main/ui/workspace/main_menu.cljs:825
+#: src/app/main/ui/workspace/main_menu.cljs:872
msgid "workspace.header.menu.option.preferences"
msgstr "Preferences"
-#: src/app/main/ui/workspace/main_menu.cljs:814
+#: src/app/main/ui/workspace/main_menu.cljs:861
msgid "workspace.header.menu.option.view"
msgstr "View"
@@ -4352,43 +4403,43 @@ msgstr "Power up your plan"
msgid "workspace.header.menu.redo"
msgstr "Redo"
-#: src/app/main/ui/workspace/main_menu.cljs:442
+#: src/app/main/ui/workspace/main_menu.cljs:443
msgid "workspace.header.menu.select-all"
msgstr "Select all"
-#: src/app/main/ui/workspace/main_menu.cljs:389
+#: src/app/main/ui/workspace/main_menu.cljs:390
msgid "workspace.header.menu.show-artboard-names"
msgstr "Show boards names"
-#: src/app/main/ui/workspace/main_menu.cljs:343
+#: src/app/main/ui/workspace/main_menu.cljs:344
msgid "workspace.header.menu.show-guides"
msgstr "Show guides"
-#: src/app/main/ui/workspace/main_menu.cljs:360
+#: src/app/main/ui/workspace/main_menu.cljs:361
msgid "workspace.header.menu.show-palette"
msgstr "Show color palette"
-#: src/app/main/ui/workspace/main_menu.cljs:401
+#: src/app/main/ui/workspace/main_menu.cljs:402
msgid "workspace.header.menu.show-pixel-grid"
msgstr "Show pixel grid"
-#: src/app/main/ui/workspace/main_menu.cljs:327
+#: src/app/main/ui/workspace/main_menu.cljs:328
msgid "workspace.header.menu.show-rules"
msgstr "Show rulers"
-#: src/app/main/ui/workspace/main_menu.cljs:374
+#: src/app/main/ui/workspace/main_menu.cljs:375
msgid "workspace.header.menu.show-textpalette"
msgstr "Show fonts palette"
-#: src/app/main/ui/workspace/main_menu.cljs:284
+#: src/app/main/ui/workspace/main_menu.cljs:285
msgid "workspace.header.menu.toggle-dark-theme"
msgstr "Switch to dark theme"
-#: src/app/main/ui/workspace/main_menu.cljs:283
+#: src/app/main/ui/workspace/main_menu.cljs:284
msgid "workspace.header.menu.toggle-light-theme"
msgstr "Switch to light theme"
-#: src/app/main/ui/workspace/main_menu.cljs:457
+#: src/app/main/ui/workspace/main_menu.cljs:458
msgid "workspace.header.menu.undo"
msgstr "Undo"
@@ -4483,15 +4534,15 @@ msgstr "Add"
msgid "workspace.libraries.colors"
msgstr "%s colors"
-#: src/app/main/ui/workspace/color_palette.cljs:129
+#: src/app/main/ui/workspace/color_palette.cljs:137
msgid "workspace.libraries.colors.empty-palette"
msgstr "There are no color styles in your library yet"
-#: src/app/main/ui/workspace/text_palette.cljs:153
+#: src/app/main/ui/workspace/text_palette.cljs:161
msgid "workspace.libraries.colors.empty-typography-palette"
msgstr "There are no typography styles in your library yet"
-#: src/app/main/ui/workspace/color_palette_ctx_menu.cljs:60, src/app/main/ui/workspace/colorpicker/libraries.cljs:73, src/app/main/ui/workspace/text_palette_ctx_menu.cljs:50
+#: src/app/main/ui/workspace/color_palette_ctx_menu.cljs:60, src/app/main/ui/workspace/colorpicker/libraries.cljs:74, src/app/main/ui/workspace/text_palette_ctx_menu.cljs:50
msgid "workspace.libraries.colors.file-library"
msgstr "File library"
@@ -4500,7 +4551,7 @@ msgstr "File library"
msgid "workspace.libraries.colors.hsv"
msgstr "HSV"
-#: src/app/main/ui/workspace/color_palette_ctx_menu.cljs:82, src/app/main/ui/workspace/colorpicker/libraries.cljs:72
+#: src/app/main/ui/workspace/color_palette_ctx_menu.cljs:82, src/app/main/ui/workspace/colorpicker/libraries.cljs:73
msgid "workspace.libraries.colors.recent-colors"
msgstr "Recent colors"
@@ -4509,11 +4560,11 @@ msgstr "Recent colors"
msgid "workspace.libraries.colors.rgb-complementary"
msgstr "RGB Complementary"
-#: src/app/main/ui/workspace/colorpicker.cljs:234
+#: src/app/main/ui/workspace/colorpicker.cljs:342
msgid "workspace.libraries.colors.rgba"
msgstr "RGBA"
-#: src/app/main/ui/workspace/colorpicker.cljs:382
+#: src/app/main/ui/workspace/colorpicker.cljs:513
msgid "workspace.libraries.colors.save-color"
msgstr "Save color style"
@@ -4731,7 +4782,7 @@ msgstr "Top & Bottom"
msgid "workspace.options.design"
msgstr "Design"
-#: src/app/main/ui/viewer/inspect/exports.cljs:147
+#: src/app/main/ui/viewer/inspect/exports.cljs:139
msgid "workspace.options.export"
msgstr "Export"
@@ -4740,37 +4791,37 @@ msgstr "Export"
msgid "workspace.options.export-multiple"
msgstr "Export selection"
-#: src/app/main/ui/viewer/inspect/exports.cljs:203, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:256
+#: src/app/main/ui/viewer/inspect/exports.cljs:195, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:248
msgid "workspace.options.export-object"
msgid_plural "workspace.options.export-object"
msgstr[0] "Export 1 element"
msgstr[1] "Export %s elements"
-#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:195
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:187
msgid "workspace.options.export.add-export"
msgstr "Add export"
-#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:207, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:242
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:199, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:234
msgid "workspace.options.export.remove-export"
msgstr "Remove export"
-#: src/app/main/ui/viewer/inspect/exports.cljs:186, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:236
+#: src/app/main/ui/viewer/inspect/exports.cljs:178, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:228
msgid "workspace.options.export.suffix"
msgstr "Suffix"
-#: src/app/main/ui/exports/assets.cljs:246
+#: src/app/main/ui/exports/assets.cljs:239
msgid "workspace.options.exporting-complete"
msgstr "Export complete"
-#: src/app/main/ui/exports/assets.cljs:176, src/app/main/ui/exports/assets.cljs:247, src/app/main/ui/viewer/inspect/exports.cljs:202, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:255
+#: src/app/main/ui/exports/assets.cljs:169, src/app/main/ui/exports/assets.cljs:240, src/app/main/ui/viewer/inspect/exports.cljs:194, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:247
msgid "workspace.options.exporting-object"
msgstr "Exporting…"
-#: src/app/main/ui/exports/assets.cljs:245
+#: src/app/main/ui/exports/assets.cljs:238
msgid "workspace.options.exporting-object-error"
msgstr "Export failed"
-#: src/app/main/ui/exports/assets.cljs:248
+#: src/app/main/ui/exports/assets.cljs:241
msgid "workspace.options.exporting-object-slow"
msgstr "Export unexpectedly slow"
@@ -5159,67 +5210,67 @@ msgstr "Add interaction"
msgid "workspace.options.interactions.remove-interaction"
msgstr "Remove interaction"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:137
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:152
msgid "workspace.options.layer-options.blend-mode.color"
msgstr "Color"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:126
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:141
msgid "workspace.options.layer-options.blend-mode.color-burn"
msgstr "Color burn"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:129
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:144
msgid "workspace.options.layer-options.blend-mode.color-dodge"
msgstr "Color dodge"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:124
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:139
msgid "workspace.options.layer-options.blend-mode.darken"
msgstr "Darken"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:133
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:148
msgid "workspace.options.layer-options.blend-mode.difference"
msgstr "Difference"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:134
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:149
msgid "workspace.options.layer-options.blend-mode.exclusion"
msgstr "Exclusion"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:132
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:147
msgid "workspace.options.layer-options.blend-mode.hard-light"
msgstr "Hard light"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:135
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:150
msgid "workspace.options.layer-options.blend-mode.hue"
msgstr "Hue"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:127
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:142
msgid "workspace.options.layer-options.blend-mode.lighten"
msgstr "Lighten"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:138
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:153
msgid "workspace.options.layer-options.blend-mode.luminosity"
msgstr "Luminosity"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:125
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:140
msgid "workspace.options.layer-options.blend-mode.multiply"
msgstr "Multiply"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:123
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:138
msgid "workspace.options.layer-options.blend-mode.normal"
msgstr "Normal"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:130
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:145
msgid "workspace.options.layer-options.blend-mode.overlay"
msgstr "Overlay"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:136
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:151
msgid "workspace.options.layer-options.blend-mode.saturation"
msgstr "Saturation"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:128
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:143
msgid "workspace.options.layer-options.blend-mode.screen"
msgstr "Screen"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:131
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:146
msgid "workspace.options.layer-options.blend-mode.soft-light"
msgstr "Soft light"
@@ -5238,7 +5289,7 @@ msgstr "Group layers"
msgid "workspace.options.layer-options.title.multiple"
msgstr "Selected layers"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:176, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:182
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:191, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:197
msgid "workspace.options.layer-options.toggle-layer"
msgstr "Toggle layer visibility"
@@ -5381,7 +5432,7 @@ msgstr "More colors"
msgid "workspace.options.more-lib-colors"
msgstr "More library colors"
-#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:161
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:176
msgid "workspace.options.opacity"
msgstr "Opacity"
@@ -5426,7 +5477,7 @@ msgstr "Independent corners"
msgid "workspace.options.recent-fonts"
msgstr "Recent"
-#: src/app/main/ui/exports/assets.cljs:290
+#: src/app/main/ui/exports/assets.cljs:283
msgid "workspace.options.retry"
msgstr "Retry"
@@ -5796,7 +5847,7 @@ msgstr "No plugins installed yet"
msgid "workspace.plugins.error.manifest"
msgstr "The plugin manifest is incorrect."
-#: src/app/main/data/plugins.cljs:86, src/app/main/ui/workspace/main_menu.cljs:696, src/app/main/ui/workspace/plugins.cljs:82
+#: src/app/main/data/plugins.cljs:86, src/app/main/ui/workspace/main_menu.cljs:743, src/app/main/ui/workspace/plugins.cljs:82
msgid "workspace.plugins.error.need-editor"
msgstr "You need to be an editor to use this plugin"
@@ -5812,11 +5863,11 @@ msgstr "Install"
msgid "workspace.plugins.installed-plugins"
msgstr "Installed plugins"
-#: src/app/main/ui/workspace/main_menu.cljs:651
+#: src/app/main/ui/workspace/main_menu.cljs:698
msgid "workspace.plugins.menu.plugins-manager"
msgstr "Plugins manager"
-#: src/app/main/ui/workspace/main_menu.cljs:837
+#: src/app/main/ui/workspace/main_menu.cljs:884
msgid "workspace.plugins.menu.title"
msgstr "Plugins"
@@ -5911,11 +5962,11 @@ msgstr "'%s' PLUGIN IS INSTALLED FOR YOUR USER!"
msgid "workspace.plugins.try-out.try"
msgstr "TRY PLUGIN"
-#: src/app/main/ui/workspace/context_menu.cljs:451
+#: src/app/main/ui/workspace/context_menu.cljs:457
msgid "workspace.shape.menu.add-flex"
msgstr "Add flex layout"
-#: src/app/main/ui/workspace/context_menu.cljs:455
+#: src/app/main/ui/workspace/context_menu.cljs:461
msgid "workspace.shape.menu.add-grid"
msgstr "Add grid layout"
@@ -5923,91 +5974,95 @@ msgstr "Add grid layout"
msgid "workspace.shape.menu.add-layout"
msgstr "Add layout"
-#: src/app/main/ui/workspace/context_menu.cljs:194
+#: src/app/main/ui/workspace/context_menu.cljs:200
msgid "workspace.shape.menu.back"
msgstr "Send to back"
-#: src/app/main/ui/workspace/context_menu.cljs:191
+#: src/app/main/ui/workspace/context_menu.cljs:197
msgid "workspace.shape.menu.backward"
msgstr "Send backward"
-#: src/app/main/ui/workspace/context_menu.cljs:140
+#: src/app/main/ui/workspace/context_menu.cljs:143
msgid "workspace.shape.menu.copy"
msgstr "Copy"
-#: src/app/main/ui/workspace/sidebar/assets/common.cljs:427
+#: src/app/main/ui/workspace/context_menu.cljs:146
+msgid "workspace.shape.menu.copy_link"
+msgstr "Copy link to clipboard"
+
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:431
msgid "workspace.shape.menu.create-annotation"
msgstr "Create annotation"
-#: src/app/main/ui/workspace/context_menu.cljs:286
+#: src/app/main/ui/workspace/context_menu.cljs:292
msgid "workspace.shape.menu.create-artboard-from-selection"
msgstr "Selection to board"
-#: src/app/main/ui/workspace/context_menu.cljs:475
+#: src/app/main/ui/workspace/context_menu.cljs:481
msgid "workspace.shape.menu.create-component"
msgstr "Create component"
-#: src/app/main/ui/workspace/context_menu.cljs:479
+#: src/app/main/ui/workspace/context_menu.cljs:485
msgid "workspace.shape.menu.create-multiple-components"
msgstr "Create multiple components"
-#: src/app/main/ui/workspace/context_menu.cljs:143
+#: src/app/main/ui/workspace/context_menu.cljs:149
msgid "workspace.shape.menu.cut"
msgstr "Cut"
-#: src/app/main/ui/workspace/context_menu.cljs:496, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:764, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1052
+#: src/app/main/ui/workspace/context_menu.cljs:502, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:764, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1052
msgid "workspace.shape.menu.delete"
msgstr "Delete"
-#: src/app/main/ui/workspace/context_menu.cljs:402
+#: src/app/main/ui/workspace/context_menu.cljs:408
msgid "workspace.shape.menu.delete-flow-start"
msgstr "Delete flow start"
-#: src/app/main/ui/workspace/sidebar/assets/common.cljs:432
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:436
msgid "workspace.shape.menu.detach-instance"
msgstr "Detach instance"
-#: src/app/main/ui/workspace/sidebar/assets/common.cljs:431
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:435
msgid "workspace.shape.menu.detach-instances-in-bulk"
msgstr "Detach instances"
-#: src/app/main/ui/workspace/context_menu.cljs:346, src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:75
+#: src/app/main/ui/workspace/context_menu.cljs:352, src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:75
msgid "workspace.shape.menu.difference"
msgstr "Difference"
-#: src/app/main/ui/workspace/context_menu.cljs:149
+#: src/app/main/ui/workspace/context_menu.cljs:155
msgid "workspace.shape.menu.duplicate"
msgstr "Duplicate"
-#: src/app/main/ui/workspace/context_menu.cljs:332
+#: src/app/main/ui/workspace/context_menu.cljs:338
msgid "workspace.shape.menu.edit"
msgstr "Edit"
-#: src/app/main/ui/workspace/context_menu.cljs:352
+#: src/app/main/ui/workspace/context_menu.cljs:358
msgid "workspace.shape.menu.exclude"
msgstr "Exclude"
-#: src/app/main/ui/workspace/context_menu.cljs:359, src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:89
+#: src/app/main/ui/workspace/context_menu.cljs:365, src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:89
msgid "workspace.shape.menu.flatten"
msgstr "Flatten"
-#: src/app/main/ui/workspace/context_menu.cljs:209
+#: src/app/main/ui/workspace/context_menu.cljs:215
msgid "workspace.shape.menu.flip-horizontal"
msgstr "Flip horizontal"
-#: src/app/main/ui/workspace/context_menu.cljs:205
+#: src/app/main/ui/workspace/context_menu.cljs:211
msgid "workspace.shape.menu.flip-vertical"
msgstr "Flip vertical"
-#: src/app/main/ui/workspace/context_menu.cljs:404
+#: src/app/main/ui/workspace/context_menu.cljs:410
msgid "workspace.shape.menu.flow-start"
msgstr "Flow start"
-#: src/app/main/ui/workspace/context_menu.cljs:185
+#: src/app/main/ui/workspace/context_menu.cljs:191
msgid "workspace.shape.menu.forward"
msgstr "Bring forward"
-#: src/app/main/ui/workspace/context_menu.cljs:188
+#: src/app/main/ui/workspace/context_menu.cljs:194
msgid "workspace.shape.menu.front"
msgstr "Bring to front"
@@ -6016,43 +6071,43 @@ msgstr "Bring to front"
msgid "workspace.shape.menu.go-main"
msgstr "Go to main component file"
-#: src/app/main/ui/workspace/context_menu.cljs:272
+#: src/app/main/ui/workspace/context_menu.cljs:278
msgid "workspace.shape.menu.group"
msgstr "Group"
-#: src/app/main/ui/workspace/context_menu.cljs:374, src/app/main/ui/workspace/sidebar/layer_item.cljs:145
+#: src/app/main/ui/workspace/context_menu.cljs:380, src/app/main/ui/workspace/sidebar/layer_item.cljs:145
msgid "workspace.shape.menu.hide"
msgstr "Hide"
-#: src/app/main/ui/workspace/context_menu.cljs:562, src/app/main/ui/workspace/main_menu.cljs:414
+#: src/app/main/ui/workspace/context_menu.cljs:570, src/app/main/ui/workspace/main_menu.cljs:415
msgid "workspace.shape.menu.hide-ui"
msgstr "Show / Hide UI"
-#: src/app/main/ui/workspace/context_menu.cljs:349
+#: src/app/main/ui/workspace/context_menu.cljs:355
msgid "workspace.shape.menu.intersection"
msgstr "Intersection"
-#: src/app/main/ui/workspace/context_menu.cljs:382, src/app/main/ui/workspace/sidebar/layer_item.cljs:153, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:189
+#: src/app/main/ui/workspace/context_menu.cljs:388, src/app/main/ui/workspace/sidebar/layer_item.cljs:153, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:204
msgid "workspace.shape.menu.lock"
msgstr "Lock"
-#: src/app/main/ui/workspace/context_menu.cljs:277
+#: src/app/main/ui/workspace/context_menu.cljs:283
msgid "workspace.shape.menu.mask"
msgstr "Mask"
-#: src/app/main/ui/workspace/context_menu.cljs:146, src/app/main/ui/workspace/context_menu.cljs:559
+#: src/app/main/ui/workspace/context_menu.cljs:152, src/app/main/ui/workspace/context_menu.cljs:567
msgid "workspace.shape.menu.paste"
msgstr "Paste"
-#: src/app/main/ui/workspace/context_menu.cljs:342
+#: src/app/main/ui/workspace/context_menu.cljs:348
msgid "workspace.shape.menu.path"
msgstr "Path"
-#: src/app/main/ui/workspace/context_menu.cljs:442
+#: src/app/main/ui/workspace/context_menu.cljs:448
msgid "workspace.shape.menu.remove-flex"
msgstr "Remove flex layout"
-#: src/app/main/ui/workspace/context_menu.cljs:445
+#: src/app/main/ui/workspace/context_menu.cljs:451
msgid "workspace.shape.menu.remove-grid"
msgstr "Remove grid layout"
@@ -6060,59 +6115,59 @@ msgstr "Remove grid layout"
msgid "workspace.shape.menu.remove-layout"
msgstr "Remove layout"
-#: src/app/main/ui/workspace/context_menu.cljs:235
+#: src/app/main/ui/workspace/context_menu.cljs:241
msgid "workspace.shape.menu.rename"
msgstr "Rename"
-#: src/app/main/ui/workspace/sidebar/assets/common.cljs:436
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:440
msgid "workspace.shape.menu.reset-overrides"
msgstr "Reset overrides"
-#: src/app/main/ui/workspace/sidebar/assets/common.cljs:439
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:443
msgid "workspace.shape.menu.restore-main"
msgstr "Restore main component"
-#: src/app/main/ui/workspace/context_menu.cljs:175
+#: src/app/main/ui/workspace/context_menu.cljs:181
msgid "workspace.shape.menu.select-layer"
msgstr "Select layer"
-#: src/app/main/ui/workspace/context_menu.cljs:371, src/app/main/ui/workspace/sidebar/layer_item.cljs:144
+#: src/app/main/ui/workspace/context_menu.cljs:377, src/app/main/ui/workspace/sidebar/layer_item.cljs:144
msgid "workspace.shape.menu.show"
msgstr "Show"
-#: src/app/main/ui/workspace/sidebar/assets/common.cljs:424
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:428
msgid "workspace.shape.menu.show-in-assets"
msgstr "Show in assets panel"
-#: src/app/main/ui/workspace/sidebar/assets/common.cljs:442, src/app/main/ui/workspace/sidebar/assets/components.cljs:585
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:446, src/app/main/ui/workspace/sidebar/assets/components.cljs:576
msgid "workspace.shape.menu.show-main"
msgstr "Show main component"
-#: src/app/main/ui/workspace/context_menu.cljs:222
+#: src/app/main/ui/workspace/context_menu.cljs:228
msgid "workspace.shape.menu.thumbnail-remove"
msgstr "Remove thumbnail"
-#: src/app/main/ui/workspace/context_menu.cljs:224
+#: src/app/main/ui/workspace/context_menu.cljs:230
msgid "workspace.shape.menu.thumbnail-set"
msgstr "Set as thumbnail"
-#: src/app/main/ui/workspace/context_menu.cljs:337
+#: src/app/main/ui/workspace/context_menu.cljs:343
msgid "workspace.shape.menu.transform-to-path"
msgstr "Transform to path"
-#: src/app/main/ui/workspace/context_menu.cljs:268
+#: src/app/main/ui/workspace/context_menu.cljs:274
msgid "workspace.shape.menu.ungroup"
msgstr "Ungroup"
-#: src/app/main/ui/workspace/context_menu.cljs:343, src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:70
+#: src/app/main/ui/workspace/context_menu.cljs:349, src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:70
msgid "workspace.shape.menu.union"
msgstr "Union"
-#: src/app/main/ui/workspace/context_menu.cljs:379, src/app/main/ui/workspace/sidebar/layer_item.cljs:152, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:195
+#: src/app/main/ui/workspace/context_menu.cljs:385, src/app/main/ui/workspace/sidebar/layer_item.cljs:152, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:210
msgid "workspace.shape.menu.unlock"
msgstr "Unlock"
-#: src/app/main/ui/workspace/context_menu.cljs:282
+#: src/app/main/ui/workspace/context_menu.cljs:288
msgid "workspace.shape.menu.unmask"
msgstr "Unmask"
@@ -6121,7 +6176,7 @@ msgstr "Unmask"
msgid "workspace.shape.menu.update-components-in-bulk"
msgstr "Update main components"
-#: src/app/main/ui/workspace/sidebar/assets/common.cljs:445
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:449
msgid "workspace.shape.menu.update-main"
msgstr "Update main component"
@@ -6137,39 +6192,39 @@ msgstr "Expand sidebar"
msgid "workspace.sidebar.history"
msgstr "History"
-#: src/app/main/ui/workspace/sidebar/layers.cljs:524, src/app/main/ui/workspace/sidebar.cljs:110, src/app/main/ui/workspace/sidebar.cljs:114, src/app/main/ui/workspace/sidebar.cljs:123
+#: src/app/main/ui/workspace/sidebar/layers.cljs:525, src/app/main/ui/workspace/sidebar.cljs:110, src/app/main/ui/workspace/sidebar.cljs:114, src/app/main/ui/workspace/sidebar.cljs:123
msgid "workspace.sidebar.layers"
msgstr "Layers"
-#: src/app/main/ui/workspace/sidebar/layers.cljs:310, src/app/main/ui/workspace/sidebar/layers.cljs:382
+#: src/app/main/ui/workspace/sidebar/layers.cljs:311, src/app/main/ui/workspace/sidebar/layers.cljs:383
msgid "workspace.sidebar.layers.components"
msgstr "Components"
-#: src/app/main/ui/workspace/sidebar/layers.cljs:307, src/app/main/ui/workspace/sidebar/layers.cljs:340
+#: src/app/main/ui/workspace/sidebar/layers.cljs:308, src/app/main/ui/workspace/sidebar/layers.cljs:341
msgid "workspace.sidebar.layers.frames"
msgstr "Boards"
-#: src/app/main/ui/workspace/sidebar/layers.cljs:308, src/app/main/ui/workspace/sidebar/layers.cljs:354
+#: src/app/main/ui/workspace/sidebar/layers.cljs:309, src/app/main/ui/workspace/sidebar/layers.cljs:355
msgid "workspace.sidebar.layers.groups"
msgstr "Groups"
-#: src/app/main/ui/workspace/sidebar/layers.cljs:312, src/app/main/ui/workspace/sidebar/layers.cljs:410
+#: src/app/main/ui/workspace/sidebar/layers.cljs:313, src/app/main/ui/workspace/sidebar/layers.cljs:411
msgid "workspace.sidebar.layers.images"
msgstr "Images"
-#: src/app/main/ui/workspace/sidebar/layers.cljs:309, src/app/main/ui/workspace/sidebar/layers.cljs:368
+#: src/app/main/ui/workspace/sidebar/layers.cljs:310, src/app/main/ui/workspace/sidebar/layers.cljs:369
msgid "workspace.sidebar.layers.masks"
msgstr "Masks"
-#: src/app/main/ui/workspace/sidebar/layers.cljs:290
+#: src/app/main/ui/workspace/sidebar/layers.cljs:291
msgid "workspace.sidebar.layers.search"
msgstr "Search layers"
-#: src/app/main/ui/workspace/sidebar/layers.cljs:313, src/app/main/ui/workspace/sidebar/layers.cljs:424
+#: src/app/main/ui/workspace/sidebar/layers.cljs:314, src/app/main/ui/workspace/sidebar/layers.cljs:425
msgid "workspace.sidebar.layers.shapes"
msgstr "Shapes"
-#: src/app/main/ui/workspace/sidebar/layers.cljs:311, src/app/main/ui/workspace/sidebar/layers.cljs:396
+#: src/app/main/ui/workspace/sidebar/layers.cljs:312, src/app/main/ui/workspace/sidebar/layers.cljs:397
msgid "workspace.sidebar.layers.texts"
msgstr "Texts"
@@ -6206,7 +6261,7 @@ msgstr "Back to theme list"
msgid "workspace.token.create-new-theme"
msgstr "Create your first theme now."
-#: src/app/main/ui/workspace/tokens/sidebar.cljs:194, src/app/main/ui/workspace/tokens/sidebar.cljs:210
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:194, src/app/main/ui/workspace/tokens/sidebar.cljs:215
msgid "workspace.token.create-one"
msgstr "Create one."
@@ -6214,7 +6269,7 @@ msgstr "Create one."
msgid "workspace.token.create-theme-title"
msgstr "Create theme"
-#: src/app/main/ui/workspace/tokens/form.cljs:362
+#: src/app/main/ui/workspace/tokens/form.cljs:364
msgid "workspace.token.create-token"
msgstr "Create new %s token"
@@ -6230,11 +6285,27 @@ msgstr "Edit theme"
msgid "workspace.token.edit-themes"
msgstr "Edit themes"
-#: src/app/main/ui/workspace/tokens/form.cljs:361
+#: src/app/main/ui/workspace/tokens/form.cljs:363
msgid "workspace.token.edit-token"
msgstr "Edit token"
+#: src/app/main/ui/workspace/tokens/form.cljs:408
+#, fuzzy
+msgid "workspace.token.enter-token-description"
+msgstr ""
+
+#: src/app/main/ui/workspace/tokens/form.cljs:370
+#, fuzzy
+msgid "workspace.token.enter-token-name"
+msgstr ""
+
+#: src/app/main/ui/workspace/tokens/form.cljs:390
+#, fuzzy
+msgid "workspace.token.enter-token-value"
+msgstr ""
+
#: src/app/main/ui/workspace/tokens/sets.cljs:186
+#, unused
msgid "workspace.token.grouping-set-alert"
msgstr "Token Set grouping is not supported yet."
@@ -6250,11 +6321,11 @@ msgstr "No theme active"
msgid "workspace.token.no-sets"
msgstr "No sets"
-#: src/app/main/ui/workspace/tokens/sets.cljs:216
+#: src/app/main/ui/workspace/tokens/sets.cljs:241, src/app/main/ui/workspace/tokens/sets.cljs:245
msgid "workspace.token.no-sets-create"
msgstr "There are no sets defined yet. Create one first."
-#: src/app/main/ui/workspace/tokens/sidebar.cljs:239
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:212
msgid "workspace.token.no-sets-yet"
msgstr "There are no sets yet."
@@ -6274,7 +6345,7 @@ msgstr "%s sets"
msgid "workspace.token.original-value"
msgstr "Original value: "
-#: src/app/main/ui/workspace/tokens/form.cljs:193, src/app/main/ui/workspace/tokens/form.cljs:196, src/app/main/ui/workspace/tokens/sidebar.cljs:67
+#: src/app/main/ui/workspace/tokens/form.cljs:194, src/app/main/ui/workspace/tokens/form.cljs:197, src/app/main/ui/workspace/tokens/sidebar.cljs:67
msgid "workspace.token.resolved-value"
msgstr "Resolved value: "
@@ -6282,7 +6353,7 @@ msgstr "Resolved value: "
msgid "workspace.token.save-theme"
msgstr "Save theme"
-#: src/app/main/ui/workspace/tokens/sets.cljs:172
+#: src/app/main/ui/workspace/tokens/sets.cljs:160
msgid "workspace.token.select-set"
msgstr "Select set."
@@ -6304,6 +6375,21 @@ msgstr "Theme %s"
msgid "workspace.token.themes"
msgstr "Themes"
+#: src/app/main/ui/workspace/tokens/form.cljs:409
+#, fuzzy
+msgid "workspace.token.token-description"
+msgstr ""
+
+#: src/app/main/ui/workspace/tokens/form.cljs:373
+#, fuzzy
+msgid "workspace.token.token-name"
+msgstr ""
+
+#: src/app/main/ui/workspace/tokens/form.cljs:391
+#, fuzzy
+msgid "workspace.token.token-value"
+msgstr ""
+
#: src/app/main/ui/workspace/sidebar.cljs:117, src/app/main/ui/workspace/sidebar.cljs:126
msgid "workspace.toolbar.assets"
msgstr "Assets"
@@ -6316,35 +6402,35 @@ msgstr "Color Palette (%s)"
msgid "workspace.toolbar.comments"
msgstr "Comments (%s)"
-#: src/app/main/ui/workspace/top_toolbar.cljs:181, src/app/main/ui/workspace/top_toolbar.cljs:182
+#: src/app/main/ui/workspace/top_toolbar.cljs:182, src/app/main/ui/workspace/top_toolbar.cljs:183
msgid "workspace.toolbar.curve"
msgstr "Curve (%s)"
-#: src/app/main/ui/workspace/top_toolbar.cljs:161, src/app/main/ui/workspace/top_toolbar.cljs:162
+#: src/app/main/ui/workspace/top_toolbar.cljs:162, src/app/main/ui/workspace/top_toolbar.cljs:163
msgid "workspace.toolbar.ellipse"
msgstr "Ellipse (%s)"
-#: src/app/main/ui/workspace/top_toolbar.cljs:143, src/app/main/ui/workspace/top_toolbar.cljs:144
+#: src/app/main/ui/workspace/top_toolbar.cljs:144, src/app/main/ui/workspace/top_toolbar.cljs:145
msgid "workspace.toolbar.frame"
msgstr "Board (%s)"
-#: src/app/main/ui/workspace/top_toolbar.cljs:60, src/app/main/ui/workspace/top_toolbar.cljs:61
+#: src/app/main/ui/workspace/top_toolbar.cljs:61, src/app/main/ui/workspace/top_toolbar.cljs:62
msgid "workspace.toolbar.image"
msgstr "Image (%s)"
-#: src/app/main/ui/workspace/top_toolbar.cljs:133, src/app/main/ui/workspace/top_toolbar.cljs:134
+#: src/app/main/ui/workspace/top_toolbar.cljs:134, src/app/main/ui/workspace/top_toolbar.cljs:135
msgid "workspace.toolbar.move"
msgstr "Move (%s)"
-#: src/app/main/ui/workspace/top_toolbar.cljs:190, src/app/main/ui/workspace/top_toolbar.cljs:191
+#: src/app/main/ui/workspace/top_toolbar.cljs:191, src/app/main/ui/workspace/top_toolbar.cljs:192
msgid "workspace.toolbar.path"
msgstr "Path (%s)"
-#: src/app/main/ui/workspace/top_toolbar.cljs:201, src/app/main/ui/workspace/top_toolbar.cljs:202
+#: src/app/main/ui/workspace/top_toolbar.cljs:202, src/app/main/ui/workspace/top_toolbar.cljs:203
msgid "workspace.toolbar.plugins"
msgstr "Plugins (%s)"
-#: src/app/main/ui/workspace/top_toolbar.cljs:152, src/app/main/ui/workspace/top_toolbar.cljs:153
+#: src/app/main/ui/workspace/top_toolbar.cljs:153, src/app/main/ui/workspace/top_toolbar.cljs:154
msgid "workspace.toolbar.rect"
msgstr "Rectangle (%s)"
@@ -6353,7 +6439,7 @@ msgstr "Rectangle (%s)"
msgid "workspace.toolbar.shortcuts"
msgstr "Shortcuts (%s)"
-#: src/app/main/ui/workspace/top_toolbar.cljs:170, src/app/main/ui/workspace/top_toolbar.cljs:171
+#: src/app/main/ui/workspace/top_toolbar.cljs:171, src/app/main/ui/workspace/top_toolbar.cljs:172
msgid "workspace.toolbar.text"
msgstr "Text (%s)"
@@ -6361,7 +6447,7 @@ msgstr "Text (%s)"
msgid "workspace.toolbar.text-palette"
msgstr "Typographies (%s)"
-#: src/app/main/ui/workspace/top_toolbar.cljs:219, src/app/main/ui/workspace/top_toolbar.cljs:220
+#: src/app/main/ui/workspace/top_toolbar.cljs:220, src/app/main/ui/workspace/top_toolbar.cljs:221
msgid "workspace.toolbar.toggle-toolbar"
msgstr "Toggle toolbar"
@@ -6374,143 +6460,143 @@ msgstr "Done"
msgid "workspace.top-bar.view-only"
msgstr "**Inspecting code** (View Only)"
-#: src/app/main/ui/workspace/sidebar/history.cljs:331
+#: src/app/main/ui/workspace/sidebar/history.cljs:332
msgid "workspace.undo.empty"
msgstr "There are no history changes so far"
-#: src/app/main/ui/workspace/sidebar/history.cljs:145
+#: src/app/main/ui/workspace/sidebar/history.cljs:146
msgid "workspace.undo.entry.delete"
msgstr "Deleted %s"
-#: src/app/main/ui/workspace/sidebar/history.cljs:144
+#: src/app/main/ui/workspace/sidebar/history.cljs:145
msgid "workspace.undo.entry.modify"
msgstr "Modified %s"
-#: src/app/main/ui/workspace/sidebar/history.cljs:146
+#: src/app/main/ui/workspace/sidebar/history.cljs:147
msgid "workspace.undo.entry.move"
msgstr "Moved objects"
-#: src/app/main/ui/workspace/sidebar/history.cljs:109
+#: src/app/main/ui/workspace/sidebar/history.cljs:110
msgid "workspace.undo.entry.multiple.circle"
msgstr "circles"
-#: src/app/main/ui/workspace/sidebar/history.cljs:110
+#: src/app/main/ui/workspace/sidebar/history.cljs:111
msgid "workspace.undo.entry.multiple.color"
msgstr "color assets"
-#: src/app/main/ui/workspace/sidebar/history.cljs:111
+#: src/app/main/ui/workspace/sidebar/history.cljs:112
msgid "workspace.undo.entry.multiple.component"
msgstr "components"
-#: src/app/main/ui/workspace/sidebar/history.cljs:112
+#: src/app/main/ui/workspace/sidebar/history.cljs:113
msgid "workspace.undo.entry.multiple.curve"
msgstr "curves"
-#: src/app/main/ui/workspace/sidebar/history.cljs:113
+#: src/app/main/ui/workspace/sidebar/history.cljs:114
msgid "workspace.undo.entry.multiple.frame"
msgstr "board"
-#: src/app/main/ui/workspace/sidebar/history.cljs:114
+#: src/app/main/ui/workspace/sidebar/history.cljs:115
msgid "workspace.undo.entry.multiple.group"
msgstr "groups"
-#: src/app/main/ui/workspace/sidebar/history.cljs:115
+#: src/app/main/ui/workspace/sidebar/history.cljs:116
msgid "workspace.undo.entry.multiple.media"
msgstr "graphic assets"
-#: src/app/main/ui/workspace/sidebar/history.cljs:116
+#: src/app/main/ui/workspace/sidebar/history.cljs:117
msgid "workspace.undo.entry.multiple.multiple"
msgstr "objects"
-#: src/app/main/ui/workspace/sidebar/history.cljs:117
+#: src/app/main/ui/workspace/sidebar/history.cljs:118
msgid "workspace.undo.entry.multiple.page"
msgstr "pages"
-#: src/app/main/ui/workspace/sidebar/history.cljs:118
+#: src/app/main/ui/workspace/sidebar/history.cljs:119
msgid "workspace.undo.entry.multiple.path"
msgstr "paths"
-#: src/app/main/ui/workspace/sidebar/history.cljs:119
+#: src/app/main/ui/workspace/sidebar/history.cljs:120
msgid "workspace.undo.entry.multiple.rect"
msgstr "rectangles"
-#: src/app/main/ui/workspace/sidebar/history.cljs:120
+#: src/app/main/ui/workspace/sidebar/history.cljs:121
msgid "workspace.undo.entry.multiple.shape"
msgstr "shapes"
-#: src/app/main/ui/workspace/sidebar/history.cljs:121
+#: src/app/main/ui/workspace/sidebar/history.cljs:122
msgid "workspace.undo.entry.multiple.text"
msgstr "texts"
-#: src/app/main/ui/workspace/sidebar/history.cljs:122
+#: src/app/main/ui/workspace/sidebar/history.cljs:123
msgid "workspace.undo.entry.multiple.typography"
msgstr "typography assets"
-#: src/app/main/ui/workspace/sidebar/history.cljs:143
+#: src/app/main/ui/workspace/sidebar/history.cljs:144
msgid "workspace.undo.entry.new"
msgstr "New %s"
-#: src/app/main/ui/workspace/sidebar/history.cljs:123
+#: src/app/main/ui/workspace/sidebar/history.cljs:124
msgid "workspace.undo.entry.single.circle"
msgstr "circle"
-#: src/app/main/ui/workspace/sidebar/history.cljs:124
+#: src/app/main/ui/workspace/sidebar/history.cljs:125
msgid "workspace.undo.entry.single.color"
msgstr "color asset"
-#: src/app/main/ui/workspace/sidebar/history.cljs:125
+#: src/app/main/ui/workspace/sidebar/history.cljs:126
msgid "workspace.undo.entry.single.component"
msgstr "component"
-#: src/app/main/ui/workspace/sidebar/history.cljs:126
+#: src/app/main/ui/workspace/sidebar/history.cljs:127
msgid "workspace.undo.entry.single.curve"
msgstr "curve"
-#: src/app/main/ui/workspace/sidebar/history.cljs:127
+#: src/app/main/ui/workspace/sidebar/history.cljs:128
msgid "workspace.undo.entry.single.frame"
msgstr "board"
-#: src/app/main/ui/workspace/sidebar/history.cljs:128
+#: src/app/main/ui/workspace/sidebar/history.cljs:129
msgid "workspace.undo.entry.single.group"
msgstr "group"
-#: src/app/main/ui/workspace/sidebar/history.cljs:129
+#: src/app/main/ui/workspace/sidebar/history.cljs:130
msgid "workspace.undo.entry.single.image"
msgstr "image"
-#: src/app/main/ui/workspace/sidebar/history.cljs:130
+#: src/app/main/ui/workspace/sidebar/history.cljs:131
msgid "workspace.undo.entry.single.media"
msgstr "graphic asset"
-#: src/app/main/ui/workspace/sidebar/history.cljs:131
+#: src/app/main/ui/workspace/sidebar/history.cljs:132
msgid "workspace.undo.entry.single.multiple"
msgstr "object"
-#: src/app/main/ui/workspace/sidebar/history.cljs:132
+#: src/app/main/ui/workspace/sidebar/history.cljs:133
msgid "workspace.undo.entry.single.page"
msgstr "page"
-#: src/app/main/ui/workspace/sidebar/history.cljs:133
+#: src/app/main/ui/workspace/sidebar/history.cljs:134
msgid "workspace.undo.entry.single.path"
msgstr "path"
-#: src/app/main/ui/workspace/sidebar/history.cljs:134
+#: src/app/main/ui/workspace/sidebar/history.cljs:135
msgid "workspace.undo.entry.single.rect"
msgstr "rectangle"
-#: src/app/main/ui/workspace/sidebar/history.cljs:135
+#: src/app/main/ui/workspace/sidebar/history.cljs:136
msgid "workspace.undo.entry.single.shape"
msgstr "shape"
-#: src/app/main/ui/workspace/sidebar/history.cljs:136
+#: src/app/main/ui/workspace/sidebar/history.cljs:137
msgid "workspace.undo.entry.single.text"
msgstr "text"
-#: src/app/main/ui/workspace/sidebar/history.cljs:137
+#: src/app/main/ui/workspace/sidebar/history.cljs:138
msgid "workspace.undo.entry.single.typography"
msgstr "typography asset"
-#: src/app/main/ui/workspace/sidebar/history.cljs:147
+#: src/app/main/ui/workspace/sidebar/history.cljs:148
msgid "workspace.undo.entry.unknown"
msgstr "Operation over %s"
@@ -6519,71 +6605,71 @@ msgstr "Operation over %s"
msgid "workspace.undo.title"
msgstr "History"
-#: src/app/main/data/workspace/libraries.cljs:1147, src/app/main/ui/workspace/sidebar/versions.cljs:285
+#: src/app/main/data/workspace/libraries.cljs:1159, src/app/main/ui/workspace/sidebar/versions.cljs:287
msgid "workspace.updates.dismiss"
msgstr "Dismiss"
-#: src/app/main/data/workspace/libraries.cljs:1145
+#: src/app/main/data/workspace/libraries.cljs:1157
msgid "workspace.updates.more-info"
msgstr "More info"
-#: src/app/main/data/workspace/libraries.cljs:1143
+#: src/app/main/data/workspace/libraries.cljs:1155
msgid "workspace.updates.there-are-updates"
msgstr "There are updates in shared libraries"
-#: src/app/main/data/workspace/libraries.cljs:1150
+#: src/app/main/data/workspace/libraries.cljs:1162
msgid "workspace.updates.update"
msgstr "Update"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:193
+#: src/app/main/ui/workspace/sidebar/versions.cljs:194
msgid "workspace.versions.autosaved.entry"
msgstr "%s autosave versions"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:187
+#: src/app/main/ui/workspace/sidebar/versions.cljs:188
msgid "workspace.versions.autosaved.version"
msgstr "Autosaved %s"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:224
+#: src/app/main/ui/workspace/sidebar/versions.cljs:225
msgid "workspace.versions.button.pin"
msgstr "Pin version"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:219
+#: src/app/main/ui/workspace/sidebar/versions.cljs:220
msgid "workspace.versions.button.restore"
msgstr "Restore version"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:345, src/app/main/ui/workspace/sidebar/versions.cljs:347
+#: src/app/main/ui/workspace/sidebar/versions.cljs:359, src/app/main/ui/workspace/sidebar/versions.cljs:361
msgid "workspace.versions.button.save"
msgstr "Save version"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:354
+#: src/app/main/ui/workspace/sidebar/versions.cljs:368
msgid "workspace.versions.empty"
msgstr "There are no versions yet"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:190
+#: src/app/main/ui/workspace/sidebar/versions.cljs:191
msgid "workspace.versions.expand-snapshot"
msgstr "Expand snapshots"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:327
+#: src/app/main/ui/workspace/sidebar/versions.cljs:341
msgid "workspace.versions.filter.all"
msgstr "All versions"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:326
+#: src/app/main/ui/workspace/sidebar/versions.cljs:340
msgid "workspace.versions.filter.label"
msgstr "Versions filter"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:328
+#: src/app/main/ui/workspace/sidebar/versions.cljs:342
msgid "workspace.versions.filter.mine"
msgstr "My versions"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:334
+#: src/app/main/ui/workspace/sidebar/versions.cljs:348
msgid "workspace.versions.filter.user"
msgstr "%s's versions"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:340
+#: src/app/main/ui/workspace/sidebar/versions.cljs:354
msgid "workspace.versions.loading"
msgstr "Loading..."
-#: src/app/main/ui/workspace/sidebar/versions.cljs:283
+#: src/app/main/ui/workspace/sidebar/versions.cljs:285
msgid "workspace.versions.restore-warning"
msgstr "Do you want to restore this version?"
@@ -6598,7 +6684,15 @@ msgstr "If you'd like to increase this limit, write to us at [support@penpot.app
msgid "workspace.versions.snapshot-menu"
msgstr "Open snapshot menu"
-#: src/app/main/ui/workspace/sidebar/versions.cljs:138
+#: src/app/main/ui/workspace/sidebar.cljs:242
+msgid "workspace.versions.tab.actions"
+msgstr "Actions"
+
+#: src/app/main/ui/workspace/sidebar.cljs:241
+msgid "workspace.versions.tab.history"
+msgstr "History"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:139
msgid "workspace.versions.version-menu"
msgstr "Open version menu"
@@ -6606,8 +6700,59 @@ msgstr "Open version menu"
msgid "workspace.viewport.click-to-close-path"
msgstr "Click to close the path"
-msgid "workspace.versions.tab.history"
-msgstr "History"
+msgid "dashboard.notifications.notifications-saved"
+msgstr "Notification settings updated"
-msgid "workspace.versions.tab.actions"
-msgstr "Actions"
+msgid "title.settings.notifications"
+msgstr "Notifications - Penpot"
+
+msgid "dashboard.settings.notifications.title"
+msgstr "Notifications"
+
+msgid "dashboard.settings.notifications.dashboard.title"
+msgstr "Dashboard Notifications"
+
+msgid "dashboard.settings.notifications.dashboard-comments.title"
+msgstr "File comments"
+
+msgid "dashboard.settings.notifications.dashboard-comments.all"
+msgstr "All comments, mentions and replies"
+
+msgid "dashboard.settings.notifications.dashboard-comments.partial"
+msgstr "Only mentions and replies"
+
+msgid "dashboard.settings.notifications.dashboard-comments.none"
+msgstr "None"
+
+msgid "dashboard.settings.notifications.email.title"
+msgstr "Email Notifications"
+
+msgid "dashboard.settings.notifications.email-comments.title"
+msgstr "File comments"
+
+msgid "dashboard.settings.notifications.email-comments.all"
+msgstr "All comments, mentions and replies"
+
+msgid "dashboard.settings.notifications.email-comments.partial"
+msgstr "Only mentions and replies"
+
+msgid "dashboard.settings.notifications.email-comments.none"
+msgstr "None"
+
+msgid "dashboard.settings.notifications.email-invites.title"
+msgstr "Invites and requests"
+
+msgid "dashboard.settings.notifications.email-invites.all"
+msgstr "All types of invites and requests"
+
+msgid "dashboard.settings.notifications.email-invites.none"
+msgstr "None"
+
+msgid "dashboard.settings.notifications.submit"
+msgstr "Update settings"
+
+msgid "labels.notifications"
+msgstr "Notifications"
+
+msgid "comments.mentions.not-found"
+msgstr "No people found for @%s"
diff --git a/frontend/translations/es.po b/frontend/translations/es.po
index d8cb5e6ef7..df0f5dc8ed 100644
--- a/frontend/translations/es.po
+++ b/frontend/translations/es.po
@@ -759,6 +759,14 @@ msgstr "No se encuentra “%s“"
msgid "dashboard.no-projects-placeholder"
msgstr "Los proyectos fijados aparecerán aquí"
+#: src/app/main/ui/dashboard/comments.cljs
+msgid "dashboard.notifications"
+msgstr "Notificaciones"
+
+#: src/app/main/ui/dashboard/comments.cljs
+msgid "dashboard.notifications.view"
+msgstr "Ver notificaciones"
+
#: src/app/main/ui/auth/verify_token.cljs:32
msgid "dashboard.notifications.email-changed-successfully"
msgstr "Tu dirección de correo ha sido actualizada"
@@ -1634,6 +1642,13 @@ msgstr "Cerrar"
msgid "labels.collapse"
msgstr "Colapsar"
+msgid "labels.comment"
+msgstr "Comentario"
+
+#: src/app/main/ui/comments.cljs:446
+msgid "labels.comment.mark-as-solved"
+msgstr "Marcar como resuelto"
+
#: src/app/main/ui/dashboard/comments.cljs:104, src/app/main/ui/viewer/comments.cljs:70, src/app/main/ui/workspace/comments.cljs:127
msgid "labels.comments"
msgstr "Comentarios"
@@ -1957,6 +1972,10 @@ msgstr "Contraseña"
msgid "labels.pending-invitation"
msgstr "Pendiente"
+#: src/app/main/ui/comments.cljs:147
+msgid "labels.post"
+msgstr "Publicar"
+
#: src/app/main/ui/onboarding/questions.cljs:51
msgid "labels.previous"
msgstr "Anterior"
@@ -2003,6 +2022,26 @@ msgstr "Renombrar"
msgid "labels.rename-team"
msgstr "Renombra el equipo"
+#: src/app/main/ui/comments.cljs:145
+msgid "labels.reply"
+msgstr "respuesta"
+
+#: src/app/main/ui/comments.cljs:150
+msgid "labels.reply.new"
+msgstr "nueva respuesta"
+
+#: src/app/main/ui/comments.cljs:188
+msgid "labels.reply.thread"
+msgstr "Responder"
+
+#: src/app/main/ui/comments.cljs:146
+msgid "labels.replies"
+msgstr "respuestas"
+
+#: src/app/main/ui/comments.cljs:151
+msgid "labels.replies.new"
+msgstr "nuevas respuestas"
+
#: src/app/main/ui/dashboard/team.cljs:681
msgid "labels.resend-invitation"
msgstr "Reenviar invitacion"
@@ -2083,6 +2122,9 @@ msgstr "Mostrar lista de comentarios"
msgid "labels.show-your-comments"
msgstr "Mostrar sólo tus comentarios"
+msgid "labels.show-mentions"
+msgstr "Mostrar sólo tus menciones"
+
#: src/app/main/ui/onboarding/questions.cljs:167
msgid "labels.sketch"
msgstr "Sketch"
@@ -3341,6 +3383,9 @@ msgstr "Limpiar historial"
msgid "shortcuts.copy"
msgstr "Copiar"
+msgid "shortcuts.copy-link"
+msgstr "Copiar enlace al portapapeles"
+
#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:94
msgid "shortcuts.create-component"
msgstr "Crear componente"
@@ -5940,6 +5985,9 @@ msgstr "Enviar atrás"
msgid "workspace.shape.menu.copy"
msgstr "Copiar"
+msgid "workspace.shape.menu.copy_link"
+msgstr "Copiar enlace al portapapeles"
+
#: src/app/main/ui/workspace/sidebar/assets/common.cljs:427
msgid "workspace.shape.menu.create-annotation"
msgstr "Crear una nota"
@@ -6607,3 +6655,60 @@ msgstr "Histórico"
msgid "workspace.versions.tab.actions"
msgstr "Acciones"
+
+msgid "dashboard.notifications.notifications-saved"
+msgstr "Configuración de notificaciones actualizada"
+
+msgid "title.settings.notifications"
+msgstr "Notificaciones - Penpot"
+
+msgid "dashboard.settings.notifications.title"
+msgstr "Notificaciones"
+
+msgid "dashboard.settings.notifications.dashboard.title"
+msgstr "Notificaciones en el panel"
+
+msgid "dashboard.settings.notifications.dashboard-comments.title"
+msgstr "Comentarios de ficheros"
+
+msgid "dashboard.settings.notifications.dashboard-comments.all"
+msgstr "Todos los comentarios, menciones y respuestas"
+
+msgid "dashboard.settings.notifications.dashboard-comments.partial"
+msgstr "Sólo menciones y respuestas"
+
+msgid "dashboard.settings.notifications.dashboard-comments.none"
+msgstr "Ninguna"
+
+msgid "dashboard.settings.notifications.email.title"
+msgstr "Notificaciones de correo electrónico"
+
+msgid "dashboard.settings.notifications.email-comments.title"
+msgstr "Comentarios de ficheros"
+
+msgid "dashboard.settings.notifications.email-comments.all"
+msgstr "Todos los comentarios, menciones y respuestas"
+
+msgid "dashboard.settings.notifications.email-comments.partial"
+msgstr "Sólo menciones y respuestas"
+
+msgid "dashboard.settings.notifications.email-comments.none"
+msgstr "Ninguna"
+
+msgid "dashboard.settings.notifications.email-invites.title"
+msgstr "Invitaciones y solicitudes"
+
+msgid "dashboard.settings.notifications.email-invites.all"
+msgstr "Todas las invitaciones y solicitudes"
+
+msgid "dashboard.settings.notifications.email-invites.none"
+msgstr "Ninguna"
+
+msgid "dashboard.settings.notifications.submit"
+msgstr "Actualizar configuración"
+
+msgid "labels.notifications"
+msgstr "Notificaciones"
+
+msgid "comments.mentions.not-found"
+msgstr "No se encuentra miembros con @%s"
diff --git a/frontend/translations/he.po b/frontend/translations/he.po
index a275e7962d..bc626150da 100644
--- a/frontend/translations/he.po
+++ b/frontend/translations/he.po
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
-"PO-Revision-Date: 2024-11-14 11:14+0000\n"
-"Last-Translator: Anonymous \n"
+"PO-Revision-Date: 2024-11-17 14:00+0000\n"
+"Last-Translator: Yaron Shahrabani \n"
"Language-Team: Hebrew \n"
"Language: he\n"
@@ -5527,9 +5527,11 @@ msgid "workspace.plugins.permissions.content-write"
msgstr "קריאה ושינוי התוכן של קבצים שלמשתמשים יש גישה אליהם."
#: src/app/main/ui/workspace/plugins.cljs:323
-#, fuzzy
msgid "workspace.plugins.permissions.disclaimer"
-msgstr "נא לשים לב שהתוסף הזה נוצר על ידי גוף חיצוני."
+msgstr ""
+"נא לשים לב שהתוסף הזה נוצר על ידי גוף חיצוני, לכן כדאי לוודא שהוא אמין לפי "
+"שמעניקים לו גישה. פרטיות ואבטחת המידע שלך חשובים לנו. במקרה של ספק נא ליצור "
+"קשר עם התמיכה."
#: src/app/main/ui/workspace/plugins.cljs:263
msgid "workspace.plugins.permissions.library-read"
@@ -5540,9 +5542,8 @@ msgid "workspace.plugins.permissions.library-write"
msgstr "קריאה ושינוי הספריות והמשאבים שלך."
#: src/app/main/ui/workspace/plugins.cljs:316
-#, fuzzy
msgid "workspace.plugins.permissions.title"
-msgstr "התוסף הזה רוצה לגשת אל:"
+msgstr "התוסף ‚%s’ רוצה לגשת אל:"
#: src/app/main/ui/workspace/plugins.cljs:250
msgid "workspace.plugins.permissions.user-read"
@@ -6060,3 +6061,449 @@ msgstr "עדכון"
#, unused
msgid "workspace.viewport.click-to-close-path"
msgstr "לחיצה תסגור את הנתיב"
+
+#: src/app/main/ui/dashboard/files.cljs:190, src/app/main/ui/dashboard/projects.cljs:284
+msgid "dashboard.empty-placeholder-drafts-subtitle"
+msgstr "כשאחד או אחת מחברי הצוות יוצרים טיוטה, היא תוצג כאן."
+
+#: src/app/main/ui/dashboard/files.cljs:186, src/app/main/ui/dashboard/projects.cljs:280
+msgid "dashboard.empty-placeholder-files-title"
+msgstr "אין קבצים עדיין."
+
+#: src/app/main/ui/dashboard/files.cljs:185, src/app/main/ui/dashboard/projects.cljs:279
+msgid "dashboard.empty-placeholder-drafts-title"
+msgstr "אין טיוטות עדיין."
+
+#: src/app/main/ui/dashboard/files.cljs:191, src/app/main/ui/dashboard/projects.cljs:285
+msgid "dashboard.empty-placeholder-files-subtitle"
+msgstr "כשחבר או חברה במיזם יוצרים קובץ, הוא יופיע כאן."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:35
+msgid "dashboard.empty-placeholder-libraries-subtitle-viewer-role"
+msgstr "ספריות שנוספו למיזם תופענה כאן."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:39
+#, markdown
+msgid "dashboard.empty-placeholder-libraries"
+msgstr ""
+"ספריות שנוספו למיזם תופענה כאן. כדאי לנסות לשתף את הקבצים שלך או להוסיף מ["
+"הספריות והתבניות](https://penpot.app/libraries-templates) שלנו."
+
+#: src/app/main/data/common.cljs:205
+msgid "dashboard.permissions-change.admin"
+msgstr "מונית לנהל את הצוות הזה."
+
+#: src/app/main/data/common.cljs:204
+msgid "dashboard.permissions-change.editor"
+msgstr "מונית לערוך בצוות הזה."
+
+#: src/app/main/data/common.cljs:206
+msgid "dashboard.permissions-change.owner"
+msgstr "מונית לבעלי הצוות הזה."
+
+#: src/app/main/ui/workspace/libraries.cljs:304
+msgid "workspace.libraries.more-templates-link"
+msgstr "תבניות נוספות כאן"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:195
+msgid "workspace.options.export.add-export"
+msgstr "הוספת ייצוא"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:150
+msgid "workspace.options.fill.add-fill"
+msgstr "הוספת צבע מילוי"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:176, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:182
+msgid "workspace.options.layer-options.toggle-layer"
+msgstr "הצגת/הסתרת שכבה"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:184
+msgid "workspace.options.stroke.remove-stroke"
+msgstr "הסרת מתאר"
+
+#: src/app/main/ui/workspace/plugins.cljs:196
+msgid "workspace.plugins.error.manifest"
+msgstr "המצהר/מניפסט של התוסף שגוי."
+
+#: src/app/main/ui/workspace/plugins.cljs:376
+msgid "workspace.plugins.permissions-update.warning"
+msgstr "התוסף הזה השתנה מאז שפתחת אותו. עכשיו הוא רוצה גם לגשת אל:"
+
+#: src/app/main/ui/workspace/plugins.cljs:283
+msgid "workspace.plugins.permissions.allow-download"
+msgstr "התחלת הורדות קבצים."
+
+#: src/app/main/ui/workspace/plugins.cljs:372
+msgid "workspace.plugins.permissions-update.title"
+msgstr "לעדכן את התוסף הזה"
+
+#: src/app/main/ui/workspace/plugins.cljs:270
+msgid "workspace.plugins.permissions.comment-write"
+msgstr "לקרוא ולשנות את ההערות שלך ולהגיב בשמך."
+
+#: src/app/main/ui/workspace/plugins.cljs:86
+msgid "workspace.plugins.remove-plugin"
+msgstr "הסרת תוסף"
+
+#: src/app/main/ui/workspace/plugins.cljs:442
+msgid "workspace.plugins.try-out.try"
+msgstr "התנסות בתוסף"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1004, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1030
+msgid "workspace.shape.menu.add-layout"
+msgstr "הוספת פריסה"
+
+#: src/app/main/ui/workspace/sidebar/sitemap.cljs:229
+msgid "workspace.sidebar.sitemap.add-page"
+msgstr "הוספת עמוד"
+
+#: src/app/main/ui/workspace/tokens/form.cljs:361
+msgid "workspace.token.edit-token"
+msgstr "עריכת אסימון"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:186
+msgid "workspace.token.grouping-set-alert"
+msgstr "אין עדיין תמיכה בקיבוץ סדרות אסימונים."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:52
+msgid "workspace.token.new-theme"
+msgstr "ערכת עיצוב חדשה"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:88
+msgid "workspace.token.no-active-theme"
+msgstr "אין ערכת עיצוב פעילה"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:133
+msgid "workspace.token.num-sets"
+msgstr "%s סדרות"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:66
+msgid "workspace.token.original-value"
+msgstr "ערך מקורי: "
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:43
+msgid "workspace.token.no-themes-currently"
+msgstr "אין לך ערכות עיצוב עדיין."
+
+#: src/app/main/ui/workspace/tokens/form.cljs:193, src/app/main/ui/workspace/tokens/form.cljs:196, src/app/main/ui/workspace/tokens/sidebar.cljs:67
+msgid "workspace.token.resolved-value"
+msgstr "ערך פתור: "
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:208
+msgid "workspace.token.save-theme"
+msgstr "שמירת ערכת עיצוב"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:172
+msgid "workspace.token.select-set"
+msgstr "בחירה ערכה."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:39, src/app/main/ui/workspace/tokens/modals/themes.cljs:84
+msgid "workspace.token.themes"
+msgstr "ערכות עיצוב"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs
+#, unused
+msgid "workspace.token.theme-name"
+msgstr "ערכת עיצוב %s"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:334
+msgid "workspace.versions.filter.user"
+msgstr "הגרסה של %s"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:328
+msgid "workspace.versions.filter.mine"
+msgstr "הגרסאות שלי"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:326
+msgid "workspace.versions.filter.label"
+msgstr "מסנן גרסאות"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:327
+msgid "workspace.versions.filter.all"
+msgstr "כל הגרסאות"
+
+#: src/app/main/ui/dashboard/placeholder.cljs:32
+msgid "dashboard.empty-placeholder-libraries-title"
+msgstr "אין ספריות עדיין."
+
+#: src/app/main/ui/dashboard/fonts.cljs:444
+msgid "dashboard.fonts.empty-placeholder-viewer"
+msgstr "אין גופנים מותאמים אישית עדיין."
+
+#: src/app/main/ui/dashboard/team.cljs:944
+msgid "dashboard.webhooks.cant-edit"
+msgstr "אפשר למחוק או לשנות את ההתליות שיצרת."
+
+#: src/app/main/ui/comments.cljs:340, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:295, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:324
+msgid "labels.options"
+msgstr "אפשרויות"
+
+#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:495
+msgid "workspace.assets.colors.add-color"
+msgstr "הוספת צבע"
+
+#: src/app/main/ui/workspace/sidebar/assets/typographies.cljs:408
+msgid "workspace.assets.typography.add-typography"
+msgstr "הוספת טיפוגרפיה"
+
+#: src/app/main/ui/workspace/right_header.cljs:255
+msgid "workspace.header.share"
+msgstr "שיתוף"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:735
+msgid "workspace.options.interactions.add-interaction"
+msgstr "הוספת אינטראקציה"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:173
+msgid "workspace.options.shadow-options.toggle-shadow"
+msgstr "הצגת/הסתרת הצללה"
+
+#: src/app/main/ui/workspace/plugins.cljs:436
+msgid "workspace.plugins.try-out.cancel"
+msgstr "לא עכשיו"
+
+#: src/app/main/ui/workspace/plugins.cljs:425
+msgid "workspace.plugins.try-out.title"
+msgstr "תוסף ‚%s’ מותקן למשתמש שלך!"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1022
+msgid "workspace.shape.menu.remove-layout"
+msgstr "הסרת פריסה"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:216
+msgid "workspace.token.no-sets-create"
+msgstr "עדיין לא מוגדרות סדרות. נא ליצור אחת קודם."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:142
+msgid "workspace.token.no-sets"
+msgstr "אין סדרות"
+
+#: src/app/main/ui/workspace/tokens/form.cljs:362
+msgid "workspace.token.create-token"
+msgstr "יצירת אסימון %s חדש"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:155, src/app/main/ui/workspace/tokens/modals/themes.cljs:239
+msgid "workspace.token.create-theme-title"
+msgstr "יצירת ערכת עיצוב"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:194, src/app/main/ui/workspace/tokens/sidebar.cljs:210
+msgid "workspace.token.create-one"
+msgstr "ליצור אחד."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:47
+msgid "workspace.token.create-new-theme"
+msgstr "אפשר ליצור את ערכת העיצוב הראשונה שלך עכשיו."
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:187
+msgid "workspace.versions.autosaved.version"
+msgstr "%s נשמר אוטומטית"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:193
+msgid "workspace.versions.autosaved.entry"
+msgstr "%s גרסאות שנשמרות אוטומטית"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:138
+msgid "workspace.versions.version-menu"
+msgstr "פתיחת תפריט גרסאות"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:190
+msgid "workspace.versions.expand-snapshot"
+msgstr "הרחבת תמונות מצב"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:207
+msgid "workspace.versions.snapshot-menu"
+msgstr "פתיחת תפריט תמונת מצב"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:283
+msgid "workspace.versions.restore-warning"
+msgstr "לשחזר את הגרסה הזאת?"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:340
+msgid "workspace.versions.loading"
+msgstr "בטעינה…"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:219
+msgid "workspace.versions.button.restore"
+msgstr "שחזור גרסה"
+
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:532
+msgid "workspace.assets.components.add-component"
+msgstr "הוספת רכיב"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:345, src/app/main/ui/workspace/sidebar/versions.cljs:347
+msgid "workspace.versions.button.save"
+msgstr "שמירת גרסה"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:354
+msgid "workspace.versions.empty"
+msgstr "אין גרסאות עדיין"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:224
+msgid "workspace.versions.button.pin"
+msgstr "נעיצת גרסה"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:191
+msgid "workspace.token.no-themes"
+msgstr "אין ערכות עיצוב."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:239
+msgid "workspace.token.no-sets-yet"
+msgstr "אין סדרות עדיין."
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1051
+#, unused
+msgid "labels.add"
+msgstr "הוספה"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:149, src/app/main/ui/workspace/sidebar/versions.cljs:288
+msgid "labels.restore"
+msgstr "שחזור"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:153
+msgid "labels.collapse"
+msgstr "צמצום"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:229
+msgid "labels.sets"
+msgstr "סדרות"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:187
+msgid "labels.themes"
+msgstr "ערכות עיצוב"
+
+#: src/app/main/ui/dashboard/team.cljs:216
+msgid "modals.invite-team-member.text"
+msgstr ""
+"אפשר להזמין חברים לצוות כדי שיוכלו לגשת לקובץ הזה ולהיחשף לכל שאר קובצי "
+"הצוות."
+
+#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:271
+msgid "settings.remove-color"
+msgstr "הסרת צבע"
+
+#: src/app/main/ui/workspace/libraries.cljs:300
+msgid "workspace.libraries.more-templates"
+msgstr "אפשר לחפש "
+
+#: src/app/main/data/common.cljs:203
+msgid "dashboard.permissions-change.viewer"
+msgstr "מונית לצפות בצוות הזה."
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:108
+msgid "workspace.options.blur-options.toggle-blur"
+msgstr "החלת/הסרת טשטוש"
+
+#: src/app/main/data/common.cljs:233
+msgid "dashboard.removed-from-team"
+msgstr "נגרעת מהצוות „%s”."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:318
+msgid "workspace.token.set-selection-theme"
+msgstr "נא להגדיר באילו סדרות אסימונים להשתמש כחלק מאפשרות ערכת העיצוב הזאת:"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:154
+msgid "workspace.options.flows.remove-flow"
+msgstr "הסרת זרימה"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
+#, unused
+msgid "workspace.options.interactions.remove-interaction"
+msgstr "הסרת אינטראקציה"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:91
+msgid "workspace.options.blur-options.add-blur"
+msgstr "הוספת טשטוש"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:323
+msgid "workspace.options.guides.add-guide"
+msgstr "הוספת קו מנחה"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:302
+msgid "workspace.options.shadow-options.add-shadow"
+msgstr "הוספת הצללה"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:310
+msgid "workspace.token.back-to-themes"
+msgstr "חזרה לרשימת ערכות העיצוב"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:112
+msgid "workspace.options.blur-options.remove-blur"
+msgstr "הסרת טשטוש"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:207, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:242
+msgid "workspace.options.export.remove-export"
+msgstr "הסרת ייצוא"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:163
+msgid "workspace.options.fill.remove-fill"
+msgstr "הסרת מילוי"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:187
+msgid "workspace.options.guides.remove-guide"
+msgstr "הסרת קו מנחה"
+
+#: src/app/main/ui/workspace/plugins.cljs:276
+msgid "workspace.plugins.permissions.comment-read"
+msgstr "קריאת התגובות שלך ומתן מענה עליהן."
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:183
+msgid "workspace.options.guides.toggle-guide"
+msgstr "הצגת/הסתרת קו מנחה"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:171
+msgid "workspace.options.stroke.add-stroke"
+msgstr "הוספת צבע מתאר"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:177, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:315
+msgid "workspace.options.shadow-options.remove-shadow"
+msgstr "הסרת הצללה"
+
+#: src/app/main/ui/workspace/plugins.cljs:429
+msgid "workspace.plugins.try-out.message"
+msgstr ""
+"מעניין אותך להציץ? בחירה בזה תיפתח בטיוטה חדשה לצוות הנוכחי שלך. (אם לא, "
+"תמיד אפשר למצוא אותו בתוספים המותקנים של כל קובץ שהוא.)"
+
+#: src/app/main/data/plugins.cljs:86, src/app/main/ui/workspace/main_menu.cljs:696, src/app/main/ui/workspace/plugins.cljs:82
+msgid "workspace.plugins.error.need-editor"
+msgstr "צריך הרשאות עריכה כדי להשתמש בתוסף הזה"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:84
+msgid "workspace.token.active-themes"
+msgstr "%s ערכות עיצוב פעילות"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs
+#, unused
+msgid "workspace.token.add set"
+msgstr "הוספת סדרה"
+
+#: src/app/main/ui/workspace/context_menu.cljs:235
+msgid "workspace.shape.menu.rename"
+msgstr "שינוי שם"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:302
+msgid "workspace.token.edit-theme-title"
+msgstr "עריכת ערכת עיצוב"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:147
+msgid "workspace.token.delete-theme-title"
+msgstr "מחיקת ערכת עיצוב"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:72
+msgid "workspace.token.edit-themes"
+msgstr "עריכת ערכות עיצוב"
+
+#: src/app/main/ui/dashboard/fonts.cljs:445
+msgid "dashboard.fonts.empty-placeholder-viewer-sub"
+msgstr "לאחר העלאת גופן בהתאמה אישית על ידי חברים, הוא יוצג כאן."
+
+#: src/app/main/ui/dashboard/placeholder.cljs
+#, markdown, unused
+msgid "dashboard.empty-placeholder-libraries-subtitle"
+msgstr ""
+"ספריות שנוספו למיזם תופענה כאן. כדאי לנסות לשתף את הקבצים שלך או להוסיף מ["
+"הספריות והתבניות](https://penpot.app/libraries-templates) שלנו."
+
+#: src/app/main/ui/dashboard/team.cljs:181, src/app/main/ui/onboarding/team_choice.cljs:100
+msgid "errors.maximum-invitations-by-request-reached"
+msgstr "הגעת למספר הכתובות המרבי (%s) שאפשר להזמין בבקשה אחת"
diff --git a/frontend/translations/id.po b/frontend/translations/id.po
index d1a6b3ca04..c2db2c50df 100644
--- a/frontend/translations/id.po
+++ b/frontend/translations/id.po
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
-"PO-Revision-Date: 2024-11-14 11:14+0000\n"
-"Last-Translator: Anonymous \n"
+"PO-Revision-Date: 2024-11-27 13:02+0000\n"
+"Last-Translator: Linerly \n"
"Language-Team: Indonesian \n"
"Language: id\n"
@@ -335,7 +335,6 @@ msgid "dashboard.access-tokens.create-success"
msgstr "Token akses berhasil dibuat."
#: src/app/main/ui/settings/access_tokens.cljs:65
-#, fuzzy
msgid "dashboard.access-tokens.create.success"
msgstr " "
@@ -1053,7 +1052,6 @@ msgstr ""
"tinggi)."
#: src/app/main/errors.cljs:228
-#, fuzzy
msgid "errors.migration-in-progress"
msgstr " "
@@ -1157,7 +1155,6 @@ msgid "errors.wrong-old-password"
msgstr "Kata sandi lama tidak benar"
#: src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:85
-#, fuzzy
msgid "exclude"
msgstr " "
@@ -1465,7 +1462,6 @@ msgid "inspect.tabs.info"
msgstr "Info"
#: src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:80
-#, fuzzy
msgid "intersection"
msgstr " "
@@ -2156,7 +2152,6 @@ msgid "modals.create-access-token.title"
msgstr "Buat token baru"
#: src/app/main/ui/settings/access_tokens.cljs:152
-#, fuzzy
msgid "modals.create-access-token.token"
msgstr " "
@@ -3646,7 +3641,6 @@ msgid "shortcuts.toggle-rulers"
msgstr "Tampilkan / Sembunyikan penggaris"
#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:199
-#, fuzzy
msgid "shortcuts.toggle-rules"
msgstr " "
@@ -5574,9 +5568,11 @@ msgid "workspace.plugins.permissions.content-write"
msgstr "Membaca dan mengubah konten berkas yang dapat diakses pengguna."
#: src/app/main/ui/workspace/plugins.cljs:323
-#, fuzzy
msgid "workspace.plugins.permissions.disclaimer"
-msgstr "Dicatat bahwa plugin ini telah dibuat oleh pihak eksternal."
+msgstr ""
+"Harap diingat bahwa plugin ini dibuat oleh pihak eksternal, jadi pastikan "
+"Anda mempercayainya sebelum memberikan akses. Privasi dan keamanan data Anda "
+"penting bagi kami. Jika Anda memiliki masalah, silakan hubungi dukungan."
#: src/app/main/ui/workspace/plugins.cljs:263
msgid "workspace.plugins.permissions.library-read"
@@ -5587,9 +5583,8 @@ msgid "workspace.plugins.permissions.library-write"
msgstr "Membaca dan mengubah pustaka dan aset Anda."
#: src/app/main/ui/workspace/plugins.cljs:316
-#, fuzzy
msgid "workspace.plugins.permissions.title"
-msgstr "PLUGIN INI MEMINTA AKSES KE:"
+msgstr "PLUGIN '%s' MEMINTA AKSES:"
#: src/app/main/ui/workspace/plugins.cljs:250
msgid "workspace.plugins.permissions.user-read"
@@ -6107,3 +6102,461 @@ msgstr "Perbarui"
#, unused
msgid "workspace.viewport.click-to-close-path"
msgstr "Klik untuk menutup jalur"
+
+#: src/app/main/ui/dashboard/files.cljs:185, src/app/main/ui/dashboard/projects.cljs:279
+msgid "dashboard.empty-placeholder-drafts-title"
+msgstr "Belum ada draf."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:119
+msgid "workspace.token.theme"
+msgstr " "
+
+#: src/app/main/ui/dashboard/fonts.cljs:445
+msgid "dashboard.fonts.empty-placeholder-viewer-sub"
+msgstr ""
+"Ketika anggota proyek mengunggah fon kustom, itu akan ditampilkan di sini."
+
+#: src/app/main/data/common.cljs:205
+msgid "dashboard.permissions-change.admin"
+msgstr "Anda sekarang seorang admin di tim ini."
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1051
+#, unused
+msgid "labels.add"
+msgstr "Tambahkan"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:153
+msgid "labels.collapse"
+msgstr "Tutup"
+
+#: src/app/main/ui/dashboard/placeholder.cljs:39
+#, markdown
+msgid "dashboard.empty-placeholder-libraries"
+msgstr ""
+"Pustaka yang ditambahkan ke proyek akan muncul di sini. Coba membagikan "
+"berkas Anda atau tambahkan dari [Pustaka dan tempat] (https://penpot.app/"
+"libraries-templates) kami."
+
+#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:271
+msgid "settings.remove-color"
+msgstr "Hapus warna"
+
+#: src/app/main/ui/dashboard/placeholder.cljs
+#, markdown, unused
+msgid "dashboard.empty-placeholder-libraries-subtitle"
+msgstr ""
+"Pustaka yang ditambahkan ke proyek akan muncul di sini. Coba membagikan "
+"berkas Anda atau tambahkan dari [Pustaka dan tempat] (https://penpot.app/"
+"libraries-templates) kami."
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:149, src/app/main/ui/workspace/sidebar/versions.cljs:288
+msgid "labels.restore"
+msgstr "Pulihkan"
+
+#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:495
+msgid "workspace.assets.colors.add-color"
+msgstr "Tambahkan warna"
+
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:532
+msgid "workspace.assets.components.add-component"
+msgstr "Tambahkan komponen"
+
+#: src/app/main/ui/workspace/libraries.cljs:304
+msgid "workspace.libraries.more-templates-link"
+msgstr "lebih banyak tempat di sini"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:108
+msgid "workspace.options.blur-options.toggle-blur"
+msgstr "Sakelar buram"
+
+#: src/app/main/ui/workspace/sidebar/assets/typographies.cljs:408
+msgid "workspace.assets.typography.add-typography"
+msgstr "Tambahkan tipografi"
+
+#: src/app/main/ui/workspace/right_header.cljs:255
+msgid "workspace.header.share"
+msgstr "Bagikan"
+
+#: src/app/main/ui/workspace/plugins.cljs:372
+msgid "workspace.plugins.permissions-update.title"
+msgstr "PERBARUI PLUGIN INI"
+
+#: src/app/main/data/plugins.cljs:86, src/app/main/ui/workspace/main_menu.cljs:696, src/app/main/ui/workspace/plugins.cljs:82
+msgid "workspace.plugins.error.need-editor"
+msgstr "Anda perlu menjadi penyunting untuk menggunakan plugin ini"
+
+#: src/app/main/ui/workspace/plugins.cljs:270
+msgid "workspace.plugins.permissions.comment-write"
+msgstr "Membaca dan mengubah komentar Anda dan membalas dengan nama Anda."
+
+#: src/app/main/ui/workspace/plugins.cljs:442
+msgid "workspace.plugins.try-out.try"
+msgstr "COBA PLUGIN"
+
+#: src/app/main/ui/workspace/plugins.cljs:429
+msgid "workspace.plugins.try-out.message"
+msgstr ""
+"Ingin melihat? Ini akan membuka dalam draf baru untuk tim Anda saat ini. ("
+"Jika tidak, Anda selalu dapat mencarinya dalam plugin terpasang dalam berkas "
+"apa pun.)"
+
+#: src/app/main/ui/workspace/plugins.cljs:425
+msgid "workspace.plugins.try-out.title"
+msgstr "PLUGIN '%s' TERPASANG UNTUK PENGGUNA ANDA!"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1004, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1030
+msgid "workspace.shape.menu.add-layout"
+msgstr "Tambahkan tata letak"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:66
+msgid "workspace.token.original-value"
+msgstr "Nilai asli: "
+
+#: src/app/main/ui/workspace/tokens/form.cljs:193, src/app/main/ui/workspace/tokens/form.cljs:196, src/app/main/ui/workspace/tokens/sidebar.cljs:67
+msgid "workspace.token.resolved-value"
+msgstr "Nilai terselesaikan: "
+
+#: src/app/main/ui/workspace/tokens/form.cljs:362
+msgid "workspace.token.create-token"
+msgstr "Buat token %s baru"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:302
+msgid "workspace.token.edit-theme-title"
+msgstr "Sunting tema"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:147
+msgid "workspace.token.delete-theme-title"
+msgstr "Hapus tema"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:72
+msgid "workspace.token.edit-themes"
+msgstr "Sunting tema"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:219
+msgid "workspace.versions.button.restore"
+msgstr "Pulihkan versi"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:354
+msgid "workspace.versions.empty"
+msgstr "Belum ada versi"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:187
+msgid "workspace.versions.autosaved.version"
+msgstr "%s disimpan otomatis"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:224
+msgid "workspace.versions.button.pin"
+msgstr "Sematkan versi"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:345, src/app/main/ui/workspace/sidebar/versions.cljs:347
+msgid "workspace.versions.button.save"
+msgstr "Simpan versi"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:190
+msgid "workspace.versions.expand-snapshot"
+msgstr "Buka snapshot"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:340
+msgid "workspace.versions.loading"
+msgstr "Memuat..."
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:283
+msgid "workspace.versions.restore-warning"
+msgstr "Apakah Anda ingin memulihkan versi ini?"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:138
+msgid "workspace.versions.version-menu"
+msgstr "Buka menu versi"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:207
+msgid "workspace.versions.snapshot-menu"
+msgstr "Buka menu snapshot"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:154
+msgid "workspace.options.flows.remove-flow"
+msgstr "Hapus alur"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:163
+msgid "workspace.options.fill.remove-fill"
+msgstr "Hapus isian"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:323
+msgid "workspace.options.guides.add-guide"
+msgstr "Tambahkan alur"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:176, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:182
+msgid "workspace.options.layer-options.toggle-layer"
+msgstr "Sakelar keterlihatan lapisan"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:187
+msgid "workspace.options.guides.remove-guide"
+msgstr "Hapus alur"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
+#, unused
+msgid "workspace.options.interactions.remove-interaction"
+msgstr "Hapus interaksi"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:173
+msgid "workspace.options.shadow-options.toggle-shadow"
+msgstr "Sakelar bayangan"
+
+#: src/app/main/ui/dashboard/files.cljs:191, src/app/main/ui/dashboard/projects.cljs:285
+msgid "dashboard.empty-placeholder-files-subtitle"
+msgstr "Ketika anggota proyek membuat berkas, itu akan ditampilkan di sini."
+
+#: src/app/main/ui/dashboard/files.cljs:190, src/app/main/ui/dashboard/projects.cljs:284
+msgid "dashboard.empty-placeholder-drafts-subtitle"
+msgstr "Ketika anggota proyek membuat draf, itu akan ditampilkan di sini."
+
+#: src/app/main/ui/dashboard/files.cljs:186, src/app/main/ui/dashboard/projects.cljs:280
+msgid "dashboard.empty-placeholder-files-title"
+msgstr "Belum ada berkas."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:35
+msgid "dashboard.empty-placeholder-libraries-subtitle-viewer-role"
+msgstr "Pustaka yang ditambahkan ke proyek akan muncul di sini."
+
+#: src/app/main/ui/dashboard/fonts.cljs:444
+msgid "dashboard.fonts.empty-placeholder-viewer"
+msgstr "Belum ada fon kustom."
+
+#: src/app/main/ui/dashboard/team.cljs:944
+msgid "dashboard.webhooks.cant-edit"
+msgstr "Anda hanya dapat menghapus atau mengubah webhook yang dibuat oleh Anda."
+
+#: src/app/main/ui/comments.cljs:340, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:295, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:324
+msgid "labels.options"
+msgstr "Opsi"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:229
+msgid "labels.sets"
+msgstr "Set"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:187
+msgid "labels.themes"
+msgstr "Tema"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:91
+msgid "workspace.options.blur-options.add-blur"
+msgstr "Tambahkan buram"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:112
+msgid "workspace.options.blur-options.remove-blur"
+msgstr "Hapus buram"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:177, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:315
+msgid "workspace.options.shadow-options.remove-shadow"
+msgstr "Hapus bayangan"
+
+#: src/app/main/ui/workspace/plugins.cljs:196
+msgid "workspace.plugins.error.manifest"
+msgstr "Manifes plugin tidak benar."
+
+#: src/app/main/ui/workspace/plugins.cljs:283
+msgid "workspace.plugins.permissions.allow-download"
+msgstr "Memulai pengunduhan berkas."
+
+#: src/app/main/ui/workspace/plugins.cljs:276
+msgid "workspace.plugins.permissions.comment-read"
+msgstr "Membaca komentar dan balasan Anda."
+
+#: src/app/main/ui/workspace/plugins.cljs:376
+msgid "workspace.plugins.permissions-update.warning"
+msgstr ""
+"Plugin ini telah diubah sejak terakhir kali Anda membukanya. Ini sekarang "
+"memerlukan akses:"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1022
+msgid "workspace.shape.menu.remove-layout"
+msgstr "Hapus tata letak"
+
+#: src/app/main/ui/workspace/context_menu.cljs:235
+msgid "workspace.shape.menu.rename"
+msgstr "Ubah nama"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:318
+msgid "workspace.token.set-selection-theme"
+msgstr "Tentukan set token apa yang digunakan sebagai bagian opsi tema ini:"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs
+#, unused
+msgid "workspace.token.theme-name"
+msgstr "Tema %s"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:39, src/app/main/ui/workspace/tokens/modals/themes.cljs:84
+msgid "workspace.token.themes"
+msgstr "Tema"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:327
+msgid "workspace.versions.filter.all"
+msgstr "Semua versi"
+
+#: src/app/main/ui/dashboard/placeholder.cljs:32
+msgid "dashboard.empty-placeholder-libraries-title"
+msgstr "Belum ada pustaka."
+
+#: src/app/main/data/common.cljs:204
+msgid "dashboard.permissions-change.editor"
+msgstr "Anda sekarang seorang penyunting di tim ini."
+
+#: src/app/main/data/common.cljs:206
+msgid "dashboard.permissions-change.owner"
+msgstr "Anda sekarang seorang pemilik di tim ini."
+
+#: src/app/main/data/common.cljs:203
+msgid "dashboard.permissions-change.viewer"
+msgstr "Anda sekarang seorang peninjau di tim ini."
+
+#: src/app/main/data/common.cljs:233
+msgid "dashboard.removed-from-team"
+msgstr "Anda bukan merupakan bagian dari tim “%s” lagi."
+
+#: src/app/main/ui/dashboard/team.cljs:181, src/app/main/ui/onboarding/team_choice.cljs:100
+msgid "errors.maximum-invitations-by-request-reached"
+msgstr ""
+"Jumlah email maksimum (%s) yang dapat diundang dalam satu permintaan telah "
+"tercapai"
+
+#: src/app/main/ui/dashboard/team.cljs:216
+msgid "modals.invite-team-member.text"
+msgstr ""
+"Anda dapat mengundang anggota ke tim supaya mereka dapat mengakses berkas "
+"ini dan semua berkas tim."
+
+#: src/app/main/ui/workspace/libraries.cljs:300
+msgid "workspace.libraries.more-templates"
+msgstr "Anda dapat mencari "
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:195
+msgid "workspace.options.export.add-export"
+msgstr "Tambahkan ekspor"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:207, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:242
+msgid "workspace.options.export.remove-export"
+msgstr "Hapus ekspor"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:150
+msgid "workspace.options.fill.add-fill"
+msgstr "Tambahkan warna isian"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:183
+msgid "workspace.options.guides.toggle-guide"
+msgstr "Sakelar pemandu"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:735
+msgid "workspace.options.interactions.add-interaction"
+msgstr "Tambahkan interaksi"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:302
+msgid "workspace.options.shadow-options.add-shadow"
+msgstr "Tambahkan bayangan"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:171
+msgid "workspace.options.stroke.add-stroke"
+msgstr "Tambahkan warna garis"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:184
+msgid "workspace.options.stroke.remove-stroke"
+msgstr "Hapus garis"
+
+#: src/app/main/ui/workspace/plugins.cljs:86
+msgid "workspace.plugins.remove-plugin"
+msgstr "Hapus plugin"
+
+#: src/app/main/ui/workspace/plugins.cljs:436
+msgid "workspace.plugins.try-out.cancel"
+msgstr "NANTI"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:310
+msgid "workspace.token.back-to-themes"
+msgstr "Kembali ke daftar tema"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs
+#, unused
+msgid "workspace.token.add set"
+msgstr "Tambahkan set"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:47
+msgid "workspace.token.create-new-theme"
+msgstr "Buat tema pertama Anda sekarang."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:194, src/app/main/ui/workspace/tokens/sidebar.cljs:210
+msgid "workspace.token.create-one"
+msgstr "Buat baru."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:155, src/app/main/ui/workspace/tokens/modals/themes.cljs:239
+msgid "workspace.token.create-theme-title"
+msgstr "Buat tema"
+
+#: src/app/main/ui/workspace/tokens/form.cljs:361
+msgid "workspace.token.edit-token"
+msgstr "Sunting token"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:186
+msgid "workspace.token.grouping-set-alert"
+msgstr "Pengelompokan Set Token belum didukung."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:52
+msgid "workspace.token.new-theme"
+msgstr "Tema baru"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:88
+msgid "workspace.token.no-active-theme"
+msgstr "Tidak ada tema aktif"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:142
+msgid "workspace.token.no-sets"
+msgstr "Tidak ada set"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:216
+msgid "workspace.token.no-sets-create"
+msgstr "Belum ada set yang ditetapkan. Buatlah terlebih dahulu."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:239
+msgid "workspace.token.no-sets-yet"
+msgstr "Belum ada set."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:191
+msgid "workspace.token.no-themes"
+msgstr "Belum ada tema."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:43
+msgid "workspace.token.no-themes-currently"
+msgstr "Anda saat ini belum memiliki tema."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:133
+msgid "workspace.token.num-sets"
+msgstr "%s set"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:208
+msgid "workspace.token.save-theme"
+msgstr "Simpan tema"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:172
+msgid "workspace.token.select-set"
+msgstr "Pilih set."
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:193
+msgid "workspace.versions.autosaved.entry"
+msgstr "%s versi tersimpan otomatis"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:326
+msgid "workspace.versions.filter.label"
+msgstr "Saringan versi"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:328
+msgid "workspace.versions.filter.mine"
+msgstr "Versi saya"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:334
+msgid "workspace.versions.filter.user"
+msgstr "Versi %s"
+
+#: src/app/main/ui/workspace/sidebar/sitemap.cljs:229
+msgid "workspace.sidebar.sitemap.add-page"
+msgstr "Tambahkan halaman"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:84
+msgid "workspace.token.active-themes"
+msgstr "%s tema aktif"
diff --git a/frontend/translations/it.po b/frontend/translations/it.po
index d20c96dfa4..4d6664918a 100644
--- a/frontend/translations/it.po
+++ b/frontend/translations/it.po
@@ -1,15 +1,15 @@
msgid ""
msgstr ""
-"PO-Revision-Date: 2024-06-17 08:07+0000\n"
+"PO-Revision-Date: 2025-01-07 11:20+0000\n"
"Last-Translator: Anonymous \n"
-"Language-Team: Italian "
-"\n"
+"Language-Team: Italian \n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 5.6-dev\n"
+"X-Generator: Weblate 5.10-dev\n"
#: src/app/main/ui/auth/register.cljs:133, src/app/main/ui/static.cljs:154, src/app/main/ui/viewer/login.cljs:98
msgid "auth.already-have-account"
@@ -183,7 +183,7 @@ msgstr "Gestisci permessi"
msgid "common.share-link.page-shared"
msgid_plural "common.share-link.page-shared"
msgstr[0] "1 pagina condivisa"
-msgstr[1] "% di pagine condivise"
+msgstr[1] "%s pagine condivise"
#: src/app/main/ui/viewer/share_link.cljs:300
msgid "common.share-link.permissions-can-comment"
@@ -303,7 +303,7 @@ msgstr "Duplica"
#: src/app/main/ui/dashboard/file_menu.cljs:249
msgid "dashboard.duplicate-multi"
-msgstr "Duplicare %s file"
+msgstr "Duplica %s file"
#: src/app/main/ui/dashboard/file_menu.cljs:259, src/app/main/ui/dashboard/file_menu.cljs:264
msgid "dashboard.export-binary-multi"
@@ -311,7 +311,7 @@ msgstr "Scarica %s file Penpot (.penpot)"
#: src/app/main/ui/workspace/main_menu.cljs:629
msgid "dashboard.export-frames"
-msgstr "Esportare le tavole da disegno in PDF"
+msgstr "Esporta le tavole da disegno in PDF"
#: src/app/main/ui/exports/assets.cljs:206
msgid "dashboard.export-frames.title"
@@ -319,7 +319,7 @@ msgstr "Esporta in PDF"
#, unused
msgid "dashboard.export-multi"
-msgstr "Esportare %s file Penpot"
+msgstr "Esporta %s file Penpot"
#: src/app/main/ui/exports/assets.cljs:113
msgid "dashboard.export-multiple.selected"
@@ -395,11 +395,11 @@ msgstr "Esporta i file"
#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:311
msgid "dashboard.fonts.deleted-placeholder"
-msgstr "Font eliminato"
+msgstr "Font mancante"
#: src/app/main/ui/dashboard/fonts.cljs:207
msgid "dashboard.fonts.dismiss-all"
-msgstr "Chiudere tutto"
+msgstr "Chiudi tutto"
#: src/app/main/ui/dashboard/fonts.cljs:441
msgid "dashboard.fonts.empty-placeholder"
@@ -437,7 +437,7 @@ msgstr "Carica tutto"
#: src/app/main/ui/dashboard/import.cljs:452, src/app/main/ui/dashboard/project_menu.cljs:108
msgid "dashboard.import"
-msgstr "Importare file Penpot"
+msgstr "Importa file Penpot"
#: src/app/main/ui/dashboard/import.cljs:288, src/app/worker/import.cljs:843, src/app/worker/import.cljs:846
msgid "dashboard.import.analyze-error"
@@ -449,10 +449,6 @@ msgstr ""
"C'è stato un problema con l'importazione del file. Il file non è stato "
"importato."
-#: src/app/main/ui/dashboard/import.cljs:466
-msgid "dashboard.import.import-message"
-msgstr "%s file sono stati importati con successo."
-
#: src/app/main/ui/dashboard/import.cljs:461
msgid "dashboard.import.import-warning"
msgstr "Alcuni file contenenti oggetti non validi sono stati rimossi."
@@ -521,15 +517,15 @@ msgstr "caricamento dei font …"
#: src/app/main/ui/dashboard/file_menu.cljs:301, src/app/main/ui/dashboard/project_menu.cljs:100
msgid "dashboard.move-to"
-msgstr "Sposta verso"
+msgstr "Sposta in"
#: src/app/main/ui/dashboard/file_menu.cljs:254
msgid "dashboard.move-to-multi"
-msgstr "Sposta %s file verso"
+msgstr "Sposta %s file in"
#: src/app/main/ui/dashboard/file_menu.cljs:233
msgid "dashboard.move-to-other-team"
-msgstr "Sposta verso un altro team"
+msgstr "Sposta in un altro team"
#: src/app/main/ui/dashboard/files.cljs:101, src/app/main/ui/dashboard/projects.cljs:251, src/app/main/ui/dashboard/projects.cljs:252
msgid "dashboard.new-file"
@@ -598,7 +594,7 @@ msgstr "Desideri eliminare il tuo account?"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
#, unused
msgid "dashboard.remove-shared"
-msgstr "Elimina come Libreria Condivisa"
+msgstr "Elimina come libreria condivisa"
#: src/app/main/ui/settings/profile.cljs:75
msgid "dashboard.save-settings"
@@ -606,7 +602,7 @@ msgstr "Salva impostazioni"
#: src/app/main/ui/dashboard/sidebar.cljs:246, src/app/main/ui/dashboard/sidebar.cljs:247
msgid "dashboard.search-placeholder"
-msgstr "Cerca …"
+msgstr "Cerca…"
#: src/app/main/ui/dashboard/search.cljs:56
msgid "dashboard.searching-for"
@@ -624,18 +620,10 @@ msgstr "Seleziona un tema"
msgid "dashboard.show-all-files"
msgstr "Mostra tutti i file"
-#: src/app/main/ui/dashboard/file_menu.cljs:101
-msgid "dashboard.success-delete-file"
-msgstr "Il tuo file è stato eliminato con successo"
-
#: src/app/main/ui/dashboard/project_menu.cljs:60
msgid "dashboard.success-delete-project"
msgstr "Il tuo progetto è stato eliminato con successo"
-#: src/app/main/ui/dashboard/file_menu.cljs:96
-msgid "dashboard.success-duplicate-file"
-msgstr "Il tuo file è stato duplicato con successo"
-
#: src/app/main/ui/dashboard/project_menu.cljs:34
msgid "dashboard.success-duplicate-project"
msgstr "Il tuo progetto è stato duplicato con successo"
@@ -678,7 +666,7 @@ msgstr "Scrivi per cercare"
#: src/app/main/ui/dashboard/file_menu.cljs:308, src/app/main/ui/workspace/main_menu.cljs:578
msgid "dashboard.unpublish-shared"
-msgstr "Spubblicare la libreria"
+msgstr "Annulla pubblicazione libreria"
#: src/app/main/ui/settings/options.cljs:68
msgid "dashboard.update-settings"
@@ -779,11 +767,11 @@ msgstr "Questo è invito può essere stato revocato o può essere scaduto."
#: src/app/main/ui/auth/login.cljs:106
msgid "errors.ldap-disabled"
-msgstr "Autenticazione LDAP disattivata."
+msgstr "Autenticazione LDAP disabilitata."
#: src/app/main/data/workspace/media.cljs:184
msgid "errors.media-too-large"
-msgstr "L'immagine è troppo grande (deve essere inferiore a 5MB)."
+msgstr "L'immagine è troppo grande per essere inserita."
#: src/app/main/data/media.cljs:68, src/app/main/data/workspace/media.cljs:187
msgid "errors.media-type-mismatch"
@@ -807,13 +795,13 @@ msgstr "La password deve contenere almeno 8 caratteri"
#: src/app/main/data/users.cljs:729, src/app/main/ui/auth/register.cljs:51
msgid "errors.registration-disabled"
-msgstr "La registrazione è al momento disattivata."
+msgstr "La registrazione è al momento disabilitata."
#: src/app/main/ui/dashboard/sidebar.cljs:365, src/app/main/ui/dashboard/team.cljs:389
msgid "errors.team-leave.insufficient-members"
msgstr ""
-"Il numero di membri non è sufficiente per abbandonare il team. Vuoi "
-"probabilmente eliminare il team."
+"Il numero di membri non è sufficiente per abbandonare il team. Probabilmente "
+"lo vuoi eliminare."
#: src/app/main/ui/dashboard/sidebar.cljs:368, src/app/main/ui/dashboard/team.cljs:392
msgid "errors.team-leave.member-does-not-exists"
@@ -893,7 +881,7 @@ msgstr "Si è verificato un errore"
#: src/app/main/ui/viewer/inspect/attributes/blur.cljs:26
msgid "inspect.attributes.blur"
-msgstr "Sfumatura"
+msgstr "Sfocatura"
#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:119
msgid "inspect.attributes.blur.value"
@@ -913,11 +901,11 @@ msgstr "RGBA"
#: src/app/main/ui/viewer/inspect/attributes/fill.cljs:57
msgid "inspect.attributes.fill"
-msgstr "Riempire"
+msgstr "Riempimento"
#: src/app/main/ui/viewer/inspect/attributes/common.cljs:99, src/app/main/ui/viewer/inspect/attributes/image.cljs:51
msgid "inspect.attributes.image.download"
-msgstr "Scaricare l'immagine sorgente"
+msgstr "Scarica l'immagine sorgente"
#: src/app/main/ui/viewer/inspect/attributes/image.cljs:39
msgid "inspect.attributes.image.height"
@@ -1025,7 +1013,7 @@ msgstr "Spaziatura delle lettere"
#: src/app/main/ui/viewer/inspect/attributes/text.cljs:125, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:367
msgid "inspect.attributes.typography.line-height"
-msgstr "Altezza Linea"
+msgstr "Interlinea"
#: src/app/main/ui/viewer/inspect/attributes/text.cljs:143
msgid "inspect.attributes.typography.text-decoration"
@@ -1077,11 +1065,11 @@ msgstr "Componente"
#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:126
msgid "inspect.tabs.code.selected.curve"
-msgstr "Curvo"
+msgstr "Curva"
#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:128
msgid "inspect.tabs.code.selected.group"
-msgstr "Raggruppa"
+msgstr "Gruppo"
#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:129
msgid "inspect.tabs.code.selected.image"
@@ -1121,11 +1109,11 @@ msgstr "Scorciatoie"
#: src/app/main/data/common.cljs:93, src/app/main/ui/dashboard/import.cljs:503
msgid "labels.accept"
-msgstr "Accettare"
+msgstr "Accetto"
#: src/app/main/ui/dashboard/fonts.cljs:176
msgid "labels.add-custom-font"
-msgstr "Aggiungere un carattere personalizzato"
+msgstr "Aggiungi un carattere personalizzato"
#: src/app/main/ui/dashboard/team.cljs:128, src/app/main/ui/dashboard/team.cljs:310, src/app/main/ui/dashboard/team.cljs:550, src/app/main/ui/dashboard/team.cljs:580, src/app/main/ui/onboarding/team_choice.cljs:66
msgid "labels.admin"
@@ -1160,7 +1148,7 @@ msgstr "Annulla"
#: src/app/main/ui/dashboard/projects.cljs:96, src/app/main/ui/exports/files.cljs:210, src/app/main/ui/settings/access_tokens.cljs:172, src/app/main/ui/viewer/login.cljs:71, src/app/main/ui/viewer/share_link.cljs:176, src/app/main/ui/workspace/comments.cljs:129, src/app/main/ui/workspace/libraries.cljs:538, src/app/main/ui/workspace/sidebar/debug.cljs:40, src/app/main/ui/workspace/sidebar/layers.cljs:299, src/app/main/ui/workspace/tokens/modals/themes.cljs:366, src/app/main/ui/workspace/tokens/modals.cljs:56
msgid "labels.close"
-msgstr "Chiudere"
+msgstr "Chiudi"
#: src/app/main/ui/dashboard/comments.cljs:104, src/app/main/ui/viewer/comments.cljs:70, src/app/main/ui/workspace/comments.cljs:127
msgid "labels.comments"
@@ -1204,27 +1192,27 @@ msgstr "Font personalizzati"
#: src/app/main/ui/settings/sidebar.cljs:73
msgid "labels.dashboard"
-msgstr "Dashboard"
+msgstr "Pannello di controllo"
#: src/app/main/ui/dashboard/file_menu.cljs:336, src/app/main/ui/dashboard/fonts.cljs:256, src/app/main/ui/dashboard/fonts.cljs:332, src/app/main/ui/dashboard/fonts.cljs:346, src/app/main/ui/dashboard/project_menu.cljs:114, src/app/main/ui/dashboard/team.cljs:942, src/app/main/ui/settings/access_tokens.cljs:198, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:209, src/app/main/ui/workspace/sidebar/versions.cljs:152, src/app/main/ui/workspace/tokens/form.cljs:425, src/app/main/ui/workspace/tokens/modals/themes.cljs:335, src/app/main/ui/workspace/tokens/sets_context_menu.cljs:44
msgid "labels.delete"
-msgstr "Eliminare"
+msgstr "Elimina"
#: src/app/main/ui/comments.cljs:363
msgid "labels.delete-comment"
-msgstr "Eliminare il commento"
+msgstr "Elimina il commento"
#: src/app/main/ui/comments.cljs:360
msgid "labels.delete-comment-thread"
-msgstr "Eliminare il thread"
+msgstr "Elimina il thread"
#: src/app/main/ui/dashboard/team.cljs:684
msgid "labels.delete-invitation"
-msgstr "Eliminare l'invito"
+msgstr "Elimina l'invito"
#: src/app/main/ui/dashboard/file_menu.cljs:280
msgid "labels.delete-multi-files"
-msgstr "Eliminare %s file"
+msgstr "Elimina %s file"
#: src/app/main/ui/dashboard/file_menu.cljs:30, src/app/main/ui/dashboard/files.cljs:75, src/app/main/ui/dashboard/files.cljs:168, src/app/main/ui/dashboard/projects.cljs:225, src/app/main/ui/dashboard/projects.cljs:229, src/app/main/ui/dashboard/sidebar.cljs:791
msgid "labels.drafts"
@@ -1232,11 +1220,11 @@ msgstr "Bozze"
#: src/app/main/ui/comments.cljs:356, src/app/main/ui/dashboard/fonts.cljs:253, src/app/main/ui/dashboard/team.cljs:940, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:205, src/app/main/ui/workspace/tokens/sidebar.cljs:199
msgid "labels.edit"
-msgstr "Modificare"
+msgstr "Modifica"
#, unused
msgid "labels.edit-file"
-msgstr "Modificare il file"
+msgstr "Modifica il file"
#: src/app/main/ui/dashboard/team.cljs:126, src/app/main/ui/dashboard/team.cljs:307, src/app/main/ui/dashboard/team.cljs:551, src/app/main/ui/dashboard/team.cljs:584, src/app/main/ui/onboarding/team_choice.cljs:65
msgid "labels.editor"
@@ -1248,7 +1236,7 @@ msgstr "Scaduto"
#: src/app/main/ui/exports/assets.cljs:177
msgid "labels.export"
-msgstr "Esportare"
+msgstr "Esporta"
#: src/app/main/ui/settings/feedback.cljs:48
msgid "labels.feedback-disabled"
@@ -1416,7 +1404,7 @@ msgstr "Note di versione"
#: src/app/main/ui/workspace/libraries.cljs, src/app/main/ui/dashboard/team.cljs
#, unused
msgid "labels.remove"
-msgstr "Rimuovere"
+msgstr "Rimuovi"
#: src/app/main/ui/dashboard/team.cljs:345
msgid "labels.remove-member"
@@ -1424,11 +1412,11 @@ msgstr "Rimuovi membro"
#: src/app/main/ui/dashboard/file_menu.cljs:288, src/app/main/ui/dashboard/project_menu.cljs:87, src/app/main/ui/dashboard/sidebar.cljs:539, src/app/main/ui/workspace/sidebar/assets/groups.cljs:153, src/app/main/ui/workspace/sidebar/versions.cljs:146, src/app/main/ui/workspace/tokens/sets_context_menu.cljs:43
msgid "labels.rename"
-msgstr "Rinominare"
+msgstr "Rinomina"
#: src/app/main/ui/dashboard/team_form.cljs:99
msgid "labels.rename-team"
-msgstr "Rinominare il team"
+msgstr "Rinomina il team"
#: src/app/main/ui/dashboard/team.cljs:681
msgid "labels.resend-invitation"
@@ -1444,7 +1432,7 @@ msgstr "Ruolo"
#: src/app/main/ui/dashboard/fonts.cljs:382, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:191, src/app/main/ui/workspace/tokens/form.cljs:433
msgid "labels.save"
-msgstr "Salvare"
+msgstr "Salva"
#: src/app/main/ui/dashboard/fonts.cljs:421
msgid "labels.search-font"
@@ -1452,7 +1440,7 @@ msgstr "Cerca un font"
#: src/app/main/ui/settings/feedback.cljs:79
msgid "labels.send"
-msgstr "Inviare"
+msgstr "Invia"
#: src/app/main/ui/settings/feedback.cljs:79
msgid "labels.sending"
@@ -1508,11 +1496,11 @@ msgstr "Aggiorna team"
#: src/app/main/ui/dashboard/fonts.cljs:242
msgid "labels.upload"
-msgstr "Caricare"
+msgstr "Carica"
#: src/app/main/ui/dashboard/fonts.cljs:170
msgid "labels.upload-custom-fonts"
-msgstr "Caricare font personalizzati"
+msgstr "Carica font personalizzati"
#: src/app/main/ui/dashboard/fonts.cljs:241
msgid "labels.uploading"
@@ -1520,11 +1508,11 @@ msgstr "Caricamento…"
#: src/app/main/ui/dashboard/team.cljs:125, src/app/main/ui/dashboard/team.cljs:304, src/app/main/ui/dashboard/team.cljs:552, src/app/main/ui/dashboard/team.cljs:588, src/app/main/ui/onboarding/team_choice.cljs:64
msgid "labels.viewer"
-msgstr ""
+msgstr "Visualizzatore"
#: src/app/main/ui/comments.cljs:197
msgid "labels.write-new-comment"
-msgstr "Scrivere un nuovo commento"
+msgstr "Scrivi un nuovo commento"
#: src/app/main/ui/dashboard/team.cljs:262
msgid "labels.you"
@@ -1550,7 +1538,7 @@ msgstr ""
#: src/app/main/data/common.cljs:129
msgid "modals.add-shared-confirm.message"
-msgstr "Aggiungere \"%s\" come libreria condivisa"
+msgstr "Aggiungi \"%s\" come libreria condivisa"
#: src/app/main/ui/workspace/nudge.cljs:60
msgid "modals.big-nudge"
@@ -1584,7 +1572,7 @@ msgstr "Annulla e mantieni il mio account"
#: src/app/main/ui/settings/delete_account.cljs:64
msgid "modals.delete-account.confirm"
-msgstr "Sì, cancellare il mio account"
+msgstr "Sì, cancella il mio account"
#: src/app/main/ui/settings/delete_account.cljs:53
msgid "modals.delete-account.info"
@@ -1791,29 +1779,25 @@ msgstr "Nuovo proprietario del team"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
#, unused
msgid "modals.remove-shared-confirm.accept"
-msgstr "Elimina come Libreria Condivisa"
+msgstr "Elimina come libreria condivisa"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
#, unused
msgid "modals.remove-shared-confirm.hint"
msgstr ""
-"Una volta eliminata come Libreria Condivisa, la Libreria dei File di questo "
+"Una volta eliminata come libreria condivisa, la libreria dei file di questo "
"file smetterà di essere a disposizione per essere usata con il resto dei "
"tuoi file."
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
#, unused
msgid "modals.remove-shared-confirm.message"
-msgstr "Elimina \"%s\" come Libreria Condivisa"
+msgstr "Elimina \"%s\" come libreria condivisa"
#: src/app/main/ui/workspace/nudge.cljs:53
msgid "modals.small-nudge"
msgstr "Piccolo scatto"
-#: src/app/main/ui/delete_shared.cljs:52
-msgid "modals.unpublish-shared-confirm.accept"
-msgstr "Annulla pubblicazione"
-
#: src/app/main/ui/delete_shared.cljs:47
msgid "modals.unpublish-shared-confirm.message"
msgid_plural "modals.unpublish-shared-confirm.message"
@@ -1969,7 +1953,7 @@ msgstr "Condizioni sulla Privacy."
#: src/app/main/ui/onboarding/newsletter.cljs:60
msgid "onboarding.newsletter.title"
-msgstr "Vuoi ricevere le news di Pentot?"
+msgstr "Vuoi ricevere le news di Penpot?"
#: src/app/main/ui/dashboard/team.cljs:764
msgid "title.team-invitations"
@@ -2003,3 +1987,4591 @@ msgstr "Inviti - %s - Penpot"
#~ msgid "onboarding.slide.1.desc1"
#~ msgstr "Crea interazioni complete per imitare al meglio il prodotto finale."
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:207
+msgid "shortcuts.undo"
+msgstr "Annulla"
+
+#: src/app/main/ui/auth/recovery_request.cljs:113, src/app/main/ui/auth/register.cljs:274
+msgid "auth.check-mail"
+msgstr "Controlla la tua email"
+
+#: src/app/main/ui/auth/register.cljs:254
+msgid "auth.register-account-tagline"
+msgstr ""
+"Facci sapere come dovremmo chiamarti nel pannello di controllo e nelle email."
+
+#: src/app/main/ui/auth/register.cljs:253
+msgid "auth.register-account-title"
+msgstr "Il tuo nome"
+
+#: src/app/main/ui/auth/register.cljs:157
+#, markdown
+msgid "auth.terms-and-privacy-agreement"
+msgstr "Accetto i [termini di servizio](%s) e la [politica sulla privacy](%s)."
+
+#: src/app/main/ui/settings/access_tokens.cljs:288
+msgid "dashboard.access-tokens.empty.no-access-tokens"
+msgstr "Al momento non hai token."
+
+#: src/app/main/ui/settings/access_tokens.cljs:135
+msgid "dashboard.access-tokens.expiration-90-days"
+msgstr "90 giorni"
+
+#: src/app/main/ui/settings/access_tokens.cljs:271
+msgid "dashboard.access-tokens.expired-on"
+msgstr "Scaduto il %s"
+
+#: src/app/main/ui/settings/access_tokens.cljs:132
+msgid "dashboard.access-tokens.expiration-never"
+msgstr "Mai"
+
+#: src/app/main/ui/settings/access_tokens.cljs:272
+msgid "dashboard.access-tokens.expires-on"
+msgstr "Scade il %s"
+
+#: src/app/main/ui/settings/access_tokens.cljs:270
+msgid "dashboard.access-tokens.no-expiration"
+msgstr "Nessuna data di scadenza"
+
+#: src/app/main/ui/settings/access_tokens.cljs:186
+msgid "dashboard.access-tokens.personal"
+msgstr "Token di accesso personale"
+
+#: src/app/main/ui/dashboard/team.cljs:900
+msgid "dashboard.webhooks.active.explain"
+msgstr ""
+"Quando questo webhook viene attivato verranno inviati i dati dell'evento"
+
+#: src/app/main/ui/settings/access_tokens.cljs:258
+msgid "modals.delete-acces-token.title"
+msgstr "Elimina token"
+
+#: src/app/main/ui/dashboard/team.cljs:223
+msgid "modals.invite-member.repeated-invitation"
+msgstr ""
+"Alcune email appartengono a membri attuali del team. I loro inviti non "
+"saranno inviati."
+
+#: src/app/main/ui/onboarding/questions.cljs:169
+msgid "labels.adobe-xd"
+msgstr "Adobe XD"
+
+#: src/app/main/ui/onboarding/questions.cljs:246
+msgid "labels.developer"
+msgstr "Sviluppo"
+
+#: src/app/main/ui/onboarding/questions.cljs:404
+msgid "labels.event"
+msgstr "Evento"
+
+#: src/app/main/ui/onboarding/questions.cljs:403
+msgid "labels.youtube"
+msgstr "YouTube"
+
+#: src/app/main/ui/dashboard/templates.cljs:275, src/app/main/ui/onboarding/questions.cljs:55
+msgid "labels.next"
+msgstr "Successivo"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:58
+msgid "shortcut-subsection.general-dashboard"
+msgstr "Generico"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:68
+msgid "shortcut-subsection.text-editor"
+msgstr "Testi"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:130
+msgid "shortcuts.line-through"
+msgstr "Attiva/disattiva testo barrato"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:146
+msgid "shortcuts.opacity-0"
+msgstr "Imposta opacità al 100%"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:188
+msgid "shortcuts.toggle-colorpalette"
+msgstr "Attiva/Disattiva palette colori"
+
+#: src/app/main/ui/workspace/sidebar/assets.cljs:135
+msgid "workspace.assets.box-filter-all"
+msgstr "Tutti gli asset"
+
+#: src/app/main/ui/workspace/sidebar/assets/groups.cljs:127
+msgid "workspace.assets.create-group"
+msgstr "Crea un gruppo"
+
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:220
+msgid "workspace.assets.sidebar.components"
+msgid_plural "workspace.assets.sidebar.components"
+msgstr[0] "1 componente"
+msgstr[1] "%s componenti"
+
+#: src/app/main/ui/workspace/context_menu.cljs:609
+msgid "workspace.context-menu.grid-track.column.delete"
+msgstr "Elimina colonna"
+
+#: src/app/main/ui/workspace/context_menu.cljs:613
+msgid "workspace.context-menu.grid-track.row.duplicate"
+msgstr "Duplica riga"
+
+#: src/app/main/ui/workspace/main_menu.cljs:400
+msgid "workspace.header.menu.hide-pixel-grid"
+msgstr "Nascondi griglia pixel"
+
+#: src/app/main/ui/workspace/libraries.cljs:75, src/app/main/ui/workspace/libraries.cljs:92
+msgid "workspace.libraries.components"
+msgstr "%s componenti"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:655
+msgid "workspace.options.clip-content"
+msgstr "Ritaglia contenuto"
+
+#: src/app/main/ui/viewer/inspect/exports.cljs:203, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:256
+msgid "workspace.options.export-object"
+msgid_plural "workspace.options.export-object"
+msgstr[0] "Esporta 1 elemento"
+msgstr[1] "Esporta %s elementi"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:57
+msgid "workspace.options.interaction-close-overlay-dest"
+msgstr "Chiudi sovrapposizione: %s"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:462
+msgid "workspace.options.interaction-delay"
+msgstr "Ritardo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:697
+msgid "workspace.options.interaction-offset-effect"
+msgstr "Effetti di offset"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:731
+msgid "workspace.options.interactions"
+msgstr "Interazioni"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs
+#, unused
+msgid "workspace.options.layer-options.title"
+msgstr "Livello"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs:136
+msgid "workspace.options.more-lib-colors"
+msgstr "Più librerie colori"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:146
+msgid "workspace.options.shadow-options.inner-shadow"
+msgstr "Ombra interna"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:296
+msgid "workspace.options.shadow-options.title.group"
+msgstr "Ombra di gruppo"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:128
+msgid "workspace.options.stroke-cap.square-marker-short"
+msgstr "Rettangolo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:143
+msgid "workspace.options.text-options.grow-fixed"
+msgstr "Fisso"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:57
+msgid "workspace.options.text-options.text-align-right"
+msgstr "Allinea a destra (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs
+#, unused
+msgid "workspace.options.text-options.titlecase"
+msgstr "Iniziale maiuscola"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:173
+msgid "workspace.options.text-options.underline"
+msgstr "Sottolineato (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs
+#, unused
+msgid "workspace.options.text-options.uppercase"
+msgstr "Maiuscolo"
+
+#: src/app/main/ui/workspace/context_menu.cljs:402
+msgid "workspace.shape.menu.delete-flow-start"
+msgstr "Elimina inizio del flusso"
+
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:432
+msgid "workspace.shape.menu.detach-instance"
+msgstr "Scollega istanza"
+
+#: src/app/main/ui/workspace/sidebar/layers.cljs:310, src/app/main/ui/workspace/sidebar/layers.cljs:382
+msgid "workspace.sidebar.layers.components"
+msgstr "Componenti"
+
+#: src/app/main/ui/workspace/sidebar/sitemap.cljs:219
+msgid "workspace.sidebar.sitemap"
+msgstr "Pagine"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:144
+msgid "workspace.undo.entry.modify"
+msgstr "Modificato %s"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:145
+msgid "workspace.undo.entry.delete"
+msgstr "Eliminato %s"
+
+#: src/app/main/ui/workspace/plugins.cljs:192
+msgid "workspace.plugins.error.url"
+msgstr "Il plugin non esiste o l'URL non è corretto."
+
+#: src/app/main/ui/auth/verify_token.cljs:46
+msgid "auth.notifications.team-invitation-accepted"
+msgstr "Unito al team con successo"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:135
+msgid "workspace.undo.entry.single.shape"
+msgstr "forma"
+
+#: src/app/main/ui/settings/access_tokens.cljs:289
+msgid "dashboard.access-tokens.empty.add-one"
+msgstr "Premi il bottone \"Genera un nuovo token\" per generarne uno."
+
+#: src/app/main/ui/dashboard/team.cljs:678
+msgid "labels.copy-invitation-link"
+msgstr "Copia link"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:436
+msgid "labels.search"
+msgstr "Cerca"
+
+#: src/app/main/ui/settings/access_tokens.cljs:180
+msgid "modals.create-access-token.submit-label"
+msgstr "Crea token"
+
+#: src/app/main/ui/onboarding/team_choice.cljs:55
+msgid "onboarding.team-modal.create-team-feature-5"
+msgstr "100% gratuito!"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:66
+msgid "shortcut-subsection.path-editor"
+msgstr "Tracciati"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:70
+msgid "shortcut-subsection.zoom-viewer"
+msgstr "Zoom"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:88
+msgid "shortcuts.bring-back"
+msgstr "Porta sotto"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:93
+msgid "shortcuts.copy"
+msgstr "Copia"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:135
+msgid "shortcuts.move"
+msgstr "Sposta"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:136
+msgid "shortcuts.move-fast-down"
+msgstr "Sposta rapidamente in basso"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:139
+msgid "shortcuts.move-fast-up"
+msgstr "Sposta rapidamente in alto"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:137
+msgid "shortcuts.move-fast-left"
+msgstr "Sposta rapidamente a sinistra"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:124
+msgid "shortcuts.italic"
+msgstr "Attiva/Disattiva corsivo"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:205
+msgid "shortcuts.toggle-zoom-style"
+msgstr "Attiva/Disattiva stile zoom"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:209
+msgid "shortcuts.unmask"
+msgstr "Rimuovi maschera"
+
+#: src/app/main/ui/workspace/context_menu.cljs:297
+msgid "workspace.focus.focus-on"
+msgstr "Modalità focus attivata"
+
+#: src/app/util/color.cljs:34
+msgid "workspace.gradients.linear"
+msgstr "Gradiente lineare"
+
+#: src/app/util/color.cljs:35
+msgid "workspace.gradients.radial"
+msgstr "Gradiente radiale"
+
+#: src/app/main/ui/workspace/libraries.cljs:210
+msgid "workspace.libraries.in-this-file"
+msgstr "LIBRERIE IN QUESTO FILE"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:314
+msgid "workspace.libraries.text.multiple-typography-tooltip"
+msgstr "Scollega tutti gli elementi tipografici"
+
+#: src/app/main/ui/workspace/libraries.cljs:84, src/app/main/ui/workspace/libraries.cljs:104
+msgid "workspace.libraries.typography"
+msgstr "%s elementi tipografici"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:87, src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:105
+msgid "workspace.options.blur-options.title"
+msgstr "Sfocatura"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:123
+msgid "workspace.options.layer-options.blend-mode.normal"
+msgstr "Normale"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:629
+msgid "workspace.options.radius-bottom-right"
+msgstr "Inferiore destro"
+
+#: src/app/main/ui/workspace/context_menu.cljs:349
+msgid "workspace.shape.menu.intersection"
+msgstr "Interesezione"
+
+#: src/app/main/ui/workspace/sidebar/layers.cljs:312, src/app/main/ui/workspace/sidebar/layers.cljs:410
+msgid "workspace.sidebar.layers.images"
+msgstr "Immagini"
+
+#: src/app/main/ui/workspace/sidebar/layers.cljs:309, src/app/main/ui/workspace/sidebar/layers.cljs:368
+msgid "workspace.sidebar.layers.masks"
+msgstr "Maschere"
+
+#: src/app/main/data/workspace/libraries.cljs:1143
+msgid "workspace.updates.there-are-updates"
+msgstr "Sono presenti degli aggiornamenti nelle librerie condivise"
+
+#: src/app/main/data/workspace/libraries.cljs:1150
+msgid "workspace.updates.update"
+msgstr "Aggiorna"
+
+#: src/app/main/ui/workspace/colorpicker.cljs:229
+msgid "media.radial"
+msgstr "Radiale"
+
+#: src/app/main/ui/workspace/colorpicker.cljs:344, src/app/main/ui/workspace/colorpicker.cljs:345, src/app/main/ui/workspace/colorpicker.cljs:347
+msgid "media.choose-image"
+msgstr "Scegli un'immagine"
+
+#: src/app/main/ui/delete_shared.cljs:59
+msgid "modals.delete-unpublish-shared-confirm.activated.hint"
+msgid_plural "modals.delete-unpublish-shared-confirm.activated.hint"
+msgstr[0] ""
+"Le risorse già utilizzate in questo file rimarranno lì (nessun design verrà "
+"compromesso)."
+msgstr[1] ""
+"Le risorse già utilizzare in questi file rimarranno lì (nessun design verrà "
+"compromesso)."
+
+#: src/app/main/ui/workspace/plugins.cljs:188
+msgid "workspace.plugins.install"
+msgstr "Installa"
+
+#: src/app/main/ui/workspace/plugins.cljs:183
+msgid "workspace.plugins.search-placeholder"
+msgstr "Scrivi URL di un plugin"
+
+#: src/app/main/ui/workspace/plugins.cljs:209
+msgid "workspace.plugins.empty-plugins"
+msgstr "Nessun plugin ancora installata"
+
+#: src/app/main/ui/workspace/plugins.cljs:214
+msgid "workspace.plugins.plugin-list-link"
+msgstr "Lista plugin"
+
+#: src/app/main/ui/exports/files.cljs:170
+msgid "dashboard.export.options.merge.title"
+msgstr "Includi gli asset delle librerie condivise nelle librerie del file"
+
+#: src/app/main/ui/workspace/main_menu.cljs:777, src/app/main/ui/workspace/sidebar/shortcuts.cljs:60
+msgid "shortcut-subsection.main-menu"
+msgstr "Menu principale"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:157
+msgid "shortcuts.open-comments"
+msgstr "Vai alla sezione commenti"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:158
+msgid "shortcuts.open-dashboard"
+msgstr "Vai al pannello di controllo"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:260
+msgid "shortcuts.or"
+msgstr " o "
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:165
+msgid "shortcuts.redo"
+msgstr "Ripeti"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:176
+msgid "shortcuts.snap-nodes"
+msgstr "Aggancia ai nodi"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:180
+msgid "shortcuts.stop-measure"
+msgstr "Interrompi misurazione"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:185
+msgid "shortcuts.thumbnail-set"
+msgstr "Imposta miniature"
+
+#: src/app/main/ui/dashboard/search.cljs:33
+msgid "title.dashboard.search"
+msgstr "Cerca - %s - Penpot"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:519
+msgid "workspace.assets.typography.line-height"
+msgstr "Interlinea"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:527
+msgid "workspace.assets.typography.text-transform"
+msgstr "Trasforma testo"
+
+#: src/app/main/ui/workspace/main_menu.cljs:401
+msgid "workspace.header.menu.show-pixel-grid"
+msgstr "Mostra griglia pixel"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:142, src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:153
+msgid "workspace.options.constraints.scale"
+msgstr "Ridimensionamento"
+
+#: src/app/main/ui/exports/assets.cljs:246
+msgid "workspace.options.exporting-complete"
+msgstr "Esportazione completata"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:620
+msgid "workspace.options.interaction-animation"
+msgstr "Animazione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:411
+msgid "workspace.options.interaction-animation-none"
+msgstr "Nessuna"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.packed"
+msgstr "compatto"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:161
+msgid "workspace.options.opacity"
+msgstr "Opacità"
+
+#: src/app/main/ui/workspace/viewport/path_actions.cljs:174
+msgid "workspace.path.actions.delete-node"
+msgstr "Elimina nodo (%s)"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:117
+msgid "workspace.undo.entry.multiple.page"
+msgstr "pagine"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:150
+msgid "workspace.options.constraints.bottom"
+msgstr "Inferiore"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:182
+msgid "workspace.options.flows.add-flow-start"
+msgstr "Aggiungi inizio flusso"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:425
+msgid "workspace.options.interaction-easing-ease-in-out"
+msgstr "Ease in out"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:53
+msgid "workspace.options.interaction-open-overlay-dest"
+msgstr "Apri la sovrapposizione: %s"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:134
+msgid "workspace.options.layer-options.blend-mode.exclusion"
+msgstr "Esclusione"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:89
+msgid "workspace.options.stroke.outer"
+msgstr "Esterno"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:178
+msgid "workspace.options.text-options.strikethrough"
+msgstr "Barrato (%s)"
+
+#: src/app/main/ui/workspace/context_menu.cljs:337
+msgid "workspace.shape.menu.transform-to-path"
+msgstr "Trasforma in tracciato"
+
+#: src/app/main/ui/workspace/sidebar/layers.cljs:527
+msgid "workspace.focus.focus-mode"
+msgstr "Modalità focus"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:196
+msgid "shortcuts.toggle-lock"
+msgstr "Blocca/Sblocca"
+
+#: src/app/main/ui/workspace/main_menu.cljs:471
+msgid "workspace.header.menu.redo"
+msgstr "Ripeti"
+
+#: src/app/main/ui/workspace/libraries.cljs
+#, unused
+msgid "workspace.libraries.library"
+msgstr "LIBRERIA"
+
+#: src/app/main/data/workspace/libraries.cljs:1147, src/app/main/ui/workspace/sidebar/versions.cljs:285
+msgid "workspace.updates.dismiss"
+msgstr "Ignora"
+
+#: src/app/main/errors.cljs:242
+msgid "errors.feature-mismatch"
+msgstr ""
+"Sembra che tu stia aprendo un file con la funzione '%s' abilitata, ma la "
+"versione attuale di Penpot non la supporta o l'ha disabilitata."
+
+#: src/app/main/ui/dashboard/team.cljs:832
+msgid "errors.webhooks.timeout"
+msgstr "Timeout"
+
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:155
+msgid "inspect.empty.more-info"
+msgstr "Maggiori informazioni sull'ispezione"
+
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:147
+msgid "inspect.empty.select"
+msgstr ""
+"Seleziona una forma, una tavola da disegno o un gruppo per ispezionare le "
+"loro proprietà e il loro codice"
+
+#: src/app/main/ui/dashboard/team.cljs:1005
+msgid "labels.active"
+msgstr "Attivo"
+
+#: src/app/main/ui/workspace/sidebar/sitemap.cljs:226
+msgid "labels.view-only"
+msgstr "Solo visualizzazione"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:61
+msgid "shortcut-subsection.modify-layers"
+msgstr "Modifica livelli"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:166
+msgid "shortcuts.reset-zoom"
+msgstr "Reimposta zoom"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:163
+msgid "shortcuts.paste"
+msgstr "Incolla"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:168
+msgid "shortcuts.search-placeholder"
+msgstr "Scorciatoie di ricerca"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:190
+msgid "shortcuts.toggle-fullscreen"
+msgstr "Attiva/Disattiva schermo intero"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:210
+msgid "shortcuts.v-distribute"
+msgstr "Distribuisci verticalmente"
+
+#: src/app/main/ui/viewer.cljs:575
+msgid "viewer.frame-not-found"
+msgstr "Tavola da disegno non trovata."
+
+#: src/app/main/ui/workspace/sidebar/assets.cljs
+#, unused
+msgid "workspace.assets.selected-count"
+msgid_plural "workspace.assets.selected-count"
+msgstr[0] "%s elemento selezionato"
+msgstr[1] "%s elementi selezionati"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:489
+msgid "workspace.options.height"
+msgstr "Altezza"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:165
+msgid "workspace.options.stroke-width"
+msgstr "Spessore traccia"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:84
+msgid "workspace.options.text-options.direction-ltr"
+msgstr "LTR"
+
+#: src/app/main/ui/workspace/context_menu.cljs:352
+msgid "workspace.shape.menu.exclude"
+msgstr "Escludi"
+
+#: src/app/main/ui/workspace/context_menu.cljs:382, src/app/main/ui/workspace/sidebar/layer_item.cljs:153, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:189
+msgid "workspace.shape.menu.lock"
+msgstr "Blocca"
+
+#: src/app/main/ui/workspace/context_menu.cljs:268
+msgid "workspace.shape.menu.ungroup"
+msgstr "Separa"
+
+#: src/app/main/ui/workspace/context_menu.cljs:282
+msgid "workspace.shape.menu.unmask"
+msgstr "Rimuovi maschera"
+
+#: src/app/main/ui/workspace/sidebar/collapsable_button.cljs:25, src/app/main/ui/workspace/sidebar/collapsable_button.cljs:29
+msgid "workspace.sidebar.expand"
+msgstr "Espandi barra laterale"
+
+#: src/app/main/ui/workspace/top_toolbar.cljs:170, src/app/main/ui/workspace/top_toolbar.cljs:171
+msgid "workspace.toolbar.text"
+msgstr "Testo (%s)"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:112
+msgid "workspace.undo.entry.multiple.curve"
+msgstr "curve"
+
+#: src/app/main/ui/onboarding/team_choice.cljs:238
+msgid "onboarding.team-modal.create-team"
+msgstr "Crea un team"
+
+#: src/app/main/ui/settings/profile.cljs:121
+msgid "title.settings.profile"
+msgstr "Profilo - Penpot"
+
+#: src/app/main/ui/viewer/header.cljs:237
+msgid "viewer.header.sitemap"
+msgstr "Sitemap"
+
+#: src/app/main/ui/workspace/context_menu.cljs:540, src/app/main/ui/workspace/sidebar/assets/colors.cljs:251, src/app/main/ui/workspace/sidebar/assets/components.cljs:576, src/app/main/ui/workspace/sidebar/assets/graphics.cljs:424, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:447
+msgid "workspace.assets.delete"
+msgstr "Elimina"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:263
+msgid "workspace.options.grid.params.gutter"
+msgstr "Interspazio"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs
+#, unused
+msgid "workspace.options.layer-options.title.multiple"
+msgstr "Livelli selezionati"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:118
+msgid "workspace.undo.entry.multiple.path"
+msgstr "tracciati"
+
+#: src/app/main/ui/settings/access_tokens.cljs:104
+msgid "dashboard.access-tokens.copied-success"
+msgstr "Token copiato"
+
+#: src/app/main/ui/settings/access_tokens.cljs:191
+msgid "dashboard.access-tokens.create"
+msgstr "Genera un nuovo token"
+
+#: src/app/main/ui/settings/access_tokens.cljs:136
+msgid "dashboard.access-tokens.expiration-180-days"
+msgstr "180 giorni"
+
+#: src/app/main/ui/settings/access_tokens.cljs:133
+msgid "dashboard.access-tokens.expiration-30-days"
+msgstr "30 giorni"
+
+#: src/app/main/ui/settings/access_tokens.cljs:144
+msgid "dashboard.access-tokens.token-will-not-expire"
+msgstr "Il token non ha una data di scadenza"
+
+#: src/app/main/data/fonts.cljs:189
+msgid "errors.bad-font"
+msgstr "Il font %s non può essere caricato"
+
+#: src/app/main/data/fonts.cljs:188
+msgid "errors.bad-font-plural"
+msgstr "I font %s non posso essere caricati"
+
+#: src/app/main/ui/viewer/thumbnails.cljs:82
+msgid "labels.num-of-frames"
+msgid_plural "labels.num-of-frames"
+msgstr[0] "1 tavola da disegno"
+msgstr[1] "%s tavole da disegno"
+
+#: src/app/main/ui/dashboard/file_menu.cljs:274
+msgid "labels.unpublish-multi-files"
+msgstr "Rimuovi pubblicazione a %s file"
+
+#: src/app/main/ui/settings/access_tokens.cljs:154, src/app/main/ui/settings/access_tokens.cljs:160
+msgid "modals.create-access-token.copy-token"
+msgstr "Copia token"
+
+#: src/app/main/ui/settings/access_tokens.cljs:112
+msgid "modals.create-access-token.title"
+msgstr "Genera token di accesso"
+
+#: src/app/main/ui/dashboard/team.cljs:911
+msgid "modals.create-webhook.submit-label"
+msgstr "Crea webhook"
+
+#: src/app/main/ui/dashboard/team.cljs:876
+msgid "modals.create-webhook.title"
+msgstr "Crea webhook"
+
+#: src/app/main/ui/dashboard/team.cljs:887
+msgid "modals.create-webhook.url.label"
+msgstr "URL del payload"
+
+#: src/app/main/ui/onboarding/newsletter.cljs:97
+msgid "onboarding-v2.newsletter.privacy2"
+msgstr ""
+"Ti invieremo solo email rilevanti. Puoi annullare l'iscrizione in qualsiasi "
+"momento tramite il link di cancellazione presente in ogni nostra newsletter."
+
+#: src/app/main/ui/onboarding/newsletter.cljs:91
+msgid "onboarding-v2.newsletter.privacy1"
+msgstr "Ci teniamo alla privacy, qui puoi leggere la nostra "
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:71
+msgid "shortcut-subsection.zoom-workspace"
+msgstr "Zoom"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:76
+msgid "shortcuts.align-hcenter"
+msgstr "Allinea al centro orizzontalmente"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:77
+msgid "shortcuts.align-justify"
+msgstr "Allinea giustificato"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:126
+msgid "shortcuts.letter-spacing-dec"
+msgstr "Diminuisci spaziatura tra le lettere"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:125
+msgid "shortcuts.join-nodes"
+msgstr "Unisci nodi"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:127
+msgid "shortcuts.letter-spacing-inc"
+msgstr "Aumenta spaziatura tra le lettere"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:147
+msgid "shortcuts.opacity-1"
+msgstr "Imposta opacità al 10%"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:149
+msgid "shortcuts.opacity-3"
+msgstr "Imposta opacità al 30%"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:183
+msgid "shortcuts.text-align-left"
+msgstr "Allinea a sinistra"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:194
+msgid "shortcuts.toggle-layout-flex"
+msgstr "Aggiungi/Rimuovi flex layout"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:202
+msgid "shortcuts.toggle-textpalette"
+msgstr "Attiva/Disattiva palette testi"
+
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:570
+msgid "workspace.assets.duplicate-main"
+msgstr "Duplica principale"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:211
+msgid "shortcuts.zoom-lense-decrease"
+msgstr "Diminuire lo zoom"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:515
+msgid "workspace.assets.typography.font-size"
+msgstr "Dimensione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:511
+msgid "workspace.assets.typography.font-variant-id"
+msgstr "Variante"
+
+#: src/app/main/ui/dashboard/grid.cljs:207, src/app/main/ui/workspace/libraries.cljs:469, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:474, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:499, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:606, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:625
+msgid "workspace.assets.typography.sample"
+msgstr "Ag"
+
+#: src/app/main/ui/workspace/main_menu.cljs:228
+msgid "workspace.header.menu.disable-snap-guides"
+msgstr "Disattiva allineamento a guide"
+
+#: src/app/main/ui/workspace/main_menu.cljs:258
+msgid "workspace.header.menu.disable-snap-pixel-grid"
+msgstr "Disattiva allineamento al pixel"
+
+#: src/app/main/ui/workspace/main_menu.cljs:244
+msgid "workspace.header.menu.enable-dynamic-alignment"
+msgstr "Attiva allineamento dinamico"
+
+#: src/app/main/ui/workspace/header.cljs
+#, unused
+msgid "workspace.header.menu.enable-scale-text"
+msgstr "Attiva ridimensionamento testo"
+
+#: src/app/main/ui/workspace/main_menu.cljs:229
+msgid "workspace.header.menu.enable-snap-guides"
+msgstr "Allinea alle guide"
+
+#: src/app/main/ui/workspace/main_menu.cljs:359
+msgid "workspace.header.menu.hide-palette"
+msgstr "Nascondi palette colori"
+
+#: src/app/main/ui/workspace/main_menu.cljs:326
+msgid "workspace.header.menu.hide-rules"
+msgstr "Nascondi righelli"
+
+#: src/app/main/ui/workspace/main_menu.cljs:825
+msgid "workspace.header.menu.option.preferences"
+msgstr "Preferenze"
+
+#: src/app/main/ui/workspace/main_menu.cljs:814
+msgid "workspace.header.menu.option.view"
+msgstr "Visualizza"
+
+#: src/app/main/ui/workspace/main_menu.cljs:442
+msgid "workspace.header.menu.select-all"
+msgstr "Seleziona tutto"
+
+#: src/app/main/ui/workspace/main_menu.cljs:327
+msgid "workspace.header.menu.show-rules"
+msgstr "Mostra righelli"
+
+#: src/app/main/ui/workspace/main_menu.cljs:374
+msgid "workspace.header.menu.show-textpalette"
+msgstr "Mostra palette caratteri"
+
+#: src/app/main/ui/workspace/header.cljs
+#, unused
+msgid "workspace.header.saving"
+msgstr "In salvataggio"
+
+#: src/app/main/ui/workspace/right_header.cljs:47, src/app/main/ui/workspace/right_header.cljs:52
+msgid "workspace.header.unsaved"
+msgstr "Cambiamenti non salvati"
+
+#: src/app/main/ui/workspace/libraries.cljs:297
+msgid "workspace.libraries.no-shared-libraries-available"
+msgstr "Non ci sono librerie condivise disponibili"
+
+#: src/app/main/ui/workspace/libraries.cljs:388
+msgid "workspace.libraries.no-libraries-need-sync"
+msgstr "Non ci sono librerie condivise che necessitano un aggiornamento"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:85
+msgid "workspace.options.blur-options.title.multiple"
+msgstr "Sfocatura della selezione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:600, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:605
+msgid "workspace.options.component"
+msgstr "Componente"
+
+#: src/app/main/ui/exports/assets.cljs:176, src/app/main/ui/exports/assets.cljs:247, src/app/main/ui/viewer/inspect/exports.cljs:202, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:255
+msgid "workspace.options.exporting-object"
+msgstr "In esportazione…"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:50, src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:178
+msgid "workspace.options.fill"
+msgstr "Riempimento"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
+#, unused
+msgid "workspace.options.flows.flow-start"
+msgstr "Inizio flusso"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:200, src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:241
+msgid "workspace.options.grid.params.color"
+msgstr "Colore"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:274
+msgid "workspace.options.grid.params.margin"
+msgstr "Margine"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:235
+msgid "workspace.options.grid.params.type.bottom"
+msgstr "Basso"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:233
+msgid "workspace.options.grid.params.type.center"
+msgstr "Centro"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:215, src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:292
+msgid "workspace.options.grid.params.use-default"
+msgstr "Usa predefinito"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:251
+msgid "workspace.options.grid.params.width"
+msgstr "Larghezza"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:42, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:373
+msgid "workspace.options.interaction-after-delay"
+msgstr "Dopo un ritardo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:474
+msgid "workspace.options.interaction-action"
+msgstr "Azione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:484
+msgid "workspace.options.interaction-destination"
+msgstr "Destinazione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:667
+msgid "workspace.options.interaction-duration"
+msgstr "Durata"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:421
+msgid "workspace.options.interaction-easing-linear"
+msgstr "Linear"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:51
+msgid "workspace.options.interaction-navigate-to-dest"
+msgstr "Naviga verso: %s"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:133
+msgid "workspace.options.layer-options.blend-mode.difference"
+msgstr "Differenza"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:531
+msgid "workspace.options.layout-item.layout-item-max-w"
+msgstr "Larghezza.Max"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:548
+msgid "workspace.options.layout-item.layout-item-min-h"
+msgstr "Altezza.Min"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
+#, unused
+msgid "workspace.options.layout-item.title.layout-item-max-h"
+msgstr "Altezza massima"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:640
+msgid "workspace.options.radius.single-corners"
+msgstr "Angoli indipendenti"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:639
+msgid "workspace.options.radius.all-corners"
+msgstr "Tutti gli angoli"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:41
+msgid "workspace.options.selection-stroke"
+msgstr "Traccia di selezione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs:118
+msgid "workspace.options.selection-color"
+msgstr "Colori selezionati"
+
+#: src/app/main/ui/viewer/inspect/attributes/shadow.cljs:39, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:225
+msgid "workspace.options.shadow-options.offsety"
+msgstr "Y"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:43
+msgid "workspace.options.stroke"
+msgstr "Traccia"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs
+#, unused
+msgid "workspace.options.stroke-cap.circle-marker"
+msgstr "Marcatore circolare"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:130
+msgid "workspace.options.stroke-cap.diamond-marker-short"
+msgstr "Diamante"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs
+#, unused
+msgid "workspace.options.stroke-cap.line-arrow"
+msgstr "Freccia di linea"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:126
+msgid "workspace.options.stroke-cap.line-arrow-short"
+msgstr "Freccia"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:109
+msgid "workspace.options.text-options.align-top"
+msgstr "Allinea in alto"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:53
+msgid "workspace.options.text-options.text-align-center"
+msgstr "Allinea al centro (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:753
+msgid "workspace.options.use-play-button"
+msgstr ""
+"Utilizza il pulsante di riproduzione nell'header per avviare la "
+"visualizzazione del prototipo."
+
+#: src/app/main/ui/workspace/viewport/path_actions.cljs:189
+msgid "workspace.path.actions.join-nodes"
+msgstr "Unisci nodi (%s)"
+
+#: src/app/main/ui/workspace/context_menu.cljs:451
+msgid "workspace.shape.menu.add-flex"
+msgstr "Aggiungi flex layout"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs, src/app/main/ui/workspace/sidebar/options/menus/component.cljs, src/app/main/ui/workspace/context_menu.cljs, src/app/main/ui/workspace/context_menu.cljs
+#, unused
+msgid "workspace.shape.menu.update-components-in-bulk"
+msgstr "Aggiorna componente principale"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:420
+msgid "shortcut-section.dashboard"
+msgstr "Pannello di controllo"
+
+#: src/app/main/ui/viewer/header.cljs:351
+msgid "viewer.header.inspect-section"
+msgstr "Ispeziona (%s)"
+
+#: src/app/main/ui/workspace/main_menu.cljs:389
+msgid "workspace.header.menu.show-artboard-names"
+msgstr "Mostra nomi delle tavole da disegno"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:38, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:368
+msgid "workspace.options.interaction-while-hovering"
+msgstr "Durante il passaggio del mouse"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:534
+msgid "workspace.options.y"
+msgstr "Asse Y"
+
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:439
+msgid "workspace.shape.menu.restore-main"
+msgstr "Ripristina componente principale"
+
+#: src/app/main/ui/onboarding/questions.cljs
+#, unused
+msgid "branding-illustrations-marketing-pieces"
+msgstr "…branding, illustrazione, materiali di marketing, etc."
+
+#: src/app/main/data/common.cljs:81
+msgid "notifications.by-code.upgrade-version"
+msgstr "Una nuova versione è disponibile, si prega di ricaricare la pagina"
+
+#: src/app/main/ui/dashboard/files.cljs:191, src/app/main/ui/dashboard/projects.cljs:285
+msgid "dashboard.empty-placeholder-files-subtitle"
+msgstr "Quando un membro del progetto crea un file, verrà mostrato qui."
+
+#: src/app/main/ui/dashboard/files.cljs:186, src/app/main/ui/dashboard/projects.cljs:280
+msgid "dashboard.empty-placeholder-files-title"
+msgstr "Nessun file presente."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:39
+#, markdown
+msgid "dashboard.empty-placeholder-libraries"
+msgstr ""
+"Le librerie aggiunte al progetto appariranno qui. Prova a condividere i tuoi "
+"file o ad aggiungerle dal nostro [Librerie e modelli](https://penpot.app/"
+"libraries-templates)."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:35
+msgid "dashboard.empty-placeholder-libraries-subtitle-viewer-role"
+msgstr "Le librerie aggiunte al progetto verrano mostrate qui."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:32
+msgid "dashboard.empty-placeholder-libraries-title"
+msgstr "Nessuna libreria presente."
+
+#: src/app/main/ui/dashboard/placeholder.cljs
+#, markdown, unused
+msgid "dashboard.empty-placeholder-libraries-subtitle"
+msgstr ""
+"Le librerie aggiunte al progetto appariranno qui. Prova a condividere i tuoi "
+"file o ad aggiungerle dal nostro [Librerie e modelli](https://penpot.app/"
+"libraries-templates)."
+
+#: src/app/main/ui/auth/register.cljs:124
+msgid "auth.register-tagline"
+msgstr ""
+"Con un account PenPot gratuito, puoi creare team illimitati e collaborare "
+"con altri designer e sviluppatori su quanti progetti desideri. "
+
+#: src/app/main/ui/auth/login.cljs:180, src/app/main/ui/auth/recovery_request.cljs:77, src/app/main/ui/auth/register.cljs:88
+msgid "auth.work-email"
+msgstr "Email di lavoro"
+
+#: src/app/main/ui/dashboard/files.cljs:185, src/app/main/ui/dashboard/projects.cljs:279
+msgid "dashboard.empty-placeholder-drafts-title"
+msgstr "Nessuna bozza presente."
+
+#: src/app/main/ui/dashboard/files.cljs:190, src/app/main/ui/dashboard/projects.cljs:284
+msgid "dashboard.empty-placeholder-drafts-subtitle"
+msgstr "Quando un membro del progetto crea una bozza, verrà mostrata qui."
+
+#: src/app/main/data/common.cljs:203
+msgid "dashboard.permissions-change.viewer"
+msgstr "Ora sei un visualizzatore di questo team."
+
+#: src/app/main/data/common.cljs:204
+msgid "dashboard.permissions-change.editor"
+msgstr "Ora sei un editor di questo team."
+
+#: src/app/main/data/common.cljs:206
+msgid "dashboard.permissions-change.owner"
+msgstr "Ora sei il proprietario di questo team."
+
+#: src/app/main/data/common.cljs:233
+msgid "dashboard.removed-from-team"
+msgstr "Non fai più parte del team \"%s\"."
+
+#: src/app/main/ui/dashboard/team.cljs:944
+msgid "dashboard.webhooks.cant-edit"
+msgstr "Puoi solo eliminare o modificare i webhook creati da te."
+
+#: src/app/main/ui/dashboard/team.cljs:890
+msgid "dashboard.webhooks.content-type"
+msgstr "Tipo di contenuto"
+
+#: src/app/main/ui/auth/recovery_request.cljs:57, src/app/main/ui/auth/register.cljs:57, src/app/main/ui/auth/register.cljs:60, src/app/main/ui/dashboard/team.cljs:615, src/app/main/ui/settings/change_email.cljs:37
+msgid "errors.email-has-permanent-bounces"
+msgstr "L'email «%s» ha molti report di rimbalzi permanenti."
+
+#, unused
+msgid "errors.field-min-length"
+msgstr "Deve contenere almeno 1 carattere."
+
+#: src/app/main/errors.cljs:254, src/app/main/ui/dashboard/team.cljs:185, src/app/main/ui/onboarding/team_choice.cljs:104
+msgid "errors.max-quote-reached"
+msgstr "Hai raggiunto la quota '%s'. Contatta il supporto."
+
+#: src/app/main/ui/dashboard/team.cljs:610
+msgid "errors.member-is-muted"
+msgstr ""
+"Il profilo che stai invitando ha le email disattivate (rapporti di spam o "
+"alti tassi di rimbalzo)."
+
+#: src/app/main/ui/dashboard/team.cljs:181, src/app/main/ui/onboarding/team_choice.cljs:100
+msgid "errors.maximum-invitations-by-request-reached"
+msgstr ""
+"È stato raggiunto il massimo numero di email (%s) che possono essere inviate "
+"con una singola richiesta"
+
+#: src/app/main/ui/workspace/colorpicker.cljs:228
+msgid "media.linear"
+msgstr "Lineare"
+
+#: src/app/main/ui/dashboard/team.cljs:888
+msgid "modals.create-webhook.url.placeholder"
+msgstr "https://example.com/postreceive"
+
+#: src/app/main/ui/settings/access_tokens.cljs:260
+msgid "modals.delete-acces-token.accept"
+msgstr "Elimina token"
+
+#: src/app/main/ui/settings/access_tokens.cljs:259
+msgid "modals.delete-acces-token.message"
+msgstr "Sei sicuro di voler eliminare questo token?"
+
+#: src/app/main/ui/delete_shared.cljs:55
+msgid "modals.delete-shared-confirm.activated.no-files-message"
+msgid_plural "modals.delete-shared-confirm.activated.no-files-message"
+msgstr[0] "Non è attivato in alcun file."
+msgstr[1] "Non sono attivati in alcun file."
+
+#: src/app/main/ui/dashboard/team.cljs:978
+msgid "modals.delete-webhook.message"
+msgstr "Sei sicuro di voler eliminare questo webhook?"
+
+#: src/app/main/ui/dashboard/team.cljs:977
+msgid "modals.delete-webhook.title"
+msgstr "Eliminazione del webhook in corso"
+
+#: src/app/main/ui/dashboard/team.cljs:910
+msgid "modals.edit-webhook.submit-label"
+msgstr "Modifica webhook"
+
+#: src/app/main/ui/static.cljs:328
+msgid "not-found.desc-message.error"
+msgstr "Errore 404"
+
+#: src/app/main/ui/auth/recovery_request.cljs:114
+msgid "not-found.login.sent-recovery"
+msgstr "Abbiamo inviato un email di recupero a"
+
+#: src/app/main/ui/static.cljs:63
+msgid "not-found.made-with-love"
+msgstr "Fatto con AMORE e Open Source"
+
+#: src/app/main/ui/static.cljs:310, src/app/main/ui/static.cljs:319
+msgid "not-found.no-permission.ask"
+msgstr "RICHIEDI ACCESSO"
+
+#: src/app/main/ui/onboarding/questions.cljs:268
+msgid "onboarding.questions.team-size.11-30"
+msgstr "11-30"
+
+#: src/app/main/ui/onboarding/questions.cljs:269
+msgid "onboarding.questions.team-size.2-10"
+msgstr "2-10"
+
+#: src/app/main/ui/onboarding/questions.cljs:80
+msgid "onboarding.questions.use.education"
+msgstr "Educazione"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:89
+msgid "shortcuts.bring-backward"
+msgstr "Porta dietro"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:91
+msgid "shortcuts.bring-front"
+msgstr "Porta in primo piano"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:92
+msgid "shortcuts.clear-undo"
+msgstr "Pulisci cronologia"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:85
+msgid "shortcuts.bool-exclude"
+msgstr "Escludi"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:86
+msgid "shortcuts.bool-intersection"
+msgstr "Interseca"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:87
+msgid "shortcuts.bool-union"
+msgstr "Unisci"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:101
+msgid "shortcuts.draw-curve"
+msgstr "Curva"
+
+#: src/app/main/ui/workspace/right_header.cljs:115, src/app/main/ui/workspace/sidebar/shortcuts.cljs:97
+msgid "shortcuts.decrease-zoom"
+msgstr "Zoom indietro"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:100
+msgid "shortcuts.detach-component"
+msgstr "Scollega componente"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:128
+msgid "shortcuts.line-height-dec"
+msgstr "Diminuisci interlinea"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:116
+msgid "shortcuts.go-to-drafts"
+msgstr "Vai alle bozze"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:119
+msgid "shortcuts.group"
+msgstr "Raggruppa"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:123
+msgid "shortcuts.insert-image"
+msgstr "Inserisci immagine"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:138
+msgid "shortcuts.move-fast-right"
+msgstr "Sposta rapidamente a destra"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:131
+msgid "shortcuts.make-corner"
+msgstr "Crea angolo"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:132
+msgid "shortcuts.make-curve"
+msgstr "Crea curva"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:134
+msgid "shortcuts.merge-nodes"
+msgstr "Fondi nodi"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:129
+msgid "shortcuts.line-height-inc"
+msgstr "Aumenta interlinea"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:133
+msgid "shortcuts.mask"
+msgstr "Maschera"
+
+#: src/app/main/ui/workspace/sidebar/assets/file_library.cljs:295
+msgid "workspace.assets.not-found"
+msgstr "Nessun asset trovato"
+
+#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:495
+msgid "workspace.assets.colors.add-color"
+msgstr "Aggiungi colore"
+
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:532
+msgid "workspace.assets.components.add-component"
+msgstr "Aggiungi componente"
+
+#: src/app/main/ui/workspace/sidebar/assets.cljs:163
+msgid "workspace.assets.libraries"
+msgstr "Librerie"
+
+#: src/app/main/ui/workspace/sidebar/assets/file_library.cljs:62, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:347
+msgid "workspace.assets.local-library"
+msgstr "libreria locale"
+
+#: src/app/main/ui/workspace/sidebar/assets/typographies.cljs:408
+msgid "workspace.assets.typography.add-typography"
+msgstr "Aggiungi elemento tipografico"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs
+#, unused
+msgid "workspace.assets.typography.font-id"
+msgstr "Carattere"
+
+#, unused
+msgid "workspace.assets.typography.text-styles"
+msgstr "Stili di testo"
+
+#: src/app/main/ui/workspace/context_menu.cljs:298, src/app/main/ui/workspace/context_menu.cljs:567
+msgid "workspace.focus.focus-off"
+msgstr "Modalità focus disattivata"
+
+#: src/app/main/ui/workspace/libraries.cljs:517, src/app/main/ui/workspace/libraries.cljs:542
+msgid "workspace.libraries.libraries"
+msgstr "LIBRERIE"
+
+#: src/app/main/ui/workspace/libraries.cljs:390
+msgid "workspace.libraries.library-updates"
+msgstr "AGGIORNAMENTI DELLA LIBRERIA"
+
+#: src/app/main/ui/workspace/libraries.cljs:300
+msgid "workspace.libraries.more-templates"
+msgstr "Puoi cercare altri "
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:173
+msgid "workspace.options.component.create-annotation"
+msgstr "Crea un'annotazione"
+
+#: src/app/main/ui/workspace/sidebar/options/page.cljs:38, src/app/main/ui/workspace/sidebar/options/page.cljs:45
+msgid "workspace.options.canvas-background"
+msgstr "Colore di sfondo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:610
+msgid "workspace.options.component.copy"
+msgstr "Copia"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:163
+msgid "workspace.options.constraints"
+msgstr "Vincoli"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:158
+msgid "workspace.options.grid.square"
+msgstr "Quadrato"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:49
+msgid "workspace.options.group-fill"
+msgstr "Riempimento di gruppo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:42
+msgid "workspace.options.group-stroke"
+msgstr "Traccia di gruppo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:159
+msgid "workspace.options.grid.column"
+msgstr "Colonne"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs
+#, unused
+msgid "workspace.options.grid.grid-title"
+msgstr "Griglia"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:229
+msgid "workspace.options.grid.params.type.stretch"
+msgstr "Estendi"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:160
+msgid "workspace.options.grid.row"
+msgstr "Righe"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:183
+msgid "workspace.options.guides.toggle-guide"
+msgstr "Attiva/Disattiva guida"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:412
+msgid "workspace.options.interaction-animation-dissolve"
+msgstr "Dissolvenza"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:418
+msgid "workspace.options.interaction-animation-push"
+msgstr "Spinta"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:323
+msgid "workspace.options.guides.add-guide"
+msgstr "Aggiungi guida"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:187
+msgid "workspace.options.guides.remove-guide"
+msgstr "Rimuovi guida"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:610
+msgid "workspace.options.interaction-background"
+msgstr "Aggiungi sovrapposizione di sfondo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:397
+msgid "workspace.options.interaction-auto"
+msgstr "automatico"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:596
+msgid "workspace.options.interaction-close-outside"
+msgstr "Chiudi al click esterno"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:378
+msgid "workspace.options.interaction-close-overlay"
+msgstr "Chiudi sovrapposizione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:52, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:54, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:56, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:386
+msgid "workspace.options.interaction-none"
+msgstr "(non impostato)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:36, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:366
+msgid "workspace.options.interaction-on-click"
+msgstr "Al click"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:500
+msgid "workspace.options.interaction-preserve-scroll"
+msgstr "Preserva posizione di scorrimento"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:59, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:379
+msgid "workspace.options.interaction-prev-screen"
+msgstr "Schermata precedente"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:521
+msgid "workspace.options.interaction-relative-to"
+msgstr "Relativo a"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:620
+msgid "workspace.options.radius-bottom-left"
+msgstr "Inferiore sinistro"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:302
+msgid "workspace.options.shadow-options.add-shadow"
+msgstr "Aggiungi ombra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:239
+msgid "workspace.options.shadow-options.color"
+msgstr "Colore ombra"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:133
+msgid "workspace.options.stroke-cap.square"
+msgstr "Quadrato"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs
+#, unused
+msgid "workspace.options.stroke-cap.diamond-marker"
+msgstr "Marcatore diamante"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:124
+msgid "workspace.options.stroke-cap.none"
+msgstr "Nessuno"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:132
+msgid "workspace.options.stroke-cap.round"
+msgstr "Rotondo"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:127
+msgid "workspace.options.stroke-cap.triangle-arrow-short"
+msgstr "Triangolo"
+
+#: src/app/main/ui/workspace/plugins.cljs:270
+msgid "workspace.plugins.permissions.comment-write"
+msgstr "Leggi e modifica i tuoi commenti e rispondi a tuo nome."
+
+#: src/app/main/ui/workspace/plugins.cljs:86
+msgid "workspace.plugins.remove-plugin"
+msgstr "Rimuovi plugin"
+
+#: src/app/main/ui/workspace/plugins.cljs:436
+msgid "workspace.plugins.try-out.cancel"
+msgstr "NON ORA"
+
+#: src/app/main/ui/workspace/plugins.cljs:429
+msgid "workspace.plugins.try-out.message"
+msgstr ""
+"Vuoi dare un'occhiata? Si aprirà in una nuova bozza per il tuo team attuale. "
+"(In caso contrario, puoi sempre trovarlo nei plugin installati di qualsiasi "
+"file.)"
+
+#: src/app/main/ui/workspace/plugins.cljs:425
+msgid "workspace.plugins.try-out.title"
+msgstr "IL PLUGIN '%s' È INSTALLATO PER IL TUO UTENTE!"
+
+#: src/app/main/ui/workspace/context_menu.cljs:404
+msgid "workspace.shape.menu.flow-start"
+msgstr "Inizio del flusso"
+
+#: src/app/main/ui/workspace/context_menu.cljs:188
+msgid "workspace.shape.menu.front"
+msgstr "Porta in primo piano"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:84
+msgid "workspace.token.active-themes"
+msgstr "%s temi attivi"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs
+#, unused
+msgid "workspace.token.add set"
+msgstr "Aggiungi set"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:310
+msgid "workspace.token.back-to-themes"
+msgstr "Torna alla lista temi"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:155, src/app/main/ui/workspace/tokens/modals/themes.cljs:239
+msgid "workspace.token.create-theme-title"
+msgstr "Crea tema"
+
+#: src/app/main/ui/workspace/tokens/form.cljs:362
+msgid "workspace.token.create-token"
+msgstr "Crea un nuovo token %s"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:142
+msgid "workspace.token.no-sets"
+msgstr "Nessun set"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:216
+msgid "workspace.token.no-sets-create"
+msgstr "Non sono ancora stati definiti dei set. Creane prima uno."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:239
+msgid "workspace.token.no-sets-yet"
+msgstr "Non ci sono ancora dei set."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:191
+msgid "workspace.token.no-themes"
+msgstr "Non ci sono temi."
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:186
+msgid "workspace.token.grouping-set-alert"
+msgstr "Il raggruppamento di set di token non è ancora supportato."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:52
+msgid "workspace.token.new-theme"
+msgstr "Nuovo tema"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:88
+msgid "workspace.token.no-active-theme"
+msgstr "Nessun tema attivo"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:43
+msgid "workspace.token.no-themes-currently"
+msgstr "Al momento non hai temi."
+
+#: src/app/main/ui/workspace/tokens/form.cljs:193, src/app/main/ui/workspace/tokens/form.cljs:196, src/app/main/ui/workspace/tokens/sidebar.cljs:67
+msgid "workspace.token.resolved-value"
+msgstr "Valore risultato: "
+
+#: src/app/main/ui/workspace/top_toolbar.cljs:133, src/app/main/ui/workspace/top_toolbar.cljs:134
+msgid "workspace.toolbar.move"
+msgstr "Sposta (%s)"
+
+#: src/app/main/ui/workspace/left_toolbar.cljs
+#, unused
+msgid "workspace.toolbar.shortcuts"
+msgstr "Scorciatoie (%s)"
+
+#: src/app/main/ui/workspace/palette.cljs:173, src/app/main/ui/workspace/palette.cljs:174
+msgid "workspace.toolbar.text-palette"
+msgstr "Tipografie (%s)"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:207
+msgid "workspace.versions.snapshot-menu"
+msgstr "Apri menu delle istantanee"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:138
+msgid "workspace.versions.version-menu"
+msgstr "Apri menu delle versioni"
+
+#: src/app/main/ui/dashboard/fonts.cljs:444
+msgid "dashboard.fonts.empty-placeholder-viewer"
+msgstr "Nessun font personalizzato presente."
+
+#: src/app/main/data/common.cljs:205
+msgid "dashboard.permissions-change.admin"
+msgstr "Ora sei un amministratore di questo team."
+
+#: src/app/main/data/workspace/media.cljs:198
+msgid "errors.cannot-upload"
+msgstr "Impossible caricare il file multimediale."
+
+#: src/app/main/errors.cljs:246, src/app/main/errors.cljs:260
+msgid "errors.feature-not-supported"
+msgstr "La funzione '%s' non è supportata."
+
+#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
+#, unused
+msgid "errors.field-not-all-whitespace"
+msgstr "Il nome deve contenere alcuni caratteri oltre allo spazio."
+
+#: src/app/main/errors.cljs:238
+msgid "errors.file-feature-mismatch"
+msgstr ""
+"Sembra che ci sia una discrepanza tra le funzioni abilitate e quelle del "
+"file che stai cercando di aprire. È necessario applicare le migrazioni per "
+"'%s' prima di poter aprire il file."
+
+#: src/app/main/errors.cljs:136
+msgid "errors.paste-data-validation"
+msgstr "Dati non validi negli appunti"
+
+#: src/app/main/ui/auth/recovery_request.cljs:53, src/app/main/ui/dashboard/team.cljs:176, src/app/main/ui/dashboard/team.cljs:606, src/app/main/ui/onboarding/team_choice.cljs:96, src/app/main/ui/settings/change_email.cljs:33
+msgid "errors.profile-is-muted"
+msgstr ""
+"Il tuo profilo ha le email disattivate (rapporti di spam o alti tassi di "
+"rimbalzo)."
+
+#: src/app/main/errors.cljs:250
+msgid "errors.version-not-supported"
+msgstr "Il file ha un numero di versione incompatibile"
+
+#: src/app/main/ui/dashboard/team.cljs:834
+msgid "errors.webhooks.connection"
+msgstr "Errore di connessione, l'URL è irraggiungibile"
+
+#: src/app/main/ui/dashboard/team.cljs:828
+msgid "errors.webhooks.invalid-uri"
+msgstr "L'URL non ha superato la validazione."
+
+#: src/app/main/ui/dashboard/team.cljs:836, src/app/main/ui/dashboard/team.cljs:992
+msgid "errors.webhooks.unexpected-status"
+msgstr "Stato inaspettato %s"
+
+#: src/app/main/ui/viewer/inspect/attributes/geometry.cljs:40
+msgid "inspect.attributes.size"
+msgstr "Dimensione e posizione"
+
+#: src/app/main/ui/viewer/inspect/attributes/text.cljs:116
+msgid "inspect.attributes.typography.font-weight"
+msgstr "Peso del carattere"
+
+#: src/app/main/ui/settings/sidebar.cljs:100
+msgid "labels.access-tokens"
+msgstr "Token di accesso"
+
+#: src/app/main/ui/viewer/inspect/attributes/text.cljs:162
+msgid "inspect.attributes.typography.text-transform.unset"
+msgstr "Annulla impostazione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1051
+#, unused
+msgid "labels.add"
+msgstr "Aggiungi"
+
+#: src/app/main/ui/onboarding/questions.cljs:171
+msgid "labels.canva"
+msgstr "Canva"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:153
+msgid "labels.collapse"
+msgstr "Comprimi"
+
+#: src/app/main/ui/onboarding/questions.cljs:260
+msgid "labels.director"
+msgstr "Direttore"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:199
+msgid "labels.discard"
+msgstr "Scarta"
+
+#: src/app/main/ui/onboarding/questions.cljs:165
+msgid "labels.figma"
+msgstr "Figma"
+
+#: src/app/main/ui/onboarding/questions.cljs:259
+msgid "labels.founder"
+msgstr "Amministratore delegato e Fondatore"
+
+#: src/app/main/ui/onboarding/questions.cljs:258
+msgid "labels.freelancer"
+msgstr "Libero professionista"
+
+#: src/app/main/ui/onboarding/questions.cljs:248
+msgid "labels.graphic-design"
+msgstr "Graphic design"
+
+#: src/app/main/ui/dashboard/team.cljs:1006
+msgid "labels.inactive"
+msgstr "Inattivo"
+
+#: src/app/main/ui/onboarding/questions.cljs:173
+msgid "labels.invision"
+msgstr "InVision"
+
+#: src/app/main/ui/onboarding/questions.cljs:249
+msgid "labels.marketing"
+msgstr "Marketing"
+
+#: src/app/main/ui/comments.cljs:340, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:295, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:324
+msgid "labels.options"
+msgstr "Opzioni"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:149, src/app/main/ui/workspace/sidebar/versions.cljs:288
+msgid "labels.restore"
+msgstr "Ricarica file"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:229
+msgid "labels.sets"
+msgstr "Set"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:187
+msgid "labels.themes"
+msgstr "Temi"
+
+#: src/app/main/ui/dashboard/sidebar.cljs:523, src/app/main/ui/dashboard/team.cljs:97, src/app/main/ui/dashboard/team.cljs:107, src/app/main/ui/dashboard/team.cljs:918
+msgid "labels.webhooks"
+msgstr "Webhook"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:140
+msgid "modals.delete-component-annotation.message"
+msgstr "Sei sicuro di voler eliminare questa annotazione?"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:139
+msgid "modals.delete-component-annotation.title"
+msgstr "Elimina annotazione"
+
+#: src/app/main/ui/delete_shared.cljs:57
+msgid "modals.delete-shared-confirm.activated.scd-message"
+msgid_plural "modals.delete-shared-confirm.activated.scd-message"
+msgstr[0] "Questa libreria è attivata qui: "
+msgstr[1] "Queste librerie sono attivate qui: "
+
+#: src/app/main/ui/dashboard/team.cljs:216
+msgid "modals.invite-team-member.text"
+msgstr ""
+"Puoi invitare membri nel team affinché possano accedere a questo file e a "
+"tutti i file del team."
+
+#: src/app/main/ui/dashboard/sidebar.cljs:400, src/app/main/ui/dashboard/sidebar.cljs:421, src/app/main/ui/dashboard/team.cljs:421, src/app/main/ui/dashboard/team.cljs:444
+msgid "modals.leave-confirm.title"
+msgstr "Lasciando il team"
+
+#: src/app/main/ui/delete_shared.cljs:48
+msgid "modals.move-shared-confirm.message"
+msgid_plural "modals.move-shared-confirm.message"
+msgstr[0] "Sei sicuro di voler spostare questa libreria?"
+msgstr[1] "Sei sicuro di voler spostare queste librerie?"
+
+#: src/app/main/ui/delete_shared.cljs:53
+msgid "modals.move-shared-confirm.accept"
+msgid_plural "modals.move-shared-confirm.accept"
+msgstr[0] "Sposta"
+msgstr[1] "Sposta"
+
+#: src/app/main/ui/static.cljs:134
+msgid "not-found.login.free"
+msgstr ""
+"Penpot è lo strumento di design gratuito e open-source per la collaborazione "
+"tra design e codice"
+
+#: src/app/main/ui/auth/recovery_request.cljs:116
+msgid "not-found.login.sent-recovery-check"
+msgstr "Controlla la tua email e clicca nel link per creare una nuova password."
+
+#: src/app/main/ui/static.cljs:148
+msgid "not-found.login.signup-free"
+msgstr "Iscriviti gratuitamente"
+
+#: src/app/main/ui/static.cljs:149
+msgid "not-found.login.start-using"
+msgstr "E inizia ad utilizzare Penpot in pochi secondi!"
+
+#: src/app/main/ui/static.cljs:290
+msgid "not-found.no-permission.already-requested.or-others.file"
+msgstr ""
+"Hai già richiesto l'accesso a questo file o ad altri file o progetti di "
+"questo team."
+
+#: src/app/main/ui/static.cljs:296
+msgid "not-found.no-permission.already-requested.or-others.project"
+msgstr ""
+"Hai già richiesto l'accesso a questo progetto o ad altri progetti o file di "
+"questo team."
+
+#: src/app/main/ui/static.cljs:295
+msgid "not-found.no-permission.already-requested.project"
+msgstr "Hai già richiesto l'accesso a questo progetto."
+
+#: src/app/main/ui/static.cljs:302
+msgid "not-found.no-permission.done.remember"
+msgstr "Ricorda che, se il proprietario lo consente, verrai invitato nel team."
+
+#: src/app/main/ui/static.cljs:301
+msgid "not-found.no-permission.done.success"
+msgstr "La tua richiesta è stata inviata correttamente!"
+
+#: src/app/main/ui/static.cljs:246, src/app/main/ui/static.cljs:257
+msgid "not-found.no-permission.project-name"
+msgstr "PROGETTO"
+
+#: src/app/main/ui/static.cljs:308
+msgid "not-found.no-permission.you-can-ask.file"
+msgstr "Per accedere a questo file, puoi chiedere al proprietario del team."
+
+#: src/app/main/data/common.cljs:90
+msgid "notifications.by-code.maintenance"
+msgstr ""
+"Pausa di manutenzione: saremo offline per una breve manutenzione tra 5 "
+"minuti."
+
+#: src/app/main/ui/dashboard/team.cljs:652
+msgid "notifications.invitation-link-copied"
+msgstr "Link d'invito copiato"
+
+#: src/app/main/ui/onboarding/newsletter.cljs:63
+msgid "onboarding-v2.newsletter.desc"
+msgstr ""
+"Iscriviti alla newsletter di Penpot per rimanere aggiornato sui progressi e "
+"le novità dello sviluppo del prodotto."
+
+#: src/app/main/ui/onboarding/newsletter.cljs:83
+msgid "onboarding-v2.newsletter.news"
+msgstr ""
+"Inviami notizie su Penpot (contenuti del blog, tutorial video, dirette…)."
+
+#: src/app/main/ui/onboarding/newsletter.cljs:71
+msgid "onboarding-v2.newsletter.updates"
+msgstr ""
+"Inviami aggiornamenti sul prodotto (nuove funzionalità, versioni, "
+"correzioni…)."
+
+#: src/app/main/ui/onboarding/team_choice.cljs:254
+msgid "onboarding.choice.team-up.continue-creating-team"
+msgstr "Continua creando un team"
+
+#: src/app/main/ui/onboarding/team_choice.cljs:194
+msgid "onboarding.choice.team-up.create-team-without-invite"
+msgstr "Crea team"
+
+#: src/app/main/ui/onboarding/team_choice.cljs:259
+msgid "onboarding.choice.team-up.start-without-a-team-description"
+msgstr "Potrai creare un team più tardi."
+
+#: src/app/main/ui/onboarding/questions.cljs:113
+msgid "onboarding.questions.lets-get-started"
+msgstr "Iniziamo!"
+
+#: src/app/main/ui/onboarding/questions.cljs:88
+msgid "onboarding.questions.reasons.exploring"
+msgstr "Sto solo esplorando"
+
+#: src/app/main/ui/onboarding/questions.cljs:91
+msgid "onboarding.questions.reasons.fit"
+msgstr "Sto valutando se Penpot è adatto al mio team"
+
+#: src/app/main/ui/onboarding/questions.cljs:97
+msgid "onboarding.questions.reasons.testing"
+msgstr "Sto testando prima del self-hosting"
+
+#: src/app/main/ui/onboarding/questions.cljs:407
+msgid "onboarding.questions.referer.article"
+msgstr "Articolo (Blog, Post, Newsletter)"
+
+#: src/app/main/ui/onboarding/questions.cljs:405
+msgid "onboarding.questions.referer.search"
+msgstr "Motore di ricerca (Google, Yahoo, Bing)"
+
+#: src/app/main/ui/onboarding/questions.cljs:349
+msgid "onboarding.questions.start-with.code"
+msgstr "Generare codice partendo dal design"
+
+#: src/app/main/ui/onboarding/questions.cljs:406
+msgid "onboarding.questions.referer.social"
+msgstr "Social Media (X, LinkedIn, Facebook, etc)"
+
+#: src/app/main/ui/onboarding/questions.cljs:347
+msgid "onboarding.questions.start-with.ds"
+msgstr "Creare Design System"
+
+#: src/app/main/ui/onboarding/questions.cljs:341
+msgid "onboarding.questions.start-with.ui"
+msgstr "Progettare la UI/UX di un'applicazione"
+
+#: src/app/main/ui/onboarding/questions.cljs:343
+msgid "onboarding.questions.start-with.wireframing"
+msgstr "Wireframing"
+
+#: src/app/main/ui/onboarding/questions.cljs:121
+msgid "onboarding.questions.step1.question1"
+msgstr "Per cosa utilizzerai Penpot?"
+
+#: src/app/main/ui/onboarding/questions.cljs:128
+msgid "onboarding.questions.step1.question2"
+msgstr "Cosa ti ha portato su Penpot oggi?"
+
+#: src/app/main/ui/onboarding/questions.cljs:117
+msgid "onboarding.questions.step1.subtitle"
+msgstr ""
+"Facci sapere qualcosa su di te per aiutarci ad ottimizzare Penpot rispetto "
+"alle tue esigenze. Le tue risposte ci aiuteranno a dare priorità a nuove "
+"funzionalità e a guidarti nella giusta direzione per iniziare."
+
+#: src/app/main/ui/onboarding/questions.cljs:115
+msgid "onboarding.questions.step1.title"
+msgstr "Aiutaci a conoscerti meglio"
+
+#: src/app/main/ui/onboarding/questions.cljs:196
+msgid "onboarding.questions.step2.title"
+msgstr "Quale di questi strumenti utilizzi maggiormente?"
+
+#: src/app/main/ui/onboarding/questions.cljs:289
+msgid "onboarding.questions.step3.question1"
+msgstr "Che genere di lavori fai?"
+
+#: src/app/main/ui/onboarding/questions.cljs:317
+msgid "onboarding.questions.step3.question3"
+msgstr "Qual è la dimensione della tua azienda?"
+
+#: src/app/main/ui/onboarding/questions.cljs:287
+msgid "onboarding.questions.step3.title"
+msgstr "Parlaci del tuo lavoro"
+
+#: src/app/main/ui/onboarding/questions.cljs:303
+msgid "onboarding.questions.step3.question2"
+msgstr "Qual è il tuo ruolo?"
+
+#: src/app/main/ui/onboarding/questions.cljs:370
+msgid "onboarding.questions.step4.title"
+msgstr "Da dove ti piacerebbe iniziare?"
+
+#: src/app/main/ui/onboarding/questions.cljs:428
+msgid "onboarding.questions.step5.title"
+msgstr "Come sei venuto a conoscenza di Penpot?"
+
+#: src/app/main/ui/onboarding/questions.cljs:81
+msgid "onboarding.questions.use.personal"
+msgstr "Personale"
+
+#: src/app/main/ui/onboarding/questions.cljs:79
+msgid "onboarding.questions.use.work"
+msgstr "Lavoro"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:271
+msgid "settings.remove-color"
+msgstr "Rimuovi colore"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:414
+msgid "shortcut-section.basics"
+msgstr "Nozioni di base"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:423
+msgid "shortcut-section.viewer"
+msgstr "Visualizzatore"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:417
+msgid "shortcut-section.workspace"
+msgstr "Area di lavoro"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:59
+msgid "shortcut-subsection.general-viewer"
+msgstr "Generico"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:83
+msgid "shortcuts.bold"
+msgstr "Attiva/Disattiva grassetto"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:67
+msgid "shortcut-subsection.shape"
+msgstr "Forme"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:69
+msgid "shortcut-subsection.tools"
+msgstr "Strumenti"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:80
+msgid "shortcuts.align-top"
+msgstr "Allinea in alto"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:81
+msgid "shortcuts.align-vcenter"
+msgstr "Allinea al centro verticalmente"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:82
+msgid "shortcuts.artboard-selection"
+msgstr "Crea una tavola da disegno a partire dalla selezione"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:84
+msgid "shortcuts.bool-difference"
+msgstr "Differenza"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:102
+msgid "shortcuts.draw-ellipse"
+msgstr "Ellisse"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:105
+msgid "shortcuts.draw-path"
+msgstr "Tracciato"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:140
+msgid "shortcuts.move-nodes"
+msgstr "Sposta nodo"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:142
+msgid "shortcuts.move-unit-left"
+msgstr "Sposta a sinistra"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:148
+msgid "shortcuts.opacity-2"
+msgstr "Imposta opacità al 20%"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:156
+msgid "shortcuts.open-color-picker"
+msgstr "Selettore colore"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:159
+msgid "shortcuts.open-inspect"
+msgstr "Vai alla sezione di ispezione"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:161
+msgid "shortcuts.open-viewer"
+msgstr "Vai alla sezione interazioni del visualizzatore"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:169
+msgid "shortcuts.select-all"
+msgstr "Seleziona tutto"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:178
+msgid "shortcuts.start-editing"
+msgstr "Inizia a modificare"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:189
+msgid "shortcuts.toggle-focus-mode"
+msgstr "Attiva/Disattiva modalità focus"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:208
+msgid "shortcuts.ungroup"
+msgstr "Separa"
+
+#: src/app/main/ui/dashboard/libraries.cljs:46
+msgid "title.dashboard.shared-libraries"
+msgstr "Librerie condivise - %s - Penpot"
+
+#: src/app/main/ui/dashboard/team.cljs:1074
+msgid "title.team-settings"
+msgstr "Impostazioni - %s - Penpot"
+
+#: src/app/main/ui/viewer.cljs:570
+msgid "viewer.empty-state"
+msgstr "Nessuna tavola da disegno trovata nella pagina."
+
+#: src/app/main/ui/viewer/header.cljs:333
+msgid "viewer.header.interactions-section"
+msgstr "Interazioni (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:66
+msgid "workspace.align.hright"
+msgstr "Allinea a destra (%s)"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:212
+msgid "shortcuts.zoom-lense-increase"
+msgstr "Aumentare lo zoom"
+
+#: src/app/main/ui.cljs:137
+msgid "viewer.breaking-change.message"
+msgstr "Spiacenti!"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:83
+msgid "workspace.align.vtop"
+msgstr "Allinea in alto (%s)"
+
+#: src/app/main/ui/workspace/sidebar/assets.cljs
+#, unused
+msgid "workspace.assets.assets"
+msgstr "Asset"
+
+#: src/app/main/ui/workspace/context_menu.cljs:606
+msgid "workspace.context-menu.grid-track.column.duplicate"
+msgstr "Duplica colonna"
+
+#: src/app/main/ui/workspace/main_menu.cljs:243
+msgid "workspace.header.menu.disable-dynamic-alignment"
+msgstr "Disattiva allineamento dinamico"
+
+#: src/app/main/ui/workspace/main_menu.cljs:373
+msgid "workspace.header.menu.hide-textpalette"
+msgstr "Nascondi palette caratteri"
+
+#: src/app/main/ui/workspace/right_header.cljs:255
+msgid "workspace.header.share"
+msgstr "Condividi"
+
+#: src/app/main/ui/workspace/right_header.cljs:128
+msgid "workspace.header.zoom-fit-all"
+msgstr "Adatta zoom a tutto"
+
+#: src/app/main/ui/workspace/colorpicker.cljs
+#, unused
+msgid "workspace.libraries.colors.rgb-complementary"
+msgstr "RGB Complementare"
+
+#: src/app/main/ui/workspace/colorpicker.cljs:382
+msgid "workspace.libraries.colors.save-color"
+msgstr "Salva stile di colore"
+
+#: src/app/main/ui/workspace/libraries.cljs:216
+msgid "workspace.libraries.file-library"
+msgstr "Libreria del file"
+
+#: src/app/main/ui/workspace/libraries.cljs:78, src/app/main/ui/workspace/libraries.cljs:96
+msgid "workspace.libraries.graphics"
+msgstr "%s grafiche"
+
+#: src/app/main/ui/workspace/libraries.cljs:304
+msgid "workspace.libraries.more-templates-link"
+msgstr "modelli qui"
+
+#: src/app/main/ui/workspace/libraries.cljs:307
+msgid "workspace.libraries.no-matches-for"
+msgstr "Nessun risultato trovato per “%s”"
+
+#: src/app/main/ui/workspace/libraries.cljs:261
+msgid "workspace.libraries.search-shared-libraries"
+msgstr "Cerca librerie condivise"
+
+#: src/app/main/ui/workspace/libraries.cljs:257
+msgid "workspace.libraries.shared-libraries"
+msgstr "LIBRERIE CONDIVISE"
+
+#: src/app/main/ui/workspace/libraries.cljs:410
+msgid "workspace.libraries.update"
+msgstr "Aggiorna"
+
+#: src/app/main/ui/workspace/libraries.cljs:485
+msgid "workspace.libraries.update.see-all-changes"
+msgstr "vedi tutti i cambiamenti"
+
+#: src/app/main/ui/workspace/libraries.cljs:524
+msgid "workspace.libraries.updates"
+msgstr "AGGIORNAMENTI"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:91
+msgid "workspace.options.blur-options.add-blur"
+msgstr "Aggiungi sfocatura"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:86
+msgid "workspace.options.blur-options.title.group"
+msgstr "Sfocatura di gruppo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:112
+msgid "workspace.options.blur-options.remove-blur"
+msgstr "Elimina sfocatura"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:108
+msgid "workspace.options.blur-options.toggle-blur"
+msgstr "Attiva/Disattiva sfocatura"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:172
+msgid "workspace.options.component.edit-annotation"
+msgstr "Modifica un'annotazione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:609
+msgid "workspace.options.component.main"
+msgstr "Principale"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:141, src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:152
+msgid "workspace.options.constraints.center"
+msgstr "Centro"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:229
+msgid "workspace.options.constraints.fix-when-scrolling"
+msgstr "Fisso durante lo scorrimento"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:140
+msgid "workspace.options.constraints.leftright"
+msgstr "Sinistra e Destra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:139
+msgid "workspace.options.constraints.right"
+msgstr "Destra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:149
+msgid "workspace.options.constraints.top"
+msgstr "Superiore"
+
+#: src/app/main/ui/workspace/sidebar/options.cljs:179
+msgid "workspace.options.design"
+msgstr "Design"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs, src/app/main/ui/inspect/exports.cljs
+#, unused
+msgid "workspace.options.export-multiple"
+msgstr "Esporta selezione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:195
+msgid "workspace.options.export.add-export"
+msgstr "Aggiungi esportazione"
+
+#: src/app/main/ui/viewer/inspect/exports.cljs:186, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:236
+msgid "workspace.options.export.suffix"
+msgstr "Suffisso"
+
+#: src/app/main/ui/exports/assets.cljs:248
+msgid "workspace.options.exporting-object-slow"
+msgstr "Esportazione inaspettatamente lenta"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:150
+msgid "workspace.options.fill.add-fill"
+msgstr "Aggiungi colore di riempimento"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:163
+msgid "workspace.options.fill.remove-fill"
+msgstr "Elimina riempimento"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:178
+msgid "workspace.options.flows.flow"
+msgstr "Flusso"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:164
+msgid "workspace.options.flows.flow-starts"
+msgstr "Inizi flusso"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:154
+msgid "workspace.options.flows.remove-flow"
+msgstr "Rimuovi flusso"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:31
+msgid "workspace.options.grid.auto"
+msgstr "Auto"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:413
+msgid "workspace.options.interaction-animation-slide"
+msgstr "Scorrimento"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:680
+msgid "workspace.options.interaction-easing"
+msgstr "Easing"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:41, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:371
+msgid "workspace.options.interaction-mouse-leave"
+msgstr "Uscita del mouse"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:376
+msgid "workspace.options.interaction-open-overlay"
+msgstr "Apri sovrapposizione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:60, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:380
+msgid "workspace.options.interaction-open-url"
+msgstr "Apri un URL"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:409
+msgid "workspace.options.interaction-pos-bottom-center"
+msgstr "In basso centrato"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:406
+msgid "workspace.options.interaction-pos-top-center"
+msgstr "In alto centrato"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:407
+msgid "workspace.options.interaction-pos-bottom-left"
+msgstr "In basso a sinistra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:530
+msgid "workspace.options.interaction-position"
+msgstr "Posizione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:377
+msgid "workspace.options.interaction-toggle-overlay"
+msgstr "Attiva/Disattiva sovrapposizione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:509
+msgid "workspace.options.interaction-url"
+msgstr "URL"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:39, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:369
+msgid "workspace.options.interaction-while-pressing"
+msgstr "Durante la pressione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:735
+msgid "workspace.options.interactions.add-interaction"
+msgstr "Aggiungi interazione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:137
+msgid "workspace.options.layer-options.blend-mode.color"
+msgstr "Colore"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:176, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:182
+msgid "workspace.options.layer-options.toggle-layer"
+msgstr "Attiva/Disattiva visibilità livello"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:515
+msgid "workspace.options.layout-item.layout-item-min-w"
+msgstr "Larghezza.Min"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
+#, unused
+msgid "workspace.options.layout-item.title.layout-item-min-h"
+msgstr "Altezza minima"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
+#, unused
+msgid "workspace.options.layout.margin-all"
+msgstr "Tutti i lati"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs:159
+msgid "workspace.options.more-colors"
+msgstr "Più colori"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:177, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:315
+msgid "workspace.options.shadow-options.remove-shadow"
+msgstr "Rimuovi ombra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:173
+msgid "workspace.options.shadow-options.toggle-shadow"
+msgstr "Attiva/Disattiva ombra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs
+#, unused
+msgid "workspace.options.stroke-cap.square-marker"
+msgstr "Marcatore quadrato"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:164
+msgid "workspace.options.size"
+msgstr "Dimensione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:425
+msgid "workspace.options.size-presets"
+msgstr "Dimensioni predefinite"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:106
+msgid "workspace.options.stroke.mixed"
+msgstr "Misto"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:184
+msgid "workspace.options.stroke.remove-stroke"
+msgstr "Rimuovi traccia"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:89
+msgid "workspace.options.text-options.direction-rtl"
+msgstr "RTL"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:61
+msgid "workspace.options.text-options.text-align-justify"
+msgstr "Giustifica (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:191
+msgid "workspace.options.text-options.title"
+msgstr "Testo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:190
+msgid "workspace.options.text-options.title-group"
+msgstr "Testo di gruppo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:189
+msgid "workspace.options.text-options.title-selection"
+msgstr "Testo della selezione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:465
+msgid "workspace.options.width"
+msgstr "Larghezza"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:523
+msgid "workspace.options.x"
+msgstr "Asse X"
+
+#: src/app/main/ui/workspace/viewport/path_actions.cljs:167
+msgid "workspace.path.actions.add-node"
+msgstr "Aggiungi nodo (%s)"
+
+#: src/app/main/ui/workspace/plugins.cljs:196
+msgid "workspace.plugins.error.manifest"
+msgstr "Il manifesto del plugin è errato."
+
+#: src/app/main/data/plugins.cljs:86, src/app/main/ui/workspace/main_menu.cljs:696, src/app/main/ui/workspace/plugins.cljs:82
+msgid "workspace.plugins.error.need-editor"
+msgstr "Devi essere un editor per utilizzare questo plugin"
+
+#: src/app/main/ui/workspace/plugins.cljs:372
+msgid "workspace.plugins.permissions-update.title"
+msgstr "AGGIORNA QUESTO PLUGIN"
+
+#: src/app/main/ui/workspace/plugins.cljs:376
+msgid "workspace.plugins.permissions-update.warning"
+msgstr ""
+"Il plugin è stato modificato da quando l'hai aperto l'ultima volta. Ora "
+"richiede l'accesso a:"
+
+#: src/app/main/ui/workspace/plugins.cljs:283
+msgid "workspace.plugins.permissions.allow-download"
+msgstr "Inizia il download dei file."
+
+#: src/app/main/ui/workspace/plugins.cljs:276
+msgid "workspace.plugins.permissions.comment-read"
+msgstr "Leggi i tuoi commenti e risposte."
+
+#: src/app/main/ui/workspace/plugins.cljs:442
+msgid "workspace.plugins.try-out.try"
+msgstr "PROVA PLUGIN"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1004, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1030
+msgid "workspace.shape.menu.add-layout"
+msgstr "Aggiungi layout"
+
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:427
+msgid "workspace.shape.menu.create-annotation"
+msgstr "Crea annotazione"
+
+#: src/app/main/ui/workspace/context_menu.cljs:209
+msgid "workspace.shape.menu.flip-horizontal"
+msgstr "Capovolgi orizzontalmente"
+
+#: src/app/main/ui/workspace/context_menu.cljs:205
+msgid "workspace.shape.menu.flip-vertical"
+msgstr "Capovolgi verticalmente"
+
+#: src/app/main/ui/workspace/context_menu.cljs:342
+msgid "workspace.shape.menu.path"
+msgstr "Tracciato"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1022
+msgid "workspace.shape.menu.remove-layout"
+msgstr "Rimuovi layout"
+
+#: src/app/main/ui/workspace/context_menu.cljs:235
+msgid "workspace.shape.menu.rename"
+msgstr "Rinomina"
+
+#: src/app/main/ui/workspace/context_menu.cljs:175
+msgid "workspace.shape.menu.select-layer"
+msgstr "Seleziona livello"
+
+#: src/app/main/ui/workspace/sidebar/layers.cljs:524, src/app/main/ui/workspace/sidebar.cljs:110, src/app/main/ui/workspace/sidebar.cljs:114, src/app/main/ui/workspace/sidebar.cljs:123
+msgid "workspace.sidebar.layers"
+msgstr "Livelli"
+
+#: src/app/main/ui/workspace/sidebar/layers.cljs:307, src/app/main/ui/workspace/sidebar/layers.cljs:340
+msgid "workspace.sidebar.layers.frames"
+msgstr "Tavole da disegno"
+
+#: src/app/main/ui/workspace/sidebar/layers.cljs:308, src/app/main/ui/workspace/sidebar/layers.cljs:354
+msgid "workspace.sidebar.layers.groups"
+msgstr "Gruppi"
+
+#: src/app/main/ui/workspace/sidebar/layers.cljs:313, src/app/main/ui/workspace/sidebar/layers.cljs:424
+msgid "workspace.sidebar.layers.shapes"
+msgstr "Forme"
+
+#: src/app/main/ui/workspace/sidebar/layers.cljs:290
+msgid "workspace.sidebar.layers.search"
+msgstr "Cerca livelli"
+
+#: src/app/main/ui/workspace/sidebar/layers.cljs:311, src/app/main/ui/workspace/sidebar/layers.cljs:396
+msgid "workspace.sidebar.layers.texts"
+msgstr "Testi"
+
+#: src/app/main/ui/viewer/inspect/attributes/svg.cljs:56, src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs:91
+msgid "workspace.sidebar.options.svg-attrs.title"
+msgstr "Attributi SVG importati"
+
+#: src/app/main/ui/workspace/sidebar/sitemap.cljs:229
+msgid "workspace.sidebar.sitemap.add-page"
+msgstr "Aggiungi pagina"
+
+#: src/app/main/ui/workspace/left_header.cljs:91
+msgid "workspace.sitemap"
+msgstr "Sitemap"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:47
+msgid "workspace.token.create-new-theme"
+msgstr "Crea ora il tuo prima tema."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:147
+msgid "workspace.token.delete-theme-title"
+msgstr "Elimina tema"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:302
+msgid "workspace.token.edit-theme-title"
+msgstr "Modifica tema"
+
+#: src/app/main/ui/workspace/tokens/form.cljs:361
+msgid "workspace.token.edit-token"
+msgstr "Modifica token"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:133
+msgid "workspace.token.num-sets"
+msgstr "%s set"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:66
+msgid "workspace.token.original-value"
+msgstr "Valore originale: "
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:208
+msgid "workspace.token.save-theme"
+msgstr "Salva tema"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs
+#, unused
+msgid "workspace.token.theme-name"
+msgstr "Tema %s"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:39, src/app/main/ui/workspace/tokens/modals/themes.cljs:84
+msgid "workspace.token.themes"
+msgstr "Temi"
+
+#: src/app/main/ui/workspace/palette.cljs:165, src/app/main/ui/workspace/palette.cljs:166
+msgid "workspace.toolbar.color-palette"
+msgstr "Palette colori (%s)"
+
+#: src/app/main/ui/workspace/right_header.cljs:235, src/app/main/ui/workspace/right_header.cljs:236
+msgid "workspace.toolbar.comments"
+msgstr "Commenti (%s)"
+
+#: src/app/main/ui/workspace/top_toolbar.cljs:181, src/app/main/ui/workspace/top_toolbar.cljs:182
+msgid "workspace.toolbar.curve"
+msgstr "Curva (%s)"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:331
+msgid "workspace.undo.empty"
+msgstr "Non ci sono cambiamenti nella cronologia al momento"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:110
+msgid "workspace.undo.entry.multiple.color"
+msgstr "colori"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:113
+msgid "workspace.undo.entry.multiple.frame"
+msgstr "tavole da disegno"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:115
+msgid "workspace.undo.entry.multiple.media"
+msgstr "asset grafici"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:121
+msgid "workspace.undo.entry.multiple.text"
+msgstr "testi"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:193
+msgid "workspace.versions.autosaved.entry"
+msgstr "%s versioni di salvataggio automatico"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:224
+msgid "workspace.versions.button.pin"
+msgstr "Fissa versione"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:345, src/app/main/ui/workspace/sidebar/versions.cljs:347
+msgid "workspace.versions.button.save"
+msgstr "Salva versione"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:354
+msgid "workspace.versions.empty"
+msgstr "Non ci sono ancora versioni"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:190
+msgid "workspace.versions.expand-snapshot"
+msgstr "Espandi istantanee"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:327
+msgid "workspace.versions.filter.all"
+msgstr "Tutte le versioni"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:326
+msgid "workspace.versions.filter.label"
+msgstr "Filtro versioni"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:328
+msgid "workspace.versions.filter.mine"
+msgstr "La mie versioni"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:334
+msgid "workspace.versions.filter.user"
+msgstr "Versioni di %s"
+
+#: src/app/main/ui/onboarding/team_choice.cljs:257
+msgid "onboarding.choice.team-up.start-without-a-team"
+msgstr "Inizia senza un team"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:94
+msgid "shortcuts.create-component"
+msgstr "Crea componente"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:110
+msgid "shortcuts.export-shapes"
+msgstr "Esporta forme"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:171
+msgid "shortcuts.select-parent-layer"
+msgstr "Seleziona livello genitore"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:174
+msgid "shortcuts.show-pixel-grid"
+msgstr "Mostra/Nascondi griglia pixel"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:175
+msgid "shortcuts.show-shortcuts"
+msgstr "Mostra/Nascondi scorciatoie"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:173
+msgid "shortcuts.separate-nodes"
+msgstr "Separa nodi"
+
+#: src/app/main/ui/viewer/interactions.cljs:315
+msgid "viewer.header.show-interactions-on-click"
+msgstr "Mostra interazioni al click"
+
+#: src/app/main/ui/workspace/colorpicker.cljs:234
+msgid "workspace.libraries.colors.rgba"
+msgstr "RGBA"
+
+#: src/app/main/ui/workspace/sidebar/options.cljs:187, src/app/main/ui/workspace/sidebar/options.cljs:190
+msgid "workspace.options.inspect"
+msgstr "Ispeziona"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:236
+msgid "workspace.options.grid.params.type.right"
+msgstr "Destra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.right"
+msgstr "A destra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.space-around"
+msgstr "spazio intorno"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.space-between"
+msgstr "spazio tra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:184
+msgid "workspace.options.recent-fonts"
+msgstr "Recenti"
+
+#: src/app/main/ui/workspace/context_menu.cljs:286
+msgid "workspace.shape.menu.create-artboard-from-selection"
+msgstr "Tavola da disegno da selezione"
+
+#: src/app/main/ui/workspace/context_menu.cljs:140
+msgid "workspace.shape.menu.copy"
+msgstr "Copia"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:114
+msgid "workspace.undo.entry.multiple.group"
+msgstr "gruppi"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:146
+msgid "workspace.undo.entry.move"
+msgstr "Oggetti spostati"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:111
+msgid "workspace.undo.entry.multiple.component"
+msgstr "componenti"
+
+#: src/app/main/ui/settings/access_tokens.cljs:134
+msgid "dashboard.access-tokens.expiration-60-days"
+msgstr "60 giorni"
+
+#: src/app/main/ui/dashboard/fonts.cljs:445
+msgid "dashboard.fonts.empty-placeholder-viewer-sub"
+msgstr ""
+"Quando un membro del progetto carica un font personalizzato, verrà mostrato "
+"qui."
+
+#: src/app/main/ui/dashboard/team.cljs:1043
+msgid "dashboard.webhooks.empty.add-one"
+msgstr "Premi il bottone \"Aggiungi webhook\" per aggiungerne uno."
+
+#: src/app/main/ui/dashboard/team.cljs:1042
+msgid "dashboard.webhooks.empty.no-webhooks"
+msgstr "Nessun webhook presente."
+
+#: src/app/main/data/users.cljs:731, src/app/main/ui/auth/login.cljs:102, src/app/main/ui/auth/login.cljs:110
+msgid "errors.profile-blocked"
+msgstr "Questo profilo è bloccato"
+
+#, unused
+msgid "errors.validation"
+msgstr "Validazione errore"
+
+#: src/app/main/ui/static.cljs:329
+msgid "not-found.desc-message.doesnt-exist"
+msgstr "Questa pagina non esiste"
+
+#: src/app/main/ui/static.cljs:289
+msgid "not-found.no-permission.already-requested.file"
+msgstr "Hai già richiesto l'accesso a questo file."
+
+#: src/app/main/ui/static.cljs:307
+msgid "not-found.no-permission.file"
+msgstr "Non hai accesso a questo file."
+
+#: src/app/main/ui/static.cljs:317
+msgid "not-found.no-permission.you-can-ask.project"
+msgstr "Per accedere a questo progetto, puoi chiedere al proprietario del team."
+
+#: src/app/main/ui/onboarding/questions.cljs:94
+msgid "onboarding.questions.reasons.alternative"
+msgstr "Sto cercando un'alternativa a Figma, XD, ecc"
+
+#: src/app/main/ui/onboarding/questions.cljs:345
+msgid "onboarding.questions.start-with.prototyping"
+msgstr "Prototipazione"
+
+#: src/app/main/ui/viewer/inspect/exports.cljs:155, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:632, src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:137, src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:148, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:204, src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:161, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:470, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:476, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:494, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:500, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:526, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:537, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:554, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:569, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:576, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:312, src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:182, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:378, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:395, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:248, src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:172
+msgid "settings.multiple"
+msgstr "Misto"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:90
+msgid "shortcuts.bring-forward"
+msgstr "Porta avanti"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:143
+msgid "shortcuts.move-unit-right"
+msgstr "Sposta a destra"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:141
+msgid "shortcuts.move-unit-down"
+msgstr "Sposta in basso"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:172
+msgid "shortcuts.select-prev"
+msgstr "Seleziona livello precedente"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:182
+msgid "shortcuts.text-align-justify"
+msgstr "Allinea giustificato"
+
+#: src/app/main/ui/dashboard/grid.cljs:138, src/app/main/ui/dashboard/grid.cljs:170, src/app/main/ui/workspace/sidebar/assets/colors.cljs:487, src/app/main/ui/workspace/sidebar/assets.cljs:147
+msgid "workspace.assets.colors"
+msgstr "Colori"
+
+#: src/app/main/ui/workspace/context_menu.cljs:607
+msgid "workspace.context-menu.grid-track.column.add-before"
+msgstr "Aggiungi 1 colonna a sinistra"
+
+#: src/app/main/ui/workspace/main_menu.cljs:803
+msgid "workspace.header.menu.option.edit"
+msgstr "Modifica"
+
+#: src/app/main/ui/workspace/main_menu.cljs:792
+msgid "workspace.header.menu.option.file"
+msgstr "File"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:311
+msgid "workspace.libraries.text.multiple-typography"
+msgstr "Elementi tipografici multipli"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:745
+msgid "workspace.options.add-interaction"
+msgstr "Clicca il bottone + per aggiungere interazioni."
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:207, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:242
+msgid "workspace.options.export.remove-export"
+msgstr "Rimuovi esportazione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:464, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:465, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:470, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:669, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:671, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:675
+msgid "workspace.options.interaction-ms"
+msgstr "ms"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
+#, unused
+msgid "workspace.options.interaction-out"
+msgstr "Fuori"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:422
+msgid "workspace.options.interaction-easing-ease"
+msgstr "Ease"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:375
+msgid "workspace.options.interaction-navigate-to"
+msgstr "Naviga verso"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:408
+msgid "workspace.options.interaction-pos-bottom-right"
+msgstr "In basso a destra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:402
+msgid "workspace.options.interaction-pos-manual"
+msgstr "Manuale"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:403
+msgid "workspace.options.interaction-pos-center"
+msgstr "Centrato"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
+#, unused
+msgid "workspace.options.interactions.remove-interaction"
+msgstr "Rimuovi interazione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:404
+msgid "workspace.options.interaction-pos-top-left"
+msgstr "In alto a sinistra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:405
+msgid "workspace.options.interaction-pos-top-right"
+msgstr "In alto a destra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:126
+msgid "workspace.options.layer-options.blend-mode.color-burn"
+msgstr "Colore brucia"
+
+#: src/app/main/ui/viewer/inspect/attributes/shadow.cljs:40, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:199, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:201
+msgid "workspace.options.shadow-options.blur"
+msgstr "Sfoca"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:669
+msgid "workspace.options.show-in-viewer"
+msgstr "Mostra in modalità visualizzazione"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:129
+msgid "workspace.options.stroke-cap.circle-marker-short"
+msgstr "Cerchio"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs
+#, unused
+msgid "workspace.options.stroke-cap.triangle-arrow"
+msgstr "Freccia triangolo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:171
+msgid "workspace.options.stroke.add-stroke"
+msgstr "Aggiungi colore traccia"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:113
+msgid "workspace.options.text-options.align-middle"
+msgstr "Allinea verticalmente al centro"
+
+#: src/app/main/ui/workspace/context_menu.cljs:346, src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:75
+msgid "workspace.shape.menu.difference"
+msgstr "Differenza"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:194, src/app/main/ui/workspace/tokens/sidebar.cljs:210
+msgid "workspace.token.create-one"
+msgstr "Creane uno."
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:72
+msgid "workspace.token.edit-themes"
+msgstr "Modifica temi"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:318
+msgid "workspace.token.set-selection-theme"
+msgstr ""
+"Definisci quali set token dovrebbe essere usati come parte di questo tema:"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:172
+msgid "workspace.token.select-set"
+msgstr "Seleziona set."
+
+#: src/app/main/ui/workspace/sidebar.cljs:117, src/app/main/ui/workspace/sidebar.cljs:126
+msgid "workspace.toolbar.assets"
+msgstr "Asset"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:187
+msgid "workspace.versions.autosaved.version"
+msgstr "Salvataggio automatico %s"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:219
+msgid "workspace.versions.button.restore"
+msgstr "Ripristina versione"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:283
+msgid "workspace.versions.restore-warning"
+msgstr "Vuoi ripristinare questa versione?"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:340
+msgid "workspace.versions.loading"
+msgstr "Caricamento…"
+
+#: src/app/main/ui/auth/login.cljs:290
+msgid "auth.login-account-title"
+msgstr "Accedi al mio account"
+
+#, unused
+msgid "auth.terms-privacy-agreement"
+msgstr ""
+"Quando crei un nuovo account, accetti i nostri termini di servizio e la "
+"politica sulla privacy."
+
+#: src/app/main/errors.cljs:233
+msgid "errors.team-feature-mismatch"
+msgstr "Rilevata funzione incompatibile '%s'"
+
+#: src/app/main/ui/dashboard/team.cljs:830, src/app/main/ui/dashboard/team.cljs:989
+msgid "errors.webhooks.ssl-validation"
+msgstr "Errore nella validazione SSL."
+
+#: src/app/main/ui/workspace/colorpicker.cljs:226
+msgid "media.solid"
+msgstr "Solido"
+
+#: src/app/main/ui/settings/access_tokens.cljs:125
+msgid "modals.create-access-token.name.label"
+msgstr "Nome"
+
+#: src/app/main/ui/settings/access_tokens.cljs:127
+msgid "modals.create-access-token.name.placeholder"
+msgstr "Il nome può aiutare a capire a cosa serve il token"
+
+#: src/app/main/ui/settings/access_tokens.cljs:131
+msgid "modals.create-access-token.expiration-date.label"
+msgstr "Data di scadenza"
+
+#: src/app/main/ui/dashboard/team.cljs:979
+msgid "modals.delete-webhook.accept"
+msgstr "Elimina webhook"
+
+#: src/app/main/ui/dashboard/team.cljs:875
+msgid "modals.edit-webhook.title"
+msgstr "Modifica webhook"
+
+#: src/app/main/ui/dashboard/change_owner.cljs:58
+msgid "modals.leave-and-reassign.forbidden"
+msgstr ""
+"Non puoi lasciare il team se non c'è un altro membro da promuovere a "
+"proprietario. Potresti voler eliminare il team."
+
+#: src/app/main/ui/delete_shared.cljs:43
+msgid "modals.move-shared-confirm.title"
+msgid_plural "modals.move-shared-confirm.title"
+msgstr[0] "Sposta libreria"
+msgstr[1] "Sposta librerie"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:177
+msgid "shortcuts.snap-pixel-grid"
+msgstr "Aggancia alla griglia pixel"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:192
+msgid "shortcuts.toggle-history"
+msgstr "Attiva/Disattiva cronologia"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:193
+msgid "shortcuts.toggle-layers"
+msgstr "Attiva/Disattiva livelli"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:195
+msgid "shortcuts.toggle-layout-grid"
+msgstr "Aggiungi/Rimuovi grid layout"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:197
+msgid "shortcuts.toggle-lock-size"
+msgstr "Blocca proporzioni"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:198
+msgid "shortcuts.toggle-rulers"
+msgstr "Mostra/Nascondi righelli"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:213
+msgid "shortcuts.zoom-selected"
+msgstr "Zoom su selezione"
+
+#: src/app/main/ui/auth/verify_token.cljs:67, src/app/main/ui/auth.cljs:34
+msgid "title.default"
+msgstr "Penpot - Libertà di design per i team"
+
+#: src/app/main/ui/settings/access_tokens.cljs:281
+msgid "title.settings.access-tokens"
+msgstr "Profilo - Token di accesso"
+
+#: src/app/main/ui/settings/password.cljs:103
+msgid "title.settings.password"
+msgstr "Password - Penpot"
+
+#: src/app/main/ui/dashboard/team.cljs:524
+msgid "title.team-members"
+msgstr "Membri - %s - Penpot"
+
+#: src/app/main/ui/dashboard/team.cljs:1027
+msgid "title.team-webhooks"
+msgstr "Webhook - %s - Penpot"
+
+#: src/app/main/ui/workspace.cljs:198
+msgid "title.workspace"
+msgstr "%s - Penpot"
+
+#: src/app/main/ui/viewer/interactions.cljs:296
+msgid "viewer.header.dont-show-interactions"
+msgstr "Non mostrare le interazioni"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:58
+msgid "workspace.align.hcenter"
+msgstr "Allinea orizzontalmente al centro (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:74
+msgid "workspace.align.hdistribute"
+msgstr "Distribuisci spaziatura orizzontale (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:50
+msgid "workspace.align.hleft"
+msgstr "Allinea a sinistra (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:99
+msgid "workspace.align.vbottom"
+msgstr "Allinea in basso (%s)"
+
+#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:255, src/app/main/ui/workspace/sidebar/assets/components.cljs:580, src/app/main/ui/workspace/sidebar/assets/graphics.cljs:428, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:452
+msgid "workspace.assets.group"
+msgstr "Gruppo"
+
+#: src/app/main/ui/workspace/sidebar/assets/groups.cljs:137
+msgid "workspace.assets.group-name"
+msgstr "Nome gruppo"
+
+#: src/app/main/ui/workspace/sidebar/assets/graphics.cljs:384, src/app/main/ui/workspace/sidebar/assets.cljs:143
+msgid "workspace.assets.graphics"
+msgstr "Grafiche"
+
+#, unused
+msgid "workspace.assets.open-library"
+msgstr "Apri file libreria"
+
+#: src/app/main/ui/workspace/sidebar/assets/groups.cljs:128
+msgid "workspace.assets.rename-group"
+msgstr "Rinomina gruppo"
+
+#: src/app/main/ui/workspace/context_menu.cljs:610
+msgid "workspace.context-menu.grid-track.column.delete-shapes"
+msgstr "Elimina colonna e forme"
+
+#: src/app/main/ui/workspace/header.cljs
+#, unused
+msgid "workspace.header.menu.disable-scale-text"
+msgstr "Disattiva ridimensionamento testo"
+
+#: src/app/main/ui/workspace/main_menu.cljs:212
+msgid "workspace.header.menu.disable-snap-ruler-guides"
+msgstr "Disattiva allineamento alle guide righello"
+
+#: src/app/main/ui/workspace/main_menu.cljs:198
+msgid "workspace.header.menu.enable-scale-content"
+msgstr "Attiva ridimensionamento proporzionale"
+
+#: src/app/main/ui/workspace/main_menu.cljs:197
+msgid "workspace.header.menu.disable-scale-content"
+msgstr "Disattiva ridimensionamento proporzionale"
+
+#: src/app/main/ui/workspace/main_menu.cljs:342
+msgid "workspace.header.menu.hide-guides"
+msgstr "Nascondi guide"
+
+#: src/app/main/ui/workspace/main_menu.cljs:213
+msgid "workspace.header.menu.enable-snap-ruler-guides"
+msgstr "Allinea alle guide righello"
+
+#: src/app/main/ui/workspace/main_menu.cljs:388
+msgid "workspace.header.menu.hide-artboard-names"
+msgstr "Nascondi nomi delle tavole da disegno"
+
+#: src/app/main/ui/viewer/header.cljs:98, src/app/main/ui/workspace/right_header.cljs:125
+msgid "workspace.header.reset-zoom"
+msgstr "Reimposta"
+
+#: src/app/main/ui/workspace/main_menu.cljs:283
+msgid "workspace.header.menu.toggle-light-theme"
+msgstr "Passa al tema chiaro"
+
+#: src/app/main/ui/workspace/main_menu.cljs:457
+msgid "workspace.header.menu.undo"
+msgstr "Annulla"
+
+#: src/app/main/ui/workspace/header.cljs
+#, unused
+msgid "workspace.header.save-error"
+msgstr "Errore durante il salvataggio"
+
+#: src/app/main/ui/workspace/right_header.cljs:57
+msgid "workspace.header.saved"
+msgstr "Salvato"
+
+#: src/app/main/ui/workspace/right_header.cljs:260
+msgid "workspace.header.viewer"
+msgstr "Modalità di visualizzazione (%s)"
+
+#: src/app/main/ui/workspace/viewport/grid_layout_editor.cljs:62
+msgid "workspace.layout_grid.editor.top-bar.locate"
+msgstr "Individua"
+
+#: src/app/main/ui/workspace/libraries.cljs:81, src/app/main/ui/workspace/libraries.cljs:100
+msgid "workspace.libraries.colors"
+msgstr "%s colori"
+
+#: src/app/main/ui/workspace/colorpicker.cljs
+#, unused
+msgid "workspace.libraries.colors.hsv"
+msgstr "HSV"
+
+#: src/app/main/ui/workspace/viewport/grid_layout_editor.cljs:65
+msgid "workspace.layout_grid.editor.top-bar.done"
+msgstr "Fatto"
+
+#: src/app/main/ui/workspace/libraries.cljs:291
+msgid "workspace.libraries.loading"
+msgstr "Caricamento…"
+
+#: src/app/main/ui/workspace/libraries.cljs:283
+msgid "workspace.libraries.shared-library-btn"
+msgstr "Connetti libreria"
+
+#: src/app/main/ui/workspace/libraries.cljs:250
+msgid "workspace.libraries.unlink-library-btn"
+msgstr "Disconnetti libreria"
+
+#: src/app/main/ui/viewer/inspect/annotation.cljs:19, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:181
+msgid "workspace.options.component.annotation"
+msgstr "Annotazione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:138
+msgid "workspace.options.constraints.left"
+msgstr "Sinistra"
+
+#: src/app/main/ui/exports/assets.cljs:245
+msgid "workspace.options.exporting-object-error"
+msgstr "Esportazione fallita"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:320
+msgid "workspace.options.guides.title"
+msgstr "Guide"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:124
+msgid "workspace.options.layer-options.blend-mode.darken"
+msgstr "Scurisci"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:138
+msgid "workspace.options.layer-options.blend-mode.luminosity"
+msgstr "Luminosità"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:129
+msgid "workspace.options.layer-options.blend-mode.color-dodge"
+msgstr "Colore scherma"
+
+#: src/app/main/ui/workspace/context_menu.cljs:496, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:764, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1052
+msgid "workspace.shape.menu.delete"
+msgstr "Elimina"
+
+#: src/app/main/ui/settings/access-tokens.cljs
+#, unused
+msgid "dashboard.access-tokens.create-success"
+msgstr "Token di accesso creato con successo."
+
+#: src/app/main/ui/settings/access_tokens.cljs:143
+msgid "dashboard.access-tokens.token-will-expire"
+msgstr "Il token scadrà il %s"
+
+#: src/app/main/ui/settings/access_tokens.cljs:187
+msgid "dashboard.access-tokens.personal.description"
+msgstr ""
+"I token di accesso personali funzionano come alternativa al nostro sistema "
+"di autenticazione login/password e può essere usato per consentire ad "
+"un'applicazione di accedere alle API di Penpot interne"
+
+#: src/app/main/ui/dashboard/fonts.cljs:188
+#, markdown
+msgid "dashboard.fonts.warning-text"
+msgstr ""
+"Abbiamo rilevato un possibile problema nei tuoi font relativo alle metriche "
+"verticali per diversi sistemi operativi. Per verificarlo, puoi utilizzare "
+"servizi per le metriche verticali dei font come [questo](https://vertical-"
+"metrics.netlify.app/). Inoltre, ti consigliamo di utilizzare "
+"[Transfonter](https://transfonter.org/) per generare webfont e correggere "
+"errori. "
+
+#: src/app/main/ui/dashboard/team.cljs:899
+msgid "dashboard.webhooks.active"
+msgstr "È attivo"
+
+#: src/app/main/ui/dashboard/team.cljs:923
+msgid "dashboard.webhooks.create"
+msgstr "Crea webhook"
+
+#: src/app/main/ui/dashboard/team.cljs:813
+msgid "dashboard.webhooks.create.success"
+msgstr "Webhook creato con successo."
+
+#: src/app/main/ui/dashboard/team.cljs:920
+msgid "dashboard.webhooks.description"
+msgstr ""
+"I webhook sono un modo semplice per consentire ad altri siti web e app di "
+"essere notificati quando si verificano determinati eventi su Penpot. "
+"Invieremo una richiesta POST a ciascuno degli URL che fornisci."
+
+#, unused
+msgid "dashboard.webhooks.update.success"
+msgstr "Webhook aggiornato con successo."
+
+#: src/app/main/ui/workspace/plugins.cljs:336, src/app/main/ui/workspace/plugins.cljs:390
+msgid "ds.confirm-allow"
+msgstr "Acconsenti"
+
+#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/setti ngs/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
+#, unused
+msgid "errors.field-max-length"
+msgstr "Deve contenere al massimo 1 carattere."
+
+#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
+#, unused
+msgid "errors.invalid-email"
+msgstr "Inserisci una email valida"
+
+#: src/app/main/ui/dashboard/team.cljs:986
+msgid "errors.webhooks.last-delivery"
+msgstr "Errore nell'ultimo invio."
+
+#: src/app/main/ui/dashboard/team.cljs:826
+msgid "errors.webhooks.unexpected"
+msgstr "Errore inaspettato durante la validazione"
+
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:152
+msgid "inspect.empty.help"
+msgstr ""
+"Per ulteriori informazioni su l'ispezione, visita il centro di supporto di "
+"Penpot"
+
+#: src/app/main/ui/static.cljs:61
+msgid "labels.copyright"
+msgstr "Kaleidos @2024"
+
+#: src/app/main/ui/static.cljs:55, src/app/main/ui/static.cljs:133
+msgid "labels.login"
+msgstr "Accesso"
+
+#, unused
+msgid "labels.ok"
+msgstr "Ok"
+
+#: src/app/main/ui/auth/verify_token.cljs:97, src/app/main/ui/dashboard/grid.cljs:104, src/app/main/ui/dashboard/grid.cljs:124, src/app/main/ui/dashboard/import.cljs:253, src/app/main/ui/dashboard/placeholder.cljs:52, src/app/main/ui/ds/product/loader.cljs:52, src/app/main/ui/exports/files.cljs:62, src/app/main/ui/viewer.cljs:637, src/app/main/ui/workspace.cljs:129
+msgid "labels.loading"
+msgstr "Caricamento…"
+
+#: src/app/main/ui/onboarding/questions.cljs:100, src/app/main/ui/onboarding/questions.cljs:175, src/app/main/ui/onboarding/questions.cljs:251, src/app/main/ui/onboarding/questions.cljs:261, src/app/main/ui/onboarding/questions.cljs:351, src/app/main/ui/onboarding/questions.cljs:408
+msgid "labels.other-short"
+msgstr "Altro"
+
+#: src/app/main/ui/onboarding/questions.cljs:140, src/app/main/ui/onboarding/questions.cljs:209, src/app/main/ui/onboarding/questions.cljs:298, src/app/main/ui/onboarding/questions.cljs:312, src/app/main/ui/onboarding/questions.cljs:383, src/app/main/ui/onboarding/questions.cljs:439
+msgid "labels.other"
+msgstr "Altro (specifica)"
+
+#: src/app/main/ui/onboarding/questions.cljs:51
+msgid "labels.previous"
+msgstr "Precedente"
+
+#: src/app/main/ui/onboarding/questions.cljs:245
+msgid "labels.product-design"
+msgstr "Design del prodotto o UX"
+
+#: src/app/main/ui/onboarding/questions.cljs:250
+msgid "labels.product-management"
+msgstr "Gestione del prodotto"
+
+#: src/app/main/ui/workspace.cljs
+#, unused
+msgid "labels.reload-file"
+msgstr "Ricarica file"
+
+#: src/app/main/ui/onboarding/questions.cljs:85, src/app/main/ui/onboarding/questions.cljs:244, src/app/main/ui/onboarding/questions.cljs:255, src/app/main/ui/onboarding/questions.cljs:265
+msgid "labels.select-option"
+msgstr "Seleziona opzione"
+
+#: src/app/main/ui/viewer/header.cljs:205
+msgid "labels.share"
+msgstr "Condividi"
+
+#: src/app/main/ui/onboarding/questions.cljs:247
+msgid "labels.student-teacher"
+msgstr "Studente o docente"
+
+#: src/app/main/ui/onboarding/questions.cljs:167
+msgid "labels.sketch"
+msgstr "Sketch"
+
+#: src/app/main/ui/onboarding/questions.cljs:56
+msgid "labels.start"
+msgstr "Inizia"
+
+#: src/app/main/ui/onboarding/questions.cljs:256
+msgid "labels.team-leader"
+msgstr "Capo del team"
+
+#: src/app/main/ui/onboarding/questions.cljs:257
+msgid "labels.team-member"
+msgstr "Membro del team"
+
+#: src/app/main/ui/workspace/libraries.cljs:189
+msgid "modals.publish-empty-library.accept"
+msgstr "Pubblica"
+
+#: src/app/main/ui/workspace/libraries.cljs:188
+msgid "modals.publish-empty-library.message"
+msgstr "La tua libreria è vuota. Sei sicuro di volerla pubblicare?"
+
+#: src/app/main/ui/workspace/libraries.cljs:187
+msgid "modals.publish-empty-library.title"
+msgstr "Pubblica libreria vuota"
+
+#: src/app/main/ui/static.cljs:50, src/app/main/ui/static.cljs:285, src/app/main/ui/static.cljs:291, src/app/main/ui/static.cljs:297, src/app/main/ui/static.cljs:303, src/app/main/ui/static.cljs:312, src/app/main/ui/static.cljs:321
+msgid "not-found.no-permission.go-dashboard"
+msgstr "Vai al tuo Penpot"
+
+#: src/app/main/ui/static.cljs:247, src/app/main/ui/static.cljs:259
+msgid "not-found.no-permission.penpot-file"
+msgstr "File Penpot"
+
+#: src/app/main/ui/static.cljs:284, src/app/main/ui/static.cljs:316
+msgid "not-found.no-permission.project"
+msgstr "Non hai accesso a questo progetto."
+
+#: src/app/main/ui/static.cljs:309, src/app/main/ui/static.cljs:318
+msgid "not-found.no-permission.if-approves"
+msgstr "Se il proprietario lo consente, sarai invitato al team."
+
+#: src/app/main/ui/onboarding/team_choice.cljs:264
+msgid "onboarding.choice.team-up.continue-without-a-team"
+msgstr "Continua senza team"
+
+#: src/app/main/ui/onboarding/team_choice.cljs:193
+msgid "onboarding.choice.team-up.create-team-and-invite"
+msgstr "Crea team e invita"
+
+#: src/app/main/ui/onboarding/team_choice.cljs:197
+msgid "onboarding.choice.team-up.create-team-and-send-invites-description"
+msgstr "Puoi inviare gli inviti più tardi"
+
+#, unused
+msgid "onboarding.choice.team-up.create-team-and-send-invites"
+msgstr "Crea team e invia inviti"
+
+#, unused
+msgid "onboarding.choice.team-up.create-team-without-inviting"
+msgstr "Crea team senza invitare"
+
+#: src/app/main/ui/onboarding/questions.cljs:267
+msgid "onboarding.questions.team-size.31-50"
+msgstr "31-50"
+
+#: src/app/main/ui/onboarding/questions.cljs:270
+msgid "onboarding.questions.team-size.freelancer"
+msgstr "Sono un libero professionista"
+
+#: src/app/main/ui/onboarding/questions.cljs:266
+msgid "onboarding.questions.team-size.more-than-50"
+msgstr "Più di 50"
+
+#: src/app/main/ui/onboarding/questions.cljs:271
+msgid "onboarding.questions.team-size.personal-project"
+msgstr "Sto lavorando a un progetto personale"
+
+#: src/app/main/ui/onboarding/team_choice.cljs:34
+msgid "onboarding.team-modal.create-team-desc"
+msgstr ""
+"Un team ti consente di collaborare con altri utenti Penpot lavorando negli "
+"stessi file e progetti."
+
+#: src/app/main/ui/onboarding/team_choice.cljs:39
+msgid "onboarding.team-modal.create-team-feature-1"
+msgstr "File e progetti illimitati"
+
+#: src/app/main/ui/onboarding/team_choice.cljs:47
+msgid "onboarding.team-modal.create-team-feature-3"
+msgstr "Gestione ruoli"
+
+#: src/app/main/ui/onboarding/team_choice.cljs:43
+msgid "onboarding.team-modal.create-team-feature-2"
+msgstr "Edizione multiplayer"
+
+#: src/app/main/ui/onboarding/team_choice.cljs:32
+msgid "onboarding.team-modal.team-definition"
+msgstr "Cos'è un team?"
+
+#: src/app/main/ui/onboarding/team_choice.cljs:51
+msgid "onboarding.team-modal.create-team-feature-4"
+msgstr "Membri illimitati"
+
+#: src/app/main/ui/auth/recovery.cljs:88
+msgid "profile.recovery.go-to-login"
+msgstr "Vai all'accesso"
+
+#: src/app/main/ui/onboarding/templates.cljs:78
+msgid "onboarding.templates.subtitle"
+msgstr "Ecco alcuni template."
+
+#: src/app/main/ui/onboarding/templates.cljs:77
+msgid "onboarding.templates.title"
+msgstr "Inizia a progettare"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:224
+msgid "settings.detach"
+msgstr "Scollega"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:276
+msgid "settings.select-this-color"
+msgstr "Seleziona gli elementi che utilizzano questo stile"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:62
+msgid "shortcut-subsection.navigation-dashboard"
+msgstr "Navigazione"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:56
+msgid "shortcut-subsection.alignment"
+msgstr "Allineamento"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:57
+msgid "shortcut-subsection.edit"
+msgstr "Modifica"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:63
+msgid "shortcut-subsection.navigation-viewer"
+msgstr "Navigazione"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:64
+msgid "shortcut-subsection.navigation-workspace"
+msgstr "Navigazione"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:65
+msgid "shortcut-subsection.panels"
+msgstr "Pannelli"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:74
+msgid "shortcuts.align-bottom"
+msgstr "Allinea in basso"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:75
+msgid "shortcuts.align-center"
+msgstr "Allinea al centro"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:72
+msgid "shortcuts.add-comment"
+msgstr "Commenti"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:73
+msgid "shortcuts.add-node"
+msgstr "Aggiungi nodo"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:98
+msgid "shortcuts.delete"
+msgstr "Elimina"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:99
+msgid "shortcuts.delete-node"
+msgstr "Elimina nodo"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:95
+msgid "shortcuts.create-new-project"
+msgstr "Crea nuovo"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:96
+msgid "shortcuts.cut"
+msgstr "Taglia"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:103
+msgid "shortcuts.draw-frame"
+msgstr "Tavola da disegno"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:104
+msgid "shortcuts.draw-nodes"
+msgstr "Disegna tracciato"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:106
+msgid "shortcuts.draw-rect"
+msgstr "Rettangolo"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:107
+msgid "shortcuts.draw-text"
+msgstr "Testo"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:108
+msgid "shortcuts.duplicate"
+msgstr "Duplica"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:109
+msgid "shortcuts.escape"
+msgstr "Annulla"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:111
+msgid "shortcuts.fit-all"
+msgstr "Adatta zoom a tutto"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:112
+msgid "shortcuts.flip-horizontal"
+msgstr "Capovolgi orizzontalmente"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:114
+msgid "shortcuts.font-size-dec"
+msgstr "Riduci dimensione carattere"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:117
+msgid "shortcuts.go-to-libs"
+msgstr "Vai alle librerie condivise"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:118
+msgid "shortcuts.go-to-search"
+msgstr "Cerca"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:113
+msgid "shortcuts.flip-vertical"
+msgstr "Capovolgi verticalmente"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:144
+msgid "shortcuts.move-unit-up"
+msgstr "Sposta in alto"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:516
+msgid "shortcuts.not-found"
+msgstr "Nessuna scorciatoia trovata"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:145
+msgid "shortcuts.next-frame"
+msgstr "Tavola da disegno successiva"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:150
+msgid "shortcuts.opacity-4"
+msgstr "Imposta opacità al 40%"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:162
+msgid "shortcuts.open-workspace"
+msgstr "Vai all'area di lavoro"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:164
+msgid "shortcuts.prev-frame"
+msgstr "Tavola da disegno precedente"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:167
+msgid "shortcuts.scale"
+msgstr "Ridimensiona"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:152
+msgid "shortcuts.opacity-6"
+msgstr "Imposta opacità al 60%"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:155
+msgid "shortcuts.opacity-9"
+msgstr "Imposta opacità al 90%"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:160
+msgid "shortcuts.open-interactions"
+msgstr "Vai alla sezione interazioni"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:186
+msgid "shortcuts.toggle-alignment"
+msgstr "Attiva/Disattiva allineamento dinamico"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:187
+msgid "shortcuts.toggle-assets"
+msgstr "Attiva/Disattiva asset"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:179
+msgid "shortcuts.start-measure"
+msgstr "Avvia misurazione"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:181
+msgid "shortcuts.text-align-center"
+msgstr "Allinea al centro"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:184
+msgid "shortcuts.text-align-right"
+msgstr "Allinea a destra"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:496, src/app/main/ui/workspace/sidebar/shortcuts.cljs:505
+msgid "shortcuts.title"
+msgstr "Scorciatoie da tastiera"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:191
+msgid "shortcuts.toggle-guides"
+msgstr "Mostra/Nascondi guide"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:201
+msgid "shortcuts.toggle-snap-ruler-guide"
+msgstr "Aggancia alle guide del righello"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:203
+msgid "shortcuts.toggle-theme"
+msgstr "Cambia tema"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:204
+msgid "shortcuts.toggle-visibility"
+msgstr "Mostra/Nascondi"
+
+#: src/app/main/ui/settings/options.cljs:77
+msgid "title.settings.options"
+msgstr "Impostazioni - Penpot"
+
+#: src/app/main/ui.cljs:138
+msgid "viewer.breaking-change.description"
+msgstr ""
+"Questi link condivisibili non sono più validi. Creane uno nuovo o chiedo al "
+"proprietario di crearne uno."
+
+#: src/app/main/ui/settings/feedback.cljs:107
+msgid "title.settings.feedback"
+msgstr "Fornisci feedback - Penpot"
+
+#: src/app/main/ui/viewer/header.cljs:194
+msgid "viewer.header.fullscreen"
+msgstr "Schermo intero"
+
+#: src/app/main/ui/viewer/interactions.cljs:286
+msgid "viewer.header.interactions"
+msgstr "Interazioni"
+
+#: src/app/main/ui/workspace/sidebar/assets/groups.cljs:138
+msgid "workspace.assets.create-group-hint"
+msgstr ""
+"I tuoi elementi verrano rinominati automaticamente come \"Nome gruppo / nome "
+"elemento\""
+
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:527
+msgid "workspace.assets.grid-view"
+msgstr "Vista a griglia"
+
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:523
+msgid "workspace.assets.list-view"
+msgstr "Vista a elenco"
+
+#: src/app/main/ui/workspace/sidebar/assets.cljs:187
+msgid "workspace.assets.sort"
+msgstr "Ordina"
+
+#: src/app/main/ui/workspace/context_menu.cljs:545, src/app/main/ui/workspace/sidebar/assets/components.cljs:571
+msgid "workspace.assets.duplicate"
+msgstr "Duplica"
+
+#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:247, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:443
+msgid "workspace.assets.edit"
+msgstr "Modifica"
+
+#: src/app/main/ui/workspace/sidebar/assets.cljs:171
+msgid "workspace.assets.filter"
+msgstr "Filtra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:533
+msgid "workspace.assets.typography.go-to-edit"
+msgstr "Vai alla libreria dello stile del file per modificare"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:523
+msgid "workspace.assets.typography.letter-spacing"
+msgstr "Spaziatura tra lettere"
+
+#: src/app/main/ui/workspace/sidebar/assets/groups.cljs:65
+msgid "workspace.assets.ungroup"
+msgstr "Separa"
+
+#: src/app/main/ui/workspace/context_menu.cljs:648
+msgid "workspace.context-menu.grid-cells.area"
+msgstr "Crea area"
+
+#: src/app/main/ui/workspace/context_menu.cljs:643
+msgid "workspace.context-menu.grid-cells.merge"
+msgstr "Unisci celle"
+
+#: src/app/main/ui/workspace/context_menu.cljs:608
+msgid "workspace.context-menu.grid-track.column.add-after"
+msgstr "Aggiungi 1 colonna a destra"
+
+#: src/app/main/ui/workspace/context_menu.cljs:616
+msgid "workspace.context-menu.grid-track.row.delete"
+msgstr "Elimina riga"
+
+#: src/app/main/ui/workspace/context_menu.cljs:615
+msgid "workspace.context-menu.grid-track.row.add-after"
+msgstr "Aggiungi 1 riga sotto"
+
+#: src/app/main/ui/workspace/context_menu.cljs:614
+msgid "workspace.context-menu.grid-track.row.add-before"
+msgstr "Aggiungi 1 riga sopra"
+
+#, unused
+msgid "workspace.focus.selection"
+msgstr "Selezione"
+
+#: src/app/main/ui/workspace/main_menu.cljs:259
+msgid "workspace.header.menu.enable-snap-pixel-grid"
+msgstr "Attiva allineamento al poxel"
+
+#: src/app/main/ui/workspace/context_menu.cljs:617
+msgid "workspace.context-menu.grid-track.row.delete-shapes"
+msgstr "Elimina riga e forme"
+
+#: src/app/main/ui/workspace/main_menu.cljs:360
+msgid "workspace.header.menu.show-palette"
+msgstr "Mostra palette colori"
+
+#: src/app/main/ui/workspace/main_menu.cljs:284
+msgid "workspace.header.menu.toggle-dark-theme"
+msgstr "Passa al tema scuro"
+
+#: src/app/main/ui/viewer/header.cljs:79, src/app/main/ui/workspace/right_header.cljs:108
+msgid "workspace.header.zoom"
+msgstr "Zoom"
+
+#: src/app/main/ui/viewer/header.cljs:102
+msgid "workspace.header.zoom-fit"
+msgstr "Adatta - Riduci per adattare"
+
+#: src/app/main/ui/viewer/header.cljs:109
+msgid "workspace.header.zoom-fill"
+msgstr "Riempi - Ridimensiona per riempire"
+
+#: src/app/main/ui/workspace/main_menu.cljs:849
+msgid "workspace.header.menu.option.help-info"
+msgstr "Aiuto e informazioni"
+
+#: src/app/main/ui/workspace/main_menu.cljs:343
+msgid "workspace.header.menu.show-guides"
+msgstr "Mostra guide"
+
+#: src/app/main/ui/workspace/right_header.cljs:135
+msgid "workspace.header.zoom-selected"
+msgstr "Zoom su selezione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs:273, src/app/main/ui/workspace/sidebar/options/menus/grid_cell.cljs:275, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:607
+msgid "workspace.layout_grid.editor.options.edit-grid"
+msgstr "Modifica griglia"
+
+#: src/app/main/ui/workspace/libraries.cljs
+#, unused
+msgid "workspace.libraries.add"
+msgstr "Aggiungi"
+
+#: src/app/main/ui/viewer/header.cljs:116
+msgid "workspace.header.zoom-full-screen"
+msgstr "Schermo intero"
+
+#: src/app/main/ui/workspace/color_palette.cljs:129
+msgid "workspace.libraries.colors.empty-palette"
+msgstr "Non ci sono ancora stili di colore nella tua libreria"
+
+#: src/app/main/ui/workspace/text_palette.cljs:153
+msgid "workspace.libraries.colors.empty-typography-palette"
+msgstr "Non ci sono ancora stili di carattere nella tua libreria"
+
+#: src/app/main/ui/workspace/color_palette_ctx_menu.cljs:60, src/app/main/ui/workspace/colorpicker/libraries.cljs:73, src/app/main/ui/workspace/text_palette_ctx_menu.cljs:50
+msgid "workspace.libraries.colors.file-library"
+msgstr "Libreria del file"
+
+#: src/app/main/ui/workspace/color_palette_ctx_menu.cljs:82, src/app/main/ui/workspace/colorpicker/libraries.cljs:72
+msgid "workspace.libraries.colors.recent-colors"
+msgstr "Colori recenti"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
+#, unused
+msgid "workspace.options.interaction-in"
+msgstr "In"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:125
+msgid "workspace.options.layer-options.blend-mode.multiply"
+msgstr "Moltiplica"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:131
+msgid "workspace.options.layer-options.blend-mode.soft-light"
+msgstr "Luce soffusa"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:130
+msgid "workspace.options.layer-options.blend-mode.overlay"
+msgstr "Sovrapponi"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:136
+msgid "workspace.options.layer-options.blend-mode.saturation"
+msgstr "Saturazione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:128
+msgid "workspace.options.layer-options.blend-mode.screen"
+msgstr "Scolora"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs
+#, unused
+msgid "workspace.options.layer-options.title.group"
+msgstr "Livelli di gruppo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:564
+msgid "workspace.options.layout-item.layout-item-max-h"
+msgstr "Altezza.Max"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
+#, unused
+msgid "workspace.options.layout-item.advanced-ops"
+msgstr "Opzioni avanzate"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
+#, unused
+msgid "workspace.options.layout-item.title.layout-item-max-w"
+msgstr "Larghezza massima"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
+#, unused
+msgid "workspace.options.layout-item.title.layout-item-min-w"
+msgstr "Larghezza minima"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.bottom"
+msgstr "In basso"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.direction.column"
+msgstr "Colonna"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.direction.column-reverse"
+msgstr "Colonna invertita"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.direction.row"
+msgstr "Riga"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.direction.row-reverse"
+msgstr "Riga invertita"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.gap"
+msgstr "Spazio"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.left"
+msgstr "A sinistra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
+#, unused
+msgid "workspace.options.layout.margin"
+msgstr "Margine"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.padding-all"
+msgstr "Tutti i lati"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.padding-simple"
+msgstr "Margine interno semplice"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
+#, unused
+msgid "workspace.options.layout.margin-simple"
+msgstr "Margine semplice"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.top"
+msgstr "In alto"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.padding"
+msgstr "Margine interno"
+
+#: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs
+#, unused
+msgid "workspace.options.position"
+msgstr "Posizione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:565, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:588
+msgid "workspace.options.radius"
+msgstr "Raggio"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:602
+msgid "workspace.options.radius-top-left"
+msgstr "Superiore sinistro"
+
+#: src/app/main/ui/workspace/sidebar/options.cljs:183
+msgid "workspace.options.prototype"
+msgstr "Prototipo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:611
+msgid "workspace.options.radius-top-right"
+msgstr "Superiore destro"
+
+#: src/app/main/ui/exports/assets.cljs:290
+msgid "workspace.options.retry"
+msgstr "Riprova"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:547
+msgid "workspace.options.rotation"
+msgstr "Rotazione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:749
+msgid "workspace.options.select-a-shape"
+msgstr ""
+"Seleziona una forma, una tavola da disegno o un gruppo per trascinare una "
+"connessione verso un'altra tavola."
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:181
+msgid "workspace.options.search-font"
+msgstr "Cerca carattere"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:295
+msgid "workspace.options.shadow-options.title.multiple"
+msgstr "Ombre della selezione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:197
+msgid "workspace.options.show-fill-on-export"
+msgstr "Mostra in esportazione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:48
+msgid "workspace.options.selection-fill"
+msgstr "Riempimento di selezione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:145
+msgid "workspace.options.shadow-options.drop-shadow"
+msgstr "Ombra esterna"
+
+#: src/app/main/ui/viewer/inspect/attributes/shadow.cljs:38, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:187
+msgid "workspace.options.shadow-options.offsetx"
+msgstr "X"
+
+#: src/app/main/ui/viewer/inspect/attributes/shadow.cljs:41, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:212, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:214
+msgid "workspace.options.shadow-options.spread"
+msgstr "Diffusione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:297
+msgid "workspace.options.shadow-options.title"
+msgstr "Ombra"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:87
+msgid "workspace.options.stroke.center"
+msgstr "Centro"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:192
+msgid "workspace.options.stroke-color"
+msgstr "Colore traccia"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:105
+msgid "workspace.options.stroke.dashed"
+msgstr "Tratteggiato"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:104
+msgid "workspace.options.stroke.dotted"
+msgstr "Puntinato"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:88
+msgid "workspace.options.stroke.inner"
+msgstr "Interno"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:151
+msgid "workspace.options.text-options.grow-auto-height"
+msgstr "Altezza automatica"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:147
+msgid "workspace.options.text-options.grow-auto-width"
+msgstr "Larghezza automatica"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:387
+msgid "workspace.options.text-options.letter-spacing"
+msgstr "Spaziatura tra lettere"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:369
+msgid "workspace.options.text-options.line-height"
+msgstr "Interlinea"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs
+#, unused
+msgid "workspace.options.text-options.lowercase"
+msgstr "Minuscolo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs
+#, unused
+msgid "workspace.options.text-options.none"
+msgstr "Nessuno"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:49
+msgid "workspace.options.text-options.text-align-left"
+msgstr "Allinea a sinistra (%s)"
+
+#: src/app/main/ui/workspace/viewport/path_actions.cljs:152
+msgid "workspace.path.actions.draw-nodes"
+msgstr "Disegna nodi (%s)"
+
+#: src/app/main/ui/workspace/viewport/path_actions.cljs:204
+msgid "workspace.path.actions.make-corner"
+msgstr "Concerti in angolo (%s)"
+
+#: src/app/main/ui/workspace/viewport/path_actions.cljs:211
+msgid "workspace.path.actions.make-curve"
+msgstr "Converti in curva (%s)"
+
+#: src/app/main/ui/workspace/viewport/path_actions.cljs:182
+msgid "workspace.path.actions.merge-nodes"
+msgstr "Fondi nodi (%s)"
+
+#: src/app/main/ui/workspace/viewport/path_actions.cljs:159
+msgid "workspace.path.actions.move-nodes"
+msgstr "Sposta nodo (%s)"
+
+#: src/app/main/ui/workspace/viewport/path_actions.cljs:196
+msgid "workspace.path.actions.separate-nodes"
+msgstr "Separa nodi (%s)"
+
+#: src/app/main/ui/workspace/viewport/path_actions.cljs:218
+msgid "workspace.path.actions.snap-nodes"
+msgstr "Aggancia nodi (%s)"
+
+#: src/app/main/ui/workspace/main_menu.cljs:837
+msgid "workspace.plugins.menu.title"
+msgstr "Plugin"
+
+#: src/app/main/ui/workspace/plugins.cljs:202
+#, markdown
+msgid "workspace.plugins.discover"
+msgstr "Scopri [altri plugin](%s)"
+
+#: src/app/main/ui/workspace/plugins.cljs:218
+msgid "workspace.plugins.installed-plugins"
+msgstr "Plugin installati"
+
+#: src/app/main/ui/workspace/plugins.cljs:83
+msgid "workspace.plugins.button-open"
+msgstr "Apri"
+
+#: src/app/main/ui/workspace/main_menu.cljs:651
+msgid "workspace.plugins.menu.plugins-manager"
+msgstr "Manager dei plugin"
+
+#: src/app/main/ui/workspace/plugins.cljs:243
+msgid "workspace.plugins.permissions.content-read"
+msgstr "Leggi il contenuto dei file a cui gli utenti hanno accesso."
+
+#: src/app/main/ui/workspace/plugins.cljs:323
+msgid "workspace.plugins.permissions.disclaimer"
+msgstr ""
+"Tieni presente che questo plugin è creato da una terza parte, quindi "
+"assicurati di fidarti prima di concedere l'accesso. La tua privacy e "
+"sicurezza dei dati sono importanti per noi. Se hai dubbi, contatta il "
+"supporto."
+
+#: src/app/main/ui/workspace/plugins.cljs:263
+msgid "workspace.plugins.permissions.library-read"
+msgstr "Leggere le tue librerie e asset."
+
+#: src/app/main/ui/workspace/plugins.cljs:257
+msgid "workspace.plugins.permissions.library-write"
+msgstr "Leggere e modificare le tue librerie e asset."
+
+#: src/app/main/ui/workspace/plugins.cljs:237
+msgid "workspace.plugins.permissions.content-write"
+msgstr "Leggi e modifica il contenuto dei file a cui gli utenti hanno accesso."
+
+#: src/app/main/ui/workspace/plugins.cljs:250
+msgid "workspace.plugins.permissions.user-read"
+msgstr "Leggere le informazioni del profilo dell'utente attuale."
+
+#, unused
+msgid "workspace.plugins.success"
+msgstr "Plugin caricato correttamente."
+
+#: src/app/main/ui/workspace/plugins.cljs:177
+msgid "workspace.plugins.title"
+msgstr "Plugin"
+
+#: src/app/main/ui/workspace/plugins.cljs:316
+msgid "workspace.plugins.permissions.title"
+msgstr "IL PLUGIN '%s' VUOLE ACCEDERE A:"
+
+#: src/app/main/ui/workspace/context_menu.cljs:455
+msgid "workspace.shape.menu.add-grid"
+msgstr "Aggiungi grid layout"
+
+#: src/app/main/ui/workspace/context_menu.cljs:194
+msgid "workspace.shape.menu.back"
+msgstr "Porta in fondo"
+
+#: src/app/main/ui/workspace/context_menu.cljs:479
+msgid "workspace.shape.menu.create-multiple-components"
+msgstr "Crea componenti multipli"
+
+#: src/app/main/ui/workspace/context_menu.cljs:143
+msgid "workspace.shape.menu.cut"
+msgstr "Taglia"
+
+#: src/app/main/ui/workspace/context_menu.cljs:191
+msgid "workspace.shape.menu.backward"
+msgstr "Porta indietro"
+
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:431
+msgid "workspace.shape.menu.detach-instances-in-bulk"
+msgstr "Scollega istanze"
+
+#: src/app/main/ui/workspace/context_menu.cljs:475
+msgid "workspace.shape.menu.create-component"
+msgstr "Crea componente"
+
+#: src/app/main/ui/workspace/context_menu.cljs:185
+msgid "workspace.shape.menu.forward"
+msgstr "Porta avanti"
+
+#: src/app/main/ui/workspace/context_menu.cljs:272
+msgid "workspace.shape.menu.group"
+msgstr "Raggruppa"
+
+#: src/app/main/ui/workspace/context_menu.cljs:149
+msgid "workspace.shape.menu.duplicate"
+msgstr "Duplica"
+
+#: src/app/main/ui/workspace/context_menu.cljs:332
+msgid "workspace.shape.menu.edit"
+msgstr "Modifica"
+
+#: src/app/main/ui/workspace/context_menu.cljs:374, src/app/main/ui/workspace/sidebar/layer_item.cljs:145
+msgid "workspace.shape.menu.hide"
+msgstr "Nascondi"
+
+#: src/app/main/ui/workspace/context_menu.cljs:562, src/app/main/ui/workspace/main_menu.cljs:414
+msgid "workspace.shape.menu.hide-ui"
+msgstr "Mostra/Nascondi UI"
+
+#: src/app/main/ui/workspace/context_menu.cljs:359, src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:89
+msgid "workspace.shape.menu.flatten"
+msgstr "Appiattisci"
+
+#: src/app/main/ui/workspace/context_menu.cljs:277
+msgid "workspace.shape.menu.mask"
+msgstr "Maschera"
+
+#: src/app/main/ui/workspace/context_menu.cljs:445
+msgid "workspace.shape.menu.remove-grid"
+msgstr "Rimuovi grid layout"
+
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:436
+msgid "workspace.shape.menu.reset-overrides"
+msgstr "Reimposta modifiche"
+
+#: src/app/main/ui/workspace/context_menu.cljs:146, src/app/main/ui/workspace/context_menu.cljs:559
+msgid "workspace.shape.menu.paste"
+msgstr "Incolla"
+
+#: src/app/main/ui/workspace/context_menu.cljs:442
+msgid "workspace.shape.menu.remove-flex"
+msgstr "Rimuovi flex layout"
+
+#: src/app/main/ui/workspace/context_menu.cljs:343, src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:70
+msgid "workspace.shape.menu.union"
+msgstr "Unione"
+
+#: src/app/main/ui/workspace/context_menu.cljs:371, src/app/main/ui/workspace/sidebar/layer_item.cljs:144
+msgid "workspace.shape.menu.show"
+msgstr "Mostra"
+
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:424
+msgid "workspace.shape.menu.show-in-assets"
+msgstr "Mostra nel pannello degli asset"
+
+#: src/app/main/ui/workspace/context_menu.cljs:379, src/app/main/ui/workspace/sidebar/layer_item.cljs:152, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:195
+msgid "workspace.shape.menu.unlock"
+msgstr "Sblocca"
+
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:445
+msgid "workspace.shape.menu.update-main"
+msgstr "Aggiorna componente principale"
+
+#: src/app/main/ui/components/tab_container.cljs:52, src/app/main/ui/workspace/sidebar.cljs:46
+msgid "workspace.sidebar.collapse"
+msgstr "Comprimi barra laterale"
+
+#: src/app/main/ui/workspace/right_header.cljs:246, src/app/main/ui/workspace/right_header.cljs:247
+#, fuzzy
+msgid "workspace.sidebar.history"
+msgstr "Cronologia (%s)"
+
+#: src/app/main/ui/workspace/top_toolbar.cljs:143, src/app/main/ui/workspace/top_toolbar.cljs:144
+msgid "workspace.toolbar.frame"
+msgstr "Tavola da disegno (%s)"
+
+#: src/app/main/ui/workspace/top_toolbar.cljs:161, src/app/main/ui/workspace/top_toolbar.cljs:162
+msgid "workspace.toolbar.ellipse"
+msgstr "Ellisse (%s)"
+
+#: src/app/main/ui/workspace/top_toolbar.cljs:60, src/app/main/ui/workspace/top_toolbar.cljs:61
+msgid "workspace.toolbar.image"
+msgstr "Immagine (%s)"
+
+#: src/app/main/ui/workspace/top_toolbar.cljs:190, src/app/main/ui/workspace/top_toolbar.cljs:191
+msgid "workspace.toolbar.path"
+msgstr "Tracciato (%s)"
+
+#: src/app/main/ui/workspace/top_toolbar.cljs:201, src/app/main/ui/workspace/top_toolbar.cljs:202
+msgid "workspace.toolbar.plugins"
+msgstr "Plugin (%s)"
+
+#: src/app/main/ui/workspace/top_toolbar.cljs:152, src/app/main/ui/workspace/top_toolbar.cljs:153
+msgid "workspace.toolbar.rect"
+msgstr "Rettangolo (%s)"
+
+#: src/app/main/ui/workspace/top_toolbar.cljs:219, src/app/main/ui/workspace/top_toolbar.cljs:220
+msgid "workspace.toolbar.toggle-toolbar"
+msgstr "Attiva/Disattiva barra degli strumenti"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:109
+msgid "workspace.undo.entry.multiple.circle"
+msgstr "cerchi"
+
+#: src/app/main/ui/workspace/viewport/top_bar.cljs:39
+msgid "workspace.top-bar.read-only.done"
+msgstr "Fatto"
+
+#: src/app/main/ui/workspace/viewport/top_bar.cljs:36
+#, markdown
+msgid "workspace.top-bar.view-only"
+msgstr "**Ispezione codice** (Solo visualizzazione)"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:120
+msgid "workspace.undo.entry.multiple.shape"
+msgstr "forme"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:116
+msgid "workspace.undo.entry.multiple.multiple"
+msgstr "oggetti"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:119
+msgid "workspace.undo.entry.multiple.rect"
+msgstr "rettangoli"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:122
+msgid "workspace.undo.entry.multiple.typography"
+msgstr "asset tipografici"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:143
+msgid "workspace.undo.entry.new"
+msgstr "Nuovo %s"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:123
+msgid "workspace.undo.entry.single.circle"
+msgstr "cerchio"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:124
+msgid "workspace.undo.entry.single.color"
+msgstr "colore"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:125
+msgid "workspace.undo.entry.single.component"
+msgstr "componente"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:128
+msgid "workspace.undo.entry.single.group"
+msgstr "gruppo"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:129
+msgid "workspace.undo.entry.single.image"
+msgstr "immagine"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:130
+msgid "workspace.undo.entry.single.media"
+msgstr "asset grafico"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:126
+msgid "workspace.undo.entry.single.curve"
+msgstr "curva"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:127
+msgid "workspace.undo.entry.single.frame"
+msgstr "tavola da disegno"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:136
+msgid "workspace.undo.entry.single.text"
+msgstr "testo"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:131
+msgid "workspace.undo.entry.single.multiple"
+msgstr "oggetto"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:132
+msgid "workspace.undo.entry.single.page"
+msgstr "pagina"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:133
+msgid "workspace.undo.entry.single.path"
+msgstr "tracciato"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:134
+msgid "workspace.undo.entry.single.rect"
+msgstr "rettangolo"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:335
+#, unused
+msgid "workspace.undo.title"
+msgstr "Cronologia"
+
+#: src/app/main/data/workspace/libraries.cljs:1145
+msgid "workspace.updates.more-info"
+msgstr "Maggiori informazioni"
+
+#, unused
+msgid "workspace.viewport.click-to-close-path"
+msgstr "Clicca per chiudere il tracciato"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:137
+msgid "workspace.undo.entry.single.typography"
+msgstr "asset tipografico"
+
+#: src/app/main/ui/workspace/sidebar/history.cljs:147
+msgid "workspace.undo.entry.unknown"
+msgstr "Operazione su %s"
+
+#: src/app/main/data/common.cljs:130
+msgid "modals.add-shared-confirm-empty.hint"
+msgstr ""
+"La tua libreria è vuota. Una volta aggiunta come libreria condivisa, le "
+"risorse che crei saranno disponibili per essere utilizzate tra i tuoi file. "
+"Sei sicuro di volerla pubblicare?"
+
+#: src/app/main/ui/auth/login.cljs:293
+msgid "auth.login-tagline"
+msgstr ""
+"Penpot è lo strumento di design open-source gratuito per la collaborazione "
+"nel Design e Sviluppo"
+
+#, unused
+msgid "dashboard.import.analyze-error.components-v2"
+msgstr "File con componenti V2 attivati ma questo team non li supporta ancora."
+
+#: src/app/main/data/users.cljs:735, src/app/main/ui/auth/register.cljs:54
+msgid "errors.email-domain-not-allowed"
+msgstr "Dominio non consentito"
+
+#: src/app/main/data/users.cljs:733
+msgid "errors.auth-provider-not-allowed"
+msgstr "Provider di autenticazione non consentito per questo profilo"
+
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:127
+msgid "inspect.tabs.code.selected.frame"
+msgstr "Tavola da disegno"
+
+#, unused
+msgid "onboarding.welcome.alt"
+msgstr "Penpot"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:78
+msgid "shortcuts.align-left"
+msgstr "Allinea a sinistra"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:79
+msgid "shortcuts.align-right"
+msgstr "Allinea a destra"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:115
+msgid "shortcuts.font-size-inc"
+msgstr "Aumenta dimensione carattere"
+
+#: src/app/main/ui/workspace/right_header.cljs:120, src/app/main/ui/workspace/sidebar/shortcuts.cljs:122
+msgid "shortcuts.increase-zoom"
+msgstr "Aumenta zoom"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:120
+msgid "shortcuts.h-distribute"
+msgstr "Distribuisci orizzontalmente"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:121
+msgid "shortcuts.hide-ui"
+msgstr "Mostra / Nascondi UI"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:151
+msgid "shortcuts.opacity-5"
+msgstr "Imposta opacità al 50%"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:153
+msgid "shortcuts.opacity-7"
+msgstr "Imposta opacità al 70%"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:154
+msgid "shortcuts.opacity-8"
+msgstr "Imposta opacità all'80%"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:170
+msgid "shortcuts.select-next"
+msgstr "Seleziona livello successivo"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:200
+msgid "shortcuts.toggle-snap-guides"
+msgstr "Aggancia alle guide"
+
+#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:206
+msgid "shortcuts.underline"
+msgstr "Attiva/Disattiva sottolineatura"
+
+#: src/app/main/ui/dashboard/fonts.cljs:38
+msgid "title.dashboard.font-providers"
+msgstr "Fornitori dei caratteri - %s - Penpot"
+
+#: src/app/main/ui/dashboard/files.cljs:170
+msgid "title.dashboard.files"
+msgstr "%s - Penpot"
+
+#: src/app/main/ui/dashboard/fonts.cljs:37
+msgid "title.dashboard.fonts"
+msgstr "Caratteri - %s - Penpot"
+
+#: src/app/main/ui/dashboard/projects.cljs:343
+msgid "title.dashboard.projects"
+msgstr "Progetti - %s - Penpot"
+
+#: src/app/main/ui/viewer.cljs:420
+msgid "title.viewer"
+msgstr "%s - Modalità di visualizzazione - Penpot"
+
+#: src/app/main/ui/viewer/header.cljs:342
+msgid "viewer.header.comments-section"
+msgstr "Commenti (%s)"
+
+#: src/app/main/ui/viewer/share_link.cljs:189
+msgid "viewer.header.share.copy-link"
+msgstr "Copia link"
+
+#: src/app/main/ui/viewer/interactions.cljs:304
+msgid "viewer.header.show-interactions"
+msgstr "Mostra interazioni"
+
+#: src/app/main/ui/dashboard/team.cljs:985
+msgid "webhooks.last-delivery.success"
+msgstr "L'ultimo invio è avvenuto con successo."
+
+#: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:91
+msgid "workspace.align.vcenter"
+msgstr "Allinea verticalmente al centro (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:104
+msgid "workspace.align.vdistribute"
+msgstr "Distribuisci spaziatura verticale (%s)"
+
+#: src/app/main/ui/dashboard/grid.cljs:134, src/app/main/ui/dashboard/grid.cljs:149, src/app/main/ui/workspace/sidebar/assets/components.cljs:511, src/app/main/ui/workspace/sidebar/assets.cljs:138
+msgid "workspace.assets.components"
+msgstr "Componenti"
+
+#: src/app/main/ui/workspace/context_menu.cljs:543, src/app/main/ui/workspace/sidebar/assets/colors.cljs:243, src/app/main/ui/workspace/sidebar/assets/components.cljs:565, src/app/main/ui/workspace/sidebar/assets/graphics.cljs:421, src/app/main/ui/workspace/sidebar/assets/groups.cljs:62, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:438
+msgid "workspace.assets.rename"
+msgstr "Rinomina"
+
+#: src/app/main/ui/workspace/sidebar/assets.cljs:168
+msgid "workspace.assets.search"
+msgstr "Cerca asset"
+
+#: src/app/main/ui/workspace/sidebar/assets.cljs
+#, unused
+msgid "workspace.assets.shared-library"
+msgstr "Librerie condivise"
+
+#: src/app/main/ui/dashboard/grid.cljs:142, src/app/main/ui/dashboard/grid.cljs:197, src/app/main/ui/workspace/sidebar/assets/typographies.cljs:400, src/app/main/ui/workspace/sidebar/assets.cljs:151
+msgid "workspace.assets.typography"
+msgstr "Elementi tipografici"
+
+#: src/app/main/ui/workspace/viewport/grid_layout_editor.cljs:59
+msgid "workspace.layout_grid.editor.title"
+msgstr "Modifica della griglia"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1295
+msgid "workspace.layout_grid.editor.options.exit"
+msgstr "Esci"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:478
+msgid "workspace.layout_grid.editor.padding.expand"
+msgstr "Mostra opzioni di padding su 4 lati"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1321
+msgid "workspace.layout_grid.editor.top-bar.locate.tooltip"
+msgstr "Individua grid layout"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:471
+msgid "workspace.options.component.swap.empty"
+msgstr "Non ci sono ancora asset in questo libreria"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:427
+msgid "workspace.options.component.swap"
+msgstr "Sostituisci componente"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:151
+msgid "workspace.options.constraints.topbottom"
+msgstr "Superiore e Inferiore"
+
+#: src/app/main/ui/viewer/inspect/exports.cljs:147
+msgid "workspace.options.export"
+msgstr "Esporta"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:250
+msgid "workspace.options.grid.params.height"
+msgstr "Altezza"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs
+#, unused
+msgid "workspace.options.grid.params.rows"
+msgstr "Righe"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:220, src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:294
+msgid "workspace.options.grid.params.set-default"
+msgstr "Imposta come predefinito"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs
+#, unused
+msgid "workspace.options.grid.params.size"
+msgstr "Dimensione"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs
+#, unused
+msgid "workspace.options.grid.params.columns"
+msgstr "Colonne"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:231
+msgid "workspace.options.grid.params.type.top"
+msgstr "Alto"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs
+#, unused
+msgid "workspace.options.grid.params.type"
+msgstr "Tipo"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:232
+msgid "workspace.options.grid.params.type.left"
+msgstr "Sinistra"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:424
+msgid "workspace.options.interaction-easing-ease-out"
+msgstr "Ease out"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:423
+msgid "workspace.options.interaction-easing-ease-in"
+msgstr "Ease in"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:40, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:370
+msgid "workspace.options.interaction-mouse-enter"
+msgstr "Entrata del mouse"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:58, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:385, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:399, src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:400
+msgid "workspace.options.interaction-self"
+msgstr "se stesso"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:55
+msgid "workspace.options.interaction-toggle-overlay-dest"
+msgstr "Attiva/Disattiva la sovrapposizione: %s"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:132
+msgid "workspace.options.layer-options.blend-mode.hard-light"
+msgstr "Luce intensa"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:135
+msgid "workspace.options.layer-options.blend-mode.hue"
+msgstr "Tonalità"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:451
+msgid "workspace.options.interaction-trigger"
+msgstr "Trigger"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:127
+msgid "workspace.options.layer-options.blend-mode.lighten"
+msgstr "Schiarisci"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:103
+msgid "workspace.options.stroke.solid"
+msgstr "Solido"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:117
+msgid "workspace.options.text-options.align-bottom"
+msgstr "Allinea in basso"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs, src/app/main/ui/workspace/context_menu.cljs
+#, unused
+msgid "workspace.shape.menu.go-main"
+msgstr "Vai al componente principale"
+
+#: src/app/main/ui/workspace/context_menu.cljs:222
+msgid "workspace.shape.menu.thumbnail-remove"
+msgstr "Rimuovi miniatura"
+
+#: src/app/main/ui/workspace/sidebar/assets/common.cljs:442, src/app/main/ui/workspace/sidebar/assets/components.cljs:585
+msgid "workspace.shape.menu.show-main"
+msgstr "Mostra componente principale"
+
+#: src/app/main/ui/workspace/context_menu.cljs:224
+msgid "workspace.shape.menu.thumbnail-set"
+msgstr "Imposta come miniatura"
+
+#, unused
+msgid "media.gradient"
+msgstr "Gradiente"
+
+#: src/app/main/data/workspace/media.cljs:272, src/app/main/ui/components/color_bullet.cljs:32, src/app/main/ui/components/color_bullet.cljs:45, src/app/main/ui/viewer/inspect/attributes/common.cljs:66, src/app/main/ui/workspace/colorpicker.cljs:231, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:240
+msgid "media.image"
+msgstr "Immagine"
+
+#: src/app/main/ui/viewer/inspect/attributes/common.cljs:77
+msgid "media.image.short"
+msgstr "Img"
+
+#: src/app/main/ui/workspace/colorpicker.cljs:337
+msgid "media.keep-aspect-ratio"
+msgstr "Mantieni proporzioni"
+
+#: src/app/main/ui/workspace/context_menu.cljs:651
+msgid "workspace.context-menu.grid-cells.create-board"
+msgstr "Crea tavola da disegno"
diff --git a/frontend/translations/lv.po b/frontend/translations/lv.po
index 732ad1551c..8973eaf1dc 100644
--- a/frontend/translations/lv.po
+++ b/frontend/translations/lv.po
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
-"PO-Revision-Date: 2024-11-14 11:14+0000\n"
-"Last-Translator: Anonymous \n"
+"PO-Revision-Date: 2024-11-20 09:00+0000\n"
+"Last-Translator: Edgars Andersons \n"
"Language-Team: Latvian \n"
"Language: lv\n"
@@ -584,7 +584,8 @@ msgstr "Ak vai! Šo datni nevarēja ievietot"
#, unused
msgid "dashboard.import.analyze-error.components-v2"
-msgstr "Datne ar v2 sastāvdaļām ir aktivizēta, bet šī komanda to vēl neatbalsta."
+msgstr ""
+"Datne ar v2 sastāvdaļām ir aktivizēta, bet šī komanda to vēl nenodrošina."
#: src/app/main/ui/dashboard/import.cljs:292
msgid "dashboard.import.import-error"
@@ -5584,9 +5585,12 @@ msgid "workspace.plugins.permissions.content-write"
msgstr "Lasīt un mainīt datņu, kurām lietotājiem ir piekļuve, saturu."
#: src/app/main/ui/workspace/plugins.cljs:323
-#, fuzzy
msgid "workspace.plugins.permissions.disclaimer"
-msgstr "Jāņem vērā, ka šo spraudni ir izveidojusi trešā puse."
+msgstr ""
+"Lūgums ņemt vērā, ka šo spraudni izveidoja trešā puse, tāpēc pirms piekļuves "
+"nodrošināšanas jāpārliecinās par tās uzticamību. Mums ir svarīga Tavu datu "
+"privātums un drošība. Ja ir kādas neskaidrības, lūgums sazināties ar "
+"atbalstu."
#: src/app/main/ui/workspace/plugins.cljs:263
msgid "workspace.plugins.permissions.library-read"
@@ -5597,9 +5601,8 @@ msgid "workspace.plugins.permissions.library-write"
msgstr "Lasīt un mainīt bibliotēkas un līdzekļus."
#: src/app/main/ui/workspace/plugins.cljs:316
-#, fuzzy
msgid "workspace.plugins.permissions.title"
-msgstr "ŠIS SPRAUDNIS PIEPRASA PIEKĻUVI:"
+msgstr "SPRAUDNIS \"%s\" PIEPRASA PIEKĻUVI:"
#: src/app/main/ui/workspace/plugins.cljs:250
msgid "workspace.plugins.permissions.user-read"
@@ -6117,3 +6120,439 @@ msgstr "Atjaunināt"
#, unused
msgid "workspace.viewport.click-to-close-path"
msgstr "Jānoklikšķina, lai aizvērtu ceļu"
+
+#: src/app/main/ui/dashboard/files.cljs:190, src/app/main/ui/dashboard/projects.cljs:284
+msgid "dashboard.empty-placeholder-drafts-subtitle"
+msgstr ""
+"Tiklīdz projekta dalībnieks izveidos melnrakstu, tas šeit tiks parādīts."
+
+#: src/app/main/ui/dashboard/files.cljs:186, src/app/main/ui/dashboard/projects.cljs:280
+msgid "dashboard.empty-placeholder-files-title"
+msgstr "Vēl nav nevienas datnes."
+
+#: src/app/main/ui/dashboard/files.cljs:191, src/app/main/ui/dashboard/projects.cljs:285
+msgid "dashboard.empty-placeholder-files-subtitle"
+msgstr "Tiklīdz projekta dalībnieks izveidos datni, tā šeit tiks parādīta."
+
+#: src/app/main/ui/dashboard/placeholder.cljs
+#, markdown, unused
+msgid "dashboard.empty-placeholder-libraries-subtitle"
+msgstr ""
+"Šeit parādīsies projektam pievienotās bibliotēkas. Mēģini kopīgot savas "
+"datnes vai pievienot no mūsu [bibliotēkām un sagatavēm](https://penpot.app/"
+"libraries-templates)!"
+
+#: src/app/main/ui/dashboard/placeholder.cljs:32
+msgid "dashboard.empty-placeholder-libraries-title"
+msgstr "Vēl nav nevienas bibliotēkas."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:35
+msgid "dashboard.empty-placeholder-libraries-subtitle-viewer-role"
+msgstr "Šeit parādīsies projektam pievienotās bibliotēkas."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:39
+#, markdown
+msgid "dashboard.empty-placeholder-libraries"
+msgstr ""
+"Šeit parādīsies projektam pievienotās bibliotēkas. Mēģini kopīgot savas "
+"datnes vai pievienot no mūsu [bibliotēkām un sagatavēm](https://penpot.app/"
+"libraries-templates)!"
+
+#: src/app/main/ui/dashboard/team.cljs:944
+msgid "dashboard.webhooks.cant-edit"
+msgstr "Var izdzēst vai mainīt tikai paša izveidotās tīmekļa aizķeres."
+
+#: src/app/main/ui/comments.cljs:340, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:295, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:324
+msgid "labels.options"
+msgstr "Iespējas"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:229
+msgid "labels.sets"
+msgstr "Kopas"
+
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:532
+msgid "workspace.assets.components.add-component"
+msgstr "Pievienot sastāvdaļu"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:108
+msgid "workspace.options.blur-options.toggle-blur"
+msgstr "Pārslēgt aizmiglojumu"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:323
+msgid "workspace.options.guides.add-guide"
+msgstr "Pievienot vadlīniju"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:187
+msgid "workspace.options.guides.remove-guide"
+msgstr "Noņemt vadlīniju"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:183
+msgid "workspace.options.guides.toggle-guide"
+msgstr "Pārslēgt vadlīniju"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:173
+msgid "workspace.options.shadow-options.toggle-shadow"
+msgstr "Pārslēgt ēnu"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:171
+msgid "workspace.options.stroke.add-stroke"
+msgstr "Pievienot vilkuma krāsu"
+
+#: src/app/main/ui/workspace/plugins.cljs:372
+msgid "workspace.plugins.permissions-update.title"
+msgstr "ATJAUNINĀT ŠO SPRAUDNI"
+
+#: src/app/main/ui/workspace/plugins.cljs:376
+msgid "workspace.plugins.permissions-update.warning"
+msgstr ""
+"Spraudnis kopš pēdējās atvēršanas reizes ir mainīts. Tam tagad ir vajadzīga "
+"piekļuve:"
+
+#: src/app/main/ui/workspace/plugins.cljs:86
+msgid "workspace.plugins.remove-plugin"
+msgstr "Noņemt spraudni"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:142
+msgid "workspace.token.no-sets"
+msgstr "Nav kopu"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:133
+msgid "workspace.token.num-sets"
+msgstr "%s kopas"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:66
+msgid "workspace.token.original-value"
+msgstr "Sākotnējā vērtība: "
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:172
+msgid "workspace.token.select-set"
+msgstr "Atlasīt kopu."
+
+#: src/app/main/ui/dashboard/fonts.cljs:444
+msgid "dashboard.fonts.empty-placeholder-viewer"
+msgstr "Vēl nav neviena pielāgota fonta."
+
+#: src/app/main/data/common.cljs:206
+msgid "dashboard.permissions-change.owner"
+msgstr "Tu tagad esi šīs komandas īpašnieks."
+
+#: src/app/main/data/common.cljs:203
+msgid "dashboard.permissions-change.viewer"
+msgstr "Tev tagad šajā komandā ir skatīšanās tiesības."
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:149, src/app/main/ui/workspace/sidebar/versions.cljs:288
+msgid "labels.restore"
+msgstr "Atjaunot"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:187
+msgid "labels.themes"
+msgstr "Izskati"
+
+#: src/app/main/ui/dashboard/team.cljs:216
+msgid "modals.invite-team-member.text"
+msgstr ""
+"Komandā var uzaicināt dalībniekus, lai viņi varētu piekļūt šai un citām "
+"komandas datnēm."
+
+#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:495
+msgid "workspace.assets.colors.add-color"
+msgstr "Pievienot krāsu"
+
+#: src/app/main/ui/workspace/libraries.cljs:300
+msgid "workspace.libraries.more-templates"
+msgstr "Var meklēt "
+
+#: src/app/main/ui/workspace/libraries.cljs:304
+msgid "workspace.libraries.more-templates-link"
+msgstr "vairāk sagatavju šeit"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:91
+msgid "workspace.options.blur-options.add-blur"
+msgstr "Pievienot aizmiglojumu"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:150
+msgid "workspace.options.fill.add-fill"
+msgstr "Pievienot aizpildījuma krāsu"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:163
+msgid "workspace.options.fill.remove-fill"
+msgstr "Noņemt aizpildījumu"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:176, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:182
+msgid "workspace.options.layer-options.toggle-layer"
+msgstr "Pārslēgt slāņa redzamību"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:177, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:315
+msgid "workspace.options.shadow-options.remove-shadow"
+msgstr "Noņemt ēnu"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:184
+msgid "workspace.options.stroke.remove-stroke"
+msgstr "Noņemt vilkumu"
+
+#: src/app/main/data/plugins.cljs:86, src/app/main/ui/workspace/main_menu.cljs:696, src/app/main/ui/workspace/plugins.cljs:82
+msgid "workspace.plugins.error.need-editor"
+msgstr "Jābūt redaktoram, lai izmantotu šo spraudni"
+
+#: src/app/main/ui/workspace/plugins.cljs:283
+msgid "workspace.plugins.permissions.allow-download"
+msgstr "Uzsākt datņu lejupielādi."
+
+#: src/app/main/ui/workspace/plugins.cljs:276
+msgid "workspace.plugins.permissions.comment-read"
+msgstr "Lasīt savas piebildes un atbildes."
+
+#: src/app/main/ui/workspace/plugins.cljs:270
+msgid "workspace.plugins.permissions.comment-write"
+msgstr "Lasīt un mainīt savas piebildes un atbildēt savā vārdā."
+
+#: src/app/main/ui/workspace/plugins.cljs:436
+msgid "workspace.plugins.try-out.cancel"
+msgstr "NE TAGAD"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:216
+msgid "workspace.token.no-sets-create"
+msgstr "Vēl nav nevienas kopas. Vispirms ir jāizveido kāda."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:239
+msgid "workspace.token.no-sets-yet"
+msgstr "Šeit vēl nav nevienas kopas."
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:187
+msgid "workspace.versions.autosaved.version"
+msgstr "Automātiski saglabāts %s"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:224
+msgid "workspace.versions.button.pin"
+msgstr "Piespraust versiju"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:345, src/app/main/ui/workspace/sidebar/versions.cljs:347
+msgid "workspace.versions.button.save"
+msgstr "Saglabāt versiju"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:190
+msgid "workspace.versions.expand-snapshot"
+msgstr "Izvērst momentuzņēmumus"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:327
+msgid "workspace.versions.filter.all"
+msgstr "Visas versijas"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:326
+msgid "workspace.versions.filter.label"
+msgstr "Versiju atlasīšana"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:328
+msgid "workspace.versions.filter.mine"
+msgstr "Manas versijas"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:334
+msgid "workspace.versions.filter.user"
+msgstr "%s versijas"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:283
+msgid "workspace.versions.restore-warning"
+msgstr "Vai atjaunot šo versiju?"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:207
+msgid "workspace.versions.snapshot-menu"
+msgstr "Atvērt momentuzņēmumu izvēlni"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:138
+msgid "workspace.versions.version-menu"
+msgstr "Atvērt versiju izvēlni"
+
+#: src/app/main/ui/dashboard/files.cljs:185, src/app/main/ui/dashboard/projects.cljs:279
+msgid "dashboard.empty-placeholder-drafts-title"
+msgstr "Vēl nav neviena melnraksta."
+
+#: src/app/main/ui/dashboard/fonts.cljs:445
+msgid "dashboard.fonts.empty-placeholder-viewer-sub"
+msgstr ""
+"Tiklīdz projekta dalībnieks augšupielādēs pielāgotu fontu, tas šeit tiks "
+"parādīts."
+
+#: src/app/main/data/common.cljs:205
+msgid "dashboard.permissions-change.admin"
+msgstr "Tu tagad esi šīs komandas pārvaldītājs."
+
+#: src/app/main/data/common.cljs:204
+msgid "dashboard.permissions-change.editor"
+msgstr "Tu tagad esi šīs komandas redaktors."
+
+#: src/app/main/data/common.cljs:233
+msgid "dashboard.removed-from-team"
+msgstr "Tu vairs neesi daļa no komandas \"%s\"."
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:195
+msgid "workspace.options.export.add-export"
+msgstr "Pievienot izguvi"
+
+#: src/app/main/ui/workspace/sidebar/assets/typographies.cljs:408
+msgid "workspace.assets.typography.add-typography"
+msgstr "Pievienot tipogrāfiju"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:112
+msgid "workspace.options.blur-options.remove-blur"
+msgstr "Noņemt aizmiglojumu"
+
+#: src/app/main/ui/workspace/right_header.cljs:255
+msgid "workspace.header.share"
+msgstr "Kopīgot"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:207, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:242
+msgid "workspace.options.export.remove-export"
+msgstr "Noņemt izguvi"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:302
+msgid "workspace.options.shadow-options.add-shadow"
+msgstr "Pievienot ēnu"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:154
+msgid "workspace.options.flows.remove-flow"
+msgstr "Noņemt plūsmu"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:735
+msgid "workspace.options.interactions.add-interaction"
+msgstr "Pievienot mijiedarbību"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
+#, unused
+msgid "workspace.options.interactions.remove-interaction"
+msgstr "Noņemt mijiedarbību"
+
+#: src/app/main/ui/workspace/plugins.cljs:196
+msgid "workspace.plugins.error.manifest"
+msgstr "Spraudņa deklarācija ir nepareiza."
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:193
+msgid "workspace.versions.autosaved.entry"
+msgstr "%s automātiskās saglabāšanas versijas"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:219
+msgid "workspace.versions.button.restore"
+msgstr "Atjaunot versiju"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:354
+msgid "workspace.versions.empty"
+msgstr "Vēl nav nevienas versijas"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:340
+msgid "workspace.versions.loading"
+msgstr "Ielādē..."
+
+#: src/app/main/ui/dashboard/team.cljs:181, src/app/main/ui/onboarding/team_choice.cljs:100
+msgid "errors.maximum-invitations-by-request-reached"
+msgstr ""
+"Sasniegts lielākais pieļaujamais e-pasta adrešu skaits (%s), ko var "
+"uzaicināt vienā pieprasījumā"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1051
+#, unused
+msgid "labels.add"
+msgstr "Pievienot"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:153
+msgid "labels.collapse"
+msgstr "Sakļaut"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:271
+msgid "settings.remove-color"
+msgstr "Noņemt krāsu"
+
+#: src/app/main/ui/workspace/plugins.cljs:425
+msgid "workspace.plugins.try-out.title"
+msgstr "SPRAUDNIS \"%s\" IR UZSTĀDĪTS."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:147
+msgid "workspace.token.delete-theme-title"
+msgstr "Izdzēst izskatu"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:302
+msgid "workspace.token.edit-theme-title"
+msgstr "Labot izskatu"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:88
+msgid "workspace.token.no-active-theme"
+msgstr "Nav izvēlēts izskats"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:208
+msgid "workspace.token.save-theme"
+msgstr "Saglabāt izskatu"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs
+#, unused
+msgid "workspace.token.theme-name"
+msgstr "Izskats \"%s\""
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:39, src/app/main/ui/workspace/tokens/modals/themes.cljs:84
+msgid "workspace.token.themes"
+msgstr "Izskati"
+
+#: src/app/main/ui/workspace/plugins.cljs:429
+msgid "workspace.plugins.try-out.message"
+msgstr ""
+"Vēlies izmēģināt? Tas tiks atvērts jaunā melnrakstā Tavai pašreizējai "
+"komandai. (Ja nē, vienmēr to var atrast jebkuras datnes uzstādītajos "
+"spraudņos.)"
+
+#: src/app/main/ui/workspace/plugins.cljs:442
+msgid "workspace.plugins.try-out.try"
+msgstr "IZMĒĢINĀT SPRAUDNI"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1022
+msgid "workspace.shape.menu.remove-layout"
+msgstr "Noņemt izkārtojumu"
+
+#: src/app/main/ui/workspace/context_menu.cljs:235
+msgid "workspace.shape.menu.rename"
+msgstr "Pārdēvēt"
+
+#: src/app/main/ui/workspace/sidebar/sitemap.cljs:229
+msgid "workspace.sidebar.sitemap.add-page"
+msgstr "Pievienot lapu"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:84
+msgid "workspace.token.active-themes"
+msgstr "%s aktīvi izskati"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs
+#, unused
+msgid "workspace.token.add set"
+msgstr "Pievienot kopu"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:310
+msgid "workspace.token.back-to-themes"
+msgstr "Atpakaļ uz izskatu sarakstu"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:47
+msgid "workspace.token.create-new-theme"
+msgstr "Tagad izveido savu pirmo izskatu!"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:52
+msgid "workspace.token.new-theme"
+msgstr "Jauns izskats"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:191
+msgid "workspace.token.no-themes"
+msgstr "Šeit nav izskatu."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:43
+msgid "workspace.token.no-themes-currently"
+msgstr "Pašlaik nav izskatu."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:194, src/app/main/ui/workspace/tokens/sidebar.cljs:210
+msgid "workspace.token.create-one"
+msgstr "Izveidot kādu."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:155, src/app/main/ui/workspace/tokens/modals/themes.cljs:239
+msgid "workspace.token.create-theme-title"
+msgstr "Izveidot izskatu"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:72
+msgid "workspace.token.edit-themes"
+msgstr "Labot izskatus"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1004, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1030
+msgid "workspace.shape.menu.add-layout"
+msgstr "Pievienot izkārtojumu"
diff --git a/frontend/translations/nl.po b/frontend/translations/nl.po
index d2a91aa0bf..a20abd162e 100644
--- a/frontend/translations/nl.po
+++ b/frontend/translations/nl.po
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
-"PO-Revision-Date: 2024-11-14 11:14+0000\n"
-"Last-Translator: Anonymous \n"
+"PO-Revision-Date: 2024-11-16 13:00+0000\n"
+"Last-Translator: Stephan Paternotte \n"
"Language-Team: Dutch \n"
"Language: nl\n"
@@ -5589,9 +5589,12 @@ msgid "workspace.plugins.permissions.content-write"
msgstr "Lees en wijzig de inhoud van bestanden waartoe gebruikers toegang hebben."
#: src/app/main/ui/workspace/plugins.cljs:323
-#, fuzzy
msgid "workspace.plugins.permissions.disclaimer"
-msgstr "Merk op dat deze plug-in is gemaakt door een externe partij."
+msgstr ""
+"Houd er rekening mee dat deze plug-in is gemaakt door een externe partij, "
+"dus zorg ervoor dat je deze vertrouwt voordat je toegang verleent. Privacy "
+"van jouw gegevens en beveiliging zijn belangrijk voor ons. Als je je zorgen "
+"maakt, neem dan contact op met ondersteuning."
#: src/app/main/ui/workspace/plugins.cljs:263
msgid "workspace.plugins.permissions.library-read"
@@ -5602,9 +5605,8 @@ msgid "workspace.plugins.permissions.library-write"
msgstr "Jouw bibliotheken en middelen lezen en aanpassen."
#: src/app/main/ui/workspace/plugins.cljs:316
-#, fuzzy
msgid "workspace.plugins.permissions.title"
-msgstr "DEZE PLUGIN WIL TOEGANG TOT:"
+msgstr "PLUG-IN '%s' WIL TOEGANG TOT:"
#: src/app/main/ui/workspace/plugins.cljs:250
msgid "workspace.plugins.permissions.user-read"
@@ -6122,3 +6124,462 @@ msgstr "Bijwerken"
#, unused
msgid "workspace.viewport.click-to-close-path"
msgstr "Klik om het pad te sluiten"
+
+#: src/app/main/ui/dashboard/files.cljs:185, src/app/main/ui/dashboard/projects.cljs:279
+msgid "dashboard.empty-placeholder-drafts-title"
+msgstr "Nog geen concepten."
+
+#: src/app/main/ui/dashboard/files.cljs:186, src/app/main/ui/dashboard/projects.cljs:280
+msgid "dashboard.empty-placeholder-files-title"
+msgstr "Nog geen bestanden."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:39
+#, markdown
+msgid "dashboard.empty-placeholder-libraries"
+msgstr ""
+"Hier verschijnen bibliotheken die aan het project zijn toegevoegd. Probeer "
+"je bestanden te delen of voeg ze toe vanuit onze [Bibliotheken en sjablonen] "
+"(https://penpot.app/libraries-templates)."
+
+#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:271
+msgid "settings.remove-color"
+msgstr "Kleur verwijderen"
+
+#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:495
+msgid "workspace.assets.colors.add-color"
+msgstr "Kleur toevoegen"
+
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:532
+msgid "workspace.assets.components.add-component"
+msgstr "Component toevoegen"
+
+#: src/app/main/ui/workspace/libraries.cljs:300
+msgid "workspace.libraries.more-templates"
+msgstr "Je kun hier "
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:195
+msgid "workspace.options.export.add-export"
+msgstr "Export toevoegen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:207, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:242
+msgid "workspace.options.export.remove-export"
+msgstr "Export verwijderen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:154
+msgid "workspace.options.flows.remove-flow"
+msgstr "Stroomdiagram verwijderen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:323
+msgid "workspace.options.guides.add-guide"
+msgstr "Hulplijn toevoegen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:187
+msgid "workspace.options.guides.remove-guide"
+msgstr "Hulplijn verwijderen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:171
+msgid "workspace.options.stroke.add-stroke"
+msgstr "Streekkleur toevoegen"
+
+#: src/app/main/ui/workspace/plugins.cljs:376
+msgid "workspace.plugins.permissions-update.warning"
+msgstr ""
+"De plug-in is gewijzigd sinds je hem voor het laatst hebt geopend. Het wil "
+"nu ook toegang krijgen tot:"
+
+#: src/app/main/ui/workspace/plugins.cljs:283
+msgid "workspace.plugins.permissions.allow-download"
+msgstr "Bestandsdownloads starten."
+
+#: src/app/main/ui/workspace/plugins.cljs:276
+msgid "workspace.plugins.permissions.comment-read"
+msgstr "Jouw opmerkingen en antwoorden lezen."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:47
+msgid "workspace.token.create-new-theme"
+msgstr "Maak nu je eerste thema aan."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:194, src/app/main/ui/workspace/tokens/sidebar.cljs:210
+msgid "workspace.token.create-one"
+msgstr "Maak er een aan."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:155, src/app/main/ui/workspace/tokens/modals/themes.cljs:239
+msgid "workspace.token.create-theme-title"
+msgstr "Thema aanmaken"
+
+#: src/app/main/ui/workspace/tokens/form.cljs:362
+msgid "workspace.token.create-token"
+msgstr "Nieuw %s token aanmaken"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:147
+msgid "workspace.token.delete-theme-title"
+msgstr "Thema verwijderen"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs
+#, unused
+msgid "workspace.token.theme-name"
+msgstr "Thema %s"
+
+#: src/app/main/ui/workspace/tokens/form.cljs:193, src/app/main/ui/workspace/tokens/form.cljs:196, src/app/main/ui/workspace/tokens/sidebar.cljs:67
+msgid "workspace.token.resolved-value"
+msgstr "Besloten waarde: "
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:208
+msgid "workspace.token.save-theme"
+msgstr "Thema opslaan"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:172
+msgid "workspace.token.select-set"
+msgstr "Verzameling kiezen."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:318
+msgid "workspace.token.set-selection-theme"
+msgstr ""
+"Bepaal welke tokenverzamelingen moeten worden gebruikt als onderdeel van "
+"deze thema-optie:"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:193
+msgid "workspace.versions.autosaved.entry"
+msgstr "%s autom. opgeslagen versies"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:187
+msgid "workspace.versions.autosaved.version"
+msgstr "Autom. opgeslagen %s"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:224
+msgid "workspace.versions.button.pin"
+msgstr "Versie vastmaken"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:219
+msgid "workspace.versions.button.restore"
+msgstr "Versie herstellen"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:354
+msgid "workspace.versions.empty"
+msgstr "Er zijn nog geen versies"
+
+#: src/app/main/ui/dashboard/files.cljs:190, src/app/main/ui/dashboard/projects.cljs:284
+msgid "dashboard.empty-placeholder-drafts-subtitle"
+msgstr ""
+"Zodra een projectlid een concept heeft gemaakt, wordt het hier weergegeven."
+
+#: src/app/main/ui/dashboard/files.cljs:191, src/app/main/ui/dashboard/projects.cljs:285
+msgid "dashboard.empty-placeholder-files-subtitle"
+msgstr ""
+"Zodra een projectlid een bestand heeft gemaakt, wordt het hier weergegeven."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:35
+msgid "dashboard.empty-placeholder-libraries-subtitle-viewer-role"
+msgstr "Hier verschijnen bibliotheken die aan het project zijn toegevoegd."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:32
+msgid "dashboard.empty-placeholder-libraries-title"
+msgstr "Nog geen bibliotheken."
+
+#: src/app/main/ui/dashboard/fonts.cljs:444
+msgid "dashboard.fonts.empty-placeholder-viewer"
+msgstr "Nog geen aangepaste lettertypen."
+
+#: src/app/main/data/common.cljs:205
+msgid "dashboard.permissions-change.admin"
+msgstr "Je bent nu een beheerder van dit team."
+
+#: src/app/main/data/common.cljs:204
+msgid "dashboard.permissions-change.editor"
+msgstr "Je bent nu redacteur van dit team."
+
+#: src/app/main/data/common.cljs:206
+msgid "dashboard.permissions-change.owner"
+msgstr "Je bent nu eigenaar van dit team."
+
+#: src/app/main/data/common.cljs:203
+msgid "dashboard.permissions-change.viewer"
+msgstr "Je bent nu een lezer in dit team."
+
+#: src/app/main/data/common.cljs:233
+msgid "dashboard.removed-from-team"
+msgstr "Je maakt geen deel meer uit van het team “%s“."
+
+#: src/app/main/ui/dashboard/team.cljs:181, src/app/main/ui/onboarding/team_choice.cljs:100
+msgid "errors.maximum-invitations-by-request-reached"
+msgstr ""
+"Het maximale (%s) aantal e-mails dat in één verzoek kan worden uitgenodigd, "
+"is bereikt"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:153
+msgid "labels.collapse"
+msgstr "Samenvouwen"
+
+#: src/app/main/ui/comments.cljs:340, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:295, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:324
+msgid "labels.options"
+msgstr "Opties"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:149, src/app/main/ui/workspace/sidebar/versions.cljs:288
+msgid "labels.restore"
+msgstr "Herstellen"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:229
+msgid "labels.sets"
+msgstr "Verzamelingen"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:187
+msgid "labels.themes"
+msgstr "Thema's"
+
+#: src/app/main/ui/workspace/sidebar/assets/typographies.cljs:408
+msgid "workspace.assets.typography.add-typography"
+msgstr "Typografie toevoegen"
+
+#: src/app/main/ui/workspace/right_header.cljs:255
+msgid "workspace.header.share"
+msgstr "Delen"
+
+#: src/app/main/ui/workspace/libraries.cljs:304
+msgid "workspace.libraries.more-templates-link"
+msgstr "meer sjablonen zoeken"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:91
+msgid "workspace.options.blur-options.add-blur"
+msgstr "Vervaging toevoegen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:112
+msgid "workspace.options.blur-options.remove-blur"
+msgstr "Vervaging verwijderen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:108
+msgid "workspace.options.blur-options.toggle-blur"
+msgstr "Vervaging wisselen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:150
+msgid "workspace.options.fill.add-fill"
+msgstr "Vulkleur toevoegen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:163
+msgid "workspace.options.fill.remove-fill"
+msgstr "Vulling verwijderen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:183
+msgid "workspace.options.guides.toggle-guide"
+msgstr "Hulplijn wisselen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:735
+msgid "workspace.options.interactions.add-interaction"
+msgstr "Interactie toevoegen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:177, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:315
+msgid "workspace.options.shadow-options.remove-shadow"
+msgstr "Schaduw verwijderen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:184
+msgid "workspace.options.stroke.remove-stroke"
+msgstr "Streek verwijderen"
+
+#: src/app/main/ui/workspace/plugins.cljs:196
+msgid "workspace.plugins.error.manifest"
+msgstr "Het plug-in-manifest is onjuist."
+
+#: src/app/main/data/plugins.cljs:86, src/app/main/ui/workspace/main_menu.cljs:696, src/app/main/ui/workspace/plugins.cljs:82
+msgid "workspace.plugins.error.need-editor"
+msgstr "Je moet een redacteur zijn om deze plug-in te gebruiken"
+
+#: src/app/main/ui/workspace/plugins.cljs:372
+msgid "workspace.plugins.permissions-update.title"
+msgstr "DEZE PLUGIN UPDATEN"
+
+#: src/app/main/ui/workspace/plugins.cljs:270
+msgid "workspace.plugins.permissions.comment-write"
+msgstr "Lees en wijzig jouw opmerkingen en antwoord in jouw naam."
+
+#: src/app/main/ui/workspace/plugins.cljs:86
+msgid "workspace.plugins.remove-plugin"
+msgstr "Plug-in verwijderen"
+
+#: src/app/main/ui/workspace/plugins.cljs:436
+msgid "workspace.plugins.try-out.cancel"
+msgstr "NIET NU"
+
+#: src/app/main/ui/workspace/plugins.cljs:429
+msgid "workspace.plugins.try-out.message"
+msgstr ""
+"Wil je even kijken? Het wordt geopend in een nieuw concept voor je huidige "
+"team. (Zo niet, dan vindt je het altijd in de geïnstalleerde plug-ins van "
+"elk bestand.)"
+
+#: src/app/main/ui/workspace/plugins.cljs:425
+msgid "workspace.plugins.try-out.title"
+msgstr "PLUG-IN '%s' IS GEÏNSTALLEERD VOOR JE GEBRUIKER!"
+
+#: src/app/main/ui/workspace/plugins.cljs:442
+msgid "workspace.plugins.try-out.try"
+msgstr "PLUG-IN UITPROBEREN"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1004, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1030
+msgid "workspace.shape.menu.add-layout"
+msgstr "Lay-out toevoegen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1022
+msgid "workspace.shape.menu.remove-layout"
+msgstr "Lay-out verwijderen"
+
+#: src/app/main/ui/workspace/context_menu.cljs:235
+msgid "workspace.shape.menu.rename"
+msgstr "Naam wijzigen"
+
+#: src/app/main/ui/workspace/sidebar/sitemap.cljs:229
+msgid "workspace.sidebar.sitemap.add-page"
+msgstr "Pagina toevoegen"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:84
+msgid "workspace.token.active-themes"
+msgstr "%s actieve thema's"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:310
+msgid "workspace.token.back-to-themes"
+msgstr "Terug naar themalijst"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:302
+msgid "workspace.token.edit-theme-title"
+msgstr "Thema bewerken"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:72
+msgid "workspace.token.edit-themes"
+msgstr "Thema's bewerken"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:186
+msgid "workspace.token.grouping-set-alert"
+msgstr "Groepering van tokenverzamelingen is nog niet ondersteund."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:142
+msgid "workspace.token.no-sets"
+msgstr "Geen verzamelingen"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:216
+msgid "workspace.token.no-sets-create"
+msgstr "Er zijn nog geen verzamelingen gedefinieerd. Maak er eerst een aan."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:239
+msgid "workspace.token.no-sets-yet"
+msgstr "Er zijn nog geen verzamelingen."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:191
+msgid "workspace.token.no-themes"
+msgstr "Er zijn geen thema's."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:133
+msgid "workspace.token.num-sets"
+msgstr "%s verzamelingen"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:66
+msgid "workspace.token.original-value"
+msgstr "Oorspronkelijke waarde: "
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:345, src/app/main/ui/workspace/sidebar/versions.cljs:347
+msgid "workspace.versions.button.save"
+msgstr "Versie opslaan"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:190
+msgid "workspace.versions.expand-snapshot"
+msgstr "Snapshots uitbreiden"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:327
+msgid "workspace.versions.filter.all"
+msgstr "Alle versies"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:326
+msgid "workspace.versions.filter.label"
+msgstr "Versiefilter"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:334
+msgid "workspace.versions.filter.user"
+msgstr "%s's versies"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:340
+msgid "workspace.versions.loading"
+msgstr "Laden…"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:283
+msgid "workspace.versions.restore-warning"
+msgstr "Wil je deze versie herstellen?"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:207
+msgid "workspace.versions.snapshot-menu"
+msgstr "Snapshot-menu openen"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:138
+msgid "workspace.versions.version-menu"
+msgstr "Versie-menu openen"
+
+#: src/app/main/ui/dashboard/placeholder.cljs
+#, markdown, unused
+msgid "dashboard.empty-placeholder-libraries-subtitle"
+msgstr ""
+"Hier verschijnen bibliotheken die aan het project zijn toegevoegd. Probeer "
+"je bestanden te delen of voeg ze toe vanuit onze [Bibliotheken en sjablonen] "
+"(https://penpot.app/libraries-templates)."
+
+#: src/app/main/ui/dashboard/fonts.cljs:445
+msgid "dashboard.fonts.empty-placeholder-viewer-sub"
+msgstr ""
+"Zodra een projectlid een aangepast lettertype heeft geüpload, wordt het hier "
+"weergegeven."
+
+#: src/app/main/ui/dashboard/team.cljs:944
+msgid "dashboard.webhooks.cant-edit"
+msgstr "Je kunt alleen door jou gemaakte webhooks verwijderen of wijzigen."
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1051
+#, unused
+msgid "labels.add"
+msgstr "Toevoegen"
+
+#: src/app/main/ui/dashboard/team.cljs:216
+msgid "modals.invite-team-member.text"
+msgstr ""
+"Je kunt leden uitnodigen voor het team zodat ze toegang hebben tot dit "
+"bestand en alle teambestanden."
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:173
+msgid "workspace.options.shadow-options.toggle-shadow"
+msgstr "Schaduw wisselen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
+#, unused
+msgid "workspace.options.interactions.remove-interaction"
+msgstr "Interactie verwijderen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:176, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:182
+msgid "workspace.options.layer-options.toggle-layer"
+msgstr "Laagzichtbaarheid wisselen"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:302
+msgid "workspace.options.shadow-options.add-shadow"
+msgstr "Schaduw toevoegen"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs
+#, unused
+msgid "workspace.token.add set"
+msgstr "Verzameling toevoegen"
+
+#: src/app/main/ui/workspace/tokens/form.cljs:361
+msgid "workspace.token.edit-token"
+msgstr "Token bewerken"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:52
+msgid "workspace.token.new-theme"
+msgstr "Nieuw thema"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:88
+msgid "workspace.token.no-active-theme"
+msgstr "Geen thema actief"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:43
+msgid "workspace.token.no-themes-currently"
+msgstr "Je hebt momenteel geen thema's."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:39, src/app/main/ui/workspace/tokens/modals/themes.cljs:84
+msgid "workspace.token.themes"
+msgstr "Thema's"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:328
+msgid "workspace.versions.filter.mine"
+msgstr "Mijn versies"
diff --git a/frontend/translations/pl.po b/frontend/translations/pl.po
index 961a019c8b..6a5bcc7647 100644
--- a/frontend/translations/pl.po
+++ b/frontend/translations/pl.po
@@ -1,16 +1,16 @@
msgid ""
msgstr ""
-"PO-Revision-Date: 2024-06-17 08:07+0000\n"
-"Last-Translator: Anonymous \n"
-"Language-Team: Polish "
-"\n"
+"PO-Revision-Date: 2024-11-16 13:00+0000\n"
+"Last-Translator: Nicola Bortoletto \n"
+"Language-Team: Polish \n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && "
-"(n%100<10 || n%100>=20) ? 1 : 2);\n"
-"X-Generator: Weblate 5.6-dev\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\n"
+"X-Generator: Weblate 5.9-dev\n"
#: src/app/main/ui/auth/register.cljs:133, src/app/main/ui/static.cljs:154, src/app/main/ui/viewer/login.cljs:98
msgid "auth.already-have-account"
@@ -4852,3 +4852,7 @@ msgstr "Aktualizuj"
#, unused
msgid "workspace.viewport.click-to-close-path"
msgstr "Kliknij, aby zamknąć ścieżkę"
+
+#: src/app/main/ui/workspace/sidebar/assets/typographies.cljs:408
+msgid "workspace.assets.typography.add-typography"
+msgstr ""
diff --git a/frontend/translations/th.po b/frontend/translations/th.po
index 9511968215..b3e89b943e 100644
--- a/frontend/translations/th.po
+++ b/frontend/translations/th.po
@@ -1,6 +1,860 @@
msgid ""
msgstr ""
-"X-Generator: Weblate\n"
+"PO-Revision-Date: 2024-12-28 16:02+0000\n"
+"Last-Translator: Late Night Defender \n"
+"Language-Team: Thai "
+"\n"
+"Language: th\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Weblate 5.10-dev\n"
+
+#: src/app/main/ui/auth/login.cljs:310, src/app/main/ui/auth/register.cljs:101, src/app/main/ui/auth/register.cljs:240, src/app/main/ui/static.cljs:144, src/app/main/ui/viewer/login.cljs:91
+msgid "auth.register-submit"
+msgstr "สร้างบัญชี"
+
+#: src/app/main/ui/dashboard/sidebar.cljs:571
+msgid "dashboard.delete-team"
+msgstr "ลบทีม"
+
+#: src/app/main/ui/dashboard/file_menu.cljs:328, src/app/main/ui/workspace/main_menu.cljs:621
+msgid "dashboard.download-standard-file"
+msgstr "ดาวน์โหลดไฟล์มาตรฐาน (.svg + .json)"
+
+#: src/app/main/ui/dashboard/file_menu.cljs:40, src/app/main/ui/dashboard/fonts.cljs:34, src/app/main/ui/dashboard/libraries.cljs:44, src/app/main/ui/dashboard/projects.cljs:341, src/app/main/ui/dashboard/search.cljs:31, src/app/main/ui/dashboard/sidebar.cljs:312, src/app/main/ui/dashboard/team.cljs:526, src/app/main/ui/dashboard/team.cljs:766, src/app/main/ui/dashboard/team.cljs:1029, src/app/main/ui/dashboard/team.cljs:1076
+msgid "dashboard.your-penpot"
+msgstr "Penpot ของคุณ"
+
+#: src/app/main/ui/viewer/share_link.cljs:271
+msgid "common.share-link.view-all"
+msgstr "เลือกทั้งหมด"
+
+#: src/app/main/ui/viewer/share_link.cljs:185
+msgid "common.share-link.placeholder"
+msgstr "ลิงก์ที่สามารถแชร์ได้จะปรากฏที่นี่"
+
+#: src/app/main/ui/auth/login.cljs:224
+msgid "auth.login-with-google-submit"
+msgstr "Google"
+
+#: src/app/main/ui/dashboard/projects.cljs:88
+msgid "dasboard.team-hero.management"
+msgstr "การจัดการทีม"
+
+#: src/app/main/ui/dashboard/fonts.cljs:444
+msgid "dashboard.fonts.empty-placeholder-viewer"
+msgstr "ยังไม่มีฟอนต์ที่กำหนดเอง"
+
+#: src/app/main/data/common.cljs:205
+msgid "dashboard.permissions-change.admin"
+msgstr "คุณเป็นแอดมินในทีมนี้แล้ว"
+
+#: src/app/main/ui/auth/verify_token.cljs:81, src/app/main/ui/settings/change_email.cljs:29
+msgid "errors.email-already-exists"
+msgstr "อีเมลถูกใช้ไปแล้ว"
+
+#: src/app/main/data/users.cljs:735, src/app/main/ui/auth/register.cljs:54
+msgid "errors.email-domain-not-allowed"
+msgstr "โดเมนนี้ไม่ได้รับอนุญาต"
+
+#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/setti ngs/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
+#, unused
+msgid "errors.field-max-length"
+msgstr "ต้องมีไม่เกิน 1 ตัวอักษร"
+
+#: src/app/main/ui/inspect/attributes/layout.cljs
+#, unused
+msgid "inspect.attributes.layout.left"
+msgstr "ซ้าย"
+
+#: src/app/main/ui/viewer/inspect/attributes/text.cljs:134, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:384
+msgid "inspect.attributes.typography.letter-spacing"
+msgstr "ระยะห่างระหว่างตัวอักษร"
+
+#: src/app/main/ui/viewer/inspect/attributes/shadow.cljs:57
+msgid "inspect.attributes.shadow"
+msgstr "เงา"
+
+#: src/app/main/ui/dashboard/files.cljs:186, src/app/main/ui/dashboard/projects.cljs:280
+msgid "dashboard.empty-placeholder-files-title"
+msgstr "ยังไม่มีไฟล์"
+
+#: src/app/main/ui/dashboard/placeholder.cljs:32
+msgid "dashboard.empty-placeholder-libraries-title"
+msgstr "ยังไม่มีไลบรารี"
+
+#: src/app/main/data/common.cljs:204
+msgid "dashboard.permissions-change.editor"
+msgstr "คุณเป็นเอดิเตอร์ในทีมนี้แล้ว"
+
+#: src/app/main/data/common.cljs:206
+msgid "dashboard.permissions-change.owner"
+msgstr "คุณเป็นเจ้าของในทีมนี้แล้ว"
+
+#, unused
+msgid "errors.field-min-length"
+msgstr "ต้องมีอย่างน้อย 1 ตัวอักษร"
+
+#: src/app/main/ui/components/color_input.cljs:57
+msgid "errors.invalid-color"
+msgstr "สีไม่ถูกต้อง"
+
+#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs
+#, unused
+msgid "errors.invalid-email"
+msgstr "กรุณาใส่อีเมลที่ถูกต้อง"
+
+#: src/app/main/ui/dashboard/fonts.cljs:53, src/app/main/ui/dashboard/sidebar.cljs:811
+msgid "labels.fonts"
+msgstr "ฟอนต์"
+
+#: src/app/main/ui/settings/password.cljs:84
+msgid "labels.new-password"
+msgstr "รหัสผ่านใหม่"
+
+#: src/app/main/ui/auth/register.cljs:133, src/app/main/ui/static.cljs:154, src/app/main/ui/viewer/login.cljs:98
+msgid "auth.already-have-account"
+msgstr "มีบัญชีแล้ว?"
+
+#: src/app/main/ui/auth/recovery_request.cljs:113, src/app/main/ui/auth/register.cljs:274
+msgid "auth.check-mail"
+msgstr "ตรวจสอบอีเมลของคุณ"
+
+#: src/app/main/ui/auth/register.cljs:277
+msgid "auth.check-your-email"
+msgstr "ตรวจสอบอีเมลของคุณและคลิกลิงก์เพื่อยืนยันและเริ่มใช้งาน Penpot"
+
+#: src/app/main/ui/auth/recovery.cljs:67
+msgid "auth.confirm-password"
+msgstr "ยืนยันรหัสผ่าน"
+
+#: src/app/main/ui/auth/register.cljs:145
+msgid "auth.create-demo-account"
+msgstr "สร้างบัญชีสาธิตการใช้งาน"
+
+#: src/app/main/ui/auth/login.cljs:197, src/app/main/ui/viewer/login.cljs:84
+msgid "auth.forgot-password"
+msgstr "ลืมรหัสผ่าน?"
+
+#: src/app/main/ui/auth/login.cljs:203
+msgid "auth.login-submit"
+msgstr "ลงชื่อเข้าใช้"
+
+#: src/app/main/ui/auth/login.cljs:42
+msgid "auth.demo-warning"
+msgstr ""
+"บริการนี้มีไว้สำหรับสาธิตการใช้งาน ห้ามใช้สำหรับชิ้นงานจริง เนื่องจากข้อมูลจะถูกลบเป็นระยะ ๆ"
+
+#: src/app/main/ui/auth/register.cljs:231
+msgid "auth.fullname"
+msgstr "ชื่อเต็ม"
+
+#: src/app/main/ui/auth/login.cljs:290
+msgid "auth.login-account-title"
+msgstr "ลงชื่อเข้าใช้บัญชีของฉัน"
+
+#: src/app/main/ui/auth/register.cljs:137, src/app/main/ui/static.cljs:157, src/app/main/ui/viewer/login.cljs:101
+msgid "auth.login-here"
+msgstr "ลงชื่อเข้าใช้ที่นี่"
+
+#: src/app/main/ui/auth/login.cljs:230
+msgid "auth.login-with-github-submit"
+msgstr "GitHub"
+
+#: src/app/main/ui/auth/login.cljs:236
+msgid "auth.login-with-gitlab-submit"
+msgstr "GitLab"
+
+#: src/app/main/ui/auth/login.cljs:209
+msgid "auth.login-with-ldap-submit"
+msgstr "LDAP"
+
+#: src/app/main/ui/auth/login.cljs:242, src/app/main/ui/auth/login.cljs:263
+msgid "auth.login-with-oidc-submit"
+msgstr "OpenID"
+
+#: src/app/main/ui/auth/recovery.cljs:60
+msgid "auth.new-password"
+msgstr "พิมพ์รหัสผ่านใหม่"
+
+#: src/app/main/ui/auth/recovery.cljs:36
+msgid "auth.notifications.password-changed-successfully"
+msgstr "เปลี่ยนรหัสผ่านแล้ว"
+
+#: src/app/main/ui/auth/login.cljs:187, src/app/main/ui/auth/register.cljs:95
+msgid "auth.password"
+msgstr "รหัสผ่าน"
+
+#: src/app/main/ui/auth/recovery_request.cljs:50
+msgid "auth.notifications.profile-not-verified"
+msgstr "โปรไฟล์นี้ยังไม่ได้รับการยืนยัน กรุณายืนยันโปรไฟล์ก่อนดำเนินการต่อ"
+
+#: src/app/main/ui/auth/recovery_request.cljs:33
+msgid "auth.notifications.recovery-token-sent"
+msgstr "ลิงก์กู้คืนรหัสผ่านถูกส่งไปยังกล่องข้อความของคุณแล้ว"
+
+#: src/app/main/ui/auth/verify_token.cljs:46
+msgid "auth.notifications.team-invitation-accepted"
+msgstr "เข้าร่วมทีมสำเร็จ"
+
+#: src/app/main/ui/auth/register.cljs:94
+msgid "auth.password-length-hint"
+msgstr "อย่างน้อย 8 ตัวอักษร"
+
+#: src/app/main/ui/auth/register.cljs:298
+msgid "auth.privacy-policy"
+msgstr "นโยบายความเป็นส่วนตัว"
+
+#: src/app/main/ui/auth/recovery_request.cljs:82
+msgid "auth.recovery-request-submit"
+msgstr "กู้คืนรหัสผ่าน"
+
+#: src/app/main/ui/auth/recovery_request.cljs:94
+msgid "auth.recovery-request-title"
+msgstr "ลืมรหัสผ่าน?"
+
+#: src/app/main/ui/auth/recovery.cljs:71
+msgid "auth.recovery-submit"
+msgstr "เปลี่ยนรหัสผ่านของคุณ"
+
+#: src/app/main/ui/auth/login.cljs:306, src/app/main/ui/static.cljs:140, src/app/main/ui/viewer/login.cljs:87
+msgid "auth.register"
+msgstr "ยังไม่มีบัญชี?"
+
+#: src/app/main/ui/auth/register.cljs:253
+msgid "auth.register-account-title"
+msgstr "ชื่อของคุณ"
+
+#: src/app/main/ui/auth/register.cljs:122
+msgid "auth.register-title"
+msgstr "สร้างบัญชี"
+
+#: src/app/main/ui/auth/register.cljs:290, src/app/main/ui/dashboard/sidebar.cljs:1022, src/app/main/ui/workspace/main_menu.cljs:154
+msgid "auth.terms-of-service"
+msgstr "เงื่อนไขการให้บริการ"
+
+#: src/app/main/ui/auth/register.cljs:275
+msgid "auth.verification-email-sent"
+msgstr "เราได้ส่งอีเมลยืนยันให้กับ"
+
+#: src/app/main/ui/auth/login.cljs:180, src/app/main/ui/auth/recovery_request.cljs:77, src/app/main/ui/auth/register.cljs:88
+msgid "auth.work-email"
+msgstr "อีเมลทำงาน"
+
+#: src/app/main/ui/viewer/share_link.cljs:306, src/app/main/ui/viewer/share_link.cljs:316
+msgid "common.share-link.all-users"
+msgstr "ผู้ใช้ Penpot ทั้งหมด"
+
+#: src/app/main/ui/viewer/share_link.cljs:209, src/app/main/ui/viewer/share_link.cljs:216
+msgid "common.share-link.destroy-link"
+msgstr "ทำลายลิงก์"
+
+#: src/app/main/ui/viewer/share_link.cljs:223
+msgid "common.share-link.get-link"
+msgstr "สร้างลิงก์"
+
+#: src/app/main/ui/viewer/share_link.cljs:139
+msgid "common.share-link.link-copied-success"
+msgstr "คัดลอกลิงก์แล้ว"
+
+#: src/app/main/ui/viewer/share_link.cljs:300
+msgid "common.share-link.permissions-can-comment"
+msgstr "สามารถคอมเมนต์"
+
+#: src/app/main/ui/viewer/share_link.cljs:310
+msgid "common.share-link.permissions-can-inspect"
+msgstr "สามารถตรวจดูโคด"
+
+#: src/app/main/ui/viewer/share_link.cljs:305, src/app/main/ui/viewer/share_link.cljs:315
+msgid "common.share-link.team-members"
+msgstr "สมาชิกในทีมเท่านั้น"
+
+#: src/app/main/ui/settings/access_tokens.cljs:136
+msgid "dashboard.access-tokens.expiration-180-days"
+msgstr "180 วัน"
+
+#: src/app/main/ui/settings/access_tokens.cljs:133
+msgid "dashboard.access-tokens.expiration-30-days"
+msgstr "30 วัน"
+
+#: src/app/main/ui/settings/access_tokens.cljs:134
+msgid "dashboard.access-tokens.expiration-60-days"
+msgstr "60 วัน"
+
+#: src/app/main/ui/settings/access_tokens.cljs:271
+msgid "dashboard.access-tokens.expired-on"
+msgstr "หมดอายุแล้วเมื่อ %s"
+
+#: src/app/main/ui/settings/access_tokens.cljs:272
+msgid "dashboard.access-tokens.expires-on"
+msgstr "จะหมดอายุเมื่อ %s"
+
+#: src/app/main/ui/settings/access_tokens.cljs:135
+msgid "dashboard.access-tokens.expiration-90-days"
+msgstr "90 วัน"
+
+#: src/app/main/ui/settings/access_tokens.cljs:270
+msgid "dashboard.access-tokens.no-expiration"
+msgstr "ไม่มีวันหมดอายุ"
+
+#: src/app/main/ui/settings/profile.cljs:72
+msgid "dashboard.change-email"
+msgstr "เปลี่ยนอีเมล"
+
+#: src/app/main/data/dashboard.cljs:771, src/app/main/data/dashboard.cljs:991
+msgid "dashboard.copy-suffix"
+msgstr "(คัดลอก)"
+
+#: src/app/main/ui/dashboard/sidebar.cljs:338
+msgid "dashboard.create-new-team"
+msgstr "สร้างทีมใหม่"
+
+#: src/app/main/ui/components/context_menu_a11y.cljs:284, src/app/main/ui/dashboard/sidebar.cljs:646
+msgid "dashboard.default-team-name"
+msgstr "Penpot ของคุณ"
+
+#: src/app/main/ui/dashboard/file_menu.cljs:318, src/app/main/ui/dashboard/file_menu.cljs:323, src/app/main/ui/workspace/main_menu.cljs:603, src/app/main/ui/workspace/main_menu.cljs:612
+msgid "dashboard.download-binary-file"
+msgstr "ดาวน์โหลดไฟล์ Penpot (.penpot)"
+
+#: src/app/main/ui/workspace/main_menu.cljs:629
+msgid "dashboard.export-frames"
+msgstr "ส่งออกบอร์ดเป็น PDF"
+
+#: src/app/main/ui/exports/assets.cljs:206
+msgid "dashboard.export-frames.title"
+msgstr "ส่งออกเป็น PDF"
+
+#: src/app/main/ui/workspace/main_menu.cljs:591
+msgid "dashboard.export-shapes"
+msgstr "ส่งออก"
+
+#: src/app/main/ui/exports/files.cljs:148
+msgid "dashboard.export.title"
+msgstr "ส่งออกไฟล์"
+
+#: src/app/main/ui/dashboard/fonts.cljs:441
+msgid "dashboard.fonts.empty-placeholder"
+msgstr "ฟอนต์ที่กำหนดเองที่คุณอัปโหลดจะปรากฏที่นี่"
+
+#: src/app/main/ui/dashboard/fonts.cljs:195
+msgid "dashboard.fonts.fonts-added"
+msgid_plural "dashboard.fonts.fonts-added"
+msgstr[0] "เพิ่มแล้ว %s ฟอนต์"
+
+#: src/app/main/ui/dashboard/fonts.cljs:203
+msgid "dashboard.fonts.upload-all"
+msgstr "อัปโหลดทั้งหมด"
+
+#: src/app/main/ui/dashboard/import.cljs:452, src/app/main/ui/dashboard/project_menu.cljs:108
+msgid "dashboard.import"
+msgstr "นำเข้าไฟล์ Penpot"
+
+#: src/app/main/ui/dashboard/import.cljs:288, src/app/worker/import.cljs:843, src/app/worker/import.cljs:846
+msgid "dashboard.import.analyze-error"
+msgstr "ไม่สามารถนำเข้าไฟล์นี้ได้"
+
+#: src/app/main/ui/dashboard/import.cljs:129
+msgid "dashboard.import.progress.process-colors"
+msgstr "กำลังประมวลผลสี"
+
+#: src/app/main/ui/dashboard/import.cljs:126
+msgid "dashboard.import.progress.process-page"
+msgstr "กำลังประมวลผลหน้า: %s"
+
+#: src/app/main/ui/dashboard/import.cljs:123
+msgid "dashboard.import.progress.upload-media"
+msgstr "กำลังอัปโหลดไฟล์: %s"
+
+#: src/app/main/ui/dashboard/sidebar.cljs:547, src/app/main/ui/dashboard/sidebar.cljs:556, src/app/main/ui/dashboard/sidebar.cljs:563, src/app/main/ui/dashboard/team.cljs:341
+msgid "dashboard.leave-team"
+msgstr "ออกจากทีม"
+
+#: src/app/main/ui/dashboard/templates.cljs:82, src/app/main/ui/dashboard/templates.cljs:157
+msgid "dashboard.libraries-and-templates"
+msgstr "ไลบรารีและเทมเพลต"
+
+#: src/app/main/ui/dashboard/libraries.cljs:55
+msgid "dashboard.libraries-title"
+msgstr "ไลบรารี"
+
+#: src/app/main/ui/dashboard/file_menu.cljs:254
+msgid "dashboard.move-to-multi"
+msgstr "ย้าน %s ไฟล์ไปยัง"
+
+#: src/app/main/ui/dashboard/file_menu.cljs:233
+msgid "dashboard.move-to-other-team"
+msgstr "ย้ายไปยังทีมอื่น"
+
+#: src/app/main/ui/dashboard/file_menu.cljs:301, src/app/main/ui/dashboard/project_menu.cljs:100
+msgid "dashboard.move-to"
+msgstr "ย้ายไปยัง"
+
+#: src/app/main/ui/settings/password.cljs:36
+msgid "dashboard.notifications.password-saved"
+msgstr "บันทึกรหัสผ่านแล้ว"
+
+#: src/app/main/ui/auth/verify_token.cljs:32
+msgid "dashboard.notifications.email-changed-successfully"
+msgstr "อัปเดตอีเมลสำเร็จแล้ว"
+
+#: src/app/main/ui/dashboard/file_menu.cljs:284
+msgid "dashboard.open-in-new-tab"
+msgstr "เปิดไฟล์ในแท็บใหม่"
+
+#: src/app/main/ui/dashboard/files.cljs:114, src/app/main/ui/dashboard/projects.cljs:260, src/app/main/ui/dashboard/projects.cljs:261
+msgid "dashboard.options"
+msgstr "ตัวเลือก"
+
+#: src/app/main/ui/settings/password.cljs:94, src/app/main/ui/settings/password.cljs:107
+msgid "dashboard.password-change"
+msgstr "เปลี่ยนรหัสผ่าน"
+
+#: src/app/main/ui/settings/profile.cljs:75
+msgid "dashboard.save-settings"
+msgstr "บันทึกการตั้งค่า"
+
+#: src/app/main/ui/dashboard/sidebar.cljs:246, src/app/main/ui/dashboard/sidebar.cljs:247
+msgid "dashboard.search-placeholder"
+msgstr "ค้นหา…"
+
+#: src/app/main/ui/settings/options.cljs:53
+msgid "dashboard.select-ui-language"
+msgstr "เลือกภาษาของ UI"
+
+#: src/app/main/ui/settings/options.cljs:60
+msgid "dashboard.select-ui-theme"
+msgstr "เลือกธีม"
+
+#: src/app/main/ui/dashboard/projects.cljs:303
+msgid "dashboard.show-all-files"
+msgstr "แสดงไฟล์ทั้งหมด"
+
+#: src/app/main/ui/dashboard/team.cljs:1090
+msgid "dashboard.team-info"
+msgstr "ข้อมูลของทีม"
+
+#: src/app/main/ui/settings/options.cljs:58
+msgid "dashboard.theme-change"
+msgstr "ธีมของ UI"
+
+#: src/app/main/ui/dashboard/search.cljs:43
+msgid "dashboard.title-search"
+msgstr "ผลการค้นหา"
+
+#: src/app/main/ui/dashboard/team.cljs:1108
+msgid "dashboard.team-members"
+msgstr "สมาชิกของทีม"
+
+#: src/app/main/ui/dashboard/team.cljs:1123
+msgid "dashboard.team-projects"
+msgstr "โปรเจกต์ของทีม"
+
+#: src/app/main/ui/settings/options.cljs:68
+msgid "dashboard.update-settings"
+msgstr "อัปเดตการตั้งค่า"
+
+#: src/app/main/ui/dashboard/team.cljs:890
+msgid "dashboard.webhooks.content-type"
+msgstr "ประเภทเนื้อหา"
+
+#: src/app/main/ui/dashboard/team.cljs:923
+msgid "dashboard.webhooks.create"
+msgstr "สร้าง Webhook"
+
+#: src/app/main/ui/dashboard/team.cljs:813
+msgid "dashboard.webhooks.create.success"
+msgstr "สร้าง Webhook แล้ว"
+
+#, unused
+msgid "dashboard.webhooks.update.success"
+msgstr "อัปเดต Webhook แล้ว"
+
+#: src/app/main/ui/settings.cljs:31
+msgid "dashboard.your-account-title"
+msgstr "บัญชีของคุณ"
+
+#: src/app/main/ui/settings/profile.cljs:67
+msgid "dashboard.your-email"
+msgstr "อีเมล"
+
+#: src/app/main/ui/settings/profile.cljs:59
+msgid "dashboard.your-name"
+msgstr "ชื่อของคุณ"
+
+#: src/app/main/ui/workspace/plugins.cljs:336, src/app/main/ui/workspace/plugins.cljs:390
+msgid "ds.confirm-allow"
+msgstr "อนุญาต"
+
+#: src/app/main/ui/confirm.cljs:36, src/app/main/ui/workspace/plugins.cljs:330, src/app/main/ui/workspace/plugins.cljs:384
+msgid "ds.confirm-cancel"
+msgstr "ยกเลิก"
+
+#: src/app/main/ui/settings/password.cljs
+#, unused
+msgid "errors.password-too-short"
+msgstr "รหัสผ่านต้องมีอย่างน้อย 8 ตัวอักษร"
+
+#: src/app/main/ui/auth/login.cljs:114, src/app/main/ui/auth/login.cljs:118
+msgid "errors.wrong-credentials"
+msgstr "อีเมลหรือรหัสผ่านไม่ถูกต้อง"
+
+#: src/app/main/ui/settings/password.cljs
+#, unused
+msgid "errors.wrong-old-password"
+msgstr "รหัสผ่านเดิมไม่ถูกต้อง"
+
+#: src/app/main/ui/settings/feedback.cljs:85
+msgid "feedback.discourse-title"
+msgstr "ชุมชน Penpot"
+
+#: src/app/main/ui/settings/feedback.cljs:65
+msgid "feedback.title"
+msgstr "อีเมล"
+
+#: src/app/main/ui/inspect/attributes/layout.cljs
+#, unused
+msgid "inspect.attributes.layout.height"
+msgstr "ความสูง"
+
+#: src/app/main/ui/inspect/attributes/stroke.cljs
+#, unused
+msgid "inspect.attributes.stroke.width"
+msgstr "ความกว้าง"
+
+#: src/app/main/ui/viewer/inspect/attributes/text.cljs:107, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:315
+msgid "inspect.attributes.typography.font-size"
+msgstr "ขนาดฟอนต์"
+
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:100
+msgid "inspect.tabs.code"
+msgstr "โคด"
+
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:127
+msgid "inspect.tabs.code.selected.frame"
+msgstr "บอร์ด"
+
+#: src/app/main/ui/viewer/inspect/right_sidebar.cljs:133
+msgid "inspect.tabs.code.selected.svg-raw"
+msgstr "SVG"
+
+#: src/app/main/ui/settings/password.cljs:91
+msgid "labels.confirm-password"
+msgstr "ยืนยันรหัสผ่าน"
+
+#: src/app/main/ui/dashboard/sidebar.cljs:985, src/app/main/ui/workspace/main_menu.cljs:114
+msgid "labels.community"
+msgstr "ชุมชน"
+
+#: src/app/main/ui/dashboard/team.cljs:678
+msgid "labels.copy-invitation-link"
+msgstr "คัดลอกลิงก์"
+
+#: src/app/main/ui/static.cljs:61
+msgid "labels.copyright"
+msgstr "Kaleidos @2024"
+
+#, unused
+msgid "labels.custom-fonts"
+msgstr "ฟอนต์ที่กำหนดเอง"
+
+#: src/app/main/ui/dashboard/team_form.cljs:101, src/app/main/ui/dashboard/team_form.cljs:121
+msgid "labels.create-team"
+msgstr "สร้างทีมใหม่"
+
+#: src/app/main/ui/settings/sidebar.cljs:73
+msgid "labels.dashboard"
+msgstr "แดชบอร์ด"
+
+#: src/app/main/ui/comments.cljs:356, src/app/main/ui/dashboard/fonts.cljs:253, src/app/main/ui/dashboard/team.cljs:940, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:205, src/app/main/ui/workspace/tokens/sidebar.cljs:199
+msgid "labels.edit"
+msgstr "แก้ไข"
+
+#: src/app/main/ui/dashboard/team.cljs:126, src/app/main/ui/dashboard/team.cljs:307, src/app/main/ui/dashboard/team.cljs:551, src/app/main/ui/dashboard/team.cljs:584, src/app/main/ui/onboarding/team_choice.cljs:65
+msgid "labels.editor"
+msgstr "เอดิเตอร์"
+
+#: src/app/main/ui/exports/assets.cljs:177
+msgid "labels.export"
+msgstr "ส่งออก"
+
+#: src/app/main/ui/onboarding/questions.cljs:165
+msgid "labels.figma"
+msgstr "Figma"
+
+#: src/app/main/ui/onboarding/questions.cljs:248
+msgid "labels.graphic-design"
+msgstr "กราฟิกดีไซน์"
+
+#: src/app/main/ui/settings/options.cljs:48
+msgid "labels.language"
+msgstr "ภาษา"
+
+#: src/app/main/ui/dashboard/sidebar.cljs:1008, src/app/main/ui/workspace/main_menu.cljs:138
+msgid "labels.libraries-and-templates"
+msgstr "ไลบรารีและเทมเพลต"
+
+#: src/app/main/ui/auth/verify_token.cljs:97, src/app/main/ui/dashboard/grid.cljs:104, src/app/main/ui/dashboard/grid.cljs:124, src/app/main/ui/dashboard/import.cljs:253, src/app/main/ui/dashboard/placeholder.cljs:52, src/app/main/ui/ds/product/loader.cljs:52, src/app/main/ui/exports/files.cljs:62, src/app/main/ui/viewer.cljs:637, src/app/main/ui/workspace.cljs:129
+msgid "labels.loading"
+msgstr "กำลังโหลด…"
+
+#: src/app/main/ui/dashboard/sidebar.cljs:1040
+msgid "labels.logout"
+msgstr "ลงชื่อออก"
+
+#: src/app/main/ui/dashboard/team.cljs:499
+msgid "labels.member"
+msgstr "สมาชิก"
+
+#: src/app/main/ui/dashboard/sidebar.cljs:510, src/app/main/ui/dashboard/team.cljs:94, src/app/main/ui/dashboard/team.cljs:102
+msgid "labels.members"
+msgstr "สมาชิก"
+
+#: src/app/main/ui/settings/password.cljs:77
+msgid "labels.old-password"
+msgstr "รหัสผ่านเดิม"
+
+#, unused
+msgid "labels.or"
+msgstr "หรือ"
+
+#: src/app/main/ui/dashboard/team.cljs:314, src/app/main/ui/dashboard/team.cljs:549, src/app/main/ui/dashboard/team.cljs:1114
+msgid "labels.owner"
+msgstr "เจ้าของ"
+
+#: src/app/main/ui/settings/sidebar.cljs:87
+msgid "labels.password"
+msgstr "รหัสผ่าน"
+
+#: src/app/main/ui/settings/profile.cljs:125, src/app/main/ui/settings/sidebar.cljs:82
+msgid "labels.profile"
+msgstr "โปรไฟล์"
+
+#: src/app/main/ui/dashboard/sidebar.cljs:784
+msgid "labels.projects"
+msgstr "โปรเจกต์"
+
+#: src/app/main/ui/viewer/share_link.cljs:173
+msgid "common.share-link.title"
+msgstr "แชร์โปรโตไทป์"
+
+#: src/app/main/ui/auth/register.cljs:124
+msgid "auth.register-tagline"
+msgstr ""
+"ด้วยบัญชี Penpot ฟรี คุณสามารถสร้างทีมได้อย่างไม่จำกัดและทำงานร่วมกับดีไซเนอร์และนักพัฒนาคนอื่น "
+"ๆ กี่โปรเจกต์ก็ได้ "
+
+#: src/app/main/ui/auth/login.cljs:293
+msgid "auth.login-tagline"
+msgstr ""
+"Penpot เป็นเครื่องมือออกแบบที่ฟรีและโอเพนซอร์สสำหรับการดีไซน์และโค้ดร่วมกัน"
+
+#: src/app/main/ui/auth/register.cljs:254
+msgid "auth.register-account-tagline"
+msgstr "เราควรเรียกคุณในแดชบอร์ดและอีเมลว่าอะไรดี"
+
+#: src/app/main/ui/auth.cljs
+#, unused
+msgid "auth.sidebar-tagline"
+msgstr "โซลูชันโอเพนซอร์สสำหรับการออกแบบและโปรโตไทป์"
+
+#, unused
+msgid "auth.terms-privacy-agreement"
+msgstr ""
+"เมื่อคุณสร้างบัญชี คุณยอมรับข้อกำหนดการให้บริการและนโยบายความเป็นส่วนตัว"
+
+#: src/app/main/ui/viewer/share_link.cljs:233
+msgid "common.share-link.manage-ops"
+msgstr "จัดการสิทธิ์"
+
+#: src/app/main/ui/viewer/share_link.cljs:279
+msgid "common.share-link.page-shared"
+msgid_plural "common.share-link.page-shared"
+msgstr[0] "แชร์แล้ว %s หน้า"
+
+#: src/app/main/ui/viewer/share_link.cljs:195
+msgid "common.share-link.permissions-hint"
+msgstr "ทุกคนที่มีลิงก์สามารถเข้าถึงได้"
+
+#: src/app/main/ui/dashboard/placeholder.cljs:39
+#, markdown
+msgid "dashboard.empty-placeholder-libraries"
+msgstr ""
+"ไลบรารีที่เพิ่มให้กับโปรเจกต์จะปรากฏที่นี่ ลองแชร์ไฟล์ของคุณหรือเพิ่มจาก[ไลบรารีและเทมเพลต]"
+"(https://penpot.app/libraries-templates)ของเรา"
+
+#: src/app/main/ui/dashboard/file_menu.cljs:269
+msgid "dashboard.export-standard-multi"
+msgstr "ดาวน์โหลด %s ไฟล์มาตรฐาน (.svg + .json)"
+
+#: src/app/main/ui/dashboard/fonts.cljs:445
+msgid "dashboard.fonts.empty-placeholder-viewer-sub"
+msgstr "เมื่อสมาชิกโปรเจกต์เพิ่มฟอนต์ที่กำหนดเอง จะปรากฏที่นี่"
+
+#: src/app/main/ui/dashboard/import.cljs:466
+msgid "dashboard.import.import-message"
+msgid_plural "dashboard.import.import-message"
+msgstr[0] "นำเข้าสำเร็จแล้ว %s ไฟล์"
+
+#: src/app/main/ui/dashboard/files.cljs:185, src/app/main/ui/dashboard/projects.cljs:279
+msgid "dashboard.empty-placeholder-drafts-title"
+msgstr "ยังไม่มีแบบร่าง"
+
+#: src/app/main/ui/dashboard/files.cljs:191, src/app/main/ui/dashboard/projects.cljs:285
+msgid "dashboard.empty-placeholder-files-subtitle"
+msgstr "เมื่อสมาชิกของโปรเจกต์สร้างไฟล์ จะแสดงผลที่นี่"
+
+#: src/app/main/ui/dashboard/placeholder.cljs:35
+msgid "dashboard.empty-placeholder-libraries-subtitle-viewer-role"
+msgstr "ไลบรารีที่เพิ่มลงในโปรเจกต์จะปรากฏที่นี่"
+
+#: src/app/main/ui/dashboard/files.cljs:190, src/app/main/ui/dashboard/projects.cljs:284
+msgid "dashboard.empty-placeholder-drafts-subtitle"
+msgstr "เมื่อสมาชิกโปรเจกต์สร้างแบบร่าง จะปรากฏที่นี่"
+
+#: src/app/main/ui/exports/assets.cljs:194
+msgid "dashboard.export-shapes.title"
+msgstr "ส่งออกส่วนที่เลือก"
+
+#: src/app/main/ui/dashboard/placeholder.cljs
+#, markdown, unused
+msgid "dashboard.empty-placeholder-libraries-subtitle"
+msgstr ""
+"ไลบรารีที่เพิ่มให้กับโปรเจกต์จะปรากฏที่นี่ ลองแชร์ไฟล์ของคุณหรือเพิ่มจาก[ไลบรารีและเทมเพลต]"
+"(https://penpot.app/libraries-templates)ของเรา"
+
+#: src/app/main/ui/auth/register.cljs:157
+#, markdown
+msgid "auth.terms-and-privacy-agreement"
+msgstr "ฉันยอมรับ [ข้อกำหนดการให้บริการ](%s)และ[นโยบายความเป็นส่วนตัว](%s)"
+
+#: src/app/main/ui/viewer/share_link.cljs:200
+msgid "common.share-link.confirm-deletion-link-description"
+msgstr "คุณแน่ใจหรือไม่ว่าต้องการลบลิงก์นี้? หากคุณลบ จะไม่มีใครสามารถเปิดได้"
+
+#: src/app/main/ui/viewer/share_link.cljs:261, src/app/main/ui/viewer/share_link.cljs:291
+msgid "common.share-link.current-tag"
+msgstr "(ปัจจุบัน)"
+
+#: src/app/main/ui/viewer/share_link.cljs:243
+msgid "common.share-link.permissions-pages"
+msgstr "หน้าที่ต้องการแชร์"
+
+#: src/app/main/ui/dashboard/projects.cljs
+#, fuzzy, unused
+msgid "dasboard.tutorial-hero.info"
+msgstr "เรียนรู้การใช้งาน Penpot เบื้องต้นด้วยการลงมือทำจริง"
+
+#: src/app/main/ui/settings/access_tokens.cljs:104
+msgid "dashboard.access-tokens.copied-success"
+msgstr "คัดลอกโทเคนแล้ว"
+
+#: src/app/main/ui/settings/access_tokens.cljs:191
+msgid "dashboard.access-tokens.create"
+msgstr "สร้างโทเคนใหม่"
+
+#: src/app/main/ui/settings/access-tokens.cljs
+#, unused
+msgid "dashboard.access-tokens.create-success"
+msgstr "สร้างโทเคนสำหรับการเข้าถึงสำเร็จแล้ว"
+
+#: src/app/main/ui/settings/access_tokens.cljs:289
+msgid "dashboard.access-tokens.empty.add-one"
+msgstr "กดปุ่ม \"สร้างโทเคนใหม่\" เพื่อสร้างโทเคน"
+
+#: src/app/main/ui/settings/access_tokens.cljs:288
+msgid "dashboard.access-tokens.empty.no-access-tokens"
+msgstr "คุณยังไม่มีโทเคนที่สร้างไว้"
+
+#: src/app/main/ui/settings/access_tokens.cljs:132
+msgid "dashboard.access-tokens.expiration-never"
+msgstr "ไม่มีวันหมดอายุ"
+
+#: src/app/main/ui/settings/access_tokens.cljs:186
+msgid "dashboard.access-tokens.personal"
+msgstr "โทเคนการเข้าถึงส่วนบุคคล"
+
+#: src/app/main/ui/settings/access_tokens.cljs:187
+msgid "dashboard.access-tokens.personal.description"
+msgstr ""
+"โทเคนการเข้าถึงส่วนบุคคลจะทำงานใกล้เคียงกับการยืนยันตัวตนด้วยชื่อผู้ใช้/รหัสผ่าน "
+"และสามารถใช้ในการอนุญาตให้แอปพลิเคชันเข้าถึง API ภายในของ Penpot ได้"
+
+#: src/app/main/ui/settings/access_tokens.cljs:143
+msgid "dashboard.access-tokens.token-will-expire"
+msgstr "โทเคนนี้จะหมดอายุใน %s"
+
+#: src/app/main/ui/settings/access_tokens.cljs:144
+msgid "dashboard.access-tokens.token-will-not-expire"
+msgstr "โทเคนนี้ไม่มีวันหมดอายุ"
+
+#: src/app/main/ui/dashboard/file_menu.cljs:259, src/app/main/ui/dashboard/file_menu.cljs:264
+msgid "dashboard.export-binary-multi"
+msgstr "ดาวน์โหลด %s ไฟล์ Penpot (.penpot)"
+
+#, unused
+msgid "dashboard.export-multi"
+msgstr "ส่งออก %s ไฟล์ Penpot"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:311
+msgid "dashboard.fonts.deleted-placeholder"
+msgstr "ฟอนต์ที่หายไป"
+
+#: src/app/main/ui/dashboard/fonts.cljs:183
+#, markdown
+msgid "dashboard.fonts.hero-text2"
+msgstr ""
+"คุณควรอัปโหลดเฉพาะฟอนต์ที่คุณเป็นเจ้าของหรือมีสิทธิ์ในการใช้งานใน Penpot "
+"ดูรายละอียดเพิ่มเติมในส่วนเนื้อหาของ[ข้อกำหนดการให้บริการของ Penpot](https://penpot.app/"
+"terms.html) นอกจากนี้คุณอาจต้องการอ่านเพิ่มเติมเกี่ยวกับ[ลิขสิทธิ์ฟอนต์](https://"
+"www.typography.com/faq)"
+
+#: src/app/main/ui/dashboard/import.cljs:292
+msgid "dashboard.import.import-error"
+msgstr "พบปัญหาในการนำเข้าไฟล์ ไฟล์นี้จึงไม่ถูกนำเข้า"
+
+#: src/app/main/ui/dashboard/import.cljs:461
+msgid "dashboard.import.import-warning"
+msgstr "บางไฟล์มีวัตถุที่ไม่ถูกต้อง ซึ่งถูกนำออกให้แล้ว"
+
+#: src/app/main/ui/dashboard/import.cljs:138, src/app/main/ui/dashboard/import.cljs:141
+msgid "dashboard.import.progress.process-components"
+msgstr "กำลังประมวลผลคอมโพเนนต์"
+
+#: src/app/main/ui/dashboard/import.cljs:135
+msgid "dashboard.import.progress.process-media"
+msgstr "กำลังประมวลผลสื่อ"
+
+#: src/app/main/ui/dashboard/import.cljs:120
+msgid "dashboard.import.progress.upload-data"
+msgstr "กำลังอัปโหลดข้อมูลไปยังเซิร์ฟเวอร์ (%s/%s)"
+
+#: src/app/main/ui/dashboard/import.cljs:358
+msgid "dashboard.libraries-and-templates.import-error"
+msgstr "พบปัญหาในการนำเข้าเทมเพลต เทมเพลตนี้จึงไม่ถูกนำเข้า"
+
+#: src/app/main/ui/dashboard/placeholder.cljs:54
+msgid "dashboard.loading-files"
+msgstr "กำลังโหลดไฟล์ของคุณ…"
+
+#: src/app/main/ui/dashboard/fonts.cljs:435
+msgid "dashboard.loading-fonts"
+msgstr "กำลังโหลดฟอนต์ของคุณ…"
+
+#: src/app/main/data/dashboard.cljs:735, src/app/main/data/dashboard.cljs:1192
+msgid "dashboard.new-project-prefix"
+msgstr "สร้างโปรเจกต์ใหม่"
+
+#: src/app/main/data/dashboard.cljs:966, src/app/main/data/dashboard.cljs:1189
+msgid "dashboard.new-file-prefix"
+msgstr "สร้างไฟล์ใหม่"
+
+#: src/app/main/ui/dashboard/projects.cljs:57
+msgid "dashboard.new-project"
+msgstr "+ สร้างโปรเจกต์ใหม่"
+
+#: src/app/main/ui/dashboard/files.cljs:101, src/app/main/ui/dashboard/projects.cljs:251, src/app/main/ui/dashboard/projects.cljs:252
+msgid "dashboard.new-file"
+msgstr "+ สร้างไฟล์ใหม่"
diff --git a/frontend/translations/ukr_UA.po b/frontend/translations/ukr_UA.po
index 073ba2f942..ec2a1bed44 100644
--- a/frontend/translations/ukr_UA.po
+++ b/frontend/translations/ukr_UA.po
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
-"PO-Revision-Date: 2024-11-14 11:14+0000\n"
-"Last-Translator: Anonymous \n"
+"PO-Revision-Date: 2024-12-19 18:02+0000\n"
+"Last-Translator: Denys Kisil \n"
"Language-Team: Ukrainian \n"
"Language: ukr_UA\n"
@@ -10,38 +10,40 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 5.9-dev\n"
+"X-Generator: Weblate 5.9.2-dev\n"
#: src/app/main/ui/auth/register.cljs:133, src/app/main/ui/static.cljs:154, src/app/main/ui/viewer/login.cljs:98
msgid "auth.already-have-account"
-msgstr "Уже маєте аккаунт?"
+msgstr "Уже маєте обліковий запис?"
#: src/app/main/ui/auth/recovery_request.cljs:113, src/app/main/ui/auth/register.cljs:274
msgid "auth.check-mail"
-msgstr "Перевірте свою електронну пошту"
+msgstr "Перевірте свою електрону скриньку"
#: src/app/main/ui/auth/register.cljs:277
msgid "auth.check-your-email"
-msgstr "Підтвердіть акаунт за посиланням в листі та почніть користування Penpot."
+msgstr ""
+"Підтвердьте обліковий запис за посиланням в листі та почніть користуватись "
+"Penpot."
#: src/app/main/ui/auth/recovery.cljs:67
msgid "auth.confirm-password"
-msgstr "Підтвердіть пароль"
+msgstr "Підтвердьте пароль"
#: src/app/main/ui/auth/register.cljs:145
msgid "auth.create-demo-account"
-msgstr "Створити демомнстраційний аккаунт"
+msgstr "Створити обліковий запис для демо"
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs
#, unused
msgid "auth.create-demo-profile"
-msgstr "Бажаєте просто спробувати?"
+msgstr "Хочете лише спробувати?"
#: src/app/main/ui/auth/login.cljs:42
msgid "auth.demo-warning"
msgstr ""
-"Це демонстраційний варіант сервісу, не використовувати для реальної роботи, "
-"проєкти періодично стиратимуться."
+"Це демонстраційний варіант сервісу, не використовуйте для реальної роботи, "
+"створені проєкти періодично очищуватимуться."
#: src/app/main/ui/auth/login.cljs:197, src/app/main/ui/viewer/login.cljs:84
msgid "auth.forgot-password"
@@ -53,7 +55,7 @@ msgstr "Повне ім'я"
#: src/app/main/ui/auth/login.cljs:290
msgid "auth.login-account-title"
-msgstr "Увійти до мого аккаунту"
+msgstr "Увійти до мого облікового запису"
#: src/app/main/ui/auth/register.cljs:137, src/app/main/ui/static.cljs:157, src/app/main/ui/viewer/login.cljs:101
msgid "auth.login-here"
@@ -100,7 +102,7 @@ msgstr "Пароль успішно змінено"
#: src/app/main/ui/auth/recovery_request.cljs:50
msgid "auth.notifications.profile-not-verified"
msgstr ""
-"Профіль не підтверджено, будь ласка, спершу підтвердіть його перш ніж "
+"Профіль не підтверджено, будь ласка, спершу підтвердьте його перш ніж "
"продовжити."
#: src/app/main/ui/auth/recovery_request.cljs:33
@@ -141,7 +143,7 @@ msgstr "Змініть свій пароль"
#: src/app/main/ui/auth/login.cljs:306, src/app/main/ui/static.cljs:140, src/app/main/ui/viewer/login.cljs:87
msgid "auth.register"
-msgstr "Ще не маєте акаунта?"
+msgstr "Не маєте облікового запису?"
#: src/app/main/ui/auth/register.cljs:254
msgid "auth.register-account-tagline"
@@ -153,18 +155,18 @@ msgstr "Ваше ім'я"
#: src/app/main/ui/auth/login.cljs:310, src/app/main/ui/auth/register.cljs:101, src/app/main/ui/auth/register.cljs:240, src/app/main/ui/static.cljs:144, src/app/main/ui/viewer/login.cljs:91
msgid "auth.register-submit"
-msgstr "Створити акаунт"
+msgstr "Створити обліковий запис"
#: src/app/main/ui/auth/register.cljs:124
msgid "auth.register-tagline"
msgstr ""
-"З безкоштовний аккаунтом Penpot ви зможете створювати необмежену кількість "
-"команд та співпрацювати з іншими дизайнерами та розробниками над будь-якою "
-"кількістю проєктів. "
+"З безкоштовний обліковим записом Penpot ви зможете створювати необмежену "
+"кількість команд та співпрацювати з іншими дизайнерами та розробниками над "
+"будь-якою кількістю проєктів. "
#: src/app/main/ui/auth/register.cljs:122
msgid "auth.register-title"
-msgstr "Створити акаунт"
+msgstr "Створити обліковий запис"
#: src/app/main/ui/auth.cljs
#, unused
@@ -185,12 +187,12 @@ msgstr "Умови користування"
#, unused
msgid "auth.terms-privacy-agreement"
msgstr ""
-"Створюючи аккаунт, ви погоджуєтеся з нашими умовами користування та "
+"Створюючи обліковий запис, ви погоджуєтеся з нашими умовами користування та "
"політикою конфіденційності."
#: src/app/main/ui/auth/register.cljs:275
msgid "auth.verification-email-sent"
-msgstr "Ми надіслали лист для підтвердження акаунту на"
+msgstr "Ми надіслали лист для підтвердження облікового запису на"
#: src/app/main/ui/auth/login.cljs:180, src/app/main/ui/auth/recovery_request.cljs:77, src/app/main/ui/auth/register.cljs:88
msgid "auth.work-email"
@@ -221,7 +223,7 @@ msgstr "(поточне)"
#: src/app/main/ui/viewer/share_link.cljs:209, src/app/main/ui/viewer/share_link.cljs:216
msgid "common.share-link.destroy-link"
-msgstr "Знищити посилання"
+msgstr "Стерти посилання"
#: src/app/main/ui/viewer/share_link.cljs:223
msgid "common.share-link.get-link"
@@ -244,11 +246,11 @@ msgstr[2] "%s сторінок було поширено"
#: src/app/main/ui/viewer/share_link.cljs:300
msgid "common.share-link.permissions-can-comment"
-msgstr "Можна коментувати"
+msgstr "Можуть додавати коментарі"
#: src/app/main/ui/viewer/share_link.cljs:310
msgid "common.share-link.permissions-can-inspect"
-msgstr "Можна переглядати код"
+msgstr "Можуть переглядати код"
#: src/app/main/ui/viewer/share_link.cljs:195
msgid "common.share-link.permissions-hint"
@@ -264,7 +266,7 @@ msgstr "Посилання для спільного використання з
#: src/app/main/ui/viewer/share_link.cljs:305, src/app/main/ui/viewer/share_link.cljs:315
msgid "common.share-link.team-members"
-msgstr "Лише члени команди"
+msgstr "Лише учасники команди"
#: src/app/main/ui/viewer/share_link.cljs:173
msgid "common.share-link.title"
@@ -295,9 +297,7 @@ msgstr "Об'єднуйтесь!"
#: src/app/main/ui/dashboard/projects.cljs
#, unused
msgid "dasboard.tutorial-hero.info"
-msgstr ""
-"Вивчайте основи Penpot, отримуючи задоволення від цього практичного "
-"посібника."
+msgstr "Вивчайте основи Penpot із задоволення, використовуючи ці посібники."
#: src/app/main/ui/dashboard/projects.cljs
#, unused
@@ -343,7 +343,7 @@ msgstr "Натисніть на кнопку \"Згенерувати новий
#: src/app/main/ui/settings/access_tokens.cljs:288
msgid "dashboard.access-tokens.empty.no-access-tokens"
-msgstr "У вас, поки що, немає токенів."
+msgstr "Ви ще не створили жодного токену."
#: src/app/main/ui/settings/access_tokens.cljs:136
msgid "dashboard.access-tokens.expiration-180-days"
@@ -384,9 +384,9 @@ msgstr "Персональні токени доступу"
#: src/app/main/ui/settings/access_tokens.cljs:187
msgid "dashboard.access-tokens.personal.description"
msgstr ""
-"Персональні токени доступу виступають альтернативою нашій системі "
-"автентифікації \"логін/пароль\" та можуть бути використаними для надання "
-"застосунку доступу до внутрішнього API Penpot"
+"Персональні токени доступу є альтернативою нашій системі автентифікації "
+"\"логін/пароль\" та можуть бути використаними для надання застосунку доступу "
+"до внутрішнього API Penpot"
#: src/app/main/ui/settings/access_tokens.cljs:143
msgid "dashboard.access-tokens.token-will-expire"
@@ -410,7 +410,7 @@ msgstr "(копія)"
#: src/app/main/ui/dashboard/sidebar.cljs:338
msgid "dashboard.create-new-team"
-msgstr "+ Створити нову команду"
+msgstr "Створити нову команду"
#: src/app/main/ui/components/context_menu_a11y.cljs:284, src/app/main/ui/dashboard/sidebar.cljs:646
msgid "dashboard.default-team-name"
@@ -484,19 +484,19 @@ msgstr "Завантажити %s стандартних файоів (.svg + .j
#: src/app/main/ui/exports/files.cljs:157
msgid "dashboard.export.detail"
-msgstr "* Може міститикомпоненти, графіку, кольори та/або типографіку."
+msgstr "* Може містити компоненти, графіки, кольори та/або типографіки."
#: src/app/main/ui/exports/files.cljs:156
msgid "dashboard.export.explain"
msgstr ""
"Файли, які ви хочете експортувати, використовують спільні бібліотеки. Що ви "
-"плануєте зробити з їхніми ресурсами?"
+"плануєте зробити з їхніми ресурсами*?"
#: src/app/main/ui/exports/files.cljs:165
msgid "dashboard.export.options.all.message"
msgstr ""
-"файли з спільними бібліотеками буде включено до експорту зі збереженням "
-"з'язків між ними."
+"файли з спільними бібліотеками буде додано до експорту зі збереженням "
+"зв'язків між ними."
#: src/app/main/ui/exports/files.cljs:166
msgid "dashboard.export.options.all.title"
@@ -505,12 +505,12 @@ msgstr "Експортувати спільні бібліотеки"
#: src/app/main/ui/exports/files.cljs:167
msgid "dashboard.export.options.detach.message"
msgstr ""
-"Спільні бібліотеки не буде включено до експорту, і до бібліотеки не буде "
+"Спільні бібліотеки не буде додано до експорту, і до бібліотеки не буде "
"додано ресурсів. "
#: src/app/main/ui/exports/files.cljs:168
msgid "dashboard.export.options.detach.title"
-msgstr "Поводитись з ресурсами спільної бібліотеки як з базовими об'єктами"
+msgstr "Розглядати ресурси спільної бібліотеки як базові об'єкти"
#: src/app/main/ui/exports/files.cljs:169
msgid "dashboard.export.options.merge.message"
@@ -550,9 +550,9 @@ msgstr[2] "% s шрифтів було додано"
msgid "dashboard.fonts.hero-text1"
msgstr ""
"Будь-який веб-шрифт, який ви завантажите сюди, буде додано до списку "
-"сімейств шрифтів, доступного у текстових властивостях файлів цієї команди. "
+"сімейств шрифтів, доступного у властивостях тексту файлів цієї команди. "
"Шрифти з однаковою назвою сімейства будуть згруповані в **одне сімейство "
-"шрифтів**. Ви можете завантажувати шрифти у таких форматах: **TTF, OTF і "
+"шрифтів**. Ви можете вивантажувати шрифти у таких форматах: **TTF, OTF і "
"WOFF** (потрібен лише один)."
#: src/app/main/ui/dashboard/fonts.cljs:183
@@ -560,10 +560,10 @@ msgstr ""
msgid "dashboard.fonts.hero-text2"
msgstr ""
"Ви повинні завантажувати лише ті шрифти, якими ви володієте або маєте "
-"ліцензію на використання в Penpot. Дізнайтеся більше в розділі \"Права на "
-"контент\" в [Умовах користування Penpot](https://penpot.app/terms.html). Ви "
-"також можете прочитати про [ліцензування "
-"шрифтів](https://www.typography.com/faq)."
+"ліцензію на використання в Penpot. Дізнайтеся більше в розділі \"Content "
+"Rights\" в [Умовах користування Penpot](https://penpot.app/terms.html). Ви "
+"також можете прочитати про [ліцензування шрифтів](https://www.typography.com/"
+"faq)."
#: src/app/main/ui/dashboard/fonts.cljs:203
msgid "dashboard.fonts.upload-all"
@@ -675,7 +675,7 @@ msgstr "Перенести в"
#: src/app/main/ui/dashboard/file_menu.cljs:254
msgid "dashboard.move-to-multi"
-msgstr "Перемістити файли (%s)"
+msgstr "Перемістити (%s) файлів до"
#: src/app/main/ui/dashboard/file_menu.cljs:233
msgid "dashboard.move-to-other-team"
@@ -707,7 +707,7 @@ msgstr "Закріплені проєкти з'являться тут"
#: src/app/main/ui/auth/verify_token.cljs:32
msgid "dashboard.notifications.email-changed-successfully"
-msgstr "Адресу вашої пошти було успішно змінено"
+msgstr "Адресу вашої електронної пошти було успішно змінено"
#: src/app/main/ui/auth/verify_token.cljs:26
msgid "dashboard.notifications.email-verified-successfully"
@@ -719,7 +719,7 @@ msgstr "Пароль успішно збережено!"
#: src/app/main/ui/dashboard/team.cljs:1119
msgid "dashboard.num-of-members"
-msgstr "%s членів"
+msgstr "%s учасників"
#: src/app/main/ui/dashboard/file_menu.cljs:284
msgid "dashboard.open-in-new-tab"
@@ -814,7 +814,7 @@ msgstr "Відомості про команду"
#: src/app/main/ui/dashboard/team.cljs:1108
msgid "dashboard.team-members"
-msgstr "Члени команди"
+msgstr "Учасники команди"
#: src/app/main/ui/dashboard/team.cljs:1123
msgid "dashboard.team-projects"
@@ -881,11 +881,11 @@ msgstr "Вебхук успішно оновлено."
#: src/app/main/ui/settings.cljs:31
msgid "dashboard.your-account-title"
-msgstr "Ваш аккаунт"
+msgstr "Ваш обліковий запис"
#: src/app/main/ui/settings/profile.cljs:67
msgid "dashboard.your-email"
-msgstr "Електрона адреса"
+msgstr "Електрона пошта"
#: src/app/main/ui/settings/profile.cljs:59
msgid "dashboard.your-name"
@@ -953,11 +953,11 @@ msgstr "Ваш браузер не може зробити це"
#: src/app/main/ui/auth/verify_token.cljs:81, src/app/main/ui/settings/change_email.cljs:29
msgid "errors.email-already-exists"
-msgstr "Електронна адреса вже використовується"
+msgstr "Електронна пошта вже використовується"
#: src/app/main/ui/auth/verify_token.cljs:86
msgid "errors.email-already-validated"
-msgstr "Електронна адреса вже підтверджена."
+msgstr "Електронна пошта вже підтверджена."
#, unused
msgid "errors.email-as-password"
@@ -970,8 +970,7 @@ msgstr "Цей домен не дозволений"
#: src/app/main/ui/auth/recovery_request.cljs:57, src/app/main/ui/auth/register.cljs:57, src/app/main/ui/auth/register.cljs:60, src/app/main/ui/dashboard/team.cljs:615, src/app/main/ui/settings/change_email.cljs:37
msgid "errors.email-has-permanent-bounces"
msgstr ""
-"Електрона адреса \"%s\" має багато скарг про постійне повернення "
-"повідомлень."
+"Електрона пошта \"%s\" має багато скарг про постійне повернення повідомлень."
#: src/app/main/ui/dashboard/team.cljs:190, src/app/main/ui/onboarding/team_choice.cljs:109
msgid "errors.email-spam-or-permanent-bounces"
@@ -1134,7 +1133,7 @@ msgstr "Помилка під'єднання, адреса недосяжна"
#: src/app/main/ui/dashboard/team.cljs:828
msgid "errors.webhooks.invalid-uri"
-msgstr "Адреса не пройшла перевірку."
+msgstr "Посилання не пройшло перевірку."
#: src/app/main/ui/dashboard/team.cljs:986
msgid "errors.webhooks.last-delivery"
@@ -1158,7 +1157,7 @@ msgstr "Неочікуваний статус %s"
#: src/app/main/ui/auth/login.cljs:114, src/app/main/ui/auth/login.cljs:118
msgid "errors.wrong-credentials"
-msgstr "Електрона адреса або пароль неправильні."
+msgstr "Електрона пошта або пароль неправильні."
#: src/app/main/ui/settings/password.cljs
#, unused
@@ -1190,12 +1189,12 @@ msgstr "Тема"
#: src/app/main/ui/settings/feedback.cljs:66
msgid "feedback.subtitle"
msgstr ""
-"Будь ласка, опишіть причину вашого листа, вказавши чи є це проблемою, ідеєю "
-"або сумнів. Член нашої команди відповість якомогашвидше."
+"Будь ласка, опишіть причину листа, вказавши чи є причина скаргою, ідеєю чи "
+"сумнівами. Учасник нашої команди відповість вам якомогашвидше."
#: src/app/main/ui/settings/feedback.cljs:65
msgid "feedback.title"
-msgstr "Електрона адреса"
+msgstr "Електрона пошта"
#: src/app/main/ui/settings/feedback.cljs:102
msgid "feedback.twitter-go-to"
@@ -1207,7 +1206,7 @@ msgstr "Ми готові допомогти з вашими технічним
#: src/app/main/ui/settings/feedback.cljs:95
msgid "feedback.twitter-title"
-msgstr "Аккаунт служби підтримки в X"
+msgstr "Обліковий запис служби підтримки в X"
#: src/app/main/ui/settings/password.cljs:29
msgid "generic.error"
@@ -1277,7 +1276,7 @@ msgstr "Обертання"
#: src/app/main/ui/inspect/attributes/layout.cljs
#, unused
msgid "inspect.attributes.layout.top"
-msgstr "Зверху"
+msgstr "Згори"
#: src/app/main/ui/inspect/attributes/layout.cljs
#, unused
@@ -1298,7 +1297,7 @@ msgstr "Обведення"
#, permanent, unused
msgid "inspect.attributes.stroke.alignment.center"
-msgstr "Центр"
+msgstr "По центру"
#, permanent, unused
msgid "inspect.attributes.stroke.alignment.inner"
@@ -1762,7 +1761,7 @@ msgstr "Член"
#: src/app/main/ui/dashboard/sidebar.cljs:510, src/app/main/ui/dashboard/team.cljs:94, src/app/main/ui/dashboard/team.cljs:102
msgid "labels.members"
-msgstr "Члени"
+msgstr "Учасники"
#: src/app/main/ui/settings/password.cljs:84
msgid "labels.new-password"
@@ -2111,7 +2110,7 @@ msgstr "Додати \"%s\" як Спільну Бібліотеку"
#: src/app/main/ui/workspace/nudge.cljs:60
msgid "modals.big-nudge"
-msgstr "Сильний поштовх"
+msgstr "Велике зміщення"
#: src/app/main/ui/settings/change_email.cljs:111
msgid "modals.change-email.confirm-email"
@@ -2125,7 +2124,7 @@ msgstr ""
#: src/app/main/ui/settings/change_email.cljs:104
msgid "modals.change-email.new-email"
-msgstr "Нова електрона адреса"
+msgstr "Нова електрона пошта"
#: src/app/main/ui/settings/change_email.cljs:119
msgid "modals.change-email.submit"
@@ -2141,7 +2140,7 @@ msgstr "Скопіювати токен"
#: src/app/main/ui/settings/access_tokens.cljs:131
msgid "modals.create-access-token.expiration-date.label"
-msgstr "Термін придатності"
+msgstr "Термін дії"
#: src/app/main/ui/settings/access_tokens.cljs:125
msgid "modals.create-access-token.name.label"
@@ -2169,7 +2168,7 @@ msgstr "Створити вебхук"
#: src/app/main/ui/dashboard/team.cljs:887
msgid "modals.create-webhook.url.label"
-msgstr "Адреса майданчику"
+msgstr "Посилання на Payload"
#: src/app/main/ui/dashboard/team.cljs:888
msgid "modals.create-webhook.url.placeholder"
@@ -2189,15 +2188,15 @@ msgstr "Видалити токен"
#: src/app/main/ui/settings/delete_account.cljs:59
msgid "modals.delete-account.cancel"
-msgstr "Скасувати та лишити мій аккаунт"
+msgstr "Скасувати та лишити мій обліковий запис"
#: src/app/main/ui/settings/delete_account.cljs:64
msgid "modals.delete-account.confirm"
-msgstr "Так, видалити мій аккаунт"
+msgstr "Так, видалити мій обліковий запис"
#: src/app/main/ui/settings/delete_account.cljs:53
msgid "modals.delete-account.info"
-msgstr "Видаливши аккаунт, ви втратите усі свої проєкти та архіви."
+msgstr "Видаливши обліковий запис, ви втратите усі свої проєкти та архіви."
#: src/app/main/ui/settings/delete_account.cljs:46
msgid "modals.delete-account.title"
@@ -2470,7 +2469,7 @@ msgstr[2] "Перемістити бібліотеки"
#: src/app/main/ui/workspace/main_menu.cljs:271, src/app/main/ui/workspace/nudge.cljs:47
msgid "modals.nudge-title"
-msgstr "Кількість поштовхів"
+msgstr "Кількість зміщень"
#: src/app/main/ui/dashboard/team.cljs:370
msgid "modals.promote-owner-confirm.accept"
@@ -2523,7 +2522,7 @@ msgstr "Видалити \"%s\" як Спільну Бібліотеку"
#: src/app/main/ui/workspace/nudge.cljs:53
msgid "modals.small-nudge"
-msgstr "Малий поштовх"
+msgstr "Мале зміщення"
#: src/app/main/ui/delete_shared.cljs:47
msgid "modals.unpublish-shared-confirm.message"
@@ -3633,7 +3632,7 @@ msgstr "Перейти в повноекраний режим"
#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:191
msgid "shortcuts.toggle-guides"
-msgstr "Показати/приховати посібники"
+msgstr "Показати/приховати орієнтири"
#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:192
msgid "shortcuts.toggle-history"
@@ -3665,11 +3664,11 @@ msgstr "Показати / приховати лінійки"
#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:200
msgid "shortcuts.toggle-snap-guides"
-msgstr "Прив'язувати до направляючих"
+msgstr "Прив'язувати до орієнтирів"
#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:201
msgid "shortcuts.toggle-snap-ruler-guide"
-msgstr "Прив'язувати до лінійок-направляючих"
+msgstr "Прив'язувати до орієнтирів лінійок"
#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:202
msgid "shortcuts.toggle-textpalette"
@@ -3855,7 +3854,7 @@ msgstr "Остання доставка була успішною."
#: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:58
msgid "workspace.align.hcenter"
-msgstr "Виривняти по центру горизонтально (%s)"
+msgstr "Вирівняти по центру горизонтально (%s)"
#: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:74
msgid "workspace.align.hdistribute"
@@ -4138,7 +4137,7 @@ msgstr "Вимкнути масштабування тексту"
#: src/app/main/ui/workspace/main_menu.cljs:228
msgid "workspace.header.menu.disable-snap-guides"
-msgstr "Вимкнути прив'язку до направляючих"
+msgstr "Зробити неактивною прив'язку до орієнтирів"
#: src/app/main/ui/workspace/main_menu.cljs:258
msgid "workspace.header.menu.disable-snap-pixel-grid"
@@ -4146,7 +4145,7 @@ msgstr "Вимкнути прив'язку до пікселів"
#: src/app/main/ui/workspace/main_menu.cljs:212
msgid "workspace.header.menu.disable-snap-ruler-guides"
-msgstr "Вимкнути прив'язку до лінійок-направляючих"
+msgstr "Зробити неактивною прив'язку до орієнтирів лінійок"
#: src/app/main/ui/workspace/main_menu.cljs:244
msgid "workspace.header.menu.enable-dynamic-alignment"
@@ -4163,7 +4162,7 @@ msgstr "Увімкнути масштабування тексту"
#: src/app/main/ui/workspace/main_menu.cljs:229
msgid "workspace.header.menu.enable-snap-guides"
-msgstr "Прив'язати до направляючих"
+msgstr "Прив'язати до орієнтирів"
#: src/app/main/ui/workspace/main_menu.cljs:259
msgid "workspace.header.menu.enable-snap-pixel-grid"
@@ -4171,7 +4170,7 @@ msgstr "Увімкнути прив'язку до пікселів"
#: src/app/main/ui/workspace/main_menu.cljs:213
msgid "workspace.header.menu.enable-snap-ruler-guides"
-msgstr "Прив'язати до лінійок-направляючих"
+msgstr "Прив'язати до орієнтирів лінійок"
#: src/app/main/ui/workspace/main_menu.cljs:388
msgid "workspace.header.menu.hide-artboard-names"
@@ -4179,7 +4178,7 @@ msgstr "Приховати імена дошок"
#: src/app/main/ui/workspace/main_menu.cljs:342
msgid "workspace.header.menu.hide-guides"
-msgstr "Приховати посібники"
+msgstr "Приховати орієнтири"
#: src/app/main/ui/workspace/main_menu.cljs:359
msgid "workspace.header.menu.hide-palette"
@@ -4231,7 +4230,7 @@ msgstr "Показати імена дошок"
#: src/app/main/ui/workspace/main_menu.cljs:343
msgid "workspace.header.menu.show-guides"
-msgstr "Показати вказівки"
+msgstr "Показати орієнтири"
#: src/app/main/ui/workspace/main_menu.cljs:360
msgid "workspace.header.menu.show-palette"
@@ -4525,7 +4524,7 @@ msgstr "У цій бібліотеці, поки що, немає ресурсі
#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:163
msgid "workspace.options.constraints"
-msgstr "Обмежити"
+msgstr "Положення"
#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:150
msgid "workspace.options.constraints.bottom"
@@ -4533,11 +4532,11 @@ msgstr "Низ"
#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:141, src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:152
msgid "workspace.options.constraints.center"
-msgstr "Центр"
+msgstr "По центру"
#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:229
msgid "workspace.options.constraints.fix-when-scrolling"
-msgstr "Виправити при прокручуванні"
+msgstr "Фіксувати при прокручуванні"
#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:138
msgid "workspace.options.constraints.left"
@@ -4553,15 +4552,15 @@ msgstr "Праворуч"
#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:142, src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:153
msgid "workspace.options.constraints.scale"
-msgstr "Масштаб"
+msgstr "Масштабувати"
#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:149
msgid "workspace.options.constraints.top"
-msgstr "Верх"
+msgstr "По верху"
#: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:151
msgid "workspace.options.constraints.topbottom"
-msgstr "Верх & низ"
+msgstr "По верху та низу"
#: src/app/main/ui/workspace/sidebar/options.cljs:179
msgid "workspace.options.design"
@@ -4683,7 +4682,7 @@ msgstr "Низ"
#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:233
msgid "workspace.options.grid.params.type.center"
-msgstr "Центр"
+msgstr "По центру"
#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:232
msgid "workspace.options.grid.params.type.left"
@@ -4699,7 +4698,7 @@ msgstr "Розтягування"
#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:231
msgid "workspace.options.grid.params.type.top"
-msgstr "Верх"
+msgstr "По верху"
#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:215, src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:292
msgid "workspace.options.grid.params.use-default"
@@ -4727,7 +4726,7 @@ msgstr "Рамка групи"
#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:320
msgid "workspace.options.guides.title"
-msgstr "Направляючі"
+msgstr "Орієнтири"
#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:489
msgid "workspace.options.height"
@@ -4989,7 +4988,7 @@ msgstr "Відтінок"
#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:127
msgid "workspace.options.layer-options.blend-mode.lighten"
-msgstr "Освітлення"
+msgstr "Освітленн"
#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:138
msgid "workspace.options.layer-options.blend-mode.luminosity"
@@ -5085,7 +5084,7 @@ msgstr "Ліворуч"
#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
#, unused
msgid "workspace.options.layout.margin"
-msgstr "Відступ"
+msgstr "Зовнішній відступ"
#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
#, unused
@@ -5095,7 +5094,7 @@ msgstr "Всі сторони"
#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
#, unused
msgid "workspace.options.layout.margin-simple"
-msgstr "Простий відступ"
+msgstr "Простий зовнішній відступ"
#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
#, unused
@@ -5180,14 +5179,15 @@ msgid "workspace.plugins.menu.title"
msgstr "Плагіни"
#: src/app/main/ui/workspace/plugins.cljs:323
-#, fuzzy
msgid "workspace.plugins.permissions.disclaimer"
-msgstr "Зауважте, що плагін створено третьою особою."
+msgstr ""
+"Зауважте, що плагін створено третьою особою, тож впевніться що ви довіряєте "
+"йому перш ніж надавати дозволи. Для нас важлива приватність та безпека ваших "
+"даних. Якщо маєте якісь сумніви, то просимо зв'язатись з підтримкою."
#: src/app/main/ui/workspace/plugins.cljs:316
-#, fuzzy
msgid "workspace.plugins.permissions.title"
-msgstr "ЦЕЙ ПЛАГІН ЗАПИТУЄ ДОСТУП НА:"
+msgstr "'%s' ПЛАГІН ЗАПИТУЄ ДОСТУП НА:"
#: src/app/main/ui/workspace/plugins.cljs:250
msgid "workspace.plugins.permissions.user-read"
@@ -5239,7 +5239,7 @@ msgstr "Вирізати"
#: src/app/main/ui/workspace/context_menu.cljs:496, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:764, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1052
msgid "workspace.shape.menu.delete"
-msgstr "Видалити це"
+msgstr "Вилучити"
#: src/app/main/ui/workspace/sidebar/assets/common.cljs:432
msgid "workspace.shape.menu.detach-instance"
@@ -5685,3 +5685,910 @@ msgstr "Оновити"
#, unused
msgid "workspace.viewport.click-to-close-path"
msgstr "Натисність щоб закінчити шлях"
+
+#: src/app/main/ui/dashboard/files.cljs:190, src/app/main/ui/dashboard/projects.cljs:284
+msgid "dashboard.empty-placeholder-drafts-subtitle"
+msgstr "Як тільки учасник проєкту створить чернетку, вона з'явиться тут."
+
+#: src/app/main/ui/dashboard/files.cljs:186, src/app/main/ui/dashboard/projects.cljs:280
+msgid "dashboard.empty-placeholder-files-title"
+msgstr "Файлів ще немає."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:39
+#, markdown
+msgid "dashboard.empty-placeholder-libraries"
+msgstr ""
+"Додані до проєкту бібліотеки з'являться тут. Можете поширити власні файли чи "
+"додати з нашої [сторінки Бібліотек та шаблонів](https://penpot.app/libraries-"
+"templates)."
+
+#: src/app/main/ui/dashboard/files.cljs:185, src/app/main/ui/dashboard/projects.cljs:279
+msgid "dashboard.empty-placeholder-drafts-title"
+msgstr "Чернеток ще немає."
+
+#: src/app/main/ui/dashboard/files.cljs:191, src/app/main/ui/dashboard/projects.cljs:285
+msgid "dashboard.empty-placeholder-files-subtitle"
+msgstr "Як тільки учасник проєкту створить файл, він буде відображений тут."
+
+#: src/app/main/ui/dashboard/placeholder.cljs:32
+msgid "dashboard.empty-placeholder-libraries-title"
+msgstr "Бібліотек ще немає."
+
+#: src/app/main/data/common.cljs:206
+msgid "dashboard.permissions-change.owner"
+msgstr "Відтепер ви власник цієї команди."
+
+#: src/app/main/data/common.cljs:203
+msgid "dashboard.permissions-change.viewer"
+msgstr "Відтепер ви спостерігач у цій команді."
+
+#: src/app/main/data/common.cljs:205
+msgid "dashboard.permissions-change.admin"
+msgstr "Відтепер ви адміністратор цієї команди."
+
+#: src/app/main/data/common.cljs:204
+msgid "dashboard.permissions-change.editor"
+msgstr "Відтепер ви редактор цієї команди."
+
+#: src/app/main/data/common.cljs:233
+msgid "dashboard.removed-from-team"
+msgstr "Більше ви не є частиною команди \"%s\"."
+
+#: src/app/main/ui/comments.cljs:340, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:295, src/app/main/ui/workspace/sidebar/options/menus/text.cljs:324
+msgid "labels.options"
+msgstr "Параметри"
+
+#: src/app/main/ui/delete_shared.cljs:52
+msgid "modals.unpublish-shared-confirm.accept"
+msgid_plural "modals.unpublish-shared-confirm.accept"
+msgstr[0] "Зняти з публікації поширену сторінку"
+msgstr[1] "Зняти з публікації декілька поширених сторінок"
+msgstr[2] "Зняти з публікації поширені сторінки"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:271
+msgid "settings.remove-color"
+msgstr "Видалити колір"
+
+#: src/app/main/ui/dashboard/placeholder.cljs
+#, markdown, unused
+msgid "dashboard.empty-placeholder-libraries-subtitle"
+msgstr ""
+"Додані до проєкту бібліотеки з'являться тут. Можете поширити власні файли чи "
+"додати з нашої [сторінки Бібліотек та шаблонів](https://penpot.app/libraries-"
+"templates)."
+
+#: src/app/main/ui/dashboard/fonts.cljs:445
+msgid "dashboard.fonts.empty-placeholder-viewer-sub"
+msgstr ""
+"Як тільки учасник проєкту завантажить користувацький шрифт, його буде "
+"відображено тут."
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:149, src/app/main/ui/workspace/sidebar/versions.cljs:288
+msgid "labels.restore"
+msgstr "Відновити"
+
+#: src/app/main/ui/workspace/sidebar/assets/colors.cljs:495
+msgid "workspace.assets.colors.add-color"
+msgstr "Додати колір"
+
+#: src/app/main/ui/workspace/sidebar/assets/components.cljs:532
+msgid "workspace.assets.components.add-component"
+msgstr "Додати компонент"
+
+#: src/app/main/ui/workspace/right_header.cljs:255
+msgid "workspace.header.share"
+msgstr "Поділитись"
+
+#: src/app/main/ui/workspace/libraries.cljs:304
+msgid "workspace.libraries.more-templates-link"
+msgstr "більше шаблонів тут"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:91
+msgid "workspace.options.blur-options.add-blur"
+msgstr "Додати розмиття"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:112
+msgid "workspace.options.blur-options.remove-blur"
+msgstr "Видалити розмиття"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/blur.cljs:108
+msgid "workspace.options.blur-options.toggle-blur"
+msgstr "Перемикання розмивання"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:195
+msgid "workspace.options.export.add-export"
+msgstr "Додати експортування"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:207, src/app/main/ui/workspace/sidebar/options/menus/exports.cljs:242
+msgid "workspace.options.export.remove-export"
+msgstr "Видалити експортування"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:735
+msgid "workspace.options.interactions.add-interaction"
+msgstr "Додати взаємодію"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
+#, unused
+msgid "workspace.options.interactions.remove-interaction"
+msgstr "Видалити взаємодію"
+
+#: src/app/main/ui/dashboard/placeholder.cljs:35
+msgid "dashboard.empty-placeholder-libraries-subtitle-viewer-role"
+msgstr "Додані до проєкту бібліотеки з'являться тут."
+
+#: src/app/main/ui/dashboard/fonts.cljs:444
+msgid "dashboard.fonts.empty-placeholder-viewer"
+msgstr "Користувацьких шрифтів ще немає."
+
+#: src/app/main/ui/dashboard/team.cljs:944
+msgid "dashboard.webhooks.cant-edit"
+msgstr "Ви можете видаляти або редагувати лише створені вами вебхуки."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:229
+msgid "labels.sets"
+msgstr "Набори"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1051
+#, unused
+msgid "labels.add"
+msgstr "Додати"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:187
+msgid "labels.themes"
+msgstr "Теми"
+
+#: src/app/main/ui/dashboard/team.cljs:216
+msgid "modals.invite-team-member.text"
+msgstr ""
+"Ви можете запросити учасників до команди для того щоб вони мали доступ до "
+"цього та інших файлів команди."
+
+#: src/app/main/ui/workspace/sidebar/assets/typographies.cljs:408
+msgid "workspace.assets.typography.add-typography"
+msgstr "Додати типографіку"
+
+#: src/app/main/ui/workspace/libraries.cljs:300
+msgid "workspace.libraries.more-templates"
+msgstr "Ви можете шукати "
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:150
+msgid "workspace.options.fill.add-fill"
+msgstr "Додати колір заливки"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:163
+msgid "workspace.options.fill.remove-fill"
+msgstr "Видалити заливку"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:154
+msgid "workspace.options.flows.remove-flow"
+msgstr "Видалити потік"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs
+#, unused
+msgid "workspace.options.layer-options.title.group"
+msgstr "Згрупувати шари"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.gap"
+msgstr "Відступ"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.padding-all"
+msgstr "Усі сторони"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.top"
+msgstr "Згори"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs:159
+msgid "workspace.options.more-colors"
+msgstr "Більше кольорів"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:161
+msgid "workspace.options.opacity"
+msgstr "Непрозорість"
+
+#: src/app/main/ui/dashboard/team.cljs:181, src/app/main/ui/onboarding/team_choice.cljs:100
+msgid "errors.maximum-invitations-by-request-reached"
+msgstr ""
+"Дрсягнуто максимальної кількості поштових скриньок, на які можна надіслати "
+"запрошення (максимум %s скриньок)"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:153
+msgid "labels.collapse"
+msgstr "Згорнути"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:323
+msgid "workspace.options.guides.add-guide"
+msgstr "Додати орієнтир"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:187
+msgid "workspace.options.guides.remove-guide"
+msgstr "Видалити орієнтир"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:183
+msgid "workspace.options.guides.toggle-guide"
+msgstr "Перемкнути орієнтир"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:176, src/app/main/ui/workspace/sidebar/options/menus/layer.cljs:182
+msgid "workspace.options.layer-options.toggle-layer"
+msgstr "Перемкнути видімість шару"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
+#, unused
+msgid "workspace.options.layout-item.advanced-ops"
+msgstr "Додаткові параметри"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.right"
+msgstr "Праворуч"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs:136
+msgid "workspace.options.more-lib-colors"
+msgstr "Більше кольорів бібліотеки"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:531
+msgid "workspace.options.layout-item.layout-item-max-w"
+msgstr "Макс. Ширина"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.padding"
+msgstr "Внутрішній відступ"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs
+#, unused
+msgid "workspace.options.layer-options.title.multiple"
+msgstr "Обрані шари"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:564
+msgid "workspace.options.layout-item.layout-item-max-h"
+msgstr "Макс. Висота"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.padding-simple"
+msgstr "Простий внутрішній відступ"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.space-around"
+msgstr "простір навколо"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, unused
+msgid "workspace.options.layout.space-between"
+msgstr "простір між"
+
+#: src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs
+#, unused
+msgid "workspace.options.position"
+msgstr "Розташування"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:547
+msgid "workspace.options.rotation"
+msgstr "Обернення"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:611
+msgid "workspace.options.radius-top-right"
+msgstr "Верхнього правого"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:48
+msgid "workspace.options.selection-fill"
+msgstr "Заливка обраного"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:145
+msgid "workspace.options.shadow-options.drop-shadow"
+msgstr "Падаюча тінь"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:297
+msgid "workspace.options.shadow-options.title"
+msgstr "Тінь"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:296
+msgid "workspace.options.shadow-options.title.group"
+msgstr "Групова тінь"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:425
+msgid "workspace.options.size-presets"
+msgstr "Шаблони розміру"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:43
+msgid "workspace.options.stroke"
+msgstr "Обведення"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs
+#, unused
+msgid "workspace.options.stroke-cap.diamond-marker"
+msgstr "Ромбоподібний маркер"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:109
+msgid "workspace.options.text-options.align-top"
+msgstr "Вирівняти по верху"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:143
+msgid "workspace.options.text-options.grow-fixed"
+msgstr "Фіксована"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs
+#, unused
+msgid "workspace.options.text-options.none"
+msgstr "Жоден"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:753
+msgid "workspace.options.use-play-button"
+msgstr ""
+"Використовуйте кнопку програвання в заголовку, щоб запустити перегляд "
+"прототипів."
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:640
+msgid "workspace.options.radius.single-corners"
+msgstr "Незалежні кути"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:192
+msgid "workspace.options.stroke-color"
+msgstr "Колір обведення"
+
+#: src/app/main/ui/workspace/sidebar/options.cljs:183
+msgid "workspace.options.prototype"
+msgstr "Прототип"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:61
+msgid "workspace.options.text-options.text-align-justify"
+msgstr "За шириною (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:620
+msgid "workspace.options.radius-bottom-left"
+msgstr "Нижнього лівого кута"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:184
+msgid "workspace.options.stroke.remove-stroke"
+msgstr "Видалити обведення"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:117
+msgid "workspace.options.text-options.align-bottom"
+msgstr "Вирівняти по низу"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:84
+msgid "workspace.options.text-options.direction-ltr"
+msgstr "LTR"
+
+#: src/app/main/ui/workspace/plugins.cljs:192
+msgid "workspace.plugins.error.url"
+msgstr "Плагіну не існує чи посилання неправильне."
+
+#: src/app/main/ui/workspace/plugins.cljs:196
+msgid "workspace.plugins.error.manifest"
+msgstr "Маніфест плагіну неправильний."
+
+#: src/app/main/ui/workspace/plugins.cljs:425
+msgid "workspace.plugins.try-out.title"
+msgstr "'%s' ПЛАГІН ВСТАНОВЛЕНО ДЛЯ ВАШОГО КОРИСТУВАЧА!"
+
+#: src/app/main/ui/workspace/plugins.cljs:429
+msgid "workspace.plugins.try-out.message"
+msgstr ""
+"Хочете переглянути? Буде створено нову чернетку для цієї команди. (Якщо ні, "
+"ви можете завжди знайти це у встановлених плагінах будь-якого файлу.)"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:43
+msgid "workspace.token.no-themes-currently"
+msgstr "Наразі у вас немає жодної теми."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:318
+msgid "workspace.token.set-selection-theme"
+msgstr ""
+"Визначити які набори токенів повинні бути використані як частину цього "
+"варіанту теми:"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs
+#, unused
+msgid "workspace.token.theme-name"
+msgstr "Тема %s"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:193
+msgid "workspace.versions.autosaved.entry"
+msgstr "%s версії автозбереження"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:326
+msgid "workspace.versions.filter.label"
+msgstr "Фільтр версій"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:328
+msgid "workspace.versions.filter.mine"
+msgstr "Мої версії"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:334
+msgid "workspace.versions.filter.user"
+msgstr "Версії %s"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:565, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:588
+msgid "workspace.options.radius"
+msgstr "Радіус"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:629
+msgid "workspace.options.radius-bottom-right"
+msgstr "Нижнього правого кута"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:749
+msgid "workspace.options.select-a-shape"
+msgstr ""
+"Оберіть фігуру, дошку чи групу щоб перетягнути з'єднання до іншої дошки."
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:302
+msgid "workspace.options.shadow-options.add-shadow"
+msgstr "Додати тінь"
+
+#: src/app/main/ui/viewer/inspect/attributes/shadow.cljs:40, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:199, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:201
+msgid "workspace.options.shadow-options.blur"
+msgstr "Розмиття"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:171
+msgid "workspace.options.stroke.add-stroke"
+msgstr "Додати колір обведення"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:104
+msgid "workspace.options.stroke.dotted"
+msgstr "Точковий"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:177, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:315
+msgid "workspace.options.shadow-options.remove-shadow"
+msgstr "Видалити тінь"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:295
+msgid "workspace.options.shadow-options.title.multiple"
+msgstr "Тінь виділеного"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:173
+msgid "workspace.options.shadow-options.toggle-shadow"
+msgstr "Перемкнути тінь"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/fill.cljs:197
+msgid "workspace.options.show-fill-on-export"
+msgstr "Показати в експортованому"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:387
+msgid "workspace.options.text-options.letter-spacing"
+msgstr "Міжлітеральний відступ"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:53
+msgid "workspace.options.text-options.text-align-center"
+msgstr "Вирівняти по центру (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:189
+msgid "workspace.options.text-options.title-selection"
+msgstr "Вибраний текст"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs
+#, unused
+msgid "workspace.options.text-options.titlecase"
+msgstr "Регістр заголовку"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:173
+msgid "workspace.options.text-options.underline"
+msgstr "Підкреслення (%s)"
+
+#: src/app/main/data/plugins.cljs:86, src/app/main/ui/workspace/main_menu.cljs:696, src/app/main/ui/workspace/plugins.cljs:82
+msgid "workspace.plugins.error.need-editor"
+msgstr "Щоб використовувати цей плагін, ви маєте бути редактором"
+
+#: src/app/main/ui/workspace/plugins.cljs:283
+msgid "workspace.plugins.permissions.allow-download"
+msgstr "Завантаження файлів розпочато."
+
+#: src/app/main/ui/workspace/plugins.cljs:276
+msgid "workspace.plugins.permissions.comment-read"
+msgstr "Читати ваші коментарі та відповіді."
+
+#: src/app/main/ui/workspace/context_menu.cljs:235
+msgid "workspace.shape.menu.rename"
+msgstr "Перейменувати"
+
+#: src/app/main/ui/workspace/context_menu.cljs:286
+msgid "workspace.shape.menu.create-artboard-from-selection"
+msgstr "Виділене на дошку"
+
+#: src/app/main/ui/workspace/plugins.cljs:270
+msgid "workspace.plugins.permissions.comment-write"
+msgstr "Читати та змінювати ваші коментарі та відповіді від вашого імені."
+
+#: src/app/main/ui/workspace/plugins.cljs:86
+msgid "workspace.plugins.remove-plugin"
+msgstr "Видалити плагін"
+
+#: src/app/main/ui/workspace/plugins.cljs:436
+msgid "workspace.plugins.try-out.cancel"
+msgstr "НЕ ЗАРАЗ"
+
+#: src/app/main/ui/workspace/plugins.cljs:442
+msgid "workspace.plugins.try-out.try"
+msgstr "СПРОБУВАТИ ПЛАГІН"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1022
+msgid "workspace.shape.menu.remove-layout"
+msgstr "Видалити макет"
+
+#: src/app/main/ui/workspace/sidebar/sitemap.cljs:229
+msgid "workspace.sidebar.sitemap.add-page"
+msgstr "Додати сторінку"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:84
+msgid "workspace.token.active-themes"
+msgstr "%s активних тем"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs
+#, unused
+msgid "workspace.token.add set"
+msgstr "Додати набір"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:47
+msgid "workspace.token.create-new-theme"
+msgstr "Створити свою першу тему зараз."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:194, src/app/main/ui/workspace/tokens/sidebar.cljs:210
+msgid "workspace.token.create-one"
+msgstr "Створити його."
+
+#: src/app/main/ui/workspace/tokens/form.cljs:362
+msgid "workspace.token.create-token"
+msgstr "Створити новий %s токен"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:147
+msgid "workspace.token.delete-theme-title"
+msgstr "Видалити тему"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:302
+msgid "workspace.token.edit-theme-title"
+msgstr "Редагувати тему"
+
+#: src/app/main/ui/workspace/tokens/form.cljs:361
+msgid "workspace.token.edit-token"
+msgstr "Редагувати токен"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:186
+msgid "workspace.token.grouping-set-alert"
+msgstr "Групування наборів токенів поки не підтримується."
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:88
+msgid "workspace.token.no-active-theme"
+msgstr "Немає активної теми"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:142
+msgid "workspace.token.no-sets"
+msgstr "Немає наборів"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:216
+msgid "workspace.token.no-sets-create"
+msgstr "Ще не оголошено жодного набору. Створіть перший."
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:239
+msgid "workspace.token.no-sets-yet"
+msgstr "Тут ще немає наборів."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:133
+msgid "workspace.token.num-sets"
+msgstr "%s наборів"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:66
+msgid "workspace.token.original-value"
+msgstr "Початкове значення: "
+
+#: src/app/main/ui/workspace/tokens/form.cljs:193, src/app/main/ui/workspace/tokens/form.cljs:196, src/app/main/ui/workspace/tokens/sidebar.cljs:67
+msgid "workspace.token.resolved-value"
+msgstr "Розв'язане значення: "
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:208
+msgid "workspace.token.save-theme"
+msgstr "Зберегти тему"
+
+#: src/app/main/ui/workspace/tokens/sets.cljs:172
+msgid "workspace.token.select-set"
+msgstr "Обрати набір."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:39, src/app/main/ui/workspace/tokens/modals/themes.cljs:84
+msgid "workspace.token.themes"
+msgstr "Теми"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:187
+msgid "workspace.versions.autosaved.version"
+msgstr "Автозбережено %s"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:224
+msgid "workspace.versions.button.pin"
+msgstr "Прикріпити версію"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:345, src/app/main/ui/workspace/sidebar/versions.cljs:347
+msgid "workspace.versions.button.save"
+msgstr "Зберегти версію"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:354
+msgid "workspace.versions.empty"
+msgstr "Тут ще немає жодної версії"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:327
+msgid "workspace.versions.filter.all"
+msgstr "Усі версії"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:340
+msgid "workspace.versions.loading"
+msgstr "Завантаження..."
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:283
+msgid "workspace.versions.restore-warning"
+msgstr "Ви бажаєте відновити ці версії?"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:207
+msgid "workspace.versions.snapshot-menu"
+msgstr "Відкрити меню знятків"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:138
+msgid "workspace.versions.version-menu"
+msgstr "Відкрити меню версій"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:602
+msgid "workspace.options.radius-top-left"
+msgstr "Верхнього лівого"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:181
+msgid "workspace.options.search-font"
+msgstr "Пошук шрифту"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:132
+msgid "workspace.options.stroke-cap.round"
+msgstr "Округле"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:124
+msgid "workspace.options.stroke-cap.none"
+msgstr "Жодний"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs
+#, unused
+msgid "workspace.options.stroke-cap.line-arrow"
+msgstr "Лінійна стрілка"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:126
+msgid "workspace.options.stroke-cap.line-arrow-short"
+msgstr "Стрілка"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:165
+msgid "workspace.options.stroke-width"
+msgstr "Довжина обведення"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:87
+msgid "workspace.options.stroke.center"
+msgstr "По центру"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:88
+msgid "workspace.options.stroke.inner"
+msgstr "Всередину"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:106
+msgid "workspace.options.stroke.mixed"
+msgstr "Комбіноване"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:89
+msgid "workspace.options.stroke.outer"
+msgstr "Назовні"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:103
+msgid "workspace.options.stroke.solid"
+msgstr "Жирне"
+
+#: src/app/main/ui/workspace/context_menu.cljs:404
+msgid "workspace.shape.menu.flow-start"
+msgstr "Початок потоку"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:639
+msgid "workspace.options.radius.all-corners"
+msgstr "Усі кути"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:184
+msgid "workspace.options.recent-fonts"
+msgstr "Нещодавній"
+
+#: src/app/main/ui/exports/assets.cljs:290
+msgid "workspace.options.retry"
+msgstr "Спробувати ще раз"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:41
+msgid "workspace.options.selection-stroke"
+msgstr "Обведення виділення"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs:118
+msgid "workspace.options.selection-color"
+msgstr "Обрані кольори"
+
+#: src/app/main/ui/viewer/inspect/attributes/shadow.cljs:38, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:187
+msgid "workspace.options.shadow-options.offsetx"
+msgstr "Вісь X"
+
+#: src/app/main/ui/viewer/inspect/attributes/shadow.cljs:39, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:225
+msgid "workspace.options.shadow-options.offsety"
+msgstr "Вісь Y"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:669
+msgid "workspace.options.show-in-viewer"
+msgstr "Показати у режимі перегляду"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:164
+msgid "workspace.options.size"
+msgstr "Розмір"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs
+#, unused
+msgid "workspace.options.stroke-cap.circle-marker"
+msgstr "Маркер кола"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:130
+msgid "workspace.options.stroke-cap.diamond-marker-short"
+msgstr "Ромб"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:133
+msgid "workspace.options.stroke-cap.square"
+msgstr "Квадратне"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:129
+msgid "workspace.options.stroke-cap.circle-marker-short"
+msgstr "Коло"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs
+#, unused
+msgid "workspace.options.stroke-cap.square-marker"
+msgstr "Квадратний маркер"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:128
+msgid "workspace.options.stroke-cap.square-marker-short"
+msgstr "Прямокутне"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs
+#, unused
+msgid "workspace.options.stroke-cap.triangle-arrow"
+msgstr "Трикутна стрілка"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:127
+msgid "workspace.options.stroke-cap.triangle-arrow-short"
+msgstr "Трикутне"
+
+#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:105
+msgid "workspace.options.stroke.dashed"
+msgstr "Пунктирний"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:113
+msgid "workspace.options.text-options.align-middle"
+msgstr "Вирівняти по середині"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:89
+msgid "workspace.options.text-options.direction-rtl"
+msgstr "RTL"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:151
+msgid "workspace.options.text-options.grow-auto-height"
+msgstr "Автоматична висота"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:369
+msgid "workspace.options.text-options.line-height"
+msgstr "Висота рядка"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:147
+msgid "workspace.options.text-options.grow-auto-width"
+msgstr "Автоматична ширина"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:178
+msgid "workspace.options.text-options.strikethrough"
+msgstr "Закреслення (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:49
+msgid "workspace.options.text-options.text-align-left"
+msgstr "Вирівняти ліворуч (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:57
+msgid "workspace.options.text-options.text-align-right"
+msgstr "Вирівняти праворуч (%s)"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:191
+msgid "workspace.options.text-options.title"
+msgstr "Текст"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs
+#, unused
+msgid "workspace.options.text-options.lowercase"
+msgstr "нижній реєстр"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:190
+msgid "workspace.options.text-options.title-group"
+msgstr "Груповий текст"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs
+#, unused
+msgid "workspace.options.text-options.uppercase"
+msgstr "ВЕРХНІЙ РЕГІСТР"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:465
+msgid "workspace.options.width"
+msgstr "Ширина"
+
+#: src/app/main/ui/workspace/plugins.cljs:243
+msgid "workspace.plugins.permissions.content-read"
+msgstr "Читати вміст файлів до яких користувачі мають доступ."
+
+#: src/app/main/ui/workspace/plugins.cljs:237
+msgid "workspace.plugins.permissions.content-write"
+msgstr "Читати та модифікувати вміст файлів, до яких користувачі мають доступ."
+
+#: src/app/main/ui/workspace/plugins.cljs:263
+msgid "workspace.plugins.permissions.library-read"
+msgstr "Читати ваші бібліотеки та матеріали."
+
+#: src/app/main/ui/workspace/plugins.cljs:257
+msgid "workspace.plugins.permissions.library-write"
+msgstr "Читати та модифікувати ваші бібліотеки та матеріали."
+
+#: src/app/main/ui/workspace/context_menu.cljs:194
+msgid "workspace.shape.menu.back"
+msgstr "Розмістити позаду"
+
+#: src/app/main/ui/workspace/context_menu.cljs:191
+msgid "workspace.shape.menu.backward"
+msgstr "Перемістити назад"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:155, src/app/main/ui/workspace/tokens/modals/themes.cljs:239
+msgid "workspace.token.create-theme-title"
+msgstr "Створити тему"
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:52
+msgid "workspace.token.new-theme"
+msgstr "Нова тема"
+
+#: src/app/main/ui/workspace/context_menu.cljs:402
+msgid "workspace.shape.menu.delete-flow-start"
+msgstr "Видалити початок потоку"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1004, src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs:1030
+msgid "workspace.shape.menu.add-layout"
+msgstr "Додати макет"
+
+#: src/app/main/ui/workspace/plugins.cljs:372
+msgid "workspace.plugins.permissions-update.title"
+msgstr "ОНОВИТИ ЦЕЙ ПЛАГІН"
+
+#: src/app/main/ui/workspace/plugins.cljs:376
+msgid "workspace.plugins.permissions-update.warning"
+msgstr ""
+"Плагін було модифіковано після вашого останнього використання. Тепер він "
+"також хоче отримати доступ до:"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:146
+msgid "workspace.options.shadow-options.inner-shadow"
+msgstr "Внутрішня тінь"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:219
+msgid "workspace.versions.button.restore"
+msgstr "Відновити версію"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:239
+msgid "workspace.options.shadow-options.color"
+msgstr "Колір тіні"
+
+#: src/app/main/ui/viewer/inspect/attributes/shadow.cljs:41, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:212, src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs:214
+msgid "workspace.options.shadow-options.spread"
+msgstr "Розтягнення"
+
+#: src/app/main/ui/workspace/sidebar/versions.cljs:190
+msgid "workspace.versions.expand-snapshot"
+msgstr "Розгорнути знятки"
+
+#: src/app/main/ui/workspace/tokens/sidebar.cljs:191
+msgid "workspace.token.no-themes"
+msgstr "Тут немає тем."
+
+#: src/app/main/ui/workspace/tokens/modals/themes.cljs:310
+msgid "workspace.token.back-to-themes"
+msgstr "Повернутись до списку тем"
+
+#: src/app/main/ui/workspace/tokens/theme_select.cljs:72
+msgid "workspace.token.edit-themes"
+msgstr "Редагувати теми"
diff --git a/frontend/vendor/mousetrap/index.js b/frontend/vendor/mousetrap/index.js
index 07a5cb9b06..0dd2e96b31 100644
--- a/frontend/vendor/mousetrap/index.js
+++ b/frontend/vendor/mousetrap/index.js
@@ -986,10 +986,10 @@ Mousetrap.prototype.stopCallback = function (e, element, combo) {
// stop for input, select, textarea and button
const shouldStop = element.tagName == "INPUT" ||
- element.tagName == "SELECT" ||
- element.tagName == "TEXTAREA" ||
- (element.tagName == "BUTTON" && combo.includes("tab")) ||
- (element.contentEditable && element.contentEditable == "true");
+ element.tagName == "SELECT" ||
+ element.tagName == "TEXTAREA" ||
+ (element.tagName == "BUTTON" && combo.includes("tab")) ||
+ (element.contentEditable && (element.contentEditable == "true" || element.contentEditable === "plaintext-only"));
return shouldStop;
}
diff --git a/render-wasm/docs/serialization.md b/render-wasm/docs/serialization.md
index 741ba57885..6ef7912c05 100644
--- a/render-wasm/docs/serialization.md
+++ b/render-wasm/docs/serialization.md
@@ -39,3 +39,29 @@ Gradient stops are serialized in a `Uint8Array`, each stop taking **5 bytes**.
**Red**, **Green**, **Blue** and **Alpha** are the RGBA components of the stop.
**Stop offset** is the offset, being integer values ranging from `0` to `100` (both inclusive).
+
+## StrokeCap
+
+Stroke caps are serialized as `u8`:
+
+| Value | Field |
+| ----- | --------- |
+| 1 | Line |
+| 2 | Triangle |
+| 3 | Rectangle |
+| 4 | Circle |
+| 5 | Diamond |
+| 6 | Round |
+| 7 | Square |
+| _ | None |
+
+## StrokeStyle
+
+Stroke styles are serialized as `u8`:
+
+| Value | Field |
+| ----- | ------ |
+| 1 | Dotted |
+| 2 | Dashed |
+| 3 | Mixed |
+| _ | Solid |
diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs
index 32f516dd93..a16fd3648e 100644
--- a/render-wasm/src/main.rs
+++ b/render-wasm/src/main.rs
@@ -245,7 +245,7 @@ pub extern "C" fn add_shape_fill_stops(ptr: *mut shapes::RawStopData, n_stops: u
unsafe {
let buffer = Vec::::from_raw_parts(ptr, len, len);
shape
- .add_gradient_stops(buffer)
+ .add_fill_gradient_stops(buffer)
.expect("could not add gradient stops");
mem::free_bytes();
}
@@ -346,6 +346,137 @@ pub extern "C" fn set_shape_path_content() {
}
}
+#[no_mangle]
+pub extern "C" fn add_shape_center_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) {
+ let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
+ if let Some(shape) = state.current_shape() {
+ shape.add_stroke(shapes::Stroke::new_center_stroke(
+ width, style, cap_start, cap_end,
+ ));
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn add_shape_inner_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) {
+ let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
+ if let Some(shape) = state.current_shape() {
+ shape.add_stroke(shapes::Stroke::new_inner_stroke(
+ width, style, cap_start, cap_end,
+ ))
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn add_shape_outer_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) {
+ let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
+ if let Some(shape) = state.current_shape() {
+ shape.add_stroke(shapes::Stroke::new_outer_stroke(
+ width, style, cap_start, cap_end,
+ ))
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn add_shape_stroke_solid_fill(raw_color: u32) {
+ let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
+ if let Some(shape) = state.current_shape() {
+ let color = skia::Color::new(raw_color);
+ shape
+ .set_stroke_fill(shapes::Fill::Solid(color))
+ .expect("could not add stroke solid fill");
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn add_shape_stroke_linear_fill(
+ start_x: f32,
+ start_y: f32,
+ end_x: f32,
+ end_y: f32,
+ opacity: f32,
+) {
+ let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
+ if let Some(shape) = state.current_shape() {
+ shape
+ .set_stroke_fill(shapes::Fill::new_linear_gradient(
+ (start_x, start_y),
+ (end_x, end_y),
+ opacity,
+ ))
+ .expect("could not add stroke linear fill");
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn add_shape_stroke_radial_fill(
+ start_x: f32,
+ start_y: f32,
+ end_x: f32,
+ end_y: f32,
+ opacity: f32,
+ width: f32,
+) {
+ let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
+ if let Some(shape) = state.current_shape() {
+ shape
+ .set_stroke_fill(shapes::Fill::new_radial_gradient(
+ (start_x, start_y),
+ (end_x, end_y),
+ opacity,
+ width,
+ ))
+ .expect("could not add stroke radial fill");
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn add_shape_stroke_stops(ptr: *mut shapes::RawStopData, n_stops: u32) {
+ let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
+
+ if let Some(shape) = state.current_shape() {
+ let len = n_stops as usize;
+
+ unsafe {
+ let buffer = Vec::::from_raw_parts(ptr, len, len);
+ shape
+ .add_stroke_gradient_stops(buffer)
+ .expect("could not add gradient stops");
+ mem::free_bytes();
+ }
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn add_shape_image_stroke(
+ a: u32,
+ b: u32,
+ c: u32,
+ d: u32,
+ alpha: f32,
+ width: i32,
+ height: i32,
+) {
+ let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
+ let id = uuid_from_u32_quartet(a, b, c, d);
+ if let Some(shape) = state.current_shape() {
+ shape
+ .set_stroke_fill(shapes::Fill::new_image_fill(
+ id,
+ (alpha * 0xff as f32).floor() as u8,
+ (width, height),
+ ))
+ .expect("could not add stroke image fill");
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn clear_shape_strokes() {
+ let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
+ if let Some(shape) = state.current_shape() {
+ shape.clear_strokes();
+ }
+}
+
fn main() {
init_gl();
}
diff --git a/render-wasm/src/shapes.rs b/render-wasm/src/shapes.rs
index 78ff1f4138..4943d8e64b 100644
--- a/render-wasm/src/shapes.rs
+++ b/render-wasm/src/shapes.rs
@@ -2,18 +2,20 @@ use crate::math;
use skia_safe as skia;
use uuid::Uuid;
-use crate::render::BlendMode;
+use crate::render::{BlendMode, Renderable};
mod fills;
mod images;
mod matrix;
mod paths;
mod renderable;
+mod strokes;
pub use fills::*;
pub use images::*;
use matrix::*;
pub use paths::*;
+pub use strokes::*;
#[derive(Debug, Clone, PartialEq)]
pub enum Kind {
@@ -35,6 +37,7 @@ pub struct Shape {
rotation: f32,
clip_content: bool,
fills: Vec,
+ strokes: Vec,
blend_mode: BlendMode,
opacity: f32,
hidden: bool,
@@ -51,6 +54,7 @@ impl Shape {
rotation: 0.,
clip_content: true,
fills: vec![],
+ strokes: vec![],
blend_mode: BlendMode::default(),
opacity: 1.,
hidden: false,
@@ -114,7 +118,7 @@ impl Shape {
self.fills.clear();
}
- pub fn add_gradient_stops(&mut self, buffer: Vec) -> Result<(), String> {
+ pub fn add_fill_gradient_stops(&mut self, buffer: Vec) -> Result<(), String> {
let fill = self.fills.last_mut().ok_or("Shape has no fills")?;
let gradient = match fill {
Fill::LinearGradient(g) => Ok(g),
@@ -129,6 +133,40 @@ impl Shape {
Ok(())
}
+ pub fn strokes(&self) -> std::slice::Iter {
+ self.strokes.iter()
+ }
+
+ pub fn add_stroke(&mut self, s: Stroke) {
+ self.strokes.push(s)
+ }
+
+ pub fn set_stroke_fill(&mut self, f: Fill) -> Result<(), String> {
+ let stroke = self.strokes.last_mut().ok_or("Shape has no strokes")?;
+ stroke.fill = f;
+ Ok(())
+ }
+
+ pub fn add_stroke_gradient_stops(&mut self, buffer: Vec) -> Result<(), String> {
+ let stroke = self.strokes.last_mut().ok_or("Shape has no strokes")?;
+ let fill = &mut stroke.fill;
+ let gradient = match fill {
+ Fill::LinearGradient(g) => Ok(g),
+ Fill::RadialGradient(g) => Ok(g),
+ _ => Err("Active stroke is not a gradient"),
+ }?;
+
+ for stop in buffer.into_iter() {
+ gradient.add_stop(stop.color(), stop.offset());
+ }
+
+ Ok(())
+ }
+
+ pub fn clear_strokes(&mut self) {
+ self.strokes.clear();
+ }
+
pub fn set_path_segments(&mut self, buffer: Vec) -> Result<(), String> {
let p = Path::try_from(buffer)?;
self.kind = Kind::Path(p);
@@ -138,6 +176,21 @@ impl Shape {
pub fn set_blend_mode(&mut self, mode: BlendMode) {
self.blend_mode = mode;
}
+
+ fn to_path_transform(&self) -> Option {
+ match self.kind {
+ Kind::Path(_) => {
+ let center = self.bounds().center();
+ let mut matrix = skia::Matrix::new_identity();
+ matrix.pre_translate(center);
+ matrix.pre_concat(&self.transform.no_translation().to_skia_matrix().invert()?);
+ matrix.pre_translate(-center);
+
+ Some(matrix)
+ }
+ _ => None,
+ }
+ }
}
#[cfg(test)]
diff --git a/render-wasm/src/shapes/images.rs b/render-wasm/src/shapes/images.rs
index 50980027a1..bbf5d600c3 100644
--- a/render-wasm/src/shapes/images.rs
+++ b/render-wasm/src/shapes/images.rs
@@ -1,71 +1,3 @@
-use crate::math;
-use crate::shapes::Kind;
use skia_safe as skia;
pub type Image = skia::Image;
-
-pub fn draw_image_in_container(
- canvas: &skia::Canvas,
- image: &Image,
- size: (i32, i32),
- kind: &Kind,
- paint: &skia::Paint,
-) {
- let width = size.0 as f32;
- let height = size.1 as f32;
- let image_aspect_ratio = width / height;
-
- let container = match kind {
- Kind::Rect(r) => r.to_owned(),
- Kind::Circle(r) => r.to_owned(),
- Kind::Path(p) => p.to_skia_path().bounds().to_owned(),
- };
-
- // Container size
- let container_width = container.width();
- let container_height = container.height();
- let container_aspect_ratio = container_width / container_height;
-
- // Calculate scale to ensure the image covers the container
- let scale = if image_aspect_ratio > container_aspect_ratio {
- // Image is widther, scale based on height to cover container
- container_height / height
- } else {
- // Image is taller, scale based on width to cover container
- container_width / width
- };
-
- // Scaled size of the image
- let scaled_width = width * scale;
- let scaled_height = height * scale;
-
- // Calculate offset to center the image in the container
- let offset_x = container.left + (container_width - scaled_width) / 2.0;
- let offset_y = container.top + (container_height - scaled_height) / 2.0;
-
- let dest_rect = math::Rect::from_xywh(offset_x, offset_y, scaled_width, scaled_height);
-
- // Save the current canvas state
- canvas.save();
-
- // Set the clipping rectangle to the container bounds
- match kind {
- Kind::Rect(_) => {
- canvas.clip_rect(container, skia::ClipOp::Intersect, true);
- }
- Kind::Circle(_) => {
- let mut oval_path = skia::Path::new();
- oval_path.add_oval(container, None);
- canvas.clip_path(&oval_path, skia::ClipOp::Intersect, true);
- }
- Kind::Path(p) => {
- canvas.clip_path(&p.to_skia_path(), skia::ClipOp::Intersect, true);
- }
- }
-
- // Draw the image with the calculated destination rectangle
- canvas.draw_image_rect(image, None, dest_rect, &paint);
-
- // Restore the canvas to remove the clipping
- canvas.restore();
-}
diff --git a/render-wasm/src/shapes/matrix.rs b/render-wasm/src/shapes/matrix.rs
index bd353b910d..294b9da066 100644
--- a/render-wasm/src/shapes/matrix.rs
+++ b/render-wasm/src/shapes/matrix.rs
@@ -1,6 +1,6 @@
use skia_safe as skia;
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Matrix {
pub a: f32,
pub b: f32,
@@ -47,6 +47,15 @@ impl Matrix {
res
}
+ pub fn no_translation(&self) -> Self {
+ let mut res = Self::identity();
+ res.c = self.c;
+ res.b = self.b;
+ res.a = self.a;
+ res.d = self.d;
+ res
+ }
+
fn translation(&self) -> (f32, f32) {
(self.e, self.f)
}
diff --git a/render-wasm/src/shapes/paths.rs b/render-wasm/src/shapes/paths.rs
index ae2367fb7f..1e77b9ccc2 100644
--- a/render-wasm/src/shapes/paths.rs
+++ b/render-wasm/src/shapes/paths.rs
@@ -73,12 +73,26 @@ impl TryFrom for Segment {
pub struct Path {
segments: Vec,
skia_path: skia::Path,
+ open: bool,
+}
+
+fn starts_and_ends_at_same_point(path: &skia::Path) -> bool {
+ if path.count_points() < 2 {
+ return false; // A path with fewer than 2 points cannot be closed
+ }
+
+ let start_point = path.get_point(0); // First point of the path
+ let end_point = path.get_point(path.count_points() - 1); // Last point of the path
+
+ // Compare the start and end points
+ start_point == end_point
}
impl TryFrom> for Path {
type Error = String;
fn try_from(value: Vec) -> Result {
+ let mut open = true;
let segments = value
.into_iter()
.map(|raw| Segment::try_from(raw))
@@ -98,13 +112,20 @@ impl TryFrom> for Path {
}
Segment::Close => {
skia_path.close();
+ open = false;
}
}
}
+ if !skia_path.is_last_contour_closed() && starts_and_ends_at_same_point(&skia_path) {
+ skia_path.close();
+ open = false;
+ }
+
Ok(Path {
segments,
skia_path,
+ open,
})
}
}
@@ -113,4 +134,8 @@ impl Path {
pub fn to_skia_path(&self) -> skia::Path {
self.skia_path.snapshot()
}
+
+ pub fn is_open(&self) -> bool {
+ self.open
+ }
}
diff --git a/render-wasm/src/shapes/renderable.rs b/render-wasm/src/shapes/renderable.rs
index ef124c272c..5bbecab4f6 100644
--- a/render-wasm/src/shapes/renderable.rs
+++ b/render-wasm/src/shapes/renderable.rs
@@ -1,7 +1,7 @@
use skia_safe as skia;
use uuid::Uuid;
-use super::{draw_image_in_container, Fill, Kind, Shape};
+use super::{Fill, Image, Kind, Path, Shape, Stroke, StrokeCap, StrokeKind};
use crate::math::Rect;
use crate::render::{ImageStore, Renderable};
@@ -10,7 +10,7 @@ impl Renderable for Shape {
let transform = self.transform.to_skia_matrix();
// Check transform-matrix code from common/src/app/common/geom/shapes/transforms.cljc
- let center = self.selrect.center();
+ let center = self.bounds().center();
let mut matrix = skia::Matrix::new_identity();
matrix.pre_translate(center);
matrix.pre_concat(&transform);
@@ -19,12 +19,26 @@ impl Renderable for Shape {
surface.canvas().concat(&matrix);
for fill in self.fills().rev() {
- render_fill(surface, images, fill, self.selrect, &self.kind);
+ render_fill(
+ surface,
+ images,
+ fill,
+ self.selrect,
+ &self.kind,
+ self.to_path_transform().as_ref(),
+ );
}
- let mut paint = skia::Paint::default();
- paint.set_blend_mode(self.blend_mode.into());
- paint.set_alpha_f(self.opacity);
+ for stroke in self.strokes().rev() {
+ render_stroke(
+ surface,
+ images,
+ stroke,
+ self.selrect,
+ &self.kind,
+ self.to_path_transform().as_ref(),
+ );
+ }
Ok(())
}
@@ -60,17 +74,20 @@ fn render_fill(
fill: &Fill,
selrect: Rect,
kind: &Kind,
+ path_transform: Option<&skia::Matrix>,
) {
match (fill, kind) {
(Fill::Image(image_fill), kind) => {
let image = images.get(&image_fill.id());
if let Some(image) = image {
- draw_image_in_container(
+ draw_image_fill_in_container(
surface.canvas(),
&image,
image_fill.size(),
kind,
&fill.to_paint(&selrect),
+ &selrect,
+ path_transform,
);
}
}
@@ -81,9 +98,429 @@ fn render_fill(
surface.canvas().draw_oval(rect, &fill.to_paint(&selrect));
}
(_, Kind::Path(path)) => {
- surface
- .canvas()
- .draw_path(&path.to_skia_path(), &fill.to_paint(&selrect));
+ surface.canvas().draw_path(
+ &path.to_skia_path().transform(path_transform.unwrap()),
+ &fill.to_paint(&selrect),
+ );
}
}
}
+
+fn render_stroke(
+ surface: &mut skia::Surface,
+ images: &ImageStore,
+ stroke: &Stroke,
+ selrect: Rect,
+ kind: &Kind,
+ path_transform: Option<&skia::Matrix>,
+) {
+ if let Fill::Image(image_fill) = &stroke.fill {
+ if let Some(image) = images.get(&image_fill.id()) {
+ draw_image_stroke_in_container(
+ surface.canvas(),
+ &image,
+ stroke,
+ image_fill.size(),
+ kind,
+ &selrect,
+ path_transform,
+ );
+ }
+ } else {
+ match kind {
+ Kind::Rect(rect) => draw_stroke_on_rect(surface.canvas(), stroke, rect, &selrect),
+ Kind::Circle(rect) => draw_stroke_on_circle(surface.canvas(), stroke, rect, &selrect),
+ Kind::Path(path) => {
+ draw_stroke_on_path(surface.canvas(), stroke, path, &selrect, path_transform);
+ }
+ }
+ }
+}
+
+fn draw_stroke_on_rect(canvas: &skia::Canvas, stroke: &Stroke, rect: &Rect, selrect: &Rect) {
+ // Draw the different kind of strokes for a rect is perry straightforward, we just need apply a stroke to:
+ // - The same rect if it's a center stroke
+ // - A bigger rect if it's an outer stroke
+ // - A smaller rect if it's an outer stroke
+ let stroke_rect = stroke.outer_rect(rect);
+ canvas.draw_rect(&stroke_rect, &stroke.to_paint(selrect));
+}
+
+fn draw_stroke_on_circle(canvas: &skia::Canvas, stroke: &Stroke, rect: &Rect, selrect: &Rect) {
+ // Draw the different kind of strokes for an oval is perry straightforward, we just need apply a stroke to:
+ // - The same oval if it's a center stroke
+ // - A bigger oval if it's an outer stroke
+ // - A smaller oval if it's an outer stroke
+ let stroke_rect = stroke.outer_rect(rect);
+ canvas.draw_oval(&stroke_rect, &stroke.to_paint(selrect));
+}
+
+fn handle_stroke_cap(
+ canvas: &skia::Canvas,
+ cap: StrokeCap,
+ width: f32,
+ paint: &mut skia::Paint,
+ p1: &skia::Point,
+ p2: &skia::Point,
+) {
+ paint.set_style(skia::PaintStyle::Fill);
+ paint.set_blend_mode(skia::BlendMode::Src);
+ match cap {
+ StrokeCap::None => {}
+ StrokeCap::Line => {
+ paint.set_style(skia::PaintStyle::Stroke);
+ draw_arrow_cap(canvas, &paint, p1, p2, width * 4.);
+ }
+ StrokeCap::Triangle => {
+ draw_triangle_cap(canvas, &paint, p1, p2, width * 4.);
+ }
+ StrokeCap::Rectangle => {
+ draw_square_cap(canvas, &paint, p1, p2, width * 4., 0.);
+ }
+ StrokeCap::Circle => {
+ canvas.draw_circle((p1.x, p1.y), width * 2., &paint);
+ }
+ StrokeCap::Diamond => {
+ draw_square_cap(canvas, &paint, p1, p2, width * 4., 45.);
+ }
+ StrokeCap::Round => {
+ canvas.draw_circle((p1.x, p1.y), width / 2.0, &paint);
+ }
+ StrokeCap::Square => {
+ draw_square_cap(canvas, &paint, p1, p2, width, 0.);
+ }
+ }
+}
+
+fn handle_stroke_caps(
+ path: &mut skia::Path,
+ stroke: &Stroke,
+ selrect: &Rect,
+ canvas: &skia::Canvas,
+ is_open: bool,
+) {
+ let points_count = path.count_points();
+ let mut points = vec![skia::Point::default(); points_count];
+ let c_points = path.get_points(&mut points);
+
+ // Closed shapes don't have caps
+ if c_points >= 2 && is_open {
+ let first_point = points.first().unwrap();
+ let last_point = points.last().unwrap();
+
+ let kind = stroke.render_kind(is_open);
+ let mut paint_stroke = stroke.to_stroked_paint(kind.clone(), selrect);
+
+ handle_stroke_cap(
+ canvas,
+ stroke.cap_start,
+ stroke.width,
+ &mut paint_stroke,
+ first_point,
+ &points[1],
+ );
+ handle_stroke_cap(
+ canvas,
+ stroke.cap_end,
+ stroke.width,
+ &mut paint_stroke,
+ last_point,
+ &points[points_count - 2],
+ );
+ }
+}
+
+fn draw_square_cap(
+ canvas: &skia::Canvas,
+ paint: &skia::Paint,
+ center: &skia::Point,
+ direction: &skia::Point,
+ size: f32,
+ extra_rotation: f32,
+) {
+ let dx = direction.x - center.x;
+ let dy = direction.y - center.y;
+ let angle = dy.atan2(dx);
+
+ let mut matrix = skia::Matrix::new_identity();
+ matrix.pre_rotate(
+ angle.to_degrees() + extra_rotation,
+ skia::Point::new(center.x, center.y),
+ );
+
+ let half_size = size / 2.0;
+ let rect = skia::Rect::from_xywh(center.x - half_size, center.y - half_size, size, size);
+
+ let points = [
+ skia::Point::new(rect.left(), rect.top()),
+ skia::Point::new(rect.right(), rect.top()),
+ skia::Point::new(rect.right(), rect.bottom()),
+ skia::Point::new(rect.left(), rect.bottom()),
+ ];
+
+ let mut transformed_points = points.clone();
+ matrix.map_points(&mut transformed_points, &points);
+
+ let mut path = skia::Path::new();
+ path.move_to(skia::Point::new(center.x, center.y));
+ path.move_to(transformed_points[0]);
+ path.line_to(transformed_points[1]);
+ path.line_to(transformed_points[2]);
+ path.line_to(transformed_points[3]);
+ path.close();
+ canvas.draw_path(&path, paint);
+}
+
+fn draw_arrow_cap(
+ canvas: &skia::Canvas,
+ paint: &skia::Paint,
+ center: &skia::Point,
+ direction: &skia::Point,
+ size: f32,
+) {
+ let dx = direction.x - center.x;
+ let dy = direction.y - center.y;
+ let angle = dy.atan2(dx);
+
+ let mut matrix = skia::Matrix::new_identity();
+ matrix.pre_rotate(
+ angle.to_degrees() - 90.,
+ skia::Point::new(center.x, center.y),
+ );
+
+ let half_height = size / 2.;
+ let points = [
+ skia::Point::new(center.x, center.y - half_height),
+ skia::Point::new(center.x - size, center.y + half_height),
+ skia::Point::new(center.x + size, center.y + half_height),
+ ];
+
+ let mut transformed_points = points.clone();
+ matrix.map_points(&mut transformed_points, &points);
+
+ let mut path = skia::Path::new();
+ path.move_to(transformed_points[1]);
+ path.line_to(transformed_points[0]);
+ path.line_to(transformed_points[2]);
+ path.move_to(skia::Point::new(center.x, center.y));
+ path.line_to(transformed_points[0]);
+
+ canvas.draw_path(&path, paint);
+}
+
+fn draw_triangle_cap(
+ canvas: &skia::Canvas,
+ paint: &skia::Paint,
+ center: &skia::Point,
+ direction: &skia::Point,
+ size: f32,
+) {
+ let dx = direction.x - center.x;
+ let dy = direction.y - center.y;
+ let angle = dy.atan2(dx);
+
+ let mut matrix = skia::Matrix::new_identity();
+ matrix.pre_rotate(
+ angle.to_degrees() - 90.,
+ skia::Point::new(center.x, center.y),
+ );
+
+ let half_height = size / 2.;
+ let points = [
+ skia::Point::new(center.x, center.y - half_height),
+ skia::Point::new(center.x - size, center.y + half_height),
+ skia::Point::new(center.x + size, center.y + half_height),
+ ];
+
+ let mut transformed_points = points.clone();
+ matrix.map_points(&mut transformed_points, &points);
+
+ let mut path = skia::Path::new();
+ path.move_to(transformed_points[0]);
+ path.line_to(transformed_points[1]);
+ path.line_to(transformed_points[2]);
+ path.close();
+
+ canvas.draw_path(&path, paint);
+}
+
+fn draw_stroke_on_path(
+ canvas: &skia::Canvas,
+ stroke: &Stroke,
+ path: &Path,
+ selrect: &Rect,
+ path_transform: Option<&skia::Matrix>,
+) {
+ let mut skia_path = path.to_skia_path();
+ skia_path.transform(path_transform.unwrap());
+
+ let kind = stroke.render_kind(path.is_open());
+ let paint_stroke = stroke.to_stroked_paint(kind.clone(), selrect);
+ // Draw the different kind of strokes for a path requires different strategies:
+ match kind {
+ // For inner stroke we draw a center stroke (with double width) and clip to the original path (that way the extra outer stroke is removed)
+ StrokeKind::InnerStroke => {
+ canvas.clip_path(&skia_path, skia::ClipOp::Intersect, true);
+ canvas.draw_path(&skia_path, &paint_stroke);
+ }
+ // For center stroke we don't need to do anything extra
+ StrokeKind::CenterStroke => {
+ canvas.draw_path(&skia_path, &paint_stroke);
+ handle_stroke_caps(&mut skia_path, stroke, selrect, canvas, path.is_open());
+ }
+ // For outer stroke we draw a center stroke (with double width) and use another path with blend mode clear to remove the inner stroke added
+ StrokeKind::OuterStroke => {
+ let mut paint = skia::Paint::default();
+ paint.set_blend_mode(skia::BlendMode::SrcOver);
+ paint.set_anti_alias(true);
+ let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
+ canvas.save_layer(&layer_rec);
+
+ canvas.draw_path(&skia_path, &paint_stroke);
+
+ let mut clear_paint = skia::Paint::default();
+ clear_paint.set_blend_mode(skia::BlendMode::Clear);
+ clear_paint.set_anti_alias(true);
+ canvas.draw_path(&skia_path, &clear_paint);
+
+ canvas.restore();
+ }
+ }
+}
+
+fn calculate_scaled_rect(size: (i32, i32), container: &Rect, delta: f32) -> Rect {
+ let (width, height) = (size.0 as f32, size.1 as f32);
+ let image_aspect_ratio = width / height;
+
+ // Container size
+ let container_width = container.width();
+ let container_height = container.height();
+ let container_aspect_ratio = container_width / container_height;
+
+ let scale = if image_aspect_ratio > container_aspect_ratio {
+ container_height / height
+ } else {
+ container_width / width
+ };
+
+ let scaled_width = width * scale;
+ let scaled_height = height * scale;
+
+ Rect::from_xywh(
+ container.left - delta - (scaled_width - container_width) / 2.0,
+ container.top - delta - (scaled_height - container_height) / 2.0,
+ scaled_width + (2. * delta) + (scaled_width - container_width),
+ scaled_height + (2. * delta) + (scaled_width - container_width),
+ )
+}
+
+pub fn draw_image_fill_in_container(
+ canvas: &skia::Canvas,
+ image: &Image,
+ size: (i32, i32),
+ kind: &Kind,
+ paint: &skia::Paint,
+ container: &Rect,
+ path_transform: Option<&skia::Matrix>,
+) {
+ // Compute scaled rect
+ let dest_rect = calculate_scaled_rect(size, container, 0.);
+
+ // Save the current canvas state
+ canvas.save();
+
+ // Set the clipping rectangle to the container bounds
+ match kind {
+ Kind::Rect(_) => {
+ canvas.clip_rect(container, skia::ClipOp::Intersect, true);
+ }
+ Kind::Circle(_) => {
+ let mut oval_path = skia::Path::new();
+ oval_path.add_oval(container, None);
+ canvas.clip_path(&oval_path, skia::ClipOp::Intersect, true);
+ }
+ Kind::Path(p) => {
+ canvas.clip_path(
+ &p.to_skia_path().transform(path_transform.unwrap()),
+ skia::ClipOp::Intersect,
+ true,
+ );
+ }
+ }
+
+ // Draw the image with the calculated destination rectangle
+ canvas.draw_image_rect(image, None, dest_rect, &paint);
+
+ // Restore the canvas to remove the clipping
+ canvas.restore();
+}
+
+pub fn draw_image_stroke_in_container(
+ canvas: &skia::Canvas,
+ image: &Image,
+ stroke: &Stroke,
+ size: (i32, i32),
+ kind: &Kind,
+ container: &Rect,
+ path_transform: Option<&skia::Matrix>,
+) {
+ // Helper to handle drawing based on kind
+ fn draw_kind(
+ canvas: &skia::Canvas,
+ kind: &Kind,
+ stroke: &Stroke,
+ container: &Rect,
+ path_transform: Option<&skia::Matrix>,
+ ) {
+ let outer_rect = stroke.outer_rect(container);
+ match kind {
+ Kind::Rect(rect) => draw_stroke_on_rect(canvas, stroke, rect, &outer_rect),
+ Kind::Circle(rect) => draw_stroke_on_circle(canvas, stroke, rect, &outer_rect),
+ Kind::Path(p) => {
+ let mut path = p.to_skia_path();
+ path.transform(path_transform.unwrap());
+ let stroke_kind = stroke.render_kind(p.is_open());
+ if stroke_kind == StrokeKind::InnerStroke {
+ canvas.clip_path(&path, skia::ClipOp::Intersect, true);
+ }
+ let paint = stroke.to_stroked_paint(stroke_kind, &outer_rect);
+ canvas.draw_path(&path, &paint);
+ handle_stroke_caps(&mut path, stroke, &outer_rect, canvas, p.is_open());
+ }
+ }
+ }
+
+ // Save canvas and layer state
+ let mut pb = skia::Paint::default();
+ pb.set_blend_mode(skia::BlendMode::SrcOver);
+ pb.set_anti_alias(true);
+ let layer_rec = skia::canvas::SaveLayerRec::default().paint(&pb);
+ canvas.save_layer(&layer_rec);
+
+ // Draw the stroke based on the kind, we are using this stroke as a "selector" of the area of the image we want to show.
+ draw_kind(canvas, kind, stroke, container, path_transform);
+
+ // Draw the image. We are using now the SrcIn blend mode, so the rendered piece of image will the area of the stroke over the image.
+ let mut image_paint = skia::Paint::default();
+ image_paint.set_blend_mode(skia::BlendMode::SrcIn);
+ image_paint.set_anti_alias(true);
+ // Compute scaled rect and clip to it
+ let dest_rect = calculate_scaled_rect(size, container, stroke.delta());
+ canvas.clip_rect(dest_rect, skia::ClipOp::Intersect, true);
+ canvas.draw_image_rect(image, None, dest_rect, &image_paint);
+
+ // Clear outer stroke for paths if necessary. When adding an outer stroke we need to empty the stroke added too in the inner area.
+ if let Kind::Path(p) = kind {
+ if stroke.render_kind(p.is_open()) == StrokeKind::OuterStroke {
+ let mut path = p.to_skia_path();
+ path.transform(path_transform.unwrap());
+ let mut clear_paint = skia::Paint::default();
+ clear_paint.set_blend_mode(skia::BlendMode::Clear);
+ clear_paint.set_anti_alias(true);
+ canvas.draw_path(&path, &clear_paint);
+ }
+ }
+
+ // Restore canvas state
+ canvas.restore();
+}
diff --git a/render-wasm/src/shapes/strokes.rs b/render-wasm/src/shapes/strokes.rs
new file mode 100644
index 0000000000..d5ec04ab82
--- /dev/null
+++ b/render-wasm/src/shapes/strokes.rs
@@ -0,0 +1,201 @@
+use crate::math;
+use crate::shapes::fills::Fill;
+use skia_safe as skia;
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum StrokeStyle {
+ Solid,
+ Dotted,
+ Dashed,
+ Mixed,
+}
+
+impl From for StrokeStyle {
+ fn from(value: u8) -> Self {
+ match value {
+ 1 => StrokeStyle::Dotted,
+ 2 => StrokeStyle::Dashed,
+ 3 => StrokeStyle::Mixed,
+ _ => StrokeStyle::Solid,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum StrokeCap {
+ None,
+ Line,
+ Triangle,
+ Rectangle,
+ Circle,
+ Diamond,
+ Round,
+ Square,
+}
+
+impl From for StrokeCap {
+ fn from(value: u8) -> Self {
+ match value {
+ 1 => StrokeCap::Line,
+ 2 => StrokeCap::Triangle,
+ 3 => StrokeCap::Rectangle,
+ 4 => StrokeCap::Circle,
+ 5 => StrokeCap::Diamond,
+ 6 => StrokeCap::Round,
+ 7 => StrokeCap::Square,
+ _ => StrokeCap::None,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum StrokeKind {
+ InnerStroke,
+ OuterStroke,
+ CenterStroke,
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct Stroke {
+ pub fill: Fill,
+ pub width: f32,
+ pub style: StrokeStyle,
+ pub cap_end: StrokeCap,
+ pub cap_start: StrokeCap,
+ kind: StrokeKind,
+}
+
+impl Stroke {
+ // Strokes for open shapes should be rendered as if they were centered.
+ pub fn render_kind(&self, is_open: bool) -> StrokeKind {
+ if is_open {
+ StrokeKind::CenterStroke
+ } else {
+ self.kind
+ }
+ }
+
+ pub fn new_center_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) -> Self {
+ let transparent = skia::Color::from_argb(0, 0, 0, 0);
+ Stroke {
+ fill: Fill::Solid(transparent),
+ width: width,
+ style: StrokeStyle::from(style),
+ cap_end: StrokeCap::from(cap_end),
+ cap_start: StrokeCap::from(cap_start),
+ kind: StrokeKind::CenterStroke,
+ }
+ }
+
+ pub fn new_inner_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) -> Self {
+ let transparent = skia::Color::from_argb(0, 0, 0, 0);
+ Stroke {
+ fill: Fill::Solid(transparent),
+ width: width,
+ style: StrokeStyle::from(style),
+ cap_end: StrokeCap::from(cap_end),
+ cap_start: StrokeCap::from(cap_start),
+ kind: StrokeKind::InnerStroke,
+ }
+ }
+
+ pub fn new_outer_stroke(width: f32, style: u8, cap_start: u8, cap_end: u8) -> Self {
+ let transparent = skia::Color::from_argb(0, 0, 0, 0);
+ Stroke {
+ fill: Fill::Solid(transparent),
+ width: width,
+ style: StrokeStyle::from(style),
+ cap_end: StrokeCap::from(cap_end),
+ cap_start: StrokeCap::from(cap_start),
+ kind: StrokeKind::OuterStroke,
+ }
+ }
+
+ pub fn delta(&self) -> f32 {
+ match self.kind {
+ StrokeKind::InnerStroke => 0.,
+ StrokeKind::CenterStroke => self.width / 2.,
+ StrokeKind::OuterStroke => self.width,
+ }
+ }
+
+ pub fn outer_rect(&self, rect: &math::Rect) -> math::Rect {
+ match self.kind {
+ StrokeKind::InnerStroke => math::Rect::from_xywh(
+ rect.left + (self.width / 2.),
+ rect.top + (self.width / 2.),
+ rect.width() - self.width,
+ rect.height() - self.width,
+ ),
+ StrokeKind::CenterStroke => {
+ math::Rect::from_xywh(rect.left, rect.top, rect.width(), rect.height())
+ }
+ StrokeKind::OuterStroke => math::Rect::from_xywh(
+ rect.left - (self.width / 2.),
+ rect.top - (self.width / 2.),
+ rect.width() + self.width,
+ rect.height() + self.width,
+ ),
+ }
+ }
+
+ pub fn to_paint(&self, rect: &math::Rect) -> skia::Paint {
+ let mut paint = self.fill.to_paint(rect);
+ paint.set_style(skia::PaintStyle::Stroke);
+ paint.set_stroke_width(self.width);
+ paint.set_anti_alias(true);
+
+ if self.style != StrokeStyle::Solid {
+ let path_effect = match self.style {
+ StrokeStyle::Dotted => {
+ let mut circle_path = skia::Path::new();
+ let width = match self.kind {
+ StrokeKind::InnerStroke => self.width,
+ StrokeKind::CenterStroke => self.width / 2.0,
+ StrokeKind::OuterStroke => self.width,
+ };
+ circle_path.add_circle((0.0, 0.0), width, None);
+ let advance = self.width + 5.0;
+ skia::PathEffect::path_1d(
+ &circle_path,
+ advance,
+ 0.0,
+ skia::path_1d_path_effect::Style::Translate,
+ )
+ }
+ StrokeStyle::Dashed => {
+ skia::PathEffect::dash(&[self.width + 10., self.width + 10.], 0.)
+ }
+ StrokeStyle::Mixed => skia::PathEffect::dash(
+ &[
+ self.width + 5.,
+ self.width + 5.,
+ self.width + 1.,
+ self.width + 5.,
+ ],
+ 0.,
+ ),
+ _ => None,
+ };
+ paint.set_path_effect(path_effect);
+ }
+
+ paint
+ }
+
+ pub fn to_stroked_paint(&self, kind: StrokeKind, rect: &math::Rect) -> skia::Paint {
+ let mut paint = self.to_paint(rect);
+ match kind {
+ StrokeKind::InnerStroke => {
+ paint.set_stroke_width(2. * self.width);
+ paint
+ }
+
+ StrokeKind::CenterStroke => paint,
+ StrokeKind::OuterStroke => {
+ paint.set_stroke_width(2. * self.width);
+ paint
+ }
+ }
+ }
+}