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) "​" 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 "​")) + + ;; 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 "​" suffix)) + sel (wapi/get-selection)] + + (dom/set-html! span-node (if (empty? prefix) "​" prefix)) + (dom/insert-after! node span-node mention-span) + (dom/insert-after! node mention-span after-span) + (wapi/set-cursor-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 "​" suffix)) + after-span (create-text-node (dm/str " " suffix)) sel (wapi/get-selection)] (dom/set-html! span-node (if (empty? prefix) "​" prefix)) (dom/insert-after! node span-node mention-span) (dom/insert-after! node mention-span after-span) - (wapi/set-cursor-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​" (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*}