From 54e8ede474637453f4bddb3ea340ad4db06e7d22 Mon Sep 17 00:00:00 2001
From: Yaron Shahrabani <sh.yaron@gmail.com>
Date: Thu, 14 Nov 2024 11:46:34 +0000
Subject: [PATCH 01/75] :globe_with_meridians: Add translations for: Hebrew.

Currently translated at 92.8% (1450 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/he/
---
 frontend/translations/he.po | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/frontend/translations/he.po b/frontend/translations/he.po
index dff9ea49d..3243492ba 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 <noreply@weblate.org>\n"
+"PO-Revision-Date: 2024-11-15 12:00+0000\n"
+"Last-Translator: Yaron Shahrabani <sh.yaron@gmail.com>\n"
 "Language-Team: Hebrew <https://hosted.weblate.org/projects/penpot/frontend/"
 "he/>\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,19 @@ 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 "כשחבר או חברה במיזם יוצרים קובץ, הוא יופיע כאן."

From f69b2f9edf388b41afadf6d9d3596132ce9145fa Mon Sep 17 00:00:00 2001
From: Nicola Bortoletto <nicola.bortoletto@live.com>
Date: Sat, 16 Nov 2024 07:23:14 +0000
Subject: [PATCH 02/75] :globe_with_meridians: Add translations for: Italian.

Currently translated at 99.4% (1553 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/it/
---
 frontend/translations/it.po | 4672 ++++++++++++++++++++++++++++++++++-
 1 file changed, 4622 insertions(+), 50 deletions(-)

diff --git a/frontend/translations/it.po b/frontend/translations/it.po
index d20c96dfa..59d400ad0 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"
-"Last-Translator: Anonymous <noreply@weblate.org>\n"
-"Language-Team: Italian "
-"<https://hosted.weblate.org/projects/penpot/frontend/it/>\n"
+"PO-Revision-Date: 2024-11-16 13:00+0000\n"
+"Last-Translator: Nicola Bortoletto <nicola.bortoletto@live.com>\n"
+"Language-Team: Italian <https://hosted.weblate.org/projects/penpot/frontend/"
+"it/>\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.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"
@@ -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"
@@ -395,7 +395,7 @@ 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"
@@ -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."
@@ -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"
@@ -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,7 +1109,7 @@ 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"
@@ -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"
@@ -1520,7 +1508,7 @@ 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"
@@ -1791,13 +1779,13 @@ 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."
 
@@ -1810,10 +1798,6 @@ msgstr "Elimina \"%s\" come Libreria Condivisa"
 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 sfondo: %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 verso il 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 tutte le tipografie"
+
+#: src/app/main/ui/workspace/libraries.cljs:84, src/app/main/ui/workspace/libraries.cljs:104
+msgid "workspace.libraries.typography"
+msgstr "%s tipografie"
+
+#: 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 "Basso"
+
+#: 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 tipografia"
+
+#: 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 sfondo"
+
+#: 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 "Alto"
+
+#: 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 "Inizio flussi"
+
+#: 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 interazione 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 "Tipografie multiple"
+
+#: 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 orizzontalmente al centro (%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
+#, fuzzy
+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
+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'ultima 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 "Tipografie"
+
+#: 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 "Alto e Basso"
+
+#: 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"

From 0590c0bf2c6e5f1eb6c47fb25804cbedcffdda92 Mon Sep 17 00:00:00 2001
From: Nicola Bortoletto <nicola.bortoletto@live.com>
Date: Sat, 16 Nov 2024 07:41:07 +0000
Subject: [PATCH 03/75] :globe_with_meridians: Add translations for: Polish.

Currently translated at 73.5% (1148 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/pl/
---
 frontend/translations/pl.po | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/frontend/translations/pl.po b/frontend/translations/pl.po
index 60f1e57cf..72fffa641 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 <noreply@weblate.org>\n"
-"Language-Team: Polish "
-"<https://hosted.weblate.org/projects/penpot/frontend/pl/>\n"
+"PO-Revision-Date: 2024-11-16 13:00+0000\n"
+"Last-Translator: Nicola Bortoletto <nicola.bortoletto@live.com>\n"
+"Language-Team: Polish <https://hosted.weblate.org/projects/penpot/frontend/"
+"pl/>\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 ""

From d253e1195e3e57ef923dd2cb7f6365358461b916 Mon Sep 17 00:00:00 2001
From: Edgars Andersons <Edgars+Weblate@gaitenis.id.lv>
Date: Fri, 15 Nov 2024 12:18:10 +0000
Subject: [PATCH 04/75] :globe_with_meridians: Add translations for: Latvian.

Currently translated at 97.7% (1526 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/lv/
---
 frontend/translations/lv.po | 356 +++++++++++++++++++++++++++++++++++-
 1 file changed, 349 insertions(+), 7 deletions(-)

diff --git a/frontend/translations/lv.po b/frontend/translations/lv.po
index 4b593f0bf..51b0a663b 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 <noreply@weblate.org>\n"
+"PO-Revision-Date: 2024-11-16 13:00+0000\n"
+"Last-Translator: Edgars Andersons <Edgars+Weblate@gaitenis.id.lv>\n"
 "Language-Team: Latvian <https://hosted.weblate.org/projects/penpot/frontend/"
 "lv/>\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,342 @@ 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"

From 1a808e05c3c465e3811af094ad45821a0a5dfa66 Mon Sep 17 00:00:00 2001
From: Stephan Paternotte <stephan@paternottes.net>
Date: Fri, 15 Nov 2024 15:55:21 +0000
Subject: [PATCH 05/75] :globe_with_meridians: Add translations for: Dutch.

Currently translated at 99.5% (1554 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/nl/
---
 frontend/translations/nl.po | 473 +++++++++++++++++++++++++++++++++++-
 1 file changed, 467 insertions(+), 6 deletions(-)

diff --git a/frontend/translations/nl.po b/frontend/translations/nl.po
index e082f4eff..fcfdbec2e 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 <noreply@weblate.org>\n"
+"PO-Revision-Date: 2024-11-16 13:00+0000\n"
+"Last-Translator: Stephan Paternotte <stephan@paternottes.net>\n"
 "Language-Team: Dutch <https://hosted.weblate.org/projects/penpot/frontend/nl/"
 ">\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"

From aecb14775c19763a1737b872bc052ec7b2d66b7a Mon Sep 17 00:00:00 2001
From: Yaron Shahrabani <sh.yaron@gmail.com>
Date: Sun, 17 Nov 2024 08:33:53 +0000
Subject: [PATCH 06/75] :globe_with_meridians: Add translations for: Hebrew.

Currently translated at 99.5% (1554 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/he/
---
 frontend/translations/he.po | 432 +++++++++++++++++++++++++++++++++++-
 1 file changed, 431 insertions(+), 1 deletion(-)

diff --git a/frontend/translations/he.po b/frontend/translations/he.po
index 3243492ba..5eee38dcf 100644
--- a/frontend/translations/he.po
+++ b/frontend/translations/he.po
@@ -1,6 +1,6 @@
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2024-11-15 12:00+0000\n"
+"PO-Revision-Date: 2024-11-17 14:00+0000\n"
 "Last-Translator: Yaron Shahrabani <sh.yaron@gmail.com>\n"
 "Language-Team: Hebrew <https://hosted.weblate.org/projects/penpot/frontend/"
 "he/>\n"
@@ -6077,3 +6077,433 @@ 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) שאפשר להזמין בבקשה אחת"

From 18fd6a47ef8453f152dc36a8ae4012c8de744004 Mon Sep 17 00:00:00 2001
From: Nicola Bortoletto <nicola.bortoletto@live.com>
Date: Sun, 17 Nov 2024 09:13:31 +0000
Subject: [PATCH 07/75] :globe_with_meridians: Add translations for: Italian.

Currently translated at 99.4% (1553 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/it/
---
 frontend/translations/it.po | 78 ++++++++++++++++++-------------------
 1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/frontend/translations/it.po b/frontend/translations/it.po
index 59d400ad0..1d1e52b5d 100644
--- a/frontend/translations/it.po
+++ b/frontend/translations/it.po
@@ -1,6 +1,6 @@
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2024-11-16 13:00+0000\n"
+"PO-Revision-Date: 2024-11-17 14:01+0000\n"
 "Last-Translator: Nicola Bortoletto <nicola.bortoletto@live.com>\n"
 "Language-Team: Italian <https://hosted.weblate.org/projects/penpot/frontend/"
 "it/>\n"
@@ -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"
@@ -399,7 +399,7 @@ 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"
@@ -517,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"
@@ -666,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"
@@ -1113,7 +1113,7 @@ 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"
@@ -1148,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"
@@ -1404,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"
@@ -1412,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"
@@ -1432,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"
@@ -1440,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"
@@ -1496,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"
@@ -1512,7 +1512,7 @@ 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"
@@ -1538,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"
@@ -1572,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"
@@ -1792,7 +1792,7 @@ msgstr ""
 #: 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"
@@ -2135,7 +2135,7 @@ 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 sfondo: %s"
+msgstr "Chiudi sovrapposizione: %s"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:462
 msgid "workspace.options.interaction-delay"
@@ -2270,7 +2270,7 @@ msgstr "Sposta"
 
 #: src/app/main/ui/workspace/sidebar/shortcuts.cljs:136
 msgid "shortcuts.move-fast-down"
-msgstr "Sposta rapidamente verso il basso"
+msgstr "Sposta rapidamente in basso"
 
 #: src/app/main/ui/workspace/sidebar/shortcuts.cljs:139
 msgid "shortcuts.move-fast-up"
@@ -2310,11 +2310,11 @@ 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 tutte le tipografie"
+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 tipografie"
+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"
@@ -2469,7 +2469,7 @@ msgstr "pagine"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:150
 msgid "workspace.options.constraints.bottom"
-msgstr "Basso"
+msgstr "Inferiore"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:182
 msgid "workspace.options.flows.add-flow-start"
@@ -3296,7 +3296,7 @@ msgstr "libreria locale"
 
 #: src/app/main/ui/workspace/sidebar/assets/typographies.cljs:408
 msgid "workspace.assets.typography.add-typography"
-msgstr "Aggiungi tipografia"
+msgstr "Aggiungi elemento tipografico"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs
 #, unused
@@ -3402,7 +3402,7 @@ 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 sfondo"
+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"
@@ -4169,7 +4169,7 @@ msgstr "Destra"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:149
 msgid "workspace.options.constraints.top"
-msgstr "Alto"
+msgstr "Superiore"
 
 #: src/app/main/ui/workspace/sidebar/options.cljs:179
 msgid "workspace.options.design"
@@ -4206,7 +4206,7 @@ msgstr "Flusso"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:164
 msgid "workspace.options.flows.flow-starts"
-msgstr "Inizio flussi"
+msgstr "Inizi flusso"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:154
 msgid "workspace.options.flows.remove-flow"
@@ -4588,7 +4588,7 @@ msgstr "Separa nodi"
 
 #: src/app/main/ui/viewer/interactions.cljs:315
 msgid "viewer.header.show-interactions-on-click"
-msgstr "Mostra interazione al click"
+msgstr "Mostra interazioni al click"
 
 #: src/app/main/ui/workspace/colorpicker.cljs:234
 msgid "workspace.libraries.colors.rgba"
@@ -4733,7 +4733,7 @@ msgstr "File"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:311
 msgid "workspace.libraries.text.multiple-typography"
-msgstr "Tipografie multiple"
+msgstr "Elementi tipografici multipli"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:745
 msgid "workspace.options.add-interaction"
@@ -4971,7 +4971,7 @@ msgstr "Allinea orizzontalmente al centro (%s)"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:74
 msgid "workspace.align.hdistribute"
-msgstr "Distribuisci orizzontalmente al centro (%s)"
+msgstr "Distribuisci spaziatura orizzontale (%s)"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:50
 msgid "workspace.align.hleft"
@@ -6396,11 +6396,11 @@ msgstr "Mostra interazioni"
 
 #: src/app/main/ui/dashboard/team.cljs:985
 msgid "webhooks.last-delivery.success"
-msgstr "L'ultima invio è avvenuto con successo."
+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)"
+msgstr "Allinea verticalmente al centro (%s)"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/align.cljs:104
 msgid "workspace.align.vdistribute"
@@ -6425,7 +6425,7 @@ 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 "Tipografie"
+msgstr "Elementi tipografici"
 
 #: src/app/main/ui/workspace/viewport/grid_layout_editor.cljs:59
 msgid "workspace.layout_grid.editor.title"
@@ -6453,7 +6453,7 @@ msgstr "Sostituisci componente"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs:151
 msgid "workspace.options.constraints.topbottom"
-msgstr "Alto e Basso"
+msgstr "Superiore e Inferiore"
 
 #: src/app/main/ui/viewer/inspect/exports.cljs:147
 msgid "workspace.options.export"

From 67f9b5d1f30acc9c1a2e84dfd1ab3ac3fb9248da Mon Sep 17 00:00:00 2001
From: Edgars Andersons <Edgars+Weblate@gaitenis.id.lv>
Date: Tue, 19 Nov 2024 10:45:55 +0000
Subject: [PATCH 08/75] :globe_with_meridians: Add translations for: Latvian.

Currently translated at 99.2% (1549 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/lv/
---
 frontend/translations/lv.po | 99 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 98 insertions(+), 1 deletion(-)

diff --git a/frontend/translations/lv.po b/frontend/translations/lv.po
index 51b0a663b..95cd3dc32 100644
--- a/frontend/translations/lv.po
+++ b/frontend/translations/lv.po
@@ -1,6 +1,6 @@
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2024-11-16 13:00+0000\n"
+"PO-Revision-Date: 2024-11-20 09:00+0000\n"
 "Last-Translator: Edgars Andersons <Edgars+Weblate@gaitenis.id.lv>\n"
 "Language-Team: Latvian <https://hosted.weblate.org/projects/penpot/frontend/"
 "lv/>\n"
@@ -6459,3 +6459,100 @@ 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"

From 6c1a299b73510ef950d38271643666a6c1b48e29 Mon Sep 17 00:00:00 2001
From: Denys Kisil <ossenjoyer@proton.me>
Date: Wed, 20 Nov 2024 10:39:19 +0000
Subject: [PATCH 09/75] :globe_with_meridians: Add translations for: Ukrainian
 (ukr_UA).

Currently translated at 88.2% (1378 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
---
 frontend/translations/ukr_UA.po | 181 +++++++++++++++++++++++++++++++-
 1 file changed, 179 insertions(+), 2 deletions(-)

diff --git a/frontend/translations/ukr_UA.po b/frontend/translations/ukr_UA.po
index d57edab81..272611f9c 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 <noreply@weblate.org>\n"
+"PO-Revision-Date: 2024-11-21 11:00+0000\n"
+"Last-Translator: Denys Kisil <ossenjoyer@proton.me>\n"
 "Language-Team: Ukrainian <https://hosted.weblate.org/projects/penpot/"
 "frontend/ukr_UA/>\n"
 "Language: ukr_UA\n"
@@ -5685,3 +5685,180 @@ 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 "Видалити потік"

From e9389a7d6ea0e5fcda5c5c109c189d6f5ae6ff0e Mon Sep 17 00:00:00 2001
From: Stas Haas <stas@girafic.de>
Date: Mon, 25 Nov 2024 09:14:33 +0000
Subject: [PATCH 10/75] :globe_with_meridians: Add translations for: German.

Currently translated at 93.0% (1452 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
---
 frontend/translations/de.po | 89 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 2 deletions(-)

diff --git a/frontend/translations/de.po b/frontend/translations/de.po
index c3e611ac4..ba0edaad5 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 <noreply@weblate.org>\n"
+"PO-Revision-Date: 2024-11-25 20:01+0000\n"
+"Last-Translator: Stas Haas <stas@girafic.de>\n"
 "Language-Team: German <https://hosted.weblate.org/projects/penpot/frontend/"
 "de/>\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"

From fc5511eef4c6e027ea80817a25f3b480b6e6ea19 Mon Sep 17 00:00:00 2001
From: Linerly <linerly@proton.me>
Date: Mon, 25 Nov 2024 06:26:50 +0000
Subject: [PATCH 11/75] :globe_with_meridians: Add translations for:
 Indonesian.

Currently translated at 93.0% (1452 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/id/
---
 frontend/translations/id.po | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/frontend/translations/id.po b/frontend/translations/id.po
index e368467f1..108fa187f 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 <noreply@weblate.org>\n"
+"PO-Revision-Date: 2024-11-25 20:01+0000\n"
+"Last-Translator: Linerly <linerly@proton.me>\n"
 "Language-Team: Indonesian <https://hosted.weblate.org/projects/penpot/"
 "frontend/id/>\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 " "
 
@@ -6107,3 +6101,11 @@ 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 "  "

From 08b20bdfd932e7d7b5afda3c0f0c28ed469a2447 Mon Sep 17 00:00:00 2001
From: Late Night Defender <pongpeera054@protonmail.com>
Date: Sun, 24 Nov 2024 19:54:50 +0000
Subject: [PATCH 12/75] :globe_with_meridians: Add translations for: Thai.

Currently translated at 9.8% (154 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/th/
---
 frontend/translations/th.po | 633 +++++++++++++++++++++++++++++++++++-
 1 file changed, 632 insertions(+), 1 deletion(-)

diff --git a/frontend/translations/th.po b/frontend/translations/th.po
index 951196821..fa44c089d 100644
--- a/frontend/translations/th.po
+++ b/frontend/translations/th.po
@@ -1,6 +1,637 @@
 msgid ""
 msgstr ""
-"X-Generator: Weblate\n"
+"PO-Revision-Date: 2024-11-25 20:01+0000\n"
+"Last-Translator: Late Night Defender <pongpeera054@protonmail.com>\n"
+"Language-Team: Thai <https://hosted.weblate.org/projects/penpot/frontend/th/>"
+"\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.9-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 "โปรเจกต์"

From 613f0fa18aacce96416b8e033b7ffaba221a115e Mon Sep 17 00:00:00 2001
From: Linerly <linerly@proton.me>
Date: Tue, 26 Nov 2024 12:13:41 +0000
Subject: [PATCH 13/75] :globe_with_meridians: Add translations for:
 Indonesian.

Currently translated at 100.0% (1561 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/id/
---
 frontend/translations/id.po | 461 +++++++++++++++++++++++++++++++++++-
 1 file changed, 456 insertions(+), 5 deletions(-)

diff --git a/frontend/translations/id.po b/frontend/translations/id.po
index 108fa187f..2b6fe8da4 100644
--- a/frontend/translations/id.po
+++ b/frontend/translations/id.po
@@ -1,6 +1,6 @@
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2024-11-25 20:01+0000\n"
+"PO-Revision-Date: 2024-11-27 13:02+0000\n"
 "Last-Translator: Linerly <linerly@proton.me>\n"
 "Language-Team: Indonesian <https://hosted.weblate.org/projects/penpot/"
 "frontend/id/>\n"
@@ -5568,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"
@@ -5581,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"
@@ -6109,3 +6110,453 @@ 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"

From 92fd918d0eae9cd9a1a6d3a299ac6243d1967bc5 Mon Sep 17 00:00:00 2001
From: Nicola Bortoletto <nicola.bortoletto@live.com>
Date: Sun, 1 Dec 2024 11:42:31 +0000
Subject: [PATCH 14/75] :globe_with_meridians: Add translations for: Italian.

Currently translated at 99.5% (1554 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/it/
---
 frontend/translations/it.po | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/frontend/translations/it.po b/frontend/translations/it.po
index 1d1e52b5d..c6bbe02fd 100644
--- a/frontend/translations/it.po
+++ b/frontend/translations/it.po
@@ -1,6 +1,6 @@
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2024-11-17 14:01+0000\n"
+"PO-Revision-Date: 2024-12-02 12:00+0000\n"
 "Last-Translator: Nicola Bortoletto <nicola.bortoletto@live.com>\n"
 "Language-Team: Italian <https://hosted.weblate.org/projects/penpot/frontend/"
 "it/>\n"
@@ -5199,7 +5199,6 @@ msgstr ""
 "Penpot"
 
 #: src/app/main/ui/static.cljs:61
-#, fuzzy
 msgid "labels.copyright"
 msgstr "Kaleidos @2024"
 

From 8bd898f0ebe4c6640ce103089ce062c173fe570d Mon Sep 17 00:00:00 2001
From: Denys Kisil <ossenjoyer@proton.me>
Date: Sun, 1 Dec 2024 22:03:37 +0000
Subject: [PATCH 15/75] :globe_with_meridians: Add translations for: Ukrainian
 (ukr_UA).

Currently translated at 89.1% (1391 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
---
 frontend/translations/ukr_UA.po | 111 +++++++++++++++++++++++++++++++-
 1 file changed, 110 insertions(+), 1 deletion(-)

diff --git a/frontend/translations/ukr_UA.po b/frontend/translations/ukr_UA.po
index 272611f9c..e63ec97c9 100644
--- a/frontend/translations/ukr_UA.po
+++ b/frontend/translations/ukr_UA.po
@@ -1,6 +1,6 @@
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2024-11-21 11:00+0000\n"
+"PO-Revision-Date: 2024-12-02 12:00+0000\n"
 "Last-Translator: Denys Kisil <ossenjoyer@proton.me>\n"
 "Language-Team: Ukrainian <https://hosted.weblate.org/projects/penpot/"
 "frontend/ukr_UA/>\n"
@@ -5862,3 +5862,112 @@ 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
+#, fuzzy, 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
+#, fuzzy, 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
+#, fuzzy
+msgid "workspace.options.guides.add-guide"
+msgstr "Додати вказівну"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:187
+#, fuzzy
+msgid "workspace.options.guides.remove-guide"
+msgstr "Додати вказівну"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:183
+#, fuzzy
+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
+#, fuzzy, 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
+#, fuzzy, 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
+#, fuzzy, unused
+msgid "workspace.options.layout.padding-simple"
+msgstr "Простий відступ"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, fuzzy, unused
+msgid "workspace.options.layout.space-around"
+msgstr "відступ навколо"
+
+#: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
+#, fuzzy, 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 "Розташування"

From dbeebf181f02296f101db2fcf54bb97aa0374c3c Mon Sep 17 00:00:00 2001
From: Dale de Silva <daledesilva@gmail.com>
Date: Wed, 11 Dec 2024 23:51:11 +1100
Subject: [PATCH 16/75] :books: Add submission form link to deployment page

The plugin submission page is hard to find while looking at the plugin help docs (As it's not linked from there). It should eventually be a page of its own but there isn't enough content yet (or an illustration) to support it.
---
 docs/plugins/deployment.md | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/docs/plugins/deployment.md b/docs/plugins/deployment.md
index 5b8951dd6..a225d0a58 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.
+
+

From 4958da63e585a74ee09fec4ca433a5d03446dcd0 Mon Sep 17 00:00:00 2001
From: Pablo Alba <pablo.alba@kaleidos.net>
Date: Thu, 12 Dec 2024 11:45:58 +0100
Subject: [PATCH 17/75] :bug: Fix a new user shouldn't see the "What's new"
 popup

---
 backend/src/app/rpc/commands/auth.clj | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj
index 062436dbe..cf9db7762 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) "!")

From 7c10f20b95fc34ec7a8defa32c0ff3609a19b390 Mon Sep 17 00:00:00 2001
From: andy <andres.gonzalez@kaleidos.net>
Date: Thu, 12 Dec 2024 11:57:08 +0100
Subject: [PATCH 18/75] :books: Remove deprecated video at History version

---
 docs/user-guide/workspace-basics/index.njk | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/docs/user-guide/workspace-basics/index.njk b/docs/user-guide/workspace-basics/index.njk
index dfb5bee2a..09fb5a07e 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:
 <h4>Navigate actions</h4>
 <p>To navigate through the actions press <kbd>Ctrl/⌘</kbd> + <kbd>Z</kbd> to go backwards and <kbd>Ctrl/⌘</kbd> + <kbd>Shift/⇧</kbd> + <kbd>Z</kbd> to go forward.</p>
 <p>You can also press any item of the actions list to get to this specific state.</p>
-<figure>
-  <video title="Navigate history" muted="" playsinline="" controls="" width="auto" poster="/img/workspace-basics/history-navigate.webp" height="auto">
-    <source src="/img/workspace-basics/history-navigate.mp4" type="video/mp4">
-  </video>
-</figure>
 
 <h2 id="comments">Comments</h2>
 <p>Comments allow the team to have one priceless conversation getting and providing feedback right over the designs and prototypes.<p>

From dc360d8096ddc24a5dd089749b8c7137c7b482a7 Mon Sep 17 00:00:00 2001
From: Pablo Alba <pablo.alba@kaleidos.net>
Date: Thu, 12 Dec 2024 12:06:24 +0100
Subject: [PATCH 19/75] :lipstick: Minor marging adjustment on penpot free
 button

---
 frontend/src/app/main/ui/dashboard/sidebar.scss | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/frontend/src/app/main/ui/dashboard/sidebar.scss b/frontend/src/app/main/ui/dashboard/sidebar.scss
index 65afa269d..26b1283ca 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;
 }
@@ -431,4 +431,4 @@
 .power-up {
   @include t.use-typography("body-small");
   color: var(--color-accent-tertiary);
-}
+}
\ No newline at end of file

From ea43a999e9871bcd2bbd16ed915ee94ccfc8df2c Mon Sep 17 00:00:00 2001
From: Pablo Alba <pablo.alba@kaleidos.net>
Date: Thu, 12 Dec 2024 12:08:10 +0100
Subject: [PATCH 20/75] :lipstick: css linter adjustment

---
 frontend/src/app/main/ui/dashboard/sidebar.scss | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/frontend/src/app/main/ui/dashboard/sidebar.scss b/frontend/src/app/main/ui/dashboard/sidebar.scss
index 26b1283ca..95ad98c32 100644
--- a/frontend/src/app/main/ui/dashboard/sidebar.scss
+++ b/frontend/src/app/main/ui/dashboard/sidebar.scss
@@ -431,4 +431,4 @@
 .power-up {
   @include t.use-typography("body-small");
   color: var(--color-accent-tertiary);
-}
\ No newline at end of file
+}

From 24e51eef5bd3763b1f4611077caf9ebe29742023 Mon Sep 17 00:00:00 2001
From: Pablo Alba <pablo.alba@kaleidos.net>
Date: Thu, 12 Dec 2024 15:15:27 +0100
Subject: [PATCH 21/75] :bug: Fix viewer role is unable to generate thumbnails
 on dashboard

---
 backend/src/app/rpc/commands/files_thumbnails.clj | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/backend/src/app/rpc/commands/files_thumbnails.clj b/backend/src/app/rpc/commands/files_thumbnails.clj
index eb7bf3c16..c3a5cb5d4 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))

From 1b2a38351d45d0439f62990dbac0796b284b74c7 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Fri, 13 Dec 2024 09:13:28 +0100
Subject: [PATCH 22/75] :bug: Fix invitations and webhooks page shows no data

Regression of the routing/state refactor
---
 frontend/src/app/main/ui/dashboard/team.cljs | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/frontend/src/app/main/ui/dashboard/team.cljs b/frontend/src/app/main/ui/dashboard/team.cljs
index ce2b9b791..bf82855e8 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)
 
@@ -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

From b18ee859b11ece679ab9182df5adf036cb7eb100 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marina=20L=C3=B3pez?= <marina.lopez.yap@gmail.com>
Date: Mon, 9 Dec 2024 12:22:35 +0100
Subject: [PATCH 23/75] :sparkles: Shareable link pointing to a specific board

---
 CHANGES.md                                    |   1 +
 frontend/src/app/main/data/workspace.cljs     |  31 +-
 .../app/main/data/workspace/selection.cljs    |  20 +-
 .../app/main/data/workspace/shortcuts.cljs    |   5 +
 .../app/main/ui/workspace/context_menu.cljs   |   5 +
 .../main/ui/workspace/sidebar/shortcuts.cljs  |   1 +
 frontend/translations/en.po                   | 948 +++++++++---------
 frontend/translations/es.po                   |   6 +
 8 files changed, 562 insertions(+), 455 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 2f0dbac7d..9c70c7504 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
 
diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs
index c289ec5ca..05353ffdf 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/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs
index 7125453b5..a4dd554b4 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
   ([]
diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs
index 40879477e..3a41175bd 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/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs
index 6352a3ea7..8261cea2b 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}]
diff --git a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs
index dad7ddcf2..70d1b1b68 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/translations/en.po b/frontend/translations/en.po
index 2e3010559..3e2066af4 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"
 
@@ -779,19 +776,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 +809,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 +837,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 +897,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 +1025,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 +1481,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 +1554,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 +1613,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,11 +1621,11 @@ 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"
 
@@ -1632,7 +1633,7 @@ msgstr "Collapse"
 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 +1665,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 +1681,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 +1717,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 +1737,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 +1777,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 +1793,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 +1831,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…"
 
@@ -1971,7 +1972,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,11 +1990,11 @@ 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"
 
@@ -2001,7 +2002,7 @@ msgstr "Rename team"
 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 +2014,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 +2046,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"
 
@@ -2105,7 +2106,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 +2118,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 +2162,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 +2178,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 +2192,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 +2384,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 +2578,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 +2665,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 +2783,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 +3159,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 +3172,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 +3205,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 +3342,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 +3910,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 +4017,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 +4041,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 +4065,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 +4088,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 +4134,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 +4183,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 +4259,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 +4272,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 +4297,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 +4361,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 +4492,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 +4509,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 +4518,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 +4740,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 +4749,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 +5168,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 +5247,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 +5390,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 +5435,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 +5805,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 +5821,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 +5920,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 +5932,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 +6029,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 +6073,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 +6134,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 +6150,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 +6219,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 +6227,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 +6243,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 +6279,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 +6303,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 +6311,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 +6333,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 +6360,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 +6397,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 +6405,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 +6418,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 +6563,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,16 +6642,18 @@ 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"
 
 #, unused
 msgid "workspace.viewport.click-to-close-path"
 msgstr "Click to close the path"
-
-msgid "workspace.versions.tab.history"
-msgstr "History"
-
-msgid "workspace.versions.tab.actions"
-msgstr "Actions"
diff --git a/frontend/translations/es.po b/frontend/translations/es.po
index d8cb5e6ef..00e1a30f0 100644
--- a/frontend/translations/es.po
+++ b/frontend/translations/es.po
@@ -3341,6 +3341,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 +5943,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"

From eaec46a67b8d15900e0c2fbf19829de75df59795 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Fri, 13 Dec 2024 10:22:40 +0100
Subject: [PATCH 24/75] :bug: Fix incorrect team invitation redirect after
 login

---
 frontend/src/app/main/data/auth.cljs     | 36 +++++++++++++-----------
 frontend/src/app/main/ui/auth/login.cljs | 11 ++------
 2 files changed, 21 insertions(+), 26 deletions(-)

diff --git a/frontend/src/app/main/data/auth.cljs b/frontend/src/app/main/data/auth.cljs
index c1ba640b5..740946b24 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/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs
index e30b25957..10bf80d3b 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

From 08516ac7cae02abfc927ad87a8b9b3eeace12480 Mon Sep 17 00:00:00 2001
From: Pablo Alba <pablo.alba@kaleidos.net>
Date: Fri, 13 Dec 2024 10:51:25 +0100
Subject: [PATCH 25/75] Revert ":sparkles: Add test AB renaming "Libraries" to
 "Add library""

This reverts commit ec7f8a6aa7be03870a69be123d54b309de75e9b9.
---
 .../app/main/ui/workspace/sidebar/assets.cljs | 20 +++++-----------
 .../app/main/ui/workspace/sidebar/assets.scss | 23 -------------------
 frontend/translations/en.po                   |  3 ---
 frontend/translations/es.po                   |  3 ---
 4 files changed, 6 insertions(+), 43 deletions(-)

diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
index 4ec585f2d..6c4d03a07 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
@@ -8,7 +8,6 @@
   (:require-macros [app.main.style :as stl])
   (:require
    [app.common.data.macros :as dm]
-   [app.config :as cf]
    [app.main.data.modal :as modal]
    [app.main.data.workspace :as dw]
    [app.main.data.workspace.assets :as dwa]
@@ -87,7 +86,6 @@
         section        (:section filters)
         ordering       (:ordering filters)
         reverse-sort?  (= :desc ordering)
-        num-libs       (count (mf/deref refs/workspace-libraries))
 
         toggle-ordering
         (mf/use-fn
@@ -157,18 +155,12 @@
     [: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))
-          [:button {:class (stl/css :add-library-button)
-                    :on-click show-libraries-dialog
-                    :data-testid "libraries"}
-           (tr "workspace.assets.add-library")]
-          [:button {:class (stl/css :libraries-button)
-                    :on-click show-libraries-dialog
-                    :data-testid "libraries"}
-           [:span {:class (stl/css :libraries-icon)}
-            i/library]
-           (tr "workspace.assets.libraries")]))
+        [:button {:class (stl/css :libraries-button)
+                  :on-click show-libraries-dialog
+                  :data-testid "libraries"}
+         [:span {:class (stl/css :libraries-icon)}
+          i/library]
+         (tr "workspace.assets.libraries")])
 
       [:div {:class (stl/css :search-wrapper)}
        [:& search-bar {:on-change on-search-term-change
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.scss b/frontend/src/app/main/ui/workspace/sidebar/assets.scss
index 21f7af9d5..acb9f3431 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/assets.scss
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets.scss
@@ -25,50 +25,34 @@
   width: 100%;
   margin-bottom: $s-4;
   border-radius: $s-8;
-
   .libraries-icon {
     @include flexCenter;
     width: $s-24;
     height: 100%;
-
     svg {
       @include flexCenter;
       @extend .button-icon;
       stroke: var(--icon-foreground);
     }
   }
-
   &:hover {
     background-color: var(--button-secondary-background-color-hover);
     color: var(--button-secondary-foreground-color-hover);
     border: $s-1 solid var(--button-secondary-border-color-hover);
-
     svg {
       stroke: var(--button-secondary-foreground-color-hover);
     }
   }
-
   &:focus {
     background-color: var(--button-secondary-background-color-focus);
     color: var(--button-secondary-foreground-color-focus);
     border: $s-1 solid var(--button-secondary-border-color-focus);
-
     svg {
       stroke: var(--button-secondary-foreground-color-focus);
     }
   }
 }
 
-.add-library-button {
-  @extend .button-primary;
-  text-transform: uppercase;
-  gap: $s-2;
-  height: $s-32;
-  width: 100%;
-  margin-bottom: $s-4;
-  border-radius: $s-8;
-}
-
 .section-button {
   @include flexCenter;
   @include buttonStyle;
@@ -78,39 +62,32 @@
   border: $s-1 solid var(--input-border-color-rest);
   border-radius: $br-8 $br-2 $br-2 $br-8;
   background-color: var(--input-background-color-rest);
-
   svg {
     height: $s-16;
     width: $s-16;
     stroke: var(--icon-foreground);
   }
-
   &:focus {
     border: $s-1 solid var(--input-border-color-focus);
     outline: 0;
     background-color: var(--input-background-color-focus);
     color: var(--input-foreground-color-focus);
-
     svg {
       background-color: var(--input-background-color-focus);
     }
   }
-
   &:hover {
     border: $s-1 solid var(--input-border-color-hover);
     background-color: var(--input-background-color-hover);
-
     svg {
       background-color: var(--input-background-color-hover);
       stroke: var(--button-foreground-hover);
     }
-
     &:focus {
       border: $s-1 solid var(--input-border-color-focus);
       outline: 0;
       background-color: var(--input-background-color-focus);
       color: var(--input-foreground-color-focus);
-
       svg {
         background-color: var(--input-background-color-focus);
       }
diff --git a/frontend/translations/en.po b/frontend/translations/en.po
index 2c0b4b84a..a6d13afe9 100644
--- a/frontend/translations/en.po
+++ b/frontend/translations/en.po
@@ -4064,9 +4064,6 @@ msgstr "Group name"
 msgid "workspace.assets.libraries"
 msgstr "Libraries"
 
-msgid "workspace.assets.add-library"
-msgstr "Add library"
-
 #: src/app/main/ui/workspace/sidebar/assets/components.cljs:523
 msgid "workspace.assets.list-view"
 msgstr "List view"
diff --git a/frontend/translations/es.po b/frontend/translations/es.po
index 23691241e..0e17088a7 100644
--- a/frontend/translations/es.po
+++ b/frontend/translations/es.po
@@ -4064,9 +4064,6 @@ msgstr "Nombre del grupo"
 msgid "workspace.assets.libraries"
 msgstr "Bibliotecas"
 
-msgid "workspace.assets.add-library"
-msgstr "Añadir biblioteca"
-
 #: src/app/main/ui/workspace/sidebar/assets/components.cljs:523
 msgid "workspace.assets.list-view"
 msgstr "Ver como lista"

From 664cacbe9d70bbfb8fc11ef4eaa334683de16592 Mon Sep 17 00:00:00 2001
From: Pablo Alba <pablo.alba@kaleidos.net>
Date: Tue, 3 Dec 2024 15:40:27 +0100
Subject: [PATCH 26/75] :sparkles: Add test AB renaming "Libraries" to "Add
 library"

---
 .../app/main/ui/workspace/sidebar/assets.cljs | 73 +++++++++++--------
 .../app/main/ui/workspace/sidebar/assets.scss | 23 ++++++
 frontend/translations/en.po                   |  3 +
 frontend/translations/es.po                   |  3 +
 4 files changed, 71 insertions(+), 31 deletions(-)

diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
index 6c4d03a07..4104fc14a 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
@@ -8,6 +8,7 @@
   (:require-macros [app.main.style :as stl])
   (:require
    [app.common.data.macros :as dm]
+   [app.config :as cf]
    [app.main.data.modal :as modal]
    [app.main.data.workspace :as dw]
    [app.main.data.workspace.assets :as dwa]
@@ -86,6 +87,10 @@
         section        (:section filters)
         ordering       (:ordering filters)
         reverse-sort?  (= :desc ordering)
+        num-libs       (count (mf/deref refs/workspace-libraries))
+
+        show-templates-02-test?
+        (and (cf/external-feature-flag "templates-02" "test") (zero? num-libs))
 
         toggle-ordering
         (mf/use-fn
@@ -155,38 +160,44 @@
     [:article  {:class (stl/css :assets-bar)}
      [:div {:class (stl/css :assets-header)}
       (when-not ^boolean read-only?
-        [:button {:class (stl/css :libraries-button)
-                  :on-click show-libraries-dialog
-                  :data-testid "libraries"}
-         [:span {:class (stl/css :libraries-icon)}
-          i/library]
-         (tr "workspace.assets.libraries")])
+        (if show-templates-02-test?
+          [:button {:class (stl/css :add-library-button)
+                    :on-click show-libraries-dialog
+                    :data-testid "libraries"}
+           (tr "workspace.assets.add-library")]
+          [:button {:class (stl/css :libraries-button)
+                    :on-click show-libraries-dialog
+                    :data-testid "libraries"}
+           [:span {:class (stl/css :libraries-icon)}
+            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.scss b/frontend/src/app/main/ui/workspace/sidebar/assets.scss
index acb9f3431..21f7af9d5 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/assets.scss
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets.scss
@@ -25,34 +25,50 @@
   width: 100%;
   margin-bottom: $s-4;
   border-radius: $s-8;
+
   .libraries-icon {
     @include flexCenter;
     width: $s-24;
     height: 100%;
+
     svg {
       @include flexCenter;
       @extend .button-icon;
       stroke: var(--icon-foreground);
     }
   }
+
   &:hover {
     background-color: var(--button-secondary-background-color-hover);
     color: var(--button-secondary-foreground-color-hover);
     border: $s-1 solid var(--button-secondary-border-color-hover);
+
     svg {
       stroke: var(--button-secondary-foreground-color-hover);
     }
   }
+
   &:focus {
     background-color: var(--button-secondary-background-color-focus);
     color: var(--button-secondary-foreground-color-focus);
     border: $s-1 solid var(--button-secondary-border-color-focus);
+
     svg {
       stroke: var(--button-secondary-foreground-color-focus);
     }
   }
 }
 
+.add-library-button {
+  @extend .button-primary;
+  text-transform: uppercase;
+  gap: $s-2;
+  height: $s-32;
+  width: 100%;
+  margin-bottom: $s-4;
+  border-radius: $s-8;
+}
+
 .section-button {
   @include flexCenter;
   @include buttonStyle;
@@ -62,32 +78,39 @@
   border: $s-1 solid var(--input-border-color-rest);
   border-radius: $br-8 $br-2 $br-2 $br-8;
   background-color: var(--input-background-color-rest);
+
   svg {
     height: $s-16;
     width: $s-16;
     stroke: var(--icon-foreground);
   }
+
   &:focus {
     border: $s-1 solid var(--input-border-color-focus);
     outline: 0;
     background-color: var(--input-background-color-focus);
     color: var(--input-foreground-color-focus);
+
     svg {
       background-color: var(--input-background-color-focus);
     }
   }
+
   &:hover {
     border: $s-1 solid var(--input-border-color-hover);
     background-color: var(--input-background-color-hover);
+
     svg {
       background-color: var(--input-background-color-hover);
       stroke: var(--button-foreground-hover);
     }
+
     &:focus {
       border: $s-1 solid var(--input-border-color-focus);
       outline: 0;
       background-color: var(--input-background-color-focus);
       color: var(--input-foreground-color-focus);
+
       svg {
         background-color: var(--input-background-color-focus);
       }
diff --git a/frontend/translations/en.po b/frontend/translations/en.po
index a6d13afe9..2c0b4b84a 100644
--- a/frontend/translations/en.po
+++ b/frontend/translations/en.po
@@ -4064,6 +4064,9 @@ msgstr "Group name"
 msgid "workspace.assets.libraries"
 msgstr "Libraries"
 
+msgid "workspace.assets.add-library"
+msgstr "Add library"
+
 #: src/app/main/ui/workspace/sidebar/assets/components.cljs:523
 msgid "workspace.assets.list-view"
 msgstr "List view"
diff --git a/frontend/translations/es.po b/frontend/translations/es.po
index 0e17088a7..23691241e 100644
--- a/frontend/translations/es.po
+++ b/frontend/translations/es.po
@@ -4064,6 +4064,9 @@ msgstr "Nombre del grupo"
 msgid "workspace.assets.libraries"
 msgstr "Bibliotecas"
 
+msgid "workspace.assets.add-library"
+msgstr "Añadir biblioteca"
+
 #: src/app/main/ui/workspace/sidebar/assets/components.cljs:523
 msgid "workspace.assets.list-view"
 msgstr "Ver como lista"

From 0945dd2920280cd3449c81b8f022e05ff76db8bf Mon Sep 17 00:00:00 2001
From: Pablo Alba <pablo.alba@kaleidos.net>
Date: Fri, 13 Dec 2024 11:10:18 +0100
Subject: [PATCH 27/75] :tada: Add config flag to hide release info

---
 frontend/src/app/main/ui.cljs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs
index 8898878db..90e3fbff4 100644
--- a/frontend/src/app/main/ui.cljs
+++ b/frontend/src/app/main/ui.cljs
@@ -67,6 +67,7 @@
 
         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)))]

From bbe0b22a8bc77ba8e178a914eaa97b7f2acbb714 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Fri, 13 Dec 2024 11:48:37 +0100
Subject: [PATCH 28/75] :bug: Fix unhandled exception on accepting invitation

In an interaction with the audit log; happens when an old invitation
(with created-by as nil) is accepted.
---
 backend/src/app/rpc/commands/verify_token.clj | 33 ++++++++++---------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/backend/src/app/rpc/commands/verify_token.clj b/backend/src/app/rpc/commands/verify_token.clj
index d725ceda2..27679536e 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))

From c61b794ab627507db9b937d6167589606205596e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marina=20L=C3=B3pez?= <marina.lopez.yap@gmail.com>
Date: Fri, 13 Dec 2024 12:02:20 +0100
Subject: [PATCH 29/75] :bug:Fix link when deselecting shapes

---
 frontend/src/app/main/data/workspace/selection.cljs | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs
index a4dd554b4..2fdd28d01 100644
--- a/frontend/src/app/main/data/workspace/selection.cljs
+++ b/frontend/src/app/main/data/workspace/selection.cljs
@@ -304,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]
 

From e1c5cd6640972e1c4d2db27373ae93b1d211eb54 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com>
Date: Fri, 13 Dec 2024 13:03:23 +0100
Subject: [PATCH 30/75] :bug: Fix path rotation

---
 render-wasm/src/shapes.rs            | 17 +++++-
 render-wasm/src/shapes/images.rs     | 68 ---------------------
 render-wasm/src/shapes/matrix.rs     | 11 +++-
 render-wasm/src/shapes/renderable.rs | 90 ++++++++++++++++++++++++++--
 4 files changed, 110 insertions(+), 76 deletions(-)

diff --git a/render-wasm/src/shapes.rs b/render-wasm/src/shapes.rs
index 78ff1f413..1b0cb4529 100644
--- a/render-wasm/src/shapes.rs
+++ b/render-wasm/src/shapes.rs
@@ -2,7 +2,7 @@ use crate::math;
 use skia_safe as skia;
 use uuid::Uuid;
 
-use crate::render::BlendMode;
+use crate::render::{BlendMode, Renderable};
 
 mod fills;
 mod images;
@@ -138,6 +138,21 @@ impl Shape {
     pub fn set_blend_mode(&mut self, mode: BlendMode) {
         self.blend_mode = mode;
     }
+
+    fn to_path_transform(&self) -> Option<skia::Matrix> {
+        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 50980027a..bbf5d600c 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 bd353b910..294b9da06 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/renderable.rs b/render-wasm/src/shapes/renderable.rs
index ef124c272..907489593 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, Shape};
 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,7 +19,14 @@ 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();
@@ -60,6 +67,7 @@ fn render_fill(
     fill: &Fill,
     selrect: Rect,
     kind: &Kind,
+    path_transform: Option<&skia::Matrix>,
 ) {
     match (fill, kind) {
         (Fill::Image(image_fill), kind) => {
@@ -71,6 +79,8 @@ fn render_fill(
                     image_fill.size(),
                     kind,
                     &fill.to_paint(&selrect),
+                    &selrect,
+                    path_transform,
                 );
             }
         }
@@ -81,9 +91,77 @@ 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),
+            );
         }
     }
 }
+
+pub fn draw_image_in_container(
+    canvas: &skia::Canvas,
+    image: &Image,
+    size: (i32, i32),
+    kind: &Kind,
+    paint: &skia::Paint,
+    container: &Rect,
+    path_transform: Option<&skia::Matrix>,
+) {
+    let width = size.0 as f32;
+    let height = 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;
+
+    // Calculate scale to ensure the image covers the container
+    let scale = if image_aspect_ratio > container_aspect_ratio {
+        // Image is wider, 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;
+
+    let dest_rect = Rect::from_xywh(
+        container.left - (scaled_width - container_width) / 2.0,
+        container.top - (scaled_height - container_height) / 2.0,
+        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().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();
+}

From feaf027abf5ce80a933bc913a0edbe00e8ed10c4 Mon Sep 17 00:00:00 2001
From: Eva Marco <evamarcod@gmail.com>
Date: Fri, 13 Dec 2024 13:26:13 +0100
Subject: [PATCH 31/75] :bug: Fix border radius tooltip

---
 .../ui/workspace/sidebar/options/menus/border_radius.cljs  | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

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 20404b3e6..b967fd917 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
@@ -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

From 8a4fbf385c006b9645e16ee675bf56b49fe1e883 Mon Sep 17 00:00:00 2001
From: Xaviju <xaviju@gmail.com>
Date: Fri, 13 Dec 2024 10:59:59 +0100
Subject: [PATCH 32/75] :bug: fix color-bullet props error

---
 frontend/src/app/main/ui/dashboard/grid.cljs                | 2 +-
 .../src/app/main/ui/viewer/inspect/attributes/common.cljs   | 4 ++--
 .../src/app/main/ui/workspace/color_palette_ctx_menu.cljs   | 6 +++---
 .../src/app/main/ui/workspace/sidebar/assets/colors.cljs    | 2 +-
 .../main/ui/workspace/sidebar/options/rows/color_row.cljs   | 2 +-
 frontend/src/app/main/ui/workspace/tokens/sidebar.cljs      | 2 +-
 6 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs
index 830d7caad..8bc7fb657 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)
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 fcc2eb250..e7d48424a 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/color_palette_ctx_menu.cljs b/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.cljs
index 9d9097d04..33f98effb 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/sidebar/assets/colors.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs
index f3dfccfd8..0738bd690 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/options/rows/color_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs
index f53360fc3..04dfdb89b 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/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs
index 157900264..8fcbab432 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

From 62307c56a0f653ee25a38ff283b88f6f3a8a3175 Mon Sep 17 00:00:00 2001
From: Denys Kisil <ossenjoyer@proton.me>
Date: Sat, 14 Dec 2024 14:57:48 +0000
Subject: [PATCH 33/75] :globe_with_meridians: Add translations for: Ukrainian
 (ukr_UA).

Currently translated at 99.5% (1554 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
---
 frontend/translations/ukr_UA.po | 826 ++++++++++++++++++++++++++++----
 1 file changed, 724 insertions(+), 102 deletions(-)

diff --git a/frontend/translations/ukr_UA.po b/frontend/translations/ukr_UA.po
index e63ec97c9..0828f0822 100644
--- a/frontend/translations/ukr_UA.po
+++ b/frontend/translations/ukr_UA.po
@@ -1,6 +1,6 @@
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2024-12-02 12:00+0000\n"
+"PO-Revision-Date: 2024-12-15 15:00+0000\n"
 "Last-Translator: Denys Kisil <ossenjoyer@proton.me>\n"
 "Language-Team: Ukrainian <https://hosted.weblate.org/projects/penpot/"
 "frontend/ukr_UA/>\n"
@@ -10,19 +10,21 @@ 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-rc\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"
@@ -30,17 +32,17 @@ 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
@@ -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"
@@ -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"
@@ -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"
@@ -510,7 +510,7 @@ 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,7 +881,7 @@ 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"
@@ -1207,7 +1207,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 +1277,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 +1298,7 @@ msgstr "Обведення"
 
 #, permanent, unused
 msgid "inspect.attributes.stroke.alignment.center"
-msgstr "Центр"
+msgstr "По центру"
 
 #, permanent, unused
 msgid "inspect.attributes.stroke.alignment.inner"
@@ -1762,7 +1762,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 +2111,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"
@@ -2189,15 +2189,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 +2470,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 +2523,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 +3633,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 +3665,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 +3855,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 +4138,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 +4146,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 +4163,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 +4171,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 +4179,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 +4231,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 +4525,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 +4533,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 +4553,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 +4683,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 +4699,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 +4727,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 +4989,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 +5085,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 +5095,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 +5180,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 +5240,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"
@@ -5688,7 +5689,7 @@ msgstr "Натисність щоб закінчити шлях"
 
 #: src/app/main/ui/dashboard/files.cljs:190, src/app/main/ui/dashboard/projects.cljs:284
 msgid "dashboard.empty-placeholder-drafts-subtitle"
-msgstr "Як тільки учасник проекту створить чернетку, вона з'явиться тут."
+msgstr "Як тільки учасник проєкту створить чернетку, вона з'явиться тут."
 
 #: src/app/main/ui/dashboard/files.cljs:186, src/app/main/ui/dashboard/projects.cljs:280
 msgid "dashboard.empty-placeholder-files-title"
@@ -5708,7 +5709,7 @@ msgstr "Чернеток ще немає."
 
 #: src/app/main/ui/dashboard/files.cljs:191, src/app/main/ui/dashboard/projects.cljs:285
 msgid "dashboard.empty-placeholder-files-subtitle"
-msgstr "Як тільки учасник проекту створить файл, він буде відображений тут."
+msgstr "Як тільки учасник проєкту створить файл, він буде відображений тут."
 
 #: src/app/main/ui/dashboard/placeholder.cljs:32
 msgid "dashboard.empty-placeholder-libraries-title"
@@ -5760,8 +5761,8 @@ msgstr ""
 #: 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"
@@ -5869,9 +5870,9 @@ msgid "workspace.options.layer-options.title.group"
 msgstr "Згрупувати шари"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
-#, fuzzy, unused
+#, unused
 msgid "workspace.options.layout.gap"
-msgstr "Проміжок"
+msgstr "Відступ"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
 #, unused
@@ -5879,9 +5880,9 @@ msgid "workspace.options.layout.padding-all"
 msgstr "Усі сторони"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
-#, fuzzy, unused
+#, unused
 msgid "workspace.options.layout.top"
-msgstr "Вгору"
+msgstr "Згори"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs:159
 msgid "workspace.options.more-colors"
@@ -5902,19 +5903,16 @@ msgid "labels.collapse"
 msgstr "Згорнути"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:323
-#, fuzzy
 msgid "workspace.options.guides.add-guide"
-msgstr "Додати вказівну"
+msgstr "Додати орієнтир"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:187
-#, fuzzy
 msgid "workspace.options.guides.remove-guide"
-msgstr "Додати вказівну"
+msgstr "Видалити орієнтир"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs:183
-#, fuzzy
 msgid "workspace.options.guides.toggle-guide"
-msgstr "Перемкнути вказівну"
+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"
@@ -5926,9 +5924,9 @@ msgid "workspace.options.layout-item.advanced-ops"
 msgstr "Додаткові параметри"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
-#, fuzzy, unused
+#, unused
 msgid "workspace.options.layout.right"
-msgstr "Право"
+msgstr "Праворуч"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs:136
 msgid "workspace.options.more-lib-colors"
@@ -5939,9 +5937,9 @@ msgid "workspace.options.layout-item.layout-item-max-w"
 msgstr "Макс. Ширина"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
-#, fuzzy, unused
+#, unused
 msgid "workspace.options.layout.padding"
-msgstr "Відступ"
+msgstr "Внутрішній відступ"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/layer.cljs
 #, unused
@@ -5953,21 +5951,645 @@ msgid "workspace.options.layout-item.layout-item-max-h"
 msgstr "Макс. Висота"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
-#, fuzzy, unused
+#, unused
 msgid "workspace.options.layout.padding-simple"
-msgstr "Простий відступ"
+msgstr "Простий внутрішній відступ"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
-#, fuzzy, unused
+#, unused
 msgid "workspace.options.layout.space-around"
-msgstr "відступ навколо"
+msgstr "простір навколо"
 
 #: src/app/main/ui/workspace/sidebar/options/menus/layout.cljs
-#, fuzzy, unused
+#, unused
 msgid "workspace.options.layout.space-between"
-msgstr "відступ між"
+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 "Редагувати теми"

From 2d512ef273d588b42d49eda50318fc31efac9e51 Mon Sep 17 00:00:00 2001
From: Alejandro Alonso <alejandroalonsofernandez@gmail.com>
Date: Tue, 17 Dec 2024 16:52:08 +0100
Subject: [PATCH 34/75] :bug: Fix path edition for plugins

---
 frontend/src/app/plugins/parser.cljs | 70 ----------------------------
 frontend/src/app/plugins/shape.cljs  |  8 ++--
 2 files changed, 3 insertions(+), 75 deletions(-)

diff --git a/frontend/src/app/plugins/parser.cljs b/frontend/src/app/plugins/parser.cljs
index c58e6f1ea..4731528ab 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 b93438b2d..bfcf2412d 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]
@@ -1326,12 +1326,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)

From 377f636b8e8cbe37b4b0bbeec10a038b7cbf8843 Mon Sep 17 00:00:00 2001
From: "alonso.torres" <alonso.torres@kaleidos.net>
Date: Wed, 11 Dec 2024 14:20:06 +0100
Subject: [PATCH 35/75] :bug: Fix problem with reorder on grid layout layers

---
 CHANGES.md                                    | 1 +
 common/src/app/common/logic/shapes.cljc       | 4 +++-
 common/src/app/common/types/shape/layout.cljc | 2 +-
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 76dac53f8..55cff84bb 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -31,6 +31,7 @@
 ### :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)
 
 ## 2.3.3
 
diff --git a/common/src/app/common/logic/shapes.cljc b/common/src/app/common/logic/shapes.cljc
index a3dee6960..2d9dd4464 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 1101fd55a..84a8f0000 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

From fee4a8ff1492fa60262eccedaf83f755d8646f3a Mon Sep 17 00:00:00 2001
From: Denys Kisil <ossenjoyer@proton.me>
Date: Wed, 18 Dec 2024 18:18:11 +0000
Subject: [PATCH 36/75] :globe_with_meridians: Add translations for: Ukrainian
 (ukr_UA).

Currently translated at 99.5% (1554 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
---
 frontend/translations/ukr_UA.po | 49 ++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 25 deletions(-)

diff --git a/frontend/translations/ukr_UA.po b/frontend/translations/ukr_UA.po
index 0828f0822..f884b1174 100644
--- a/frontend/translations/ukr_UA.po
+++ b/frontend/translations/ukr_UA.po
@@ -1,6 +1,6 @@
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2024-12-15 15:00+0000\n"
+"PO-Revision-Date: 2024-12-19 18:02+0000\n"
 "Last-Translator: Denys Kisil <ossenjoyer@proton.me>\n"
 "Language-Team: Ukrainian <https://hosted.weblate.org/projects/penpot/"
 "frontend/ukr_UA/>\n"
@@ -10,7 +10,7 @@ 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-rc\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"
@@ -18,17 +18,17 @@ 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."
 
 #: 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"
@@ -43,7 +43,7 @@ msgstr "Хочете лише спробувати?"
 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"
@@ -102,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
@@ -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"
@@ -495,7 +495,7 @@ msgstr ""
 #: src/app/main/ui/exports/files.cljs:165
 msgid "dashboard.export.options.all.message"
 msgstr ""
-"файли з спільними бібліотеками буде включено до експорту зі збереженням "
+"файли з спільними бібліотеками буде додано до експорту зі збереженням "
 "зв'язків між ними."
 
 #: src/app/main/ui/exports/files.cljs:166
@@ -505,7 +505,7 @@ msgstr "Експортувати спільні бібліотеки"
 #: src/app/main/ui/exports/files.cljs:167
 msgid "dashboard.export.options.detach.message"
 msgstr ""
-"Спільні бібліотеки не буде включено до експорту, і до бібліотеки не буде "
+"Спільні бібліотеки не буде додано до експорту, і до бібліотеки не буде "
 "додано ресурсів. "
 
 #: src/app/main/ui/exports/files.cljs:168
@@ -885,7 +885,7 @@ 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"
@@ -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"

From a5c6faf6395a03b87c06b530db87c5fda8224e55 Mon Sep 17 00:00:00 2001
From: Late Night Defender <pongpeera054@protonmail.com>
Date: Thu, 19 Dec 2024 07:24:45 +0000
Subject: [PATCH 37/75] :globe_with_meridians: Add translations for: Thai.

Currently translated at 10.4% (163 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/th/
---
 frontend/translations/th.po | 46 +++++++++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/frontend/translations/th.po b/frontend/translations/th.po
index fa44c089d..61c3ddac0 100644
--- a/frontend/translations/th.po
+++ b/frontend/translations/th.po
@@ -1,6 +1,6 @@
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2024-11-25 20:01+0000\n"
+"PO-Revision-Date: 2024-12-19 18:02+0000\n"
 "Last-Translator: Late Night Defender <pongpeera054@protonmail.com>\n"
 "Language-Team: Thai <https://hosted.weblate.org/projects/penpot/frontend/th/>"
 "\n"
@@ -9,7 +9,7 @@ msgstr ""
 "Content-Type: text/plain; charset=utf-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 5.9-dev\n"
+"X-Generator: Weblate 5.9.2-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"
@@ -635,3 +635,45 @@ 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 "ทุกคนที่มีลิงก์สามารถเข้าถึงได้"

From 7b6c2da6da365685427dc77fc6a2ca43dca8e8ec Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Mon, 23 Dec 2024 09:09:38 +0100
Subject: [PATCH 38/75] :paperclip: Add externs for main build

With all combinations of small symbols for indicate
to compiler to not use them for internal renaming
---
 frontend/externs/main.txt | 3392 +++++++++++++++++++++++++++++++++++++
 1 file changed, 3392 insertions(+)
 create mode 100644 frontend/externs/main.txt

diff --git a/frontend/externs/main.txt b/frontend/externs/main.txt
new file mode 100644
index 000000000..cb9613622
--- /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

From d6f98a6c7978417bedbf3eede312c1cda36839b7 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Mon, 23 Dec 2024 09:13:34 +0100
Subject: [PATCH 39/75] :paperclip: Add externs for worker build

---
 frontend/externs/worker.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 120000 frontend/externs/worker.txt

diff --git a/frontend/externs/worker.txt b/frontend/externs/worker.txt
new file mode 120000
index 000000000..f446a60e6
--- /dev/null
+++ b/frontend/externs/worker.txt
@@ -0,0 +1 @@
+main.txt
\ No newline at end of file

From 068acb430397f8ef8a302459a35a4fb211117cdb Mon Sep 17 00:00:00 2001
From: BackRunner <dev@backrunner.top>
Date: Sun, 15 Dec 2024 22:00:09 +0800
Subject: [PATCH 40/75] :bug: Fix assets proxy ssl handshake error

---
 docker/devenv/files/nginx.conf | 1 +
 docker/images/files/nginx.conf | 1 +
 2 files changed, 2 insertions(+)

diff --git a/docker/devenv/files/nginx.conf b/docker/devenv/files/nginx.conf
index 961b3a4fb..1777f8a88 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 ee2f64175..e03f7ef0b 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";

From 585c273cd661cc30be95095cf288f02828c752ce Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Mon, 23 Dec 2024 12:20:03 +0100
Subject: [PATCH 41/75] :bug: Fix dashboard fonts section nav link

---
 frontend/src/app/main/data/common.cljs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/frontend/src/app/main/data/common.cljs b/frontend/src/app/main/data/common.cljs
index 925c31467..f1ff93055 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}]

From 2813fda136f32963b0310731b960b094139e094a Mon Sep 17 00:00:00 2001
From: "alonso.torres" <alonso.torres@kaleidos.net>
Date: Mon, 23 Dec 2024 12:36:22 +0100
Subject: [PATCH 42/75] :bug: Fix problem with component swap style

---
 CHANGES.md                                                       | 1 +
 .../app/main/ui/workspace/sidebar/options/menus/component.scss   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/CHANGES.md b/CHANGES.md
index 55cff84bb..8b2a77093 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -32,6 +32,7 @@
 
 - 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/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss
index aa443fa33..030d64cac 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 {

From 8d74d82fd0c2f865e98927807cfedecd08639cf0 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Mon, 23 Dec 2024 12:39:49 +0100
Subject: [PATCH 43/75] :arrow_up: Update potok dependency

Improves internal symbol naming for objects created with
ptk/reify. Helps on debugging
---
 frontend/deps.edn | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/frontend/deps.edn b/frontend/deps.edn
index 8febd1edd..67e2de069 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]}
 

From 2b31613853e45d55d46e29a72e8af10b6fb3db51 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Mon, 23 Dec 2024 12:40:40 +0100
Subject: [PATCH 44/75] :bug: Fix file deletion exception

---
 frontend/src/app/main/data/dashboard.cljs | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/frontend/src/app/main/data/dashboard.cljs b/frontend/src/app/main/data/dashboard.cljs
index 49756a559..54f64e965 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
 

From b5e5c4b0dd603745749bce82730de1670c832970 Mon Sep 17 00:00:00 2001
From: luisddm <luis.dedios@kaleidos.net>
Date: Mon, 9 Dec 2024 17:16:27 +0100
Subject: [PATCH 45/75] :recycle: Visual changes in comments

---
 frontend/playwright/ui/pages/ViewerPage.js    |   3 +-
 .../styles/common/refactor/basic-rules.scss   |  22 -
 frontend/src/app/main/data/comments.cljs      |   4 +-
 .../src/app/main/data/workspace/comments.cljs |  12 +-
 frontend/src/app/main/refs.cljs               |   6 +-
 frontend/src/app/main/ui/comments.cljs        | 728 ++++++++++--------
 frontend/src/app/main/ui/comments.scss        | 351 +++++----
 .../src/app/main/ui/dashboard/comments.cljs   |  64 +-
 .../src/app/main/ui/dashboard/comments.scss   |  35 +-
 .../src/app/main/ui/dashboard/sidebar.cljs    |   5 +-
 frontend/src/app/main/ui/viewer/comments.cljs |  11 +-
 .../src/app/main/ui/workspace/comments.cljs   |   4 +-
 .../src/app/main/ui/workspace/comments.scss   |   1 -
 .../src/app/main/ui/workspace/viewport.cljs   |   2 +-
 .../main/ui/workspace/viewport/comments.cljs  |  25 +-
 frontend/translations/en.po                   |  39 +
 frontend/translations/es.po                   |  39 +
 17 files changed, 745 insertions(+), 606 deletions(-)

diff --git a/frontend/playwright/ui/pages/ViewerPage.js b/frontend/playwright/ui/pages/ViewerPage.js
index 311c0c45f..7a2a96bce 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/resources/styles/common/refactor/basic-rules.scss b/frontend/resources/styles/common/refactor/basic-rules.scss
index 5096ecd6a..8b43750ab 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/main/data/comments.cljs b/frontend/src/app/main/data/comments.cljs
index 3dc86b5a3..1f631203d 100644
--- a/frontend/src/app/main/data/comments.cljs
+++ b/frontend/src/app/main/data/comments.cljs
@@ -502,11 +502,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
   []
diff --git a/frontend/src/app/main/data/workspace/comments.cljs b/frontend/src/app/main/data/workspace/comments.cljs
index d1b250cc1..1688ec332 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/refs.cljs b/frontend/src/app/main/refs.cljs
index 88f8383f8..04a099208 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/comments.cljs b/frontend/src/app/main/ui/comments.cljs
index 643c35d23..4f64a246d 100644
--- a/frontend/src/app/main/ui/comments.cljs
+++ b/frontend/src/app/main/ui/comments.cljs
@@ -9,7 +9,9 @@
   (: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.uuid :as uuid]
    [app.config :as cfg]
    [app.main.data.comments :as dcm]
    [app.main.data.modal :as modal]
@@ -17,12 +19,15 @@
    [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.icons :as i]
    [app.util.dom :as dom]
    [app.util.i18n :as i18n :refer [tr]]
    [app.util.keyboard :as kbd]
    [app.util.time :as dt]
+   [clojure.math :refer [floor]]
    [cuerdas.core :as str]
    [okulary.core :as l]
    [rumext.v2 :as mf]))
@@ -93,8 +98,66 @@
                 :on-change on-change*
                 :max-length max-length}]))
 
-(mf/defc reply-form
-  [{:keys [thread] :as props}]
+(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)}
+    (: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,9 +187,10 @@
          (fn []
            (st/emit! (dcm/add-comment thread @content))
            (on-cancel)))]
-    [:div {:class (stl/css :reply-form)}
+    [:div {:class (stl/css :form)}
      [:& resizing-textarea {:value @content
-                            :placeholder "Reply"
+                            :placeholder (tr "labels.reply.thread")
+                            :autofocus true
                             :on-blur on-blur
                             :on-focus on-focus
                             :select-on-focus? false
@@ -134,29 +198,62 @@
                             :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)}
+        [:> 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
+(mf/defc comment-edit-form*
+  {::mf/props :obj
+   ::mf/private true}
+  [{:keys [content on-submit on-cancel]}]
+  (let [content (mf/use-state content)
+
+        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)}
+     [:& 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 :form-buttons-wrapper)}
+      [:> 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]}]
-  (let [position (cond-> (:position draft)
-                   (some? position-modifier)
-                   (gpt/transform position-modifier))
-        content  (:content draft)
+  (let [profile   (mf/deref refs/profile)
 
-        pos-x    (* (:x position) zoom)
-        pos-y    (* (:y position) zoom)
+        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))
@@ -183,17 +280,18 @@
 
     [:*
      [: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)}
+      [:div {:class (stl/css :form)}
        [:& resizing-textarea {:placeholder (tr "labels.write-new-comment")
                               :value (or content "")
                               :autofocus true
@@ -202,58 +300,89 @@
                               :on-change on-change
                               :on-ctrl-enter on-submit
                               :max-length 750}]
-       [:div {:class (stl/css :buttons-wrapper)}
+       [:div {:class (stl/css :form-buttons-wrapper)}
+        [:> 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-esc
-                 :class (stl/css :cancel-btn)
-                 :type "button"
-                 :value "Cancel"}]
+(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)
 
-        [:input {:on-click on-submit
-                 :type "button"
-                 :value "Post"
-                 :class (stl/css-case :post-btn true
-                                      :global/disabled disabled?)
-                 :disabled disabled?}]]]]]))
-
-(mf/defc edit-form
-  [{:keys [content on-submit on-cancel] :as props}]
-  (let [content (mf/use-state content)
-
-        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 +393,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 +414,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 +422,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 +438,21 @@
                            :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}]
+         [:> comment-edit-form* {:content (:content comment)
+                                 :on-submit on-submit
+                                 :on-cancel on-cancel}]
          [:span {:class (stl/css :text)} (: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 +464,54 @@
   (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)
+        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)))
+        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)
+        bubble-margin {:x 24 :y 24}
+        pos           (offset-position base-pos viewport zoom bubble-margin)
 
-        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)
+        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-ref (mf/with-memo [thread-id]
-                       (make-comments-ref thread-id))
-        comments-map (mf/deref comments-ref)
+        comments-ref  (mf/with-memo [thread-id]
+                        (make-comments-ref thread-id))
+        comments-map  (mf/deref comments-ref)
 
-        comments     (mf/with-memo [comments-map]
-                       (->> (vals comments-map)
-                            (sort-by :created-at)))
+        comments      (mf/with-memo [comments-map]
+                        (->> (vals comments-map)
+                             (sort-by :created-at)))
 
-        comment      (first comments)]
+        first-comment (first comments)]
 
     (mf/with-effect [thread-id]
       (st/emit! (dcm/retrieve-comments thread-id)))
@@ -423,158 +523,170 @@
       (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))
+    (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}]
+       [:div {:class (stl/css :floating-thread-header)}
+        [:> comment-floating-thread-header* {:profiles profiles
+                                             :thread thread
+                                             :origin origin}]]
+
+       [: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-item {:comment item
-                             :profiles profiles
-                             :origin origin}]])]
-       [:& reply-form {:thread thread}]
-       [:div {:ref ref}]])))
+           [:> comment-floating-thread-item* {:comment item
+                                              :profiles profiles}]])]
 
-(defn use-buble
-  [zoom {:keys [position frame-id]}]
-  (let [dragging-ref (mf/use-ref false)
+       [:> comment-reply-form* {:thread thread}]])))
+
+(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 (true? (: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 +696,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* {: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 d90a158dd..229c13932 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,10 @@
       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: flex;
+  justify-content: flex-end;
+  gap: $s-8;
 }
diff --git a/frontend/src/app/main/ui/dashboard/comments.cljs b/frontend/src/app/main/ui/dashboard/comments.cljs
index c2b77134a..b0700e735 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 af55f6dd1..93070c2f7 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/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs
index dfb3691d7..a4f327015 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/viewer/comments.cljs b/frontend/src/app/main/ui/viewer/comments.cljs
index 2ab261bb3..45c023a1b 100644
--- a/frontend/src/app/main/ui/viewer/comments.cljs
+++ b/frontend/src/app/main/ui/viewer/comments.cljs
@@ -206,25 +206,26 @@
      [: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
            :position-modifier modifier1
            :on-cancel on-draft-cancel
diff --git a/frontend/src/app/main/ui/workspace/comments.cljs b/frontend/src/app/main/ui/workspace/comments.cljs
index 7fa35a9af..22da3f663 100644
--- a/frontend/src/app/main/ui/workspace/comments.cljs
+++ b/frontend/src/app/main/ui/workspace/comments.cljs
@@ -150,12 +150,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 0d9026a78..af3fa9d43 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/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs
index 8aa9942b8..33f0cc925 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 1b226dcae..c7e92dffd 100644
--- a/frontend/src/app/main/ui/workspace/viewport/comments.cljs
+++ b/frontend/src/app/main/ui/workspace/viewport/comments.cljs
@@ -75,22 +75,23 @@
       [: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
+                                                 :on-cancel on-draft-cancel
+                                                 :on-submit on-draft-submit
+                                                 :zoom zoom}])]]]))
 
diff --git a/frontend/translations/en.po b/frontend/translations/en.po
index 3e2066af4..972ec32b6 100644
--- a/frontend/translations/en.po
+++ b/frontend/translations/en.po
@@ -748,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"
@@ -1629,6 +1637,13 @@ msgstr "Close"
 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"
@@ -1952,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"
@@ -1998,6 +2017,26 @@ msgstr "Rename"
 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"
diff --git a/frontend/translations/es.po b/frontend/translations/es.po
index 00e1a30f0..8b481c78b 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"

From 4cde30ee8595ac0e4e352427a023d07a1d72665f Mon Sep 17 00:00:00 2001
From: Late Night Defender <pongpeera054@protonmail.com>
Date: Fri, 27 Dec 2024 23:10:19 +0000
Subject: [PATCH 46/75] :globe_with_meridians: Add translations for: Thai.

Currently translated at 13.0% (203 of 1561 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/th/
---
 frontend/translations/th.po | 185 +++++++++++++++++++++++++++++++++++-
 1 file changed, 183 insertions(+), 2 deletions(-)

diff --git a/frontend/translations/th.po b/frontend/translations/th.po
index 61c3ddac0..b3e89b943 100644
--- a/frontend/translations/th.po
+++ b/frontend/translations/th.po
@@ -1,6 +1,6 @@
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2024-12-19 18:02+0000\n"
+"PO-Revision-Date: 2024-12-28 16:02+0000\n"
 "Last-Translator: Late Night Defender <pongpeera054@protonmail.com>\n"
 "Language-Team: Thai <https://hosted.weblate.org/projects/penpot/frontend/th/>"
 "\n"
@@ -9,7 +9,7 @@ msgstr ""
 "Content-Type: text/plain; charset=utf-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 5.9.2-dev\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"
@@ -677,3 +677,184 @@ 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 "+ สร้างไฟล์ใหม่"

From bcdf5d86ae0c1a5dc61887ecbd6fa6b17e8926d6 Mon Sep 17 00:00:00 2001
From: "alonso.torres" <alonso.torres@kaleidos.net>
Date: Thu, 2 Jan 2025 12:01:30 +0100
Subject: [PATCH 47/75] :bug: Fix problem with thumbnail generation when
 changing between versions

---
 CHANGES.md                                    |  6 +++++
 .../app/main/data/workspace/thumbnails.cljs   |  5 ++++
 .../src/app/main/data/workspace/versions.cljs |  2 ++
 frontend/src/app/util/queue.cljs              | 23 +++++++++++++------
 4 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 8b2a77093..68ed86a7f 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,11 @@
 # CHANGELOG
 
+## 2.4.1
+
+### :bug: Bugs fixed
+
+- Fix problem with thumbnail generation when changing between versions [Taiga #9624](https://tree.taiga.io/project/penpot/issue/9624)
+
 ## 2.4.0
 
 ### :rocket: Epics and highlights
diff --git a/frontend/src/app/main/data/workspace/thumbnails.cljs b/frontend/src/app/main/data/workspace/thumbnails.cljs
index 0d2ef2239..132db9156 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 0808c6f47..7b350d65a 100644
--- a/frontend/src/app/main/data/workspace/versions.cljs
+++ b/frontend/src/app/main/data/workspace/versions.cljs
@@ -11,6 +11,7 @@
    [app.main.data.events :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]
@@ -132,6 +133,7 @@
             (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-file project-id file-id)))
        (case origin
          :version
diff --git a/frontend/src/app/util/queue.cljs b/frontend/src/app/util/queue.cljs
index 564fd3cda..4fbc72b30 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)))

From 54c63fef069c97317f730fd68c099b44f13a652c Mon Sep 17 00:00:00 2001
From: Pablo Alba <pablo.alba@kaleidos.net>
Date: Thu, 26 Dec 2024 13:51:11 +0100
Subject: [PATCH 48/75] :bug: Fix create team modal when user is creating
 account via invitation

---
 frontend/src/app/main/ui.cljs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs
index 418c14ad5..700883883 100644
--- a/frontend/src/app/main/ui.cljs
+++ b/frontend/src/app/main/ui.cljs
@@ -148,6 +148,7 @@
   (let [{:keys [data params]} route
         props   (get profile :props)
         section (get data :name)
+        team    (mf/deref refs/team)
 
 
         show-question-modal?
@@ -165,7 +166,8 @@
         (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)

From 6bd1f19e36d32a869f20edf503e21c3d729a8908 Mon Sep 17 00:00:00 2001
From: Pablo Alba <pablo.alba@kaleidos.net>
Date: Thu, 26 Dec 2024 15:44:03 +0100
Subject: [PATCH 49/75] :bug: Fix on libraries section, items shouldn't have
 context menu

---
 frontend/src/app/main/ui/dashboard/grid.cljs | 58 ++++++++++++--------
 1 file changed, 34 insertions(+), 24 deletions(-)

diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs
index 8bc7fb657..2fee69696 100644
--- a/frontend/src/app/main/ui/dashboard/grid.cljs
+++ b/frontend/src/app/main/ui/dashboard/grid.cljs
@@ -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}

From 8ae326ed06513f4b5db61ad7ae82b44fa674674f Mon Sep 17 00:00:00 2001
From: Pablo Alba <pablo.alba@kaleidos.net>
Date: Thu, 26 Dec 2024 16:17:46 +0100
Subject: [PATCH 50/75] :bug: Fix silent crash uploading a font too big

---
 frontend/src/app/main/ui/dashboard/fonts.cljs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/frontend/src/app/main/ui/dashboard/fonts.cljs b/frontend/src/app/main/ui/dashboard/fonts.cljs
index 7ae210b5f..c9cb383fd 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

From ad552eaf681a8c16305faea6e0034af76ee6ac3a Mon Sep 17 00:00:00 2001
From: Pablo Alba <pablo.alba@kaleidos.net>
Date: Thu, 26 Dec 2024 12:32:35 +0100
Subject: [PATCH 51/75] :bug: Fix version history control exit is not intuitive

---
 frontend/src/app/main/ui/workspace/sidebar.cljs | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs
index 80f8a0379..13d978290 100644
--- a/frontend/src/app/main/ui/workspace/sidebar.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar.cljs
@@ -14,6 +14,7 @@
    [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]]
@@ -205,6 +206,9 @@
          (fn [section]
            (reset! current-section* section)))
 
+        on-close-history
+        (mf/use-fn #(st/emit! (dw/remove-layout-flag :document-history)))
+
         handle-expand
         (mf/use-callback
          (mf/deps size)
@@ -255,7 +259,12 @@
           {: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)}]
+           :class (stl/css :left-sidebar-tabs)
+           :action-button-position "end"
+           :action-button (mf/html [:> icon-button* {:variant "ghost"
+                                                     :aria-label (tr "labels.close")
+                                                     :on-click on-close-history
+                                                     :icon "close"}])}]
 
          :else
          [:> options-toolbox props])]]]))

From beb9120b2b36c57cbd6e0ea6506b454624ef3897 Mon Sep 17 00:00:00 2001
From: Alejandro Alonso <alejandroalonsofernandez@gmail.com>
Date: Fri, 27 Dec 2024 13:59:35 +0100
Subject: [PATCH 52/75] :tada: Basic strokes wasm support

---
 frontend/src/app/render_wasm/api.cljs   |  70 ++++++-
 frontend/src/app/render_wasm/shape.cljs |   1 +
 render-wasm/src/main.rs                 | 127 ++++++++++++-
 render-wasm/src/shapes.rs               |  40 +++-
 render-wasm/src/shapes/paths.rs         |  16 ++
 render-wasm/src/shapes/renderable.rs    | 232 ++++++++++++++++++++----
 render-wasm/src/shapes/strokes.rs       | 129 +++++++++++++
 7 files changed, 577 insertions(+), 38 deletions(-)
 create mode 100644 render-wasm/src/shapes/strokes.rs

diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs
index 96e045d24..3882dc245 100644
--- a/frontend/src/app/render_wasm/api.cljs
+++ b/frontend/src/app/render_wasm/api.cljs
@@ -211,6 +211,70 @@
                   (store-image id))))))
         fills))
 
+(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)]
+            (case align
+              :inner (h/call internal-module "_add_shape_inner_stroke" width)
+              :outer (h/call internal-module "_add_shape_outer_stroke" width)
+              (h/call internal-module "_add_shape_center_stroke" width))
+
+            (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 +344,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 +363,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 582c61103..9be274472 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/render-wasm/src/main.rs b/render-wasm/src/main.rs
index 32f516dd9..fbf52c665 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::<shapes::RawStopData>::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,131 @@ pub extern "C" fn set_shape_path_content() {
     }
 }
 
+#[no_mangle]
+pub extern "C" fn add_shape_center_stroke(width: f32) {
+    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))
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn add_shape_inner_stroke(width: f32) {
+    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))
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn add_shape_outer_stroke(width: f32) {
+    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))
+    }
+}
+
+#[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::<shapes::RawStopData>::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 1b0cb4529..4943d8e64 100644
--- a/render-wasm/src/shapes.rs
+++ b/render-wasm/src/shapes.rs
@@ -9,11 +9,13 @@ 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<Fill>,
+    strokes: Vec<Stroke>,
     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<RawStopData>) -> Result<(), String> {
+    pub fn add_fill_gradient_stops(&mut self, buffer: Vec<RawStopData>) -> 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<Stroke> {
+        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<RawStopData>) -> 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<RawPathData>) -> Result<(), String> {
         let p = Path::try_from(buffer)?;
         self.kind = Kind::Path(p);
diff --git a/render-wasm/src/shapes/paths.rs b/render-wasm/src/shapes/paths.rs
index ae2367fb7..f4528bc4a 100644
--- a/render-wasm/src/shapes/paths.rs
+++ b/render-wasm/src/shapes/paths.rs
@@ -75,6 +75,18 @@ pub struct Path {
     skia_path: skia::Path,
 }
 
+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<Vec<RawPathData>> for Path {
     type Error = String;
 
@@ -102,6 +114,10 @@ impl TryFrom<Vec<RawPathData>> for Path {
             }
         }
 
+        if !skia_path.is_last_contour_closed() && starts_and_ends_at_same_point(&skia_path) {
+            skia_path.close();
+        }
+
         Ok(Path {
             segments,
             skia_path,
diff --git a/render-wasm/src/shapes/renderable.rs b/render-wasm/src/shapes/renderable.rs
index 907489593..5f4ad4fc8 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::{Fill, Image, Kind, Shape};
+use super::{Fill, Image, Kind, Path, Shape, Stroke, StrokeKind};
 use crate::math::Rect;
 use crate::render::{ImageStore, Renderable};
 
@@ -29,9 +29,16 @@ impl Renderable for Shape {
             );
         }
 
-        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(())
     }
@@ -73,7 +80,7 @@ fn render_fill(
         (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(),
@@ -99,7 +106,124 @@ fn render_fill(
     }
 }
 
-pub fn draw_image_in_container(
+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 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 paint_stroke = stroke.to_stroked_paint(selrect);
+    // Draw the different kind of strokes for a path requires different strategies:
+    match stroke.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);
+        }
+        // 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),
@@ -108,34 +232,8 @@ pub fn draw_image_in_container(
     container: &Rect,
     path_transform: Option<&skia::Matrix>,
 ) {
-    let width = size.0 as f32;
-    let height = 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;
-
-    // Calculate scale to ensure the image covers the container
-    let scale = if image_aspect_ratio > container_aspect_ratio {
-        // Image is wider, 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;
-
-    let dest_rect = Rect::from_xywh(
-        container.left - (scaled_width - container_width) / 2.0,
-        container.top - (scaled_height - container_height) / 2.0,
-        scaled_width,
-        scaled_height,
-    );
+    // Compute scaled rect
+    let dest_rect = calculate_scaled_rect(size, container, 0.);
 
     // Save the current canvas state
     canvas.save();
@@ -165,3 +263,69 @@ pub fn draw_image_in_container(
     // 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());
+                if stroke.kind == StrokeKind::InnerStroke {
+                    canvas.clip_path(&path, skia::ClipOp::Intersect, true);
+                }
+                let paint = stroke.to_stroked_paint(&outer_rect);
+                canvas.draw_path(&path, &paint);
+            }
+        }
+    }
+
+    // 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), StrokeKind::OuterStroke) = (kind, &stroke.kind) {
+        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 000000000..a4bef5a72
--- /dev/null
+++ b/render-wasm/src/shapes/strokes.rs
@@ -0,0 +1,129 @@
+use crate::math;
+use crate::shapes::fills::Fill;
+use skia_safe as skia;
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum StrokeStyle {
+    Solid,
+    // Dotted,
+    // Dashed,
+    // Mixed,
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum StrokeCap {
+    None,
+    // Line,
+    // Triangle,
+    // Circle,
+    // Diamond,
+    // Round,
+    // Square,
+}
+
+#[derive(Debug, Clone, 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,
+    pub kind: StrokeKind,
+}
+
+impl Stroke {
+    pub fn new_center_stroke(width: f32) -> Self {
+        let transparent = skia::Color::from_argb(0, 0, 0, 0);
+        Stroke {
+            fill: Fill::Solid(transparent),
+            width: width,
+            style: StrokeStyle::Solid,
+            cap_end: StrokeCap::None,
+            cap_start: StrokeCap::None,
+            kind: StrokeKind::CenterStroke,
+        }
+    }
+
+    pub fn new_inner_stroke(width: f32) -> Self {
+        let transparent = skia::Color::from_argb(0, 0, 0, 0);
+        Stroke {
+            fill: Fill::Solid(transparent),
+            width: width,
+            style: StrokeStyle::Solid,
+            cap_end: StrokeCap::None,
+            cap_start: StrokeCap::None,
+            kind: StrokeKind::InnerStroke,
+        }
+    }
+
+    pub fn new_outer_stroke(width: f32) -> Self {
+        let transparent = skia::Color::from_argb(0, 0, 0, 0);
+        Stroke {
+            fill: Fill::Solid(transparent),
+            width: width,
+            style: StrokeStyle::Solid,
+            cap_end: StrokeCap::None,
+            cap_start: StrokeCap::None,
+            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);
+        paint
+    }
+
+    pub fn to_stroked_paint(&self, rect: &math::Rect) -> skia::Paint {
+        let mut paint = self.to_paint(rect);
+        match self.kind {
+            StrokeKind::InnerStroke => {
+                paint.set_stroke_width(2. * self.width);
+                paint
+            }
+
+            StrokeKind::CenterStroke => paint,
+            StrokeKind::OuterStroke => {
+                paint.set_stroke_width(2. * self.width);
+                paint
+            }
+        }
+    }
+}

From 2467e033b7801c7e155afa75eb7ddcb3911a84f8 Mon Sep 17 00:00:00 2001
From: Alejandro Alonso <alejandroalonsofernandez@gmail.com>
Date: Fri, 3 Jan 2025 14:07:40 +0100
Subject: [PATCH 53/75] :tada: Stroke style support for wasm render

---
 frontend/src/app/render_wasm/api.cljs | 17 ++++++--
 render-wasm/src/main.rs               | 12 +++---
 render-wasm/src/shapes/strokes.rs     | 60 +++++++++++++++++++++++----
 3 files changed, 70 insertions(+), 19 deletions(-)

diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs
index 3882dc245..f6b895b55 100644
--- a/frontend/src/app/render_wasm/api.cljs
+++ b/frontend/src/app/render_wasm/api.cljs
@@ -211,6 +211,14 @@
                   (store-image id))))))
         fills))
 
+(defn- translate-stroke-style
+  [stroke-style]
+  (case stroke-style
+    :dotted 1
+    :dashed 2
+    :mixed  3
+    0))
+
 (defn set-shape-strokes
   [strokes]
   (h/call internal-module "_clear_shape_strokes")
@@ -220,11 +228,12 @@
                 gradient (:stroke-color-gradient stroke)
                 image    (:stroke-image stroke)
                 width    (:stroke-width stroke)
-                align    (:stroke-alignment stroke)]
+                align    (:stroke-alignment stroke)
+                style    (-> stroke :stroke-style translate-stroke-style)]
             (case align
-              :inner (h/call internal-module "_add_shape_inner_stroke" width)
-              :outer (h/call internal-module "_add_shape_outer_stroke" width)
-              (h/call internal-module "_add_shape_center_stroke" width))
+              :inner (h/call internal-module "_add_shape_inner_stroke" width style)
+              :outer (h/call internal-module "_add_shape_outer_stroke" width style)
+              (h/call internal-module "_add_shape_center_stroke" width style))
 
             (cond
               (some? gradient)
diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs
index fbf52c665..4911dff18 100644
--- a/render-wasm/src/main.rs
+++ b/render-wasm/src/main.rs
@@ -347,26 +347,26 @@ pub extern "C" fn set_shape_path_content() {
 }
 
 #[no_mangle]
-pub extern "C" fn add_shape_center_stroke(width: f32) {
+pub extern "C" fn add_shape_center_stroke(width: f32, style: i32) {
     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))
+        shape.add_stroke(shapes::Stroke::new_center_stroke(width, style));
     }
 }
 
 #[no_mangle]
-pub extern "C" fn add_shape_inner_stroke(width: f32) {
+pub extern "C" fn add_shape_inner_stroke(width: f32, style: i32) {
     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))
+        shape.add_stroke(shapes::Stroke::new_inner_stroke(width, style))
     }
 }
 
 #[no_mangle]
-pub extern "C" fn add_shape_outer_stroke(width: f32) {
+pub extern "C" fn add_shape_outer_stroke(width: f32, style: i32) {
     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))
+        shape.add_stroke(shapes::Stroke::new_outer_stroke(width, style))
     }
 }
 
diff --git a/render-wasm/src/shapes/strokes.rs b/render-wasm/src/shapes/strokes.rs
index a4bef5a72..2eec2293b 100644
--- a/render-wasm/src/shapes/strokes.rs
+++ b/render-wasm/src/shapes/strokes.rs
@@ -5,9 +5,20 @@ use skia_safe as skia;
 #[derive(Debug, Clone, PartialEq)]
 pub enum StrokeStyle {
     Solid,
-    // Dotted,
-    // Dashed,
-    // Mixed,
+    Dotted,
+    Dashed,
+    Mixed,
+}
+
+impl From<i32> for StrokeStyle {
+    fn from(value: i32) -> Self {
+        match value {
+            1 => StrokeStyle::Dotted,
+            2 => StrokeStyle::Dashed,
+            3 => StrokeStyle::Mixed,
+            _ => StrokeStyle::Solid,
+        }
+    }
 }
 
 #[derive(Debug, Clone, PartialEq)]
@@ -39,36 +50,36 @@ pub struct Stroke {
 }
 
 impl Stroke {
-    pub fn new_center_stroke(width: f32) -> Self {
+    pub fn new_center_stroke(width: f32, style: i32) -> Self {
         let transparent = skia::Color::from_argb(0, 0, 0, 0);
         Stroke {
             fill: Fill::Solid(transparent),
             width: width,
-            style: StrokeStyle::Solid,
+            style: StrokeStyle::from(style),
             cap_end: StrokeCap::None,
             cap_start: StrokeCap::None,
             kind: StrokeKind::CenterStroke,
         }
     }
 
-    pub fn new_inner_stroke(width: f32) -> Self {
+    pub fn new_inner_stroke(width: f32, style: i32) -> Self {
         let transparent = skia::Color::from_argb(0, 0, 0, 0);
         Stroke {
             fill: Fill::Solid(transparent),
             width: width,
-            style: StrokeStyle::Solid,
+            style: StrokeStyle::from(style),
             cap_end: StrokeCap::None,
             cap_start: StrokeCap::None,
             kind: StrokeKind::InnerStroke,
         }
     }
 
-    pub fn new_outer_stroke(width: f32) -> Self {
+    pub fn new_outer_stroke(width: f32, style: i32) -> Self {
         let transparent = skia::Color::from_argb(0, 0, 0, 0);
         Stroke {
             fill: Fill::Solid(transparent),
             width: width,
-            style: StrokeStyle::Solid,
+            style: StrokeStyle::from(style),
             cap_end: StrokeCap::None,
             cap_start: StrokeCap::None,
             kind: StrokeKind::OuterStroke,
@@ -108,6 +119,37 @@ impl Stroke {
         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();
+                    circle_path.add_circle((0.0, 0.0), self.width / 2.0, 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
     }
 

From e4c427609d34a7011e150d6a4393fe8c17e1e5a0 Mon Sep 17 00:00:00 2001
From: Pablo Alba <pablo.alba@kaleidos.net>
Date: Mon, 30 Dec 2024 16:20:52 +0100
Subject: [PATCH 54/75] :sparkles: Add feature flags info to posthog events

---
 frontend/src/app/config.cljs           | 5 +++++
 frontend/src/app/main/data/events.cljs | 8 ++++++++
 2 files changed, 13 insertions(+)

diff --git a/frontend/src/app/config.cljs b/frontend/src/app/config.cljs
index b58876f97..b809f7e2e 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/events.cljs b/frontend/src/app/main/data/events.cljs
index 27001909a..ef1838884 100644
--- a/frontend/src/app/main/data/events.cljs
+++ b/frontend/src/app/main/data/events.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

From 6553861a6cc338e8dfd63be47d5b6d8442301578 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Wed, 18 Dec 2024 17:34:29 +0100
Subject: [PATCH 55/75] :zap: Update rumext version

Mainly for usability and performance improvements
---
 frontend/deps.edn                             |   4 +-
 .../main/ui/components/context_menu_a11y.cljs |   4 +-
 .../app/main/ui/components/radio_buttons.cljs |  14 ++-
 .../src/app/main/ui/ds/controls/input.cljs    |  10 +-
 frontend/src/app/main/ui/ds/storybook.cljs    |   9 +-
 frontend/src/app/main/ui/workspace.cljs       |   4 +-
 .../app/main/ui/workspace/context_menu.cljs   |   2 +-
 .../app/main/ui/workspace/right_header.cljs   |   3 +-
 .../src/app/main/ui/workspace/sidebar.cljs    | 113 ++++++++++--------
 .../main/ui/workspace/sidebar/history.cljs    |   2 +-
 .../app/main/ui/workspace/sidebar/layers.cljs |   2 +-
 .../main/ui/workspace/sidebar/options.cljs    |  25 ++--
 .../options/menus/layout_container.cljs       |   2 +-
 .../sidebar/options/menus/layout_item.cljs    |  25 ++--
 .../main/ui/workspace/sidebar/versions.cljs   |   3 +-
 15 files changed, 118 insertions(+), 104 deletions(-)

diff --git a/frontend/deps.edn b/frontend/deps.edn
index 67e2de069..a64a3d5ba 100644
--- a/frontend/deps.edn
+++ b/frontend/deps.edn
@@ -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/src/app/main/ui/components/context_menu_a11y.cljs b/frontend/src/app/main/ui/components/context_menu_a11y.cljs
index 04475e7c2..546cec563 100644
--- a/frontend/src/app/main/ui/components/context_menu_a11y.cljs
+++ b/frontend/src/app/main/ui/components/context_menu_a11y.cljs
@@ -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]
diff --git a/frontend/src/app/main/ui/components/radio_buttons.cljs b/frontend/src/app/main/ui/components/radio_buttons.cljs
index 17a3fe594..c51aa6ab4 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/ds/controls/input.cljs b/frontend/src/app/main/ui/ds/controls/input.cljs
index 0df0c0c6d..963fe93e6 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
diff --git a/frontend/src/app/main/ui/ds/storybook.cljs b/frontend/src/app/main/ui/ds/storybook.cljs
index d503f3a8f..bec97b7b0 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/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs
index 67a831f30..325834266 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/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs
index 8261cea2b..8e160a564 100644
--- a/frontend/src/app/main/ui/workspace/context_menu.cljs
+++ b/frontend/src/app/main/ui/workspace/context_menu.cljs
@@ -536,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 32d679fea..6cb9618e9 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 13d978290..d22493f14 100644
--- a/frontend/src/app/main/ui/workspace/sidebar.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar.cljs
@@ -20,16 +20,16 @@
    [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]]
@@ -189,82 +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)))
 
         on-close-history
         (mf/use-fn #(st/emit! (dw/remove-layout-flag :document-history)))
 
-        handle-expand
-        (mf/use-callback
+        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)
-           :action-button-position "end"
-           :action-button (mf/html [:> icon-button* {:variant "ghost"
-                                                     :aria-label (tr "labels.close")
-                                                     :on-click on-close-history
-                                                     :icon "close"}])}]
+         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/history.cljs b/frontend/src/app/main/ui/workspace/sidebar/history.cljs
index 753c99c3c..d5eb76bc3 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 9dd8d234a..491b86707 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 ebf93ffb8..f8fd19e1a 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/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs
index 57cf42d9d..b1b1a1c7e 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 681e879f3..21a5c5faf 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/versions.cljs b/frontend/src/app/main/ui/workspace/sidebar/versions.cljs
index c8d8a55a4..8d893e55e 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)
 

From 7aa46a1f62df96ebceffd1d206c74f3439ffe591 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Tue, 7 Jan 2025 10:51:46 +0100
Subject: [PATCH 56/75] :fire: Remove 2.4.1 from changelog

---
 CHANGES.md | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 68ed86a7f..8b2a77093 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,11 +1,5 @@
 # CHANGELOG
 
-## 2.4.1
-
-### :bug: Bugs fixed
-
-- Fix problem with thumbnail generation when changing between versions [Taiga #9624](https://tree.taiga.io/project/penpot/issue/9624)
-
 ## 2.4.0
 
 ### :rocket: Epics and highlights

From c3688d6ab001c3bfdecff8ce87ee5e9244e189c4 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Tue, 7 Jan 2025 11:28:45 +0100
Subject: [PATCH 57/75] :paperclip: Fix issues from previous merge

---
 frontend/src/app/main/data/workspace/versions.cljs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/frontend/src/app/main/data/workspace/versions.cljs b/frontend/src/app/main/data/workspace/versions.cljs
index 0925df03a..250d13deb 100644
--- a/frontend/src/app/main/data/workspace/versions.cljs
+++ b/frontend/src/app/main/data/workspace/versions.cljs
@@ -96,7 +96,7 @@
   (assert (uuid? id) "expected valid uuid for `id`")
   (ptk/reify ::restore-version
     ptk/WatchEvent
-    (watch [_ _ _]
+    (watch [_ state _]
       (let [file-id (:current-file-id state)]
         (rx/concat
          (rx/of ::dwp/force-persist
@@ -106,7 +106,7 @@
               (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-file project-id file-id)))
+              (rx/map #(dw/initialize-workspace file-id)))
          (case origin
            :version
            (rx/of (ptk/event ::ev/event {::ev/name "restore-pin-version"}))

From 27374b1b3949ac093b82b83634a9f9467f3a5d1d Mon Sep 17 00:00:00 2001
From: Anonymous <noreply@weblate.org>
Date: Tue, 7 Jan 2025 11:12:37 +0000
Subject: [PATCH 58/75] :globe_with_meridians: Add translations for: Italian.

Currently translated at 97.1% (1549 of 1595 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/it/
---
 frontend/translations/it.po | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/frontend/translations/it.po b/frontend/translations/it.po
index c6bbe02fd..4d6664918 100644
--- a/frontend/translations/it.po
+++ b/frontend/translations/it.po
@@ -1,7 +1,7 @@
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2024-12-02 12:00+0000\n"
-"Last-Translator: Nicola Bortoletto <nicola.bortoletto@live.com>\n"
+"PO-Revision-Date: 2025-01-07 11:20+0000\n"
+"Last-Translator: Anonymous <noreply@weblate.org>\n"
 "Language-Team: Italian <https://hosted.weblate.org/projects/penpot/frontend/"
 "it/>\n"
 "Language: it\n"
@@ -9,7 +9,7 @@ msgstr ""
 "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.9-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"
@@ -6143,6 +6143,7 @@ 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)"
 

From 7d4535ebd4e985a6a25ffa0ea69dfdbe6bbd4f44 Mon Sep 17 00:00:00 2001
From: "alonso.torres" <alonso.torres@kaleidos.net>
Date: Tue, 7 Jan 2025 13:03:56 +0100
Subject: [PATCH 59/75] :bug: Fix problem with currentUser in plugins

---
 frontend/src/app/plugins/user.cljs | 53 ++++++++++++++----------------
 1 file changed, 25 insertions(+), 28 deletions(-)

diff --git a/frontend/src/app/plugins/user.cljs b/frontend/src/app/plugins/user.cljs
index bf2022435..b8087f6e9 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]

From 09d73a2f5133c43a8f3959605fcfe6f249cb4cb3 Mon Sep 17 00:00:00 2001
From: AzazelN28 <asakon28@gmail.com>
Date: Tue, 7 Jan 2025 13:42:18 +0100
Subject: [PATCH 60/75] :bug: Fix pasting text changes opacity to 0

---
 frontend/text-editor/src/editor/content/dom/Style.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/frontend/text-editor/src/editor/content/dom/Style.js b/frontend/text-editor/src/editor/content/dom/Style.js
index a4a883770..b7abe2f8b 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 {

From 3d370de49ed0dde27ef14bb0602727c280e744f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= <belen@hey.com>
Date: Wed, 8 Jan 2025 11:36:26 +0100
Subject: [PATCH 61/75] :bug: Fix race condition when rendering the background
 color before shape tree has been initialized

---
 frontend/src/app/main/ui/workspace/viewport_wasm.cljs | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs
index 00ac12944..30964d869 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)))
 

From 0bffca2dc72bd4d7cbd8284ff2ea69181887a6d2 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Wed, 8 Jan 2025 12:44:49 +0100
Subject: [PATCH 62/75] :bug: Fix unexpected exception on closing dropdown
 event

Caused by a incorrect call to the internal dropdown
component
---
 .../main/ui/components/context_menu_a11y.cljs |  4 +--
 .../src/app/main/ui/components/dropdown.cljs  | 27 +++++++++----------
 2 files changed, 15 insertions(+), 16 deletions(-)

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 546cec563..a3f199ebb 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]]
@@ -219,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 f27662421..8da3f0b03 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}]))

From 384f13a9e2f0bf701b1483458bc48fb903fc7f30 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Wed, 8 Jan 2025 17:44:26 +0100
Subject: [PATCH 63/75] :bug: Fix incorrect navigate event on assets tab click

---
 frontend/src/app/main/data/common.cljs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/frontend/src/app/main/data/common.cljs b/frontend/src/app/main/data/common.cljs
index f1ff93055..0036824b1 100644
--- a/frontend/src/app/main/data/common.cljs
+++ b/frontend/src/app/main/data/common.cljs
@@ -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))))))
 

From 98806defbfb736ec7147c70b3c7d5463a4d62e26 Mon Sep 17 00:00:00 2001
From: Alejandro Alonso <alejandroalonsofernandez@gmail.com>
Date: Tue, 7 Jan 2025 12:56:20 +0100
Subject: [PATCH 64/75] :bug: Open paths should always be rendered with center
 alignment

---
 render-wasm/src/shapes/paths.rs      |  9 +++++++++
 render-wasm/src/shapes/renderable.rs | 28 ++++++++++++++++------------
 render-wasm/src/shapes/strokes.rs    | 15 ++++++++++++---
 3 files changed, 37 insertions(+), 15 deletions(-)

diff --git a/render-wasm/src/shapes/paths.rs b/render-wasm/src/shapes/paths.rs
index f4528bc4a..1e77b9ccc 100644
--- a/render-wasm/src/shapes/paths.rs
+++ b/render-wasm/src/shapes/paths.rs
@@ -73,6 +73,7 @@ impl TryFrom<RawPathData> for Segment {
 pub struct Path {
     segments: Vec<Segment>,
     skia_path: skia::Path,
+    open: bool,
 }
 
 fn starts_and_ends_at_same_point(path: &skia::Path) -> bool {
@@ -91,6 +92,7 @@ impl TryFrom<Vec<RawPathData>> for Path {
     type Error = String;
 
     fn try_from(value: Vec<RawPathData>) -> Result<Self, Self::Error> {
+        let mut open = true;
         let segments = value
             .into_iter()
             .map(|raw| Segment::try_from(raw))
@@ -110,17 +112,20 @@ impl TryFrom<Vec<RawPathData>> 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,
         })
     }
 }
@@ -129,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 5f4ad4fc8..de752dba1 100644
--- a/render-wasm/src/shapes/renderable.rs
+++ b/render-wasm/src/shapes/renderable.rs
@@ -131,7 +131,7 @@ fn render_stroke(
             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)
+                draw_stroke_on_path(surface.canvas(), stroke, path, &selrect, path_transform);
             }
         }
     }
@@ -165,9 +165,10 @@ fn draw_stroke_on_path(
     let mut skia_path = path.to_skia_path();
     skia_path.transform(path_transform.unwrap());
 
-    let paint_stroke = stroke.to_stroked_paint(selrect);
+    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 stroke.kind {
+    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);
@@ -288,10 +289,11 @@ pub fn draw_image_stroke_in_container(
             Kind::Path(p) => {
                 let mut path = p.to_skia_path();
                 path.transform(path_transform.unwrap());
-                if stroke.kind == StrokeKind::InnerStroke {
+                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(&outer_rect);
+                let paint = stroke.to_stroked_paint(stroke_kind, &outer_rect);
                 canvas.draw_path(&path, &paint);
             }
         }
@@ -317,13 +319,15 @@ pub fn draw_image_stroke_in_container(
     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), StrokeKind::OuterStroke) = (kind, &stroke.kind) {
-        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);
+    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
diff --git a/render-wasm/src/shapes/strokes.rs b/render-wasm/src/shapes/strokes.rs
index 2eec2293b..95f99a9f0 100644
--- a/render-wasm/src/shapes/strokes.rs
+++ b/render-wasm/src/shapes/strokes.rs
@@ -46,10 +46,19 @@ pub struct Stroke {
     pub style: StrokeStyle,
     pub cap_end: StrokeCap,
     pub cap_start: StrokeCap,
-    pub kind: StrokeKind,
+    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.clone()
+        }
+    }
+
     pub fn new_center_stroke(width: f32, style: i32) -> Self {
         let transparent = skia::Color::from_argb(0, 0, 0, 0);
         Stroke {
@@ -153,9 +162,9 @@ impl Stroke {
         paint
     }
 
-    pub fn to_stroked_paint(&self, rect: &math::Rect) -> skia::Paint {
+    pub fn to_stroked_paint(&self, kind: StrokeKind, rect: &math::Rect) -> skia::Paint {
         let mut paint = self.to_paint(rect);
-        match self.kind {
+        match kind {
             StrokeKind::InnerStroke => {
                 paint.set_stroke_width(2. * self.width);
                 paint

From bb071489f1252a416ccf731c2e90e5bf7c744ab0 Mon Sep 17 00:00:00 2001
From: Alejandro Alonso <alejandroalonsofernandez@gmail.com>
Date: Tue, 7 Jan 2025 12:56:54 +0100
Subject: [PATCH 65/75] :bug: Fix dotted path widh calculation

---
 render-wasm/src/shapes/strokes.rs | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/render-wasm/src/shapes/strokes.rs b/render-wasm/src/shapes/strokes.rs
index 95f99a9f0..cf56a02f9 100644
--- a/render-wasm/src/shapes/strokes.rs
+++ b/render-wasm/src/shapes/strokes.rs
@@ -32,7 +32,7 @@ pub enum StrokeCap {
     // Square,
 }
 
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq)]
 pub enum StrokeKind {
     InnerStroke,
     OuterStroke,
@@ -55,7 +55,7 @@ impl Stroke {
         if is_open {
             StrokeKind::CenterStroke
         } else {
-            self.kind.clone()
+            self.kind
         }
     }
 
@@ -133,7 +133,12 @@ impl Stroke {
             let path_effect = match self.style {
                 StrokeStyle::Dotted => {
                     let mut circle_path = skia::Path::new();
-                    circle_path.add_circle((0.0, 0.0), self.width / 2.0, None);
+                    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,

From b1dda02b472f03356601e68f7c32f5d382ffcea8 Mon Sep 17 00:00:00 2001
From: "alonso.torres" <alonso.torres@kaleidos.net>
Date: Wed, 27 Nov 2024 11:28:51 +0100
Subject: [PATCH 66/75] :sparkles: Add mentions to notifications

---
 .../app/email/comment-mention/en.html         | 244 +++++++
 .../app/email/comment-mention/en.subj         |   1 +
 .../app/email/comment-mention/en.txt          |  13 +
 .../app/email/comment-notification/en.html    | 244 +++++++
 .../app/email/comment-notification/en.subj    |   1 +
 .../app/email/comment-notification/en.txt     |  13 +
 .../app/email/comment-thread/en.html          | 244 +++++++
 .../app/email/comment-thread/en.subj          |   1 +
 .../resources/app/email/comment-thread/en.txt |  13 +
 backend/src/app/email.clj                     |  39 ++
 backend/src/app/migrations.clj                |   5 +-
 .../sql/0136-mod-comments-mentions.sql        |   3 +
 backend/src/app/rpc/commands/comments.clj     | 367 +++++++---
 backend/src/app/rpc/commands/profile.clj      |  47 +-
 backend/src/app/rpc/commands/teams.clj        |  30 +-
 backend/src/app/rpc/commands/viewer.clj       |  10 +-
 .../test/backend_tests/rpc_comment_test.clj   |   2 +-
 common/src/app/common/data.cljc               |  22 +
 .../ui/specs/viewer-comments.spec.js          |   8 +-
 frontend/resources/images/icons/at.svg        |   1 +
 frontend/src/app/main/data/comments.cljs      |  39 +-
 frontend/src/app/main/data/profile.cljs       |  27 +-
 frontend/src/app/main/ui.cljs                 |   3 +-
 frontend/src/app/main/ui/comments.cljs        | 632 +++++++++++++++---
 frontend/src/app/main/ui/comments.scss        | 110 ++-
 .../main/ui/ds/foundations/assets/icon.cljs   |   1 +
 frontend/src/app/main/ui/routes.cljs          |   3 +-
 frontend/src/app/main/ui/settings.cljs        |   6 +-
 .../app/main/ui/settings/notifications.cljs   | 106 +++
 .../app/main/ui/settings/notifications.scss   |  42 ++
 .../src/app/main/ui/settings/sidebar.cljs     |   9 +
 frontend/src/app/main/ui/viewer/comments.cljs |   1 +
 .../main/ui/workspace/viewport/comments.cljs  |   1 +
 frontend/src/app/util/dom.cljs                |  37 +-
 frontend/src/app/util/keyboard.cljs           |   1 +
 frontend/src/app/util/webapi.cljs             |  80 +++
 frontend/translations/en.po                   |  57 ++
 frontend/translations/es.po                   |  57 ++
 frontend/vendor/mousetrap/index.js            |   8 +-
 39 files changed, 2316 insertions(+), 212 deletions(-)
 create mode 100644 backend/resources/app/email/comment-mention/en.html
 create mode 100644 backend/resources/app/email/comment-mention/en.subj
 create mode 100644 backend/resources/app/email/comment-mention/en.txt
 create mode 100644 backend/resources/app/email/comment-notification/en.html
 create mode 100644 backend/resources/app/email/comment-notification/en.subj
 create mode 100644 backend/resources/app/email/comment-notification/en.txt
 create mode 100644 backend/resources/app/email/comment-thread/en.html
 create mode 100644 backend/resources/app/email/comment-thread/en.subj
 create mode 100644 backend/resources/app/email/comment-thread/en.txt
 create mode 100644 backend/src/app/migrations/sql/0136-mod-comments-mentions.sql
 create mode 100644 frontend/resources/images/icons/at.svg
 create mode 100644 frontend/src/app/main/ui/settings/notifications.cljs
 create mode 100644 frontend/src/app/main/ui/settings/notifications.scss

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 000000000..fa45cab25
--- /dev/null
+++ b/backend/resources/app/email/comment-mention/en.html
@@ -0,0 +1,244 @@
+<!doctype html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
+  xmlns:o="urn:schemas-microsoft-com:office:office">
+
+<head>
+  <title>
+  </title>
+  <!--[if !mso]><!-- -->
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <!--<![endif]-->
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <style type="text/css">
+    #outlook a {
+      padding: 0;
+    }
+
+    body {
+      margin: 0;
+      padding: 0;
+      -webkit-text-size-adjust: 100%;
+      -ms-text-size-adjust: 100%;
+    }
+
+    table,
+    td {
+      border-collapse: collapse;
+      mso-table-lspace: 0pt;
+      mso-table-rspace: 0pt;
+    }
+
+    img {
+      border: 0;
+      height: auto;
+      line-height: 100%;
+      outline: none;
+      text-decoration: none;
+      -ms-interpolation-mode: bicubic;
+    }
+
+    p {
+      display: block;
+      margin: 13px 0;
+    }
+  </style>
+  <!--[if mso]>
+        <xml>
+        <o:OfficeDocumentSettings>
+          <o:AllowPNG/>
+          <o:PixelsPerInch>96</o:PixelsPerInch>
+        </o:OfficeDocumentSettings>
+        </xml>
+        <![endif]-->
+  <!--[if lte mso 11]>
+        <style type="text/css">
+          .mj-outlook-group-fix { width:100% !important; }
+        </style>
+        <![endif]-->
+  <!--[if !mso]><!-->
+  <link href="https://fonts.googleapis.com/css?family=Source%20Sans%20Pro" rel="stylesheet" type="text/css">
+  <style type="text/css">
+    @import url(https://fonts.googleapis.com/css?family=Source%20Sans%20Pro);
+  </style>
+  <!--<![endif]-->
+  <style type="text/css">
+    @media only screen and (min-width:480px) {
+      .mj-column-per-100 {
+        width: 100% !important;
+        max-width: 100%;
+      }
+
+      .mj-column-px-425 {
+        width: 425px !important;
+        max-width: 425px;
+      }
+    }
+  </style>
+  <style type="text/css">
+    @media only screen and (max-width:480px) {
+      table.mj-full-width-mobile {
+        width: 100% !important;
+      }
+
+      td.mj-full-width-mobile {
+        width: auto !important;
+      }
+    }
+  </style>
+</head>
+
+<body style="background-color:#E5E5E5;">
+  <div style="background-color:#E5E5E5;">
+    <!--[if mso | IE]>
+      <table
+         align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
+      >
+        <tr>
+          <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
+      <![endif]-->
+    <div style="margin:0px auto;max-width:600px;">
+      <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
+        <tbody>
+          <tr>
+            <td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
+              <!--[if mso | IE]>
+                  <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+
+        <tr>
+
+            <td
+               class="" style="vertical-align:top;width:600px;"
+            >
+          <![endif]-->
+              <div class="mj-column-per-100 mj-outlook-group-fix"
+                style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
+                <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
+                  width="100%">
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:16px;word-break:break-word;">
+                      <table border="0" cellpadding="0" cellspacing="0" role="presentation"
+                        style="border-collapse:collapse;border-spacing:0px;">
+                        <tbody>
+                          <tr>
+                            <td style="width:97px;">
+                              <img height="32" src="{{ public-uri }}/images/email/uxbox-title.png"
+                                style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;"
+                                width="97" />
+                            </td>
+                          </tr>
+                        </tbody>
+                      </table>
+                    </td>
+                  </tr>
+                </table>
+              </div>
+              <!--[if mso | IE]>
+            </td>
+
+        </tr>
+
+                  </table>
+                <![endif]-->
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+    <!--[if mso | IE]>
+          </td>
+        </tr>
+      </table>
+
+      <table
+         align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
+      >
+        <tr>
+          <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
+      <![endif]-->
+    <div style="background:#FFFFFF;background-color:#FFFFFF;margin:0px auto;max-width:600px;">
+      <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
+        style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
+        <tbody>
+          <tr>
+            <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
+              <!--[if mso | IE]>
+                  <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+
+        <tr>
+
+            <td
+               class="" style="vertical-align:top;width:600px;"
+            >
+          <![endif]-->
+              <div class="mj-column-per-100 mj-outlook-group-fix"
+                style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
+                <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
+                  width="100%">
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <div
+                        style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">
+                        Hello {{name|abbreviate:25}}!</div>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <div
+                        style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
+                        <span style="font-weight:bold;">{{ source-user }}</span> has mentioned you on a comment at "{{ comment-reference }}".</div>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <div style="font-family:Source Sans Pro, sans-serif;font-size:16px;font-style:italic;line-height:150%;text-align:left;color:#212426;
+                                  border-top: 1px solid #bfbfbf; border-bottom: 1px solid #bfbfbf; padding: 32px 0px;">
+                        {{ comment-content }}
+                      </div>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td align="center" vertical-align="middle"
+                      style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <table border="0" cellpadding="0" cellspacing="0" role="presentation"
+                        style="border-collapse:separate;line-height:100%;">
+                        <tr>
+                          <td align="center" bgcolor="#6911d4#31EFB8" role="presentation"
+                              style="border:none;border-radius:8px;cursor:auto;mso-padding-alt:10px 25px;background:#6911d4;"
+                              valign="middle">
+                            <a href="{{ comment-url }}"
+                               style="display:inline-block;background:#6911d4;color:#FFFFFF;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:8px;"
+                               target="_blank"> GO TO THE COMMENT </a>
+                          </td>
+                        </tr>
+                      </table>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <div
+                        style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
+                        The Penpot team.</div>
+                    </td>
+                  </tr>
+                </table>
+              </div>
+              <!--[if mso | IE]>
+            </td>
+
+        </tr>
+
+                  </table>
+                <![endif]-->
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+
+    {% include "app/email/includes/footer.html" %}
+
+  </div>
+</body>
+
+</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 000000000..c3f027d5d
--- /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 000000000..32a15a4d5
--- /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 000000000..595c6b53d
--- /dev/null
+++ b/backend/resources/app/email/comment-notification/en.html
@@ -0,0 +1,244 @@
+<!doctype html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
+  xmlns:o="urn:schemas-microsoft-com:office:office">
+
+<head>
+  <title>
+  </title>
+  <!--[if !mso]><!-- -->
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <!--<![endif]-->
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <style type="text/css">
+    #outlook a {
+      padding: 0;
+    }
+
+    body {
+      margin: 0;
+      padding: 0;
+      -webkit-text-size-adjust: 100%;
+      -ms-text-size-adjust: 100%;
+    }
+
+    table,
+    td {
+      border-collapse: collapse;
+      mso-table-lspace: 0pt;
+      mso-table-rspace: 0pt;
+    }
+
+    img {
+      border: 0;
+      height: auto;
+      line-height: 100%;
+      outline: none;
+      text-decoration: none;
+      -ms-interpolation-mode: bicubic;
+    }
+
+    p {
+      display: block;
+      margin: 13px 0;
+    }
+  </style>
+  <!--[if mso]>
+        <xml>
+        <o:OfficeDocumentSettings>
+          <o:AllowPNG/>
+          <o:PixelsPerInch>96</o:PixelsPerInch>
+        </o:OfficeDocumentSettings>
+        </xml>
+        <![endif]-->
+  <!--[if lte mso 11]>
+        <style type="text/css">
+          .mj-outlook-group-fix { width:100% !important; }
+        </style>
+        <![endif]-->
+  <!--[if !mso]><!-->
+  <link href="https://fonts.googleapis.com/css?family=Source%20Sans%20Pro" rel="stylesheet" type="text/css">
+  <style type="text/css">
+    @import url(https://fonts.googleapis.com/css?family=Source%20Sans%20Pro);
+  </style>
+  <!--<![endif]-->
+  <style type="text/css">
+    @media only screen and (min-width:480px) {
+      .mj-column-per-100 {
+        width: 100% !important;
+        max-width: 100%;
+      }
+
+      .mj-column-px-425 {
+        width: 425px !important;
+        max-width: 425px;
+      }
+    }
+  </style>
+  <style type="text/css">
+    @media only screen and (max-width:480px) {
+      table.mj-full-width-mobile {
+        width: 100% !important;
+      }
+
+      td.mj-full-width-mobile {
+        width: auto !important;
+      }
+    }
+  </style>
+</head>
+
+<body style="background-color:#E5E5E5;">
+  <div style="background-color:#E5E5E5;">
+    <!--[if mso | IE]>
+      <table
+         align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
+      >
+        <tr>
+          <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
+      <![endif]-->
+    <div style="margin:0px auto;max-width:600px;">
+      <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
+        <tbody>
+          <tr>
+            <td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
+              <!--[if mso | IE]>
+                  <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+
+        <tr>
+
+            <td
+               class="" style="vertical-align:top;width:600px;"
+            >
+          <![endif]-->
+              <div class="mj-column-per-100 mj-outlook-group-fix"
+                style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
+                <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
+                  width="100%">
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:16px;word-break:break-word;">
+                      <table border="0" cellpadding="0" cellspacing="0" role="presentation"
+                        style="border-collapse:collapse;border-spacing:0px;">
+                        <tbody>
+                          <tr>
+                            <td style="width:97px;">
+                              <img height="32" src="{{ public-uri }}/images/email/uxbox-title.png"
+                                style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;"
+                                width="97" />
+                            </td>
+                          </tr>
+                        </tbody>
+                      </table>
+                    </td>
+                  </tr>
+                </table>
+              </div>
+              <!--[if mso | IE]>
+            </td>
+
+        </tr>
+
+                  </table>
+                <![endif]-->
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+    <!--[if mso | IE]>
+          </td>
+        </tr>
+      </table>
+
+      <table
+         align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
+      >
+        <tr>
+          <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
+      <![endif]-->
+    <div style="background:#FFFFFF;background-color:#FFFFFF;margin:0px auto;max-width:600px;">
+      <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
+        style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
+        <tbody>
+          <tr>
+            <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
+              <!--[if mso | IE]>
+                  <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+
+        <tr>
+
+            <td
+               class="" style="vertical-align:top;width:600px;"
+            >
+          <![endif]-->
+              <div class="mj-column-per-100 mj-outlook-group-fix"
+                style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
+                <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
+                  width="100%">
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <div
+                        style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">
+                        Hello {{name|abbreviate:25}}!</div>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <div
+                        style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
+                        <span style="font-weight:bold;">{{ source-user }}</span> has commented at "{{ comment-reference }}".</div>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <div style="font-family:Source Sans Pro, sans-serif;font-size:16px;font-style:italic;line-height:150%;text-align:left;color:#212426;
+                                  border-top: 1px solid #bfbfbf; border-bottom: 1px solid #bfbfbf; padding: 32px 0px;">
+                        {{ comment-content }}
+                      </div>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td align="center" vertical-align="middle"
+                      style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <table border="0" cellpadding="0" cellspacing="0" role="presentation"
+                        style="border-collapse:separate;line-height:100%;">
+                        <tr>
+                          <td align="center" bgcolor="#6911d4#31EFB8" role="presentation"
+                              style="border:none;border-radius:8px;cursor:auto;mso-padding-alt:10px 25px;background:#6911d4;"
+                              valign="middle">
+                            <a href="{{ comment-url }}"
+                               style="display:inline-block;background:#6911d4;color:#FFFFFF;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:8px;"
+                               target="_blank"> GO TO THE COMMENT </a>
+                          </td>
+                        </tr>
+                      </table>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <div
+                        style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
+                        The Penpot team.</div>
+                    </td>
+                  </tr>
+                </table>
+              </div>
+              <!--[if mso | IE]>
+            </td>
+
+        </tr>
+
+                  </table>
+                <![endif]-->
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+
+    {% include "app/email/includes/footer.html" %}
+
+  </div>
+</body>
+
+</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 000000000..94a261f31
--- /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 000000000..166ffc14b
--- /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 000000000..8676a3529
--- /dev/null
+++ b/backend/resources/app/email/comment-thread/en.html
@@ -0,0 +1,244 @@
+<!doctype html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
+  xmlns:o="urn:schemas-microsoft-com:office:office">
+
+<head>
+  <title>
+  </title>
+  <!--[if !mso]><!-- -->
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <!--<![endif]-->
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <style type="text/css">
+    #outlook a {
+      padding: 0;
+    }
+
+    body {
+      margin: 0;
+      padding: 0;
+      -webkit-text-size-adjust: 100%;
+      -ms-text-size-adjust: 100%;
+    }
+
+    table,
+    td {
+      border-collapse: collapse;
+      mso-table-lspace: 0pt;
+      mso-table-rspace: 0pt;
+    }
+
+    img {
+      border: 0;
+      height: auto;
+      line-height: 100%;
+      outline: none;
+      text-decoration: none;
+      -ms-interpolation-mode: bicubic;
+    }
+
+    p {
+      display: block;
+      margin: 13px 0;
+    }
+  </style>
+  <!--[if mso]>
+        <xml>
+        <o:OfficeDocumentSettings>
+          <o:AllowPNG/>
+          <o:PixelsPerInch>96</o:PixelsPerInch>
+        </o:OfficeDocumentSettings>
+        </xml>
+        <![endif]-->
+  <!--[if lte mso 11]>
+        <style type="text/css">
+          .mj-outlook-group-fix { width:100% !important; }
+        </style>
+        <![endif]-->
+  <!--[if !mso]><!-->
+  <link href="https://fonts.googleapis.com/css?family=Source%20Sans%20Pro" rel="stylesheet" type="text/css">
+  <style type="text/css">
+    @import url(https://fonts.googleapis.com/css?family=Source%20Sans%20Pro);
+  </style>
+  <!--<![endif]-->
+  <style type="text/css">
+    @media only screen and (min-width:480px) {
+      .mj-column-per-100 {
+        width: 100% !important;
+        max-width: 100%;
+      }
+
+      .mj-column-px-425 {
+        width: 425px !important;
+        max-width: 425px;
+      }
+    }
+  </style>
+  <style type="text/css">
+    @media only screen and (max-width:480px) {
+      table.mj-full-width-mobile {
+        width: 100% !important;
+      }
+
+      td.mj-full-width-mobile {
+        width: auto !important;
+      }
+    }
+  </style>
+</head>
+
+<body style="background-color:#E5E5E5;">
+  <div style="background-color:#E5E5E5;">
+    <!--[if mso | IE]>
+      <table
+         align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
+      >
+        <tr>
+          <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
+      <![endif]-->
+    <div style="margin:0px auto;max-width:600px;">
+      <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
+        <tbody>
+          <tr>
+            <td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
+              <!--[if mso | IE]>
+                  <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+
+        <tr>
+
+            <td
+               class="" style="vertical-align:top;width:600px;"
+            >
+          <![endif]-->
+              <div class="mj-column-per-100 mj-outlook-group-fix"
+                style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
+                <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
+                  width="100%">
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:16px;word-break:break-word;">
+                      <table border="0" cellpadding="0" cellspacing="0" role="presentation"
+                        style="border-collapse:collapse;border-spacing:0px;">
+                        <tbody>
+                          <tr>
+                            <td style="width:97px;">
+                              <img height="32" src="{{ public-uri }}/images/email/uxbox-title.png"
+                                style="border:0;display:block;outline:none;text-decoration:none;height:32px;width:100%;font-size:13px;"
+                                width="97" />
+                            </td>
+                          </tr>
+                        </tbody>
+                      </table>
+                    </td>
+                  </tr>
+                </table>
+              </div>
+              <!--[if mso | IE]>
+            </td>
+
+        </tr>
+
+                  </table>
+                <![endif]-->
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+    <!--[if mso | IE]>
+          </td>
+        </tr>
+      </table>
+
+      <table
+         align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
+      >
+        <tr>
+          <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
+      <![endif]-->
+    <div style="background:#FFFFFF;background-color:#FFFFFF;margin:0px auto;max-width:600px;">
+      <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation"
+        style="background:#FFFFFF;background-color:#FFFFFF;width:100%;">
+        <tbody>
+          <tr>
+            <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
+              <!--[if mso | IE]>
+                  <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+
+        <tr>
+
+            <td
+               class="" style="vertical-align:top;width:600px;"
+            >
+          <![endif]-->
+              <div class="mj-column-per-100 mj-outlook-group-fix"
+                style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
+                <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;"
+                  width="100%">
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <div
+                        style="font-family:Source Sans Pro, sans-serif;font-size:24px;font-weight:600;line-height:150%;text-align:left;color:#000000;">
+                        Hello {{name|abbreviate:25}}!</div>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <div
+                        style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
+                        <span style="font-weight:bold;">{{ source-user }}</span> has created a comment in a thread you've been mentioned at "{{ comment-reference }}".</div>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <div style="font-family:Source Sans Pro, sans-serif;font-size:16px;font-style:italic;line-height:150%;text-align:left;color:#212426;
+                                  border-top: 1px solid #bfbfbf; border-bottom: 1px solid #bfbfbf; padding: 32px 0px;">
+                        {{ comment-content }}
+                      </div>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td align="center" vertical-align="middle"
+                      style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <table border="0" cellpadding="0" cellspacing="0" role="presentation"
+                        style="border-collapse:separate;line-height:100%;">
+                        <tr>
+                          <td align="center" bgcolor="#6911d4#31EFB8" role="presentation"
+                              style="border:none;border-radius:8px;cursor:auto;mso-padding-alt:10px 25px;background:#6911d4;"
+                              valign="middle">
+                            <a href="{{ comment-url }}"
+                               style="display:inline-block;background:#6911d4;color:#FFFFFF;font-family:Source Sans Pro, sans-serif;font-size:16px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:8px;"
+                               target="_blank"> GO TO THE COMMENT </a>
+                          </td>
+                        </tr>
+                      </table>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
+                      <div
+                        style="font-family:Source Sans Pro, sans-serif;font-size:16px;line-height:150%;text-align:left;color:#000000;">
+                        The Penpot team.</div>
+                    </td>
+                  </tr>
+                </table>
+              </div>
+              <!--[if mso | IE]>
+            </td>
+
+        </tr>
+
+                  </table>
+                <![endif]-->
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+
+    {% include "app/email/includes/footer.html" %}
+
+  </div>
+</body>
+
+</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 000000000..547760572
--- /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 000000000..52d79de54
--- /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 5bcf741f1..75365fe75 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 566095a19..cefa94b65 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 000000000..f5a8cf9f0
--- /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/comments.clj b/backend/src/app/rpc/commands/comments.clj
index fafecd8b8..4585b3eb3 100644
--- a/backend/src/app/rpc/commands/comments.clj
+++ b/backend/src/app/rpc/commands/comments.clj
@@ -6,13 +6,16 @@
 
 (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.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]
@@ -24,22 +27,135 @@
    [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 [project-id file-id page-id]}]
+  (str/ffmt "%/#/workspace/%/%?page-id=%" (cf/get :public-uri) project-id file-id page-id))
+
+(defn- format-comment-ref
+  [{:keys [seqn]} {:keys [file-name page-name]}]
+  (str/ffmt "#%, %, %" seqn file-name page-name))
+
+(defn decode-user-row
+  [user]
+  (-> user
+      (d/update-when :props db/decode-transit-pgobject)
+      (update
+       :mention-email?
+       (fn [{:keys [props]}]
+         (not= :none (-> props :notifications :email-comments))))
+
+      (update
+       :notification-email?
+       (fn [{:keys [props]}]
+         (= :all (-> props :notifications :email-comments))))))
+
+(defn get-team-users
+  [conn team-id]
+  (->> (teams/get-users+props conn team-id)
+       (map decode-user-row)
+       (d/index-by :id)))
+
+(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 (->> (db/query conn :profile {:id profile-id} {:columns [:fullname]}) first :fullname)
+
+        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
+        (-> (set (:mentions comment))
+            (set/difference #{profile-id}))
+
+        ;; Users mentioned in this thread
+        thread-mentions
+        (-> (set (:mentions thread))
+            ;; Remove the mentions in the thread because we're already sending a
+            ;; notification
+            (set/difference comment-mentions)
+            (set/difference #{profile-id}))
+
+        ;; All users
+        notificate-users-ids
+        (-> (set (keys team-users))
+            (set/difference comment-mentions)
+            (set/difference thread-mentions)
+            (set/difference #{profile-id}))]
+
+    (doseq [mention comment-mentions]
+      (let [{:keys [fullname email mention-email?]} (get team-users mention)]
+        (when mention-email?
+          (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 mention-email?]} (get team-users mention)]
+        (when mention-email?
+          (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 [fullname email notification-email?]} (get team-users user-id)]
+        (when notification-email?
+          (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 +207,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])))
 
@@ -161,11 +277,13 @@
   {::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
+(def sql:all-comment-threads-by-team
   "select distinct on (ct.id)
           ct.*,
           f.name as file_name,
@@ -188,14 +306,56 @@
     where p.team_id = ?
    window w as (partition by c.thread_id order by c.created_at asc)")
 
-(def sql:unread-comment-threads-by-team
-  (str "with threads as (" sql:comment-threads-by-team ")"
+(def sql:unread-all-comment-threads-by-team
+  (str "with threads as (" sql:all-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:partial-comment-threads-by-team
+  "select distinct on (ct.id)
+          ct.*,
+          ct.owner_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 = ?)
+    where p.team_id = ?
+      and (ct.owner_id = ?
+       or ? = any(ct.mentions))
+   window w as (partition by c.thread_id order by c.created_at asc)")
+
+(def sql:unread-partial-comment-threads-by-team
+  (str "with threads as (" sql:partial-comment-threads-by-team ")"
        "select * from threads where count_unread_comments > 0"))
 
 (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/query conn :profile {:id profile-id})
+             (first)
+             (decode-user-row))]
+    (case (or (-> profile :props :notifications :dashboard-comments) :all)
+      :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
 
@@ -300,7 +460,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 +469,11 @@
    ::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 +485,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 +514,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 +547,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
@@ -429,56 +602,76 @@
   [: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)]
+  [cfg {:keys [::rpc/profile-id ::rpc/request-at thread-id share-id content mentions]}]
+  (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)
+           {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,12 +680,14 @@
   [: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]}]
+  [cfg {:keys [::rpc/profile-id ::rpc/request-at id share-id content mentions]}]
   (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)
@@ -508,12 +703,18 @@
                   (let [{:keys [page-name]} (get-file cfg file-id page-id)]
                     (db/update! conn :comment
                                 {:content content
-                                 :modified-at request-at}
+                                 :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}
+                                 :page-name page-name
+                                 :mentions
+                                 (-> (:mentions thread)
+                                     (set)
+                                     (into mentions)
+                                     (db/encode-pgarray conn "uuid"))}
                                 {:id thread-id})
                     nil)))))
 
diff --git a/backend/src/app/rpc/commands/profile.clj b/backend/src/app/rpc/commands/profile.clj
index 7c7ca3339..7760c96b5 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 f111b1184..7e4d0c261 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/viewer.clj b/backend/src/app/rpc/commands/viewer.clj
index 641d564af..b258420ee 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 9e0f86474..d500352b3 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 0f59271f8..2465a9e98 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/frontend/playwright/ui/specs/viewer-comments.spec.js b/frontend/playwright/ui/specs/viewer-comments.spec.js
index 4ed32135a..5e923ef6a 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 000000000..72e5ff01d
--- /dev/null
+++ b/frontend/resources/images/icons/at.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14.499" height="14.507" viewBox="700.734 827.762 14.499 14.507"><path d="M707.948 827.762c-.193 0-.386.007-.578.022-2.311.181-4.574 1.452-5.839 3.982-1.686 3.372-.52 6.821 1.835 8.787 2.354 1.966 5.955 2.497 8.974.233a.566.566 0 1 0-.68-.906c-2.611 1.959-5.563 1.478-7.568-.196-2.004-1.675-3.005-4.495-1.546-7.412 1.458-2.917 4.314-3.808 6.856-3.208 2.543.599 4.698 2.672 4.698 5.936v.667c0 .525-.176.847-.435 1.076-.258.23-.624.357-.998.357s-.741-.127-.999-.357c-.258-.229-.435-.551-.435-1.076v-3.334a.567.567 0 0 0-1.133 0v.215a3.215 3.215 0 0 0-2.1-.781 3.241 3.241 0 0 0-3.233 3.233 3.241 3.241 0 0 0 3.233 3.233 3.23 3.23 0 0 0 2.482-1.168c.122.199.267.377.433.525a2.63 2.63 0 0 0 1.752.643c.626 0 1.259-.206 1.751-.643.492-.437.815-1.115.815-1.923V835c0-3.773-2.586-6.336-5.572-7.04a7.405 7.405 0 0 0-1.713-.198ZM708 832.9c1.167 0 2.1.933 2.1 2.1a2.09 2.09 0 0 1-2.1 2.1 2.09 2.09 0 0 1-2.1-2.1c0-1.167.933-2.1 2.1-2.1Z"/></svg>
diff --git a/frontend/src/app/main/data/comments.cljs b/frontend/src/app/main/data/comments.cljs
index 1f631203d..dd52e7353 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)))))))
 
diff --git a/frontend/src/app/main/data/profile.cljs b/frontend/src/app/main/data/profile.cljs
index 6ae164169..2a22ad57e 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/ui.cljs b/frontend/src/app/main/ui.cljs
index 700883883..752beded1 100644
--- a/frontend/src/app/main/ui.cljs
+++ b/frontend/src/app/main/ui.cljs
@@ -193,7 +193,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/comments.cljs b/frontend/src/app/main/ui/comments.cljs
index 4f64a246d..9b2696647 100644
--- a/frontend/src/app/main/ui/comments.cljs
+++ b/frontend/src/app/main/ui/comments.cljs
@@ -11,6 +11,7 @@
    [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]
@@ -22,11 +23,15 @@
    [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]
@@ -34,53 +39,337 @@
 
 (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) "&#8203;" 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)
+        anchor-node   (wapi/get-anchor-node selection)
+        anchor-offset (wapi/get-anchor-offset selection)]
+    (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 "&#8203;"))
+
+               ;; 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)
+                 [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 "&#8203;" suffix))
+                    sel (wapi/get-selection)]
+
+                (dom/set-html! span-node (if (empty? prefix) "&#8203;" prefix))
+                (dom/insert-after! node span-node mention-span)
+                (dom/insert-after! node mention-span after-span)
+                (wapi/set-cursor-before! 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)
          (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/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 []
@@ -88,15 +377,158 @@
          (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))
+
+           (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 "plaintext-only"
+      :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
@@ -137,7 +569,7 @@
      [:div {:class (stl/css :author-timeago)} (dt/timeago (:modified-at item))]]]
 
    [:div {:class (stl/css :item)}
-    (:content item)]
+    [:> comment-content {:content (:content item)}]]
 
    [:div {:class (stl/css :replies)}
     (let [total-comments (:count-comments item 1)
@@ -188,17 +620,19 @@
            (st/emit! (dcm/add-comment thread @content))
            (on-cancel)))]
     [:div {:class (stl/css :form)}
-     [:& resizing-textarea {: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}]
+     [:& 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 :form-buttons-wrapper)}
+        [:> mentions-button]
         [:> button* {:variant "ghost"
                      :on-click on-cancel}
          (tr "ds.confirm-cancel")]
@@ -226,14 +660,16 @@
                       (str/empty? @content))]
 
     [:div {:class (stl/css :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}]
+     [:& 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")]
@@ -244,9 +680,11 @@
 
 (mf/defc comment-floating-thread-draft*
   {::mf/props :obj}
-  [{:keys [draft zoom on-cancel on-submit position-modifier]}]
+  [{: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))
@@ -278,7 +716,7 @@
          (mf/deps draft)
          (partial on-submit draft))]
 
-    [:*
+    [:& (mf/provider mentions-context) {:value mentions-str}
      [:div
       {:class (stl/css :floating-preview-wrapper)
        :data-testid "floating-thread-bubble"
@@ -292,22 +730,27 @@
                     :left (str (+ pos-x 28) "px")}
             :on-click dom/stop-propagation}
       [:div {:class (stl/css :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}]
+       [:& 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}]
+
        [: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")]]]]]))
+         (tr "labels.post")]]]
+
+      [:& mentions-panel {:profiles profiles}]]]))
 
 (mf/defc comment-floating-thread-header*
   {::mf/props :obj
@@ -443,7 +886,8 @@
          [:> comment-edit-form* {:content (:content comment)
                                  :on-submit on-submit
                                  :on-cancel on-cancel}]
-         [:span {:class (stl/css :text)} (:content comment)])]]
+         [:span {:class (stl/css :text)}
+          [:> comment-content {:content (:content comment)}]])]]
 
      [:& dropdown {:show (= options (:id comment))
                    :on-close on-hide-options}
@@ -486,6 +930,7 @@
    ::mf/wrap [mf/memo]}
   [{:keys [thread zoom profiles origin position-modifier viewport]}]
   (let [ref           (mf/use-ref)
+        mentions-str (mf/use-memo #(rx/subject))
         thread-id     (:id thread)
         thread-pos    (:position thread)
 
@@ -493,8 +938,9 @@
                         (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.
+        max-height    (when (some? viewport) (int (* (obj/get viewport "height") 0.75)))
+
+        ;; 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)
 
@@ -523,31 +969,34 @@
       (when-let [node (mf/ref-val ref)]
         (dom/scroll-into-view-if-needed! node)))
 
-    (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}
+    [:& (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 :floating-thread-header)}
-        [:> comment-floating-thread-header* {:profiles profiles
-                                             :thread thread
-                                             :origin origin}]]
+        [:div {:class (stl/css :floating-thread-header)}
+         [:> comment-floating-thread-header* {:profiles profiles
+                                              :thread thread
+                                              :origin origin}]]
 
-       [: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}]])]
+        [: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}]])))
+        [:> comment-reply-form* {:thread thread}]
+
+        [:& mentions-panel {:profiles profiles}]])]))
 
 (mf/defc comment-floating-bubble*
   {::mf/props :obj
@@ -664,8 +1113,7 @@
                                 :floating-preview-bubble (false? (:hover? @state))
                                 :grabbing (true? (:grabbing? @state)))}
 
-     (if (true? (:hover? @state))
-
+     (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)}
diff --git a/frontend/src/app/main/ui/comments.scss b/frontend/src/app/main/ui/comments.scss
index 229c13932..f1a65fd01 100644
--- a/frontend/src/app/main/ui/comments.scss
+++ b/frontend/src/app/main/ui/comments.scss
@@ -248,7 +248,115 @@
 }
 
 .form-buttons-wrapper {
-  display: flex;
+  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;
+  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/ds/foundations/assets/icon.cljs b/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs
index 5609a3749..2c6c7f42d 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")
diff --git a/frontend/src/app/main/ui/routes.cljs b/frontend/src/app/main/ui/routes.cljs
index a19905697..5a114cfc6 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 d5192320d..e66c3f5ad 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 000000000..b402b3af8
--- /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 000000000..7e2cd4ae0
--- /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 8da8bb6a3..5de595091 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/viewer/comments.cljs b/frontend/src/app/main/ui/viewer/comments.cljs
index 45c023a1b..db9d66c05 100644
--- a/frontend/src/app/main/ui/viewer/comments.cljs
+++ b/frontend/src/app/main/ui/viewer/comments.cljs
@@ -227,6 +227,7 @@
        (when-let [draft (:draft local)]
          [:> 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/workspace/viewport/comments.cljs b/frontend/src/app/main/ui/workspace/viewport/comments.cljs
index c7e92dffd..5cc97b574 100644
--- a/frontend/src/app/main/ui/workspace/viewport/comments.cljs
+++ b/frontend/src/app/main/ui/workspace/viewport/comments.cljs
@@ -91,6 +91,7 @@
 
        (when-let [draft (:comment drawing)]
          [:> 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/util/dom.cljs b/frontend/src/app/util/dom.cljs
index f13553a26..4257e8c36 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 5151b2f50..27ff1493a 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/webapi.cljs b/frontend/src/app/util/webapi.cljs
index 722067fe7..76db6cb9d 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,82 @@
        (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)))
diff --git a/frontend/translations/en.po b/frontend/translations/en.po
index 972ec32b6..a4c16f4bb 100644
--- a/frontend/translations/en.po
+++ b/frontend/translations/en.po
@@ -6696,3 +6696,60 @@ msgstr "Open version menu"
 #, unused
 msgid "workspace.viewport.click-to-close-path"
 msgstr "Click to close the path"
+
+msgid "dashboard.notifications.notifications-saved"
+msgstr "Notification settings updated"
+
+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 8b481c78b..f5fed1d09 100644
--- a/frontend/translations/es.po
+++ b/frontend/translations/es.po
@@ -6652,3 +6652,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/vendor/mousetrap/index.js b/frontend/vendor/mousetrap/index.js
index 07a5cb9b0..0dd2e96b3 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;
 }
 

From 5c63a5c58ef3559ba775bb65a0e83a92a26a8eed Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Wed, 8 Jan 2025 11:48:04 +0100
Subject: [PATCH 67/75] :lipstick: Adapt sql style

---
 backend/src/app/rpc/commands/comments.clj | 43 +++++++++++------------
 1 file changed, 21 insertions(+), 22 deletions(-)

diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj
index 4585b3eb3..b156c918a 100644
--- a/backend/src/app/rpc/commands/comments.clj
+++ b/backend/src/app/rpc/commands/comments.clj
@@ -313,32 +313,31 @@
 ;; The partial configuration will retrieve only comments created by the user and
 ;; threads that have a mention to the user.
 (def sql:partial-comment-threads-by-team
-  "select distinct on (ct.id)
+  "SELECT DISTINCT ON (ct.id)
           ct.*,
           ct.owner_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 = ?)
-    where p.team_id = ?
-      and (ct.owner_id = ?
-       or ? = any(ct.mentions))
-   window w as (partition by c.thread_id order by c.created_at asc)")
+          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 = ?
+      AND (ct.owner_id = ? OR ? = any(ct.mentions))
+   WINDOW w AS (PARTITION BY c.thread_id ORDER BY c.created_at ASC)")
 
 (def sql:unread-partial-comment-threads-by-team
-  (str "with threads as (" sql:partial-comment-threads-by-team ")"
-       "select * from threads where count_unread_comments > 0"))
+  (str "WITH threads AS (" sql:partial-comment-threads-by-team ")"
+       "SELECT * FROM threads WHERE count_unread_comments > 0"))
 
 (defn- get-unread-comment-threads
   [conn profile-id team-id]

From 27c2db6cde2cafeadb309e4401e8dcd481ec2f9c Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Wed, 8 Jan 2025 11:50:30 +0100
Subject: [PATCH 68/75] :lipstick: Replace db/query with db/get

---
 backend/src/app/rpc/commands/comments.clj | 24 ++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj
index b156c918a..b03058930 100644
--- a/backend/src/app/rpc/commands/comments.clj
+++ b/backend/src/app/rpc/commands/comments.clj
@@ -72,15 +72,21 @@
        (map decode-user-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 send-comment-emails!
   [conn {:keys [profile-id team-id] :as params} comment thread]
 
-  (let [team-users (get-team-users conn team-id)
-        source-user (->> (db/query conn :profile {:id profile-id} {:columns [:fullname]}) first :fullname)
+  (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)
+        comment-content   (format-comment comment)
+        comment-url       (format-comment-url params)
 
         ;; Users mentioned in this comment
         comment-mentions
@@ -341,11 +347,11 @@
 
 (defn- get-unread-comment-threads
   [conn profile-id team-id]
-  (let [profile
-        (->> (db/query conn :profile {:id profile-id})
-             (first)
-             (decode-user-row))]
-    (case (or (-> profile :props :notifications :dashboard-comments) :all)
+  (let [profile (-> (db/get conn :profile {:id profile-id})
+                    (decode-user-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))

From 1f4fafe781d5b1a7454f5977465d1b01e636dfe3 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Wed, 8 Jan 2025 12:00:38 +0100
Subject: [PATCH 69/75] :lipstick: Remove neesting with ::db/transaction

---
 backend/src/app/rpc/commands/comments.clj | 284 +++++++++++-----------
 1 file changed, 139 insertions(+), 145 deletions(-)

diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj
index b03058930..da6fdbc1f 100644
--- a/backend/src/app/rpc/commands/comments.clj
+++ b/backend/src/app/rpc/commands/comments.clj
@@ -238,7 +238,6 @@
   {::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))))
@@ -474,8 +473,7 @@
    ::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 mentions 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 name]} (get-file cfg file-id page-id)]
@@ -569,12 +567,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
 
@@ -587,16 +585,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
 
@@ -613,70 +610,68 @@
 (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 mentions]}]
-  (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)
-           {file-name :name :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
-                           :mentions
-                           (-> mentions
-                               (set)
-                               (db/encode-pgarray conn "uuid"))})
-                         (decode-row))
-             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))
-                      :mentions (-> (:mentions thread)
-                                    (set)
-                                    (into mentions)
-                                    (db/encode-pgarray conn "uuid"))}
-                     {: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)
+      ;; Update the current profile status in relation to the
+      ;; current thread.
+      (upsert-comment-thread-status! conn profile-id thread-id)
 
-         (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))
+      (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))))))
+      (vary-meta comment assoc ::audit/props props))))
 
 ;; --- COMMAND: Update Comment
 
@@ -691,37 +686,36 @@
 ;; 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 mentions]}]
-  (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
-                                 :mentions (db/encode-pgarray mentions conn "uuid")}
-                                {: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
-                                 :mentions
-                                 (-> (:mentions thread)
-                                     (set)
-                                     (into mentions)
-                                     (db/encode-pgarray conn "uuid"))}
-                                {: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
 
@@ -733,17 +727,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
 
@@ -755,17 +749,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
 
@@ -779,17 +773,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
 
@@ -802,13 +796,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))

From aa583b0707821573a861fcbbe421dc89354b09f8 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Wed, 8 Jan 2025 13:34:13 +0100
Subject: [PATCH 70/75] :lipstick: Remove redundant set conversions

---
 backend/src/app/rpc/commands/comments.clj | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj
index da6fdbc1f..2d4c6d293 100644
--- a/backend/src/app/rpc/commands/comments.clj
+++ b/backend/src/app/rpc/commands/comments.clj
@@ -90,23 +90,23 @@
 
         ;; Users mentioned in this comment
         comment-mentions
-        (-> (set (:mentions comment))
+        (-> (:mentions comment)
             (set/difference #{profile-id}))
 
         ;; Users mentioned in this thread
         thread-mentions
-        (-> (set (:mentions thread))
+        (-> (:mentions thread)
             ;; Remove the mentions in the thread because we're already sending a
             ;; notification
             (set/difference comment-mentions)
-            (set/difference #{profile-id}))
+            (disj profile-id))
 
         ;; All users
         notificate-users-ids
         (-> (set (keys team-users))
             (set/difference comment-mentions)
             (set/difference thread-mentions)
-            (set/difference #{profile-id}))]
+            (disj profile-id))]
 
     (doseq [mention comment-mentions]
       (let [{:keys [fullname email mention-email?]} (get team-users mention)]
@@ -154,7 +154,7 @@
   (cond-> row
     (db/pgpoint? position) (assoc :position (db/decode-pgpoint position))
     (db/pgobject? participants) (assoc :participants (db/decode-transit-pgobject participants))
-    (db/pgarray? mentions) (assoc :mentions (db/decode-pgarray mentions))))
+    (db/pgarray? mentions) (assoc :mentions (db/decode-pgarray mentions #{}))))
 
 (def xf-decode-row
   (map decode-row))

From 45d52539158ee54173a54f69a8cbe2b160b4a27a Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Wed, 8 Jan 2025 14:40:53 +0100
Subject: [PATCH 71/75] :sparkles: Add better reusability for comment related
 queries

---
 backend/src/app/rpc/commands/comments.clj | 106 +++++++---------------
 1 file changed, 33 insertions(+), 73 deletions(-)

diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj
index 2d4c6d293..cf529b6c4 100644
--- a/backend/src/app/rpc/commands/comments.clj
+++ b/backend/src/app/rpc/commands/comments.clj
@@ -243,30 +243,33 @@
                  (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
@@ -288,61 +291,18 @@
      (teams/check-read-permissions! conn profile-id team-id)
      (get-unread-comment-threads conn profile-id team-id))))
 
-(def sql:all-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:all-comment-threads-by-team ")"
-       "select * from threads where count_unread_comments > 0"))
+  (str "WITH threads AS (" sql:comment-threads ")"
+       "SELECT * FROM threads WHERE count_unread_comments > 0 AND team_id = ?"))
 
 ;; The partial configuration will retrieve only comments created by the user and
 ;; threads that have a mention to the user.
-(def sql:partial-comment-threads-by-team
-  "SELECT DISTINCT ON (ct.id)
-          ct.*,
-          ct.owner_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 = ?)
-    WHERE p.team_id = ?
-      AND (ct.owner_id = ? OR ? = any(ct.mentions))
-   WINDOW w AS (PARTITION BY c.thread_id ORDER BY c.created_at ASC)")
-
 (def sql:unread-partial-comment-threads-by-team
-  (str "WITH threads AS (" sql:partial-comment-threads-by-team ")"
-       "SELECT * FROM threads WHERE count_unread_comments > 0"))
+  (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]
@@ -376,9 +336,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

From 8239b9666b82b0423b41a1316a386183cd33f28e Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Wed, 8 Jan 2025 14:20:04 +0100
Subject: [PATCH 72/75] :lipstick: Use correct frontend url on comment related
 emails

---
 backend/src/app/rpc/commands/comments.clj | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj
index cf529b6c4..d87e5cb59 100644
--- a/backend/src/app/rpc/commands/comments.clj
+++ b/backend/src/app/rpc/commands/comments.clj
@@ -11,6 +11,7 @@
    [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]
@@ -45,8 +46,13 @@
        (str/join "")))
 
 (defn- format-comment-url
-  [{:keys [project-id file-id page-id]}]
-  (str/ffmt "%/#/workspace/%/%?page-id=%" (cf/get :public-uri) project-id file-id page-id))
+  [{: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]}]

From 13ec04dd6547c4eadbe339e87d763b56a3f4a394 Mon Sep 17 00:00:00 2001
From: Alejandro Alonso <alejandroalonsofernandez@gmail.com>
Date: Wed, 8 Jan 2025 14:14:26 +0100
Subject: [PATCH 73/75] :tada: Stroke caps support for wasm render

---
 frontend/src/app/render_wasm/api.cljs |  34 +++--
 render-wasm/docs/serialization.md     |  26 ++++
 render-wasm/src/main.rs               |  18 ++-
 render-wasm/src/shapes/renderable.rs  | 193 +++++++++++++++++++++++++-
 render-wasm/src/shapes/strokes.rs     |  52 ++++---
 5 files changed, 288 insertions(+), 35 deletions(-)

diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs
index f6b895b55..eb3f38dd3 100644
--- a/frontend/src/app/render_wasm/api.cljs
+++ b/frontend/src/app/render_wasm/api.cljs
@@ -219,21 +219,35 @@
     :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)]
+          (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)
-              :outer (h/call internal-module "_add_shape_outer_stroke" width style)
-              (h/call internal-module "_add_shape_center_stroke" width style))
+              :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)
diff --git a/render-wasm/docs/serialization.md b/render-wasm/docs/serialization.md
index 741ba5788..6ef7912c0 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 4911dff18..a16fd3648 100644
--- a/render-wasm/src/main.rs
+++ b/render-wasm/src/main.rs
@@ -347,26 +347,32 @@ pub extern "C" fn set_shape_path_content() {
 }
 
 #[no_mangle]
-pub extern "C" fn add_shape_center_stroke(width: f32, style: i32) {
+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));
+        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: i32) {
+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))
+        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: i32) {
+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))
+        shape.add_stroke(shapes::Stroke::new_outer_stroke(
+            width, style, cap_start, cap_end,
+        ))
     }
 }
 
diff --git a/render-wasm/src/shapes/renderable.rs b/render-wasm/src/shapes/renderable.rs
index de752dba1..5bbecab4f 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::{Fill, Image, Kind, Path, Shape, Stroke, StrokeKind};
+use super::{Fill, Image, Kind, Path, Shape, Stroke, StrokeCap, StrokeKind};
 use crate::math::Rect;
 use crate::render::{ImageStore, Renderable};
 
@@ -155,6 +155,195 @@ fn draw_stroke_on_circle(canvas: &skia::Canvas, stroke: &Stroke, rect: &Rect, se
     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,
@@ -177,6 +366,7 @@ fn draw_stroke_on_path(
         // 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 => {
@@ -295,6 +485,7 @@ pub fn draw_image_stroke_in_container(
                 }
                 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());
             }
         }
     }
diff --git a/render-wasm/src/shapes/strokes.rs b/render-wasm/src/shapes/strokes.rs
index cf56a02f9..d5ec04ab8 100644
--- a/render-wasm/src/shapes/strokes.rs
+++ b/render-wasm/src/shapes/strokes.rs
@@ -10,8 +10,8 @@ pub enum StrokeStyle {
     Mixed,
 }
 
-impl From<i32> for StrokeStyle {
-    fn from(value: i32) -> Self {
+impl From<u8> for StrokeStyle {
+    fn from(value: u8) -> Self {
         match value {
             1 => StrokeStyle::Dotted,
             2 => StrokeStyle::Dashed,
@@ -21,15 +21,31 @@ impl From<i32> for StrokeStyle {
     }
 }
 
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq)]
 pub enum StrokeCap {
     None,
-    // Line,
-    // Triangle,
-    // Circle,
-    // Diamond,
-    // Round,
-    // Square,
+    Line,
+    Triangle,
+    Rectangle,
+    Circle,
+    Diamond,
+    Round,
+    Square,
+}
+
+impl From<u8> 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)]
@@ -59,38 +75,38 @@ impl Stroke {
         }
     }
 
-    pub fn new_center_stroke(width: f32, style: i32) -> Self {
+    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::None,
-            cap_start: StrokeCap::None,
+            cap_end: StrokeCap::from(cap_end),
+            cap_start: StrokeCap::from(cap_start),
             kind: StrokeKind::CenterStroke,
         }
     }
 
-    pub fn new_inner_stroke(width: f32, style: i32) -> Self {
+    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::None,
-            cap_start: StrokeCap::None,
+            cap_end: StrokeCap::from(cap_end),
+            cap_start: StrokeCap::from(cap_start),
             kind: StrokeKind::InnerStroke,
         }
     }
 
-    pub fn new_outer_stroke(width: f32, style: i32) -> Self {
+    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::None,
-            cap_start: StrokeCap::None,
+            cap_end: StrokeCap::from(cap_end),
+            cap_start: StrokeCap::from(cap_start),
             kind: StrokeKind::OuterStroke,
         }
     }

From 6e3f9db744889597593b096c5ae16064d0d1672c Mon Sep 17 00:00:00 2001
From: "alonso.torres" <alonso.torres@kaleidos.net>
Date: Wed, 8 Jan 2025 15:35:12 +0100
Subject: [PATCH 74/75] :bug: Fix problem in firefox comments

---
 backend/src/app/rpc/commands/comments.clj     | 41 +++++++++----------
 frontend/src/app/main/data/comments.cljs      |  5 ++-
 frontend/src/app/main/ui/comments.cljs        | 36 +++++++++++++---
 frontend/src/app/main/ui/comments.scss        |  1 +
 .../src/app/main/ui/workspace/comments.cljs   | 14 +++++--
 frontend/src/app/util/webapi.cljs             | 29 +++++++++++--
 frontend/translations/en.po                   |  3 ++
 frontend/translations/es.po                   |  3 ++
 8 files changed, 96 insertions(+), 36 deletions(-)

diff --git a/backend/src/app/rpc/commands/comments.clj b/backend/src/app/rpc/commands/comments.clj
index d87e5cb59..f649f577b 100644
--- a/backend/src/app/rpc/commands/comments.clj
+++ b/backend/src/app/rpc/commands/comments.clj
@@ -22,6 +22,7 @@
    [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]
@@ -58,24 +59,10 @@
   [{:keys [seqn]} {:keys [file-name page-name]}]
   (str/ffmt "#%, %, %" seqn file-name page-name))
 
-(defn decode-user-row
-  [user]
-  (-> user
-      (d/update-when :props db/decode-transit-pgobject)
-      (update
-       :mention-email?
-       (fn [{:keys [props]}]
-         (not= :none (-> props :notifications :email-comments))))
-
-      (update
-       :notification-email?
-       (fn [{:keys [props]}]
-         (= :all (-> props :notifications :email-comments))))))
-
 (defn get-team-users
   [conn team-id]
   (->> (teams/get-users+props conn team-id)
-       (map decode-user-row)
+       (map profile/decode-row)
        (d/index-by :id)))
 
 (defn- resolve-profile-name
@@ -84,6 +71,16 @@
               {::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]
 
@@ -115,8 +112,8 @@
             (disj profile-id))]
 
     (doseq [mention comment-mentions]
-      (let [{:keys [fullname email mention-email?]} (get team-users mention)]
-        (when mention-email?
+      (let [{:keys [fullname email props]} (get team-users mention)]
+        (when (mention-email? props)
           (eml/send!
            {::eml/conn conn
             ::eml/factory eml/comment-mention
@@ -129,8 +126,8 @@
 
     ;; Send to the thread users
     (doseq [mention thread-mentions]
-      (let [{:keys [fullname email mention-email?]} (get team-users mention)]
-        (when mention-email?
+      (let [{:keys [fullname email props]} (get team-users mention)]
+        (when (mention-email? props)
           (eml/send!
            {::eml/conn conn
             ::eml/factory eml/comment-thread
@@ -143,8 +140,8 @@
 
     ;; Send to users with the "all" flag activated
     (doseq [user-id notificate-users-ids]
-      (let [{:keys [fullname email notification-email?]} (get team-users user-id)]
-        (when notification-email?
+      (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
@@ -313,7 +310,7 @@
 (defn- get-unread-comment-threads
   [conn profile-id team-id]
   (let [profile (-> (db/get conn :profile {:id profile-id})
-                    (decode-user-row))
+                    (profile/decode-row))
         notify  (or (-> profile :props :notifications :dashboard-comments) :all)]
 
     (case notify
diff --git a/frontend/src/app/main/data/comments.cljs b/frontend/src/app/main/data/comments.cljs
index dd52e7353..73d8a4c0f 100644
--- a/frontend/src/app/main/data/comments.cljs
+++ b/frontend/src/app/main/data/comments.cljs
@@ -584,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/ui/comments.cljs b/frontend/src/app/main/ui/comments.cljs
index 9b2696647..f7c64af9a 100644
--- a/frontend/src/app/main/ui/comments.cljs
+++ b/frontend/src/app/main/ui/comments.cljs
@@ -94,9 +94,11 @@
 (defn current-text-node
   "Retrieves the text node and the offset that the cursor is positioned on"
   [node]
+
   (let [selection     (wapi/get-selection)
-        anchor-node   (wapi/get-anchor-node selection)
-        anchor-offset (wapi/get-anchor-offset 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)
@@ -203,6 +205,13 @@
         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]
@@ -285,13 +294,13 @@
                     (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 "&#8203;" suffix))
+                    after-span (create-text-node (dm/str " " suffix))
                     sel (wapi/get-selection)]
 
                 (dom/set-html! span-node (if (empty? prefix) "&#8203;" prefix))
                 (dom/insert-after! node span-node mention-span)
                 (dom/insert-after! node mention-span after-span)
-                (wapi/set-cursor-before! after-span)
+                (wapi/set-cursor-after! after-span)
                 (wapi/collapse-end! sel)
 
                 (when on-change
@@ -299,7 +308,7 @@
 
         handle-key-down
         (mf/use-fn
-         (mf/deps on-esc on-ctrl-enter handle-select)
+         (mf/deps on-esc on-ctrl-enter handle-select handle-input)
          (fn [event]
            (handle-select event)
 
@@ -333,6 +342,21 @@
                (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&#8203;" (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)
@@ -397,7 +421,7 @@
     [:div
      {:role "textbox"
       :class (stl/css :comment-input)
-      :content-editable "plaintext-only"
+      :content-editable "true"
       :suppress-content-editable-warning true
       :on-input handle-input
       :ref init-input
diff --git a/frontend/src/app/main/ui/comments.scss b/frontend/src/app/main/ui/comments.scss
index f1a65fd01..f02df3bd1 100644
--- a/frontend/src/app/main/ui/comments.scss
+++ b/frontend/src/app/main/ui/comments.scss
@@ -321,6 +321,7 @@
 
 .comment-input {
   @include bodySmallTypography;
+  white-space: pre;
   background: var(--input-background-color);
   border-radius: $br-8;
   border: $s-1 solid var(--input-border-color);
diff --git a/frontend/src/app/main/ui/workspace/comments.cljs b/frontend/src/app/main/ui/workspace/comments.cljs
index 22da3f663..290e3f299 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?
diff --git a/frontend/src/app/util/webapi.cljs b/frontend/src/app/util/webapi.cljs
index 76db6cb9d..4a280f57f 100644
--- a/frontend/src/app/util/webapi.cljs
+++ b/frontend/src/app/util/webapi.cljs
@@ -266,9 +266,6 @@
 
 (def empty-png-size (memoize empty-png-size*))
 
-
-
-
 (defn create-range
   []
   (let [document globals/document]
@@ -328,7 +325,7 @@
              (remove-all-ranges! sel)
              (add-range! sel r))
 
-         (let [text-node   (aget child-nodes 0)]
+         (let [text-node (aget child-nodes 0)]
            (.setStart r text-node offset)
            (.setEnd r text-node offset)
            (remove-all-ranges! sel)
@@ -344,3 +341,27 @@
         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/translations/en.po b/frontend/translations/en.po
index a4c16f4bb..a69ddf28b 100644
--- a/frontend/translations/en.po
+++ b/frontend/translations/en.po
@@ -2117,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"
diff --git a/frontend/translations/es.po b/frontend/translations/es.po
index f5fed1d09..df0f5dc8e 100644
--- a/frontend/translations/es.po
+++ b/frontend/translations/es.po
@@ -2122,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"

From 5ee87018b9979e4257f8069e427ab1d6070303e6 Mon Sep 17 00:00:00 2001
From: Eva Marco <evamarcod@gmail.com>
Date: Thu, 9 Jan 2025 11:54:36 +0100
Subject: [PATCH 75/75] :bug: Fix icon* component prop

---
 docs/technical-guide/developer/ui.md               |  4 ++--
 frontend/src/app/main/ui/comments.cljs             |  2 +-
 .../app/main/ui/components/reorder_handler.cljs    |  2 +-
 frontend/src/app/main/ui/dashboard/team.cljs       |  2 +-
 frontend/src/app/main/ui/ds/buttons/button.cljs    |  2 +-
 .../src/app/main/ui/ds/buttons/icon_button.cljs    |  2 +-
 frontend/src/app/main/ui/ds/controls/combobox.cljs |  4 ++--
 frontend/src/app/main/ui/ds/controls/input.cljs    |  2 +-
 frontend/src/app/main/ui/ds/controls/select.cljs   |  4 ++--
 .../ui/ds/controls/shared/options_dropdown.cljs    |  4 ++--
 .../app/main/ui/ds/foundations/assets/icon.cljs    |  6 +++---
 .../src/app/main/ui/ds/foundations/assets/icon.mdx |  6 +++---
 .../src/app/main/ui/ds/layout/tab_switcher.cljs    |  2 +-
 frontend/src/app/main/ui/static.cljs               |  3 ++-
 frontend/src/app/main/ui/workspace/sidebar.cljs    |  2 +-
 .../sidebar/options/menus/border_radius.cljs       |  2 +-
 .../main/ui/workspace/tokens/modals/themes.cljs    | 10 +++++-----
 .../src/app/main/ui/workspace/tokens/sets.cljs     | 14 ++++++--------
 .../app/main/ui/workspace/tokens/theme_select.cljs |  6 +++---
 19 files changed, 39 insertions(+), 40 deletions(-)

diff --git a/docs/technical-guide/developer/ui.md b/docs/technical-guide/developer/ui.md
index fbcf300ca..db958e2cd 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/frontend/src/app/main/ui/comments.cljs b/frontend/src/app/main/ui/comments.cljs
index 4f64a246d..bf635d5ba 100644
--- a/frontend/src/app/main/ui/comments.cljs
+++ b/frontend/src/app/main/ui/comments.cljs
@@ -737,7 +737,7 @@
     [:div {:class (stl/css :cover)
            :on-click on-click*}
      [:div {:class (stl/css :location)}
-      [:> icon* {:id "comments"
+      [:> icon* {:icon-id "comments"
                  :class (stl/css :location-icon)}]
       [:div {:class (stl/css :location-text)}
        (str "#" (:seqn item))
diff --git a/frontend/src/app/main/ui/components/reorder_handler.cljs b/frontend/src/app/main/ui/components/reorder_handler.cljs
index 8f4acfe32..a8df96020 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/team.cljs b/frontend/src/app/main/ui/dashboard/team.cljs
index bf82855e8..3daefc5d7 100644
--- a/frontend/src/app/main/ui/dashboard/team.cljs
+++ b/frontend/src/app/main/ui/dashboard/team.cljs
@@ -953,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]
diff --git a/frontend/src/app/main/ui/ds/buttons/button.cljs b/frontend/src/app/main/ui/ds/buttons/button.cljs
index cfb30409d..73af4824e 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 0b45ad238..88bf48bd1 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 e39efedb1..5ed27a05e 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 963fe93e6..5637b287f 100644
--- a/frontend/src/app/main/ui/ds/controls/input.cljs
+++ b/frontend/src/app/main/ui/ds/controls/input.cljs
@@ -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 0d2730ebb..02e291cfa 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 16ce0240a..6173366de 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 5609a3749..62bf02b4b 100644
--- a/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs
+++ b/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs
@@ -287,17 +287,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 140b897a2..c1184acd5 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 `<Icon>`
 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 1228c4c1f..5871c61d3 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/static.cljs b/frontend/src/app/main/ui/static.cljs
index ccf892622..5b77a7b24 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/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs
index d22493f14..2c86658ec 100644
--- a/frontend/src/app/main/ui/workspace/sidebar.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar.cljs
@@ -44,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")}]])
 
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 b967fd917..7809c8568 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*
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 e6cb23f38..b40762495 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 127f13c3f..0c3eb6928 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/theme_select.cljs b/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs
index 484c806c5..85a3e2eeb 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*}