feat(web): added image cropping to avatar uploads (#185)

* feat(web): added image cropping to avatar uploads

* chore: add translations

* refactor: move react crop css import to avatar component

* refactor: remove duplicate interface

---------

Co-authored-by: Henry <henry_ball@hotmail.co.uk>
This commit is contained in:
Morfixx
2025-09-19 22:44:20 +03:00
committed by GitHub
parent cea5cf84c8
commit 7ccd2ac1e0
19 changed files with 359 additions and 92 deletions

View File

@@ -30,6 +30,7 @@ checksums:
added%20checklist%20item%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: bdd202da20b1fffbec21792c5453f90c added%20checklist%20item%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: bdd202da20b1fffbec21792c5453f90c
added%20label%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: b32be052b3d57de0c9120fa7f9fc86ee added%20label%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: b32be052b3d57de0c9120fa7f9fc86ee
Adding%20a%20new%20member%20will%20cost%20an%20additional%20%7Bprice%7D%20(%7BbillingType%7D)%20per%20seat./singular: 12e88573028306110fbc15ef1e714892 Adding%20a%20new%20member%20will%20cost%20an%20additional%20%7Bprice%7D%20(%7BbillingType%7D)%20per%20seat./singular: 12e88573028306110fbc15ef1e714892
Adjust%20the%20square%20crop%20to%20fit%20your%20avatar./singular: a4df26bbce6f14c6962fac1324db00a8
Admin%20roles/singular: 32a5d78073b9bb9a246773afba8831df Admin%20roles/singular: 32a5d78073b9bb9a246773afba8831df
All%20systems%20operational/singular: ee943a4046b09e6334cceeea9fda2bfc All%20systems%20operational/singular: ee943a4046b09e6334cceeea9fda2bfc
Already%20have%20an%20account%3F%20%3C0%3E%3C1%3ESign%20in%3C%2F1%3E%3C%2F0%3E/singular: 2959fd276248208b65cb27ed46b20135 Already%20have%20an%20account%3F%20%3C0%3E%3C1%3ESign%20in%3C%2F1%3E%3C%2F0%3E/singular: 2959fd276248208b65cb27ed46b20135
@@ -119,6 +120,7 @@ checksums:
Create%20workspace/singular: 2e6718e79964ea5ce22d76c2189c77ca Create%20workspace/singular: 2e6718e79964ea5ce22d76c2189c77ca
created%20the%20card/singular: 605475f5aaeb4dbccbf7c4eb9107b43d created%20the%20card/singular: 605475f5aaeb4dbccbf7c4eb9107b43d
Critical/singular: eb327cd411b50aee954f8d1d215d003a Critical/singular: eb327cd411b50aee954f8d1d215d003a
Crop%20your%20avatar/singular: eb25e2d5972ec36a0b40481c8136ab15
Current%20password%20is%20required/singular: 72536bca9598680027f2be8ce80ac280 Current%20password%20is%20required/singular: 72536bca9598680027f2be8ce80ac280
Custom%20domain/singular: b09e7a9c187b7163b4a6cfc78042fe42 Custom%20domain/singular: b09e7a9c187b7163b4a6cfc78042fe42
Custom%20URLs%20require%20upgrading%20to%20a%20Pro%20plan/singular: f7275e3b473b8f7b39dab6b37eb26fea Custom%20URLs%20require%20upgrading%20to%20a%20Pro%20plan/singular: f7275e3b473b8f7b39dab6b37eb26fea

View File

@@ -59,6 +59,7 @@
"react-dom": "catalog:react18", "react-dom": "catalog:react18",
"react-hook-form": "^7.51.1", "react-hook-form": "^7.51.1",
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
"react-image-crop": "^11.0.10",
"react-lottie-player": "^1.5.5", "react-lottie-player": "^1.5.5",
"react-markdown": "^10.1.0", "react-markdown": "^10.1.0",
"superjson": "2.2.1", "superjson": "2.2.1",

View File

@@ -140,6 +140,10 @@ msgstr "hat Label <0>{0}</0> hinzugefügt"
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "Das Hinzufügen eines neuen Mitglieds kostet zusätzlich {price} ({billingType}) pro Platz." msgstr "Das Hinzufügen eines neuen Mitglieds kostet zusätzlich {price} ({billingType}) pro Platz."
#: src/views/settings/components/Avatar.tsx:278
msgid "Adjust the square crop to fit your avatar."
msgstr "Passe den quadratischen Zuschnitt an deinen Avatar an."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Administratorrollen" msgstr "Administratorrollen"
@@ -338,6 +342,7 @@ msgstr "Fehlerbericht"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:309
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -527,6 +532,10 @@ msgstr "hat die Karte erstellt"
msgid "Critical" msgid "Critical"
msgstr "Kritisch" msgstr "Kritisch"
#: src/views/settings/components/Avatar.tsx:275
msgid "Crop your avatar"
msgstr "Schneide deinen Avatar zu"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "Aktuelles Passwort ist erforderlich" msgstr "Aktuelles Passwort ist erforderlich"
@@ -749,7 +758,7 @@ msgstr "Fehler beim Einladen des Mitglieds"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Fehler beim Aktualisieren des Anzeigenamens" msgstr "Fehler beim Aktualisieren des Anzeigenamens"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:80
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Fehler beim Aktualisieren des Profilbilds" msgstr "Fehler beim Aktualisieren des Profilbilds"
@@ -774,8 +783,8 @@ msgstr "Fehler beim Upgrade des Abonnements"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Fehler beim Upgrade auf Pro" msgstr "Fehler beim Upgrade auf Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:94
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:221
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Fehler beim Hochladen des Profilbilds" msgstr "Fehler beim Hochladen des Profilbilds"
@@ -1321,7 +1330,7 @@ msgstr "Bitte gib einen gültigen Namen ein"
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Bitte gib ein gültiges Passwort ein" msgstr "Bitte gib ein gültiges Passwort ein"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:95
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Bitte wähle eine Datei zum Hochladen aus." msgstr "Bitte wähle eine Datei zum Hochladen aus."
@@ -1352,8 +1361,8 @@ msgstr "Bitte wähle eine Datei zum Hochladen aus."
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:78
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:131
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:81
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:222
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1391,7 +1400,7 @@ msgstr "Pro-Plan"
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Pro-Plan ∞" msgstr "Pro-Plan ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:67
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Profilbild aktualisiert" msgstr "Profilbild aktualisiert"
@@ -1492,6 +1501,7 @@ msgid "Run on your own infrastructure"
msgstr "Auf eigener Infrastruktur betreiben" msgstr "Auf eigener Infrastruktur betreiben"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:312
msgid "Save" msgid "Save"
msgstr "Speichern" msgstr "Speichern"
@@ -2118,7 +2128,7 @@ msgstr "Dein Anzeigename wurde aktualisiert."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "Ihr Passwort wurde geändert." msgstr "Ihr Passwort wurde geändert."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:68
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "Dein Profilbild wurde aktualisiert." msgstr "Dein Profilbild wurde aktualisiert."

File diff suppressed because one or more lines are too long

View File

@@ -160,6 +160,10 @@ msgstr "added label <0>{0}</0>"
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "Adding a new member will cost an additional {price} ({billingType}) per seat." msgstr "Adding a new member will cost an additional {price} ({billingType}) per seat."
#: src/views/settings/components/Avatar.tsx:278
msgid "Adjust the square crop to fit your avatar."
msgstr "Adjust the square crop to fit your avatar."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Admin roles" msgstr "Admin roles"
@@ -387,6 +391,7 @@ msgstr "Bug Report"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:309
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -592,6 +597,10 @@ msgstr "created the card"
msgid "Critical" msgid "Critical"
msgstr "Critical" msgstr "Critical"
#: src/views/settings/components/Avatar.tsx:275
msgid "Crop your avatar"
msgstr "Crop your avatar"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "Current password is required" msgstr "Current password is required"
@@ -822,7 +831,7 @@ msgstr "Error inviting member"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Error updating display name" msgstr "Error updating display name"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:80
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Error updating profile image" msgstr "Error updating profile image"
@@ -847,8 +856,8 @@ msgstr "Error upgrading subscription"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Error upgrading to Pro" msgstr "Error upgrading to Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:94
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:221
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Error uploading profile image" msgstr "Error uploading profile image"
@@ -1411,7 +1420,7 @@ msgstr "Please enter a valid name"
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Please enter a valid password" msgstr "Please enter a valid password"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:95
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Please select a file to upload." msgstr "Please select a file to upload."
@@ -1442,8 +1451,8 @@ msgstr "Please select a file to upload."
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:78
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:131
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:81
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:222
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1481,7 +1490,7 @@ msgstr "Pro Plan"
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Pro Plan ∞" msgstr "Pro Plan ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:67
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Profile image updated" msgstr "Profile image updated"
@@ -1590,6 +1599,7 @@ msgid "Run on your own infrastructure"
msgstr "Run on your own infrastructure" msgstr "Run on your own infrastructure"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:312
msgid "Save" msgid "Save"
msgstr "Save" msgstr "Save"
@@ -2240,7 +2250,7 @@ msgstr "Your display name has been updated."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "Your password has been changed." msgstr "Your password has been changed."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:68
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "Your profile image has been updated." msgstr "Your profile image has been updated."

File diff suppressed because one or more lines are too long

View File

@@ -140,6 +140,10 @@ msgstr "añadió la etiqueta <0>{0}</0>"
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "Añadir un nuevo miembro costará {price} adicionales ({billingType}) por asiento." msgstr "Añadir un nuevo miembro costará {price} adicionales ({billingType}) por asiento."
#: src/views/settings/components/Avatar.tsx:278
msgid "Adjust the square crop to fit your avatar."
msgstr "Ajusta el recorte cuadrado para que se adapte a tu avatar."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Roles de administrador" msgstr "Roles de administrador"
@@ -338,6 +342,7 @@ msgstr "Informe de error"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:309
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -527,6 +532,10 @@ msgstr "creó la tarjeta"
msgid "Critical" msgid "Critical"
msgstr "Crítico" msgstr "Crítico"
#: src/views/settings/components/Avatar.tsx:275
msgid "Crop your avatar"
msgstr "Recorta tu avatar"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "Se requiere la contraseña actual" msgstr "Se requiere la contraseña actual"
@@ -749,7 +758,7 @@ msgstr "Error al invitar al miembro"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Error al actualizar el nombre visible" msgstr "Error al actualizar el nombre visible"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:80
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Error al actualizar la imagen de perfil" msgstr "Error al actualizar la imagen de perfil"
@@ -774,8 +783,8 @@ msgstr "Error al actualizar la suscripción"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Error al actualizar a Pro" msgstr "Error al actualizar a Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:94
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:221
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Error al subir la imagen de perfil" msgstr "Error al subir la imagen de perfil"
@@ -1321,7 +1330,7 @@ msgstr "Por favor, introduce un nombre válido"
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Por favor, introduce una contraseña válida" msgstr "Por favor, introduce una contraseña válida"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:95
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Por favor selecciona un archivo para subir." msgstr "Por favor selecciona un archivo para subir."
@@ -1352,8 +1361,8 @@ msgstr "Por favor selecciona un archivo para subir."
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:78
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:131
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:81
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:222
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1391,7 +1400,7 @@ msgstr "Plan Pro"
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Plan Pro ∞" msgstr "Plan Pro ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:67
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Imagen de perfil actualizada" msgstr "Imagen de perfil actualizada"
@@ -1492,6 +1501,7 @@ msgid "Run on your own infrastructure"
msgstr "Ejecuta en tu propia infraestructura" msgstr "Ejecuta en tu propia infraestructura"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:312
msgid "Save" msgid "Save"
msgstr "Guardar" msgstr "Guardar"
@@ -2118,7 +2128,7 @@ msgstr "Tu nombre de visualización ha sido actualizado."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "Tu contraseña ha sido cambiada." msgstr "Tu contraseña ha sido cambiada."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:68
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "Tu imagen de perfil ha sido actualizada." msgstr "Tu imagen de perfil ha sido actualizada."

File diff suppressed because one or more lines are too long

View File

@@ -140,6 +140,10 @@ msgstr "a ajouté l'étiquette <0>{0}</0>"
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "L'ajout d'un nouveau membre coûtera {price} supplémentaires ({billingType}) par siège." msgstr "L'ajout d'un nouveau membre coûtera {price} supplémentaires ({billingType}) par siège."
#: src/views/settings/components/Avatar.tsx:278
msgid "Adjust the square crop to fit your avatar."
msgstr "Ajustez le recadrage carré pour adapter votre avatar."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Rôles d'administrateur" msgstr "Rôles d'administrateur"
@@ -338,6 +342,7 @@ msgstr "Rapport de bug"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:309
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -527,6 +532,10 @@ msgstr "a créé la carte"
msgid "Critical" msgid "Critical"
msgstr "Critique" msgstr "Critique"
#: src/views/settings/components/Avatar.tsx:275
msgid "Crop your avatar"
msgstr "Recadrez votre avatar"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "Le mot de passe actuel est requis" msgstr "Le mot de passe actuel est requis"
@@ -749,7 +758,7 @@ msgstr "Erreur lors de l'invitation du membre"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Erreur lors de la mise à jour du nom d'affichage" msgstr "Erreur lors de la mise à jour du nom d'affichage"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:80
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Erreur lors de la mise à jour de l'image de profil" msgstr "Erreur lors de la mise à jour de l'image de profil"
@@ -774,8 +783,8 @@ msgstr "Erreur lors de la mise à niveau de l'abonnement"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Erreur lors de la mise à niveau vers Pro" msgstr "Erreur lors de la mise à niveau vers Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:94
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:221
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Erreur lors du téléchargement de l'image de profil" msgstr "Erreur lors du téléchargement de l'image de profil"
@@ -1321,7 +1330,7 @@ msgstr "Veuillez saisir un nom valide"
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Veuillez saisir un mot de passe valide" msgstr "Veuillez saisir un mot de passe valide"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:95
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Veuillez sélectionner un fichier à télécharger." msgstr "Veuillez sélectionner un fichier à télécharger."
@@ -1352,8 +1361,8 @@ msgstr "Veuillez sélectionner un fichier à télécharger."
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:78
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:131
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:81
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:222
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1391,7 +1400,7 @@ msgstr "Plan Pro"
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Plan Pro ∞" msgstr "Plan Pro ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:67
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Image de profil mise à jour" msgstr "Image de profil mise à jour"
@@ -1492,6 +1501,7 @@ msgid "Run on your own infrastructure"
msgstr "Exécutez sur votre propre infrastructure" msgstr "Exécutez sur votre propre infrastructure"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:312
msgid "Save" msgid "Save"
msgstr "Enregistrer" msgstr "Enregistrer"
@@ -2118,7 +2128,7 @@ msgstr "Votre nom d'affichage a été mis à jour."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "Votre mot de passe a été modifié." msgstr "Votre mot de passe a été modifié."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:68
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "Votre image de profil a été mise à jour." msgstr "Votre image de profil a été mise à jour."

File diff suppressed because one or more lines are too long

View File

@@ -140,6 +140,10 @@ msgstr "ha aggiunto l'etichetta <0>{0}</0>"
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "L'aggiunta di un nuovo membro costerà un supplemento di {price} ({billingType}) per posto." msgstr "L'aggiunta di un nuovo membro costerà un supplemento di {price} ({billingType}) per posto."
#: src/views/settings/components/Avatar.tsx:278
msgid "Adjust the square crop to fit your avatar."
msgstr "Regola il ritaglio quadrato per adattarlo al tuo avatar."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Ruoli amministratore" msgstr "Ruoli amministratore"
@@ -338,6 +342,7 @@ msgstr "Segnalazione bug"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:309
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -527,6 +532,10 @@ msgstr "ha creato la carta"
msgid "Critical" msgid "Critical"
msgstr "Critico" msgstr "Critico"
#: src/views/settings/components/Avatar.tsx:275
msgid "Crop your avatar"
msgstr "Ritaglia il tuo avatar"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "La password attuale è obbligatoria" msgstr "La password attuale è obbligatoria"
@@ -749,7 +758,7 @@ msgstr "Errore durante l'invito del membro"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Errore durante l'aggiornamento del nome visualizzato" msgstr "Errore durante l'aggiornamento del nome visualizzato"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:80
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Errore durante l'aggiornamento dell'immagine del profilo" msgstr "Errore durante l'aggiornamento dell'immagine del profilo"
@@ -774,8 +783,8 @@ msgstr "Errore nell'aggiornamento dell'abbonamento"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Errore durante l'aggiornamento a Pro" msgstr "Errore durante l'aggiornamento a Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:94
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:221
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Errore durante il caricamento dell'immagine del profilo" msgstr "Errore durante il caricamento dell'immagine del profilo"
@@ -1321,7 +1330,7 @@ msgstr "Inserisci un nome valido"
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Inserisci una password valida" msgstr "Inserisci una password valida"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:95
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Seleziona un file da caricare." msgstr "Seleziona un file da caricare."
@@ -1352,8 +1361,8 @@ msgstr "Seleziona un file da caricare."
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:78
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:131
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:81
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:222
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1391,7 +1400,7 @@ msgstr "Piano Pro"
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Piano Pro ∞" msgstr "Piano Pro ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:67
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Immagine del profilo aggiornata" msgstr "Immagine del profilo aggiornata"
@@ -1492,6 +1501,7 @@ msgid "Run on your own infrastructure"
msgstr "Esegui sulla tua infrastruttura" msgstr "Esegui sulla tua infrastruttura"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:312
msgid "Save" msgid "Save"
msgstr "Salva" msgstr "Salva"
@@ -2118,7 +2128,7 @@ msgstr "Il tuo nome visualizzato è stato aggiornato."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "La tua password è stata modificata." msgstr "La tua password è stata modificata."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:68
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "La tua immagine del profilo è stata aggiornata." msgstr "La tua immagine del profilo è stata aggiornata."

File diff suppressed because one or more lines are too long

View File

@@ -140,6 +140,10 @@ msgstr "heeft label <0>{0}</0> toegevoegd"
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "Het toevoegen van een nieuw lid kost een extra {price} ({billingType}) per plaats." msgstr "Het toevoegen van een nieuw lid kost een extra {price} ({billingType}) per plaats."
#: src/views/settings/components/Avatar.tsx:278
msgid "Adjust the square crop to fit your avatar."
msgstr "Pas de vierkante uitsnede aan zodat je avatar goed past."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Beheerdersrollen" msgstr "Beheerdersrollen"
@@ -338,6 +342,7 @@ msgstr "Bugrapport"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:309
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -527,6 +532,10 @@ msgstr "heeft de kaart aangemaakt"
msgid "Critical" msgid "Critical"
msgstr "Kritiek" msgstr "Kritiek"
#: src/views/settings/components/Avatar.tsx:275
msgid "Crop your avatar"
msgstr "Snijd je avatar bij"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "Huidig wachtwoord is vereist" msgstr "Huidig wachtwoord is vereist"
@@ -749,7 +758,7 @@ msgstr "Fout bij het uitnodigen van lid"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Fout bij bijwerken weergavenaam" msgstr "Fout bij bijwerken weergavenaam"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:80
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Fout bij het bijwerken van profielafbeelding" msgstr "Fout bij het bijwerken van profielafbeelding"
@@ -774,8 +783,8 @@ msgstr "Fout bij het upgraden van abonnement"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Fout bij upgraden naar Pro" msgstr "Fout bij upgraden naar Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:94
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:221
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Fout bij het uploaden van profielafbeelding" msgstr "Fout bij het uploaden van profielafbeelding"
@@ -1321,7 +1330,7 @@ msgstr "Voer een geldige naam in"
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Voer een geldig wachtwoord in" msgstr "Voer een geldig wachtwoord in"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:95
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Selecteer een bestand om te uploaden." msgstr "Selecteer een bestand om te uploaden."
@@ -1352,8 +1361,8 @@ msgstr "Selecteer een bestand om te uploaden."
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:78
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:131
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:81
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:222
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1391,7 +1400,7 @@ msgstr "Pro Plan"
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Pro Plan ∞" msgstr "Pro Plan ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:67
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Profielafbeelding bijgewerkt" msgstr "Profielafbeelding bijgewerkt"
@@ -1492,6 +1501,7 @@ msgid "Run on your own infrastructure"
msgstr "Draai op je eigen infrastructuur" msgstr "Draai op je eigen infrastructuur"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:312
msgid "Save" msgid "Save"
msgstr "Opslaan" msgstr "Opslaan"
@@ -2118,7 +2128,7 @@ msgstr "Je weergavenaam is bijgewerkt."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "Je wachtwoord is gewijzigd." msgstr "Je wachtwoord is gewijzigd."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:68
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "Je profielafbeelding is bijgewerkt." msgstr "Je profielafbeelding is bijgewerkt."

File diff suppressed because one or more lines are too long

View File

@@ -140,6 +140,10 @@ msgstr "добавлена метка <0>{0}</0>"
msgid "Adding a new member will cost an additional {price} ({billingType}) per seat." msgid "Adding a new member will cost an additional {price} ({billingType}) per seat."
msgstr "Добавление нового участника будет стоить дополнительно {price} ({billingType}) за место." msgstr "Добавление нового участника будет стоить дополнительно {price} ({billingType}) за место."
#: src/views/settings/components/Avatar.tsx:278
msgid "Adjust the square crop to fit your avatar."
msgstr "Настройте квадратное кадрирование, чтобы оно подходило для вашего аватара."
#: src/views/home/components/Pricing.tsx:55 #: src/views/home/components/Pricing.tsx:55
msgid "Admin roles" msgid "Admin roles"
msgstr "Роли администратора" msgstr "Роли администратора"
@@ -338,6 +342,7 @@ msgstr "Отчет об ошибке"
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63 #: src/views/card/components/DeleteChecklistConfirmation.tsx:63
#: src/views/card/components/DeleteCommentConfirmation.tsx:76 #: src/views/card/components/DeleteCommentConfirmation.tsx:76
#: src/views/members/components/DeleteMemberConfirmation.tsx:55 #: src/views/members/components/DeleteMemberConfirmation.tsx:55
#: src/views/settings/components/Avatar.tsx:309
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168 #: src/views/settings/components/ChangePasswordConfirmation.tsx:168
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88 #: src/views/settings/components/DeleteAccountConfirmation.tsx:88
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
@@ -527,6 +532,10 @@ msgstr "создал(а) карточку"
msgid "Critical" msgid "Critical"
msgstr "Критический" msgstr "Критический"
#: src/views/settings/components/Avatar.tsx:275
msgid "Crop your avatar"
msgstr "Обрежьте ваш аватар"
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19 #: src/views/settings/components/ChangePasswordConfirmation.tsx:19
msgid "Current password is required" msgid "Current password is required"
msgstr "Требуется текущий пароль" msgstr "Требуется текущий пароль"
@@ -749,7 +758,7 @@ msgstr "Ошибка при приглашении участника"
msgid "Error updating display name" msgid "Error updating display name"
msgstr "Ошибка при обновлении отображаемого имени" msgstr "Ошибка при обновлении отображаемого имени"
#: src/views/settings/components/Avatar.tsx:39 #: src/views/settings/components/Avatar.tsx:80
msgid "Error updating profile image" msgid "Error updating profile image"
msgstr "Ошибка при обновлении изображения профиля" msgstr "Ошибка при обновлении изображения профиля"
@@ -774,8 +783,8 @@ msgstr "Ошибка при обновлении подписки"
msgid "Error upgrading to Pro" msgid "Error upgrading to Pro"
msgstr "Ошибка при обновлении до Pro" msgstr "Ошибка при обновлении до Pro"
#: src/views/settings/components/Avatar.tsx:56 #: src/views/settings/components/Avatar.tsx:94
#: src/views/settings/components/Avatar.tsx:97 #: src/views/settings/components/Avatar.tsx:221
msgid "Error uploading profile image" msgid "Error uploading profile image"
msgstr "Ошибка загрузки изображения профиля" msgstr "Ошибка загрузки изображения профиля"
@@ -1280,6 +1289,10 @@ msgstr "Пароль должен содержать не менее 8 симв
msgid "Passwords do not match" msgid "Passwords do not match"
msgstr "Пароли не совпадают" msgstr "Пароли не совпадают"
#: src/views/members/index.tsx:134
msgid "Paused"
msgstr "Приостановлено"
#: src/views/home/components/Pricing.tsx:102 #: src/views/home/components/Pricing.tsx:102
msgid "Payment frequency" msgid "Payment frequency"
msgstr "Частота платежей" msgstr "Частота платежей"
@@ -1317,7 +1330,7 @@ msgstr "Пожалуйста, введите действительное имя
msgid "Please enter a valid password" msgid "Please enter a valid password"
msgstr "Пожалуйста, введите действительный пароль" msgstr "Пожалуйста, введите действительный пароль"
#: src/views/settings/components/Avatar.tsx:57 #: src/views/settings/components/Avatar.tsx:95
msgid "Please select a file to upload." msgid "Please select a file to upload."
msgstr "Пожалуйста, выберите файл для загрузки." msgstr "Пожалуйста, выберите файл для загрузки."
@@ -1348,8 +1361,8 @@ msgstr "Пожалуйста, выберите файл для загрузки.
#: src/views/members/components/DeleteMemberConfirmation.tsx:28 #: src/views/members/components/DeleteMemberConfirmation.tsx:28
#: src/views/members/components/InviteMemberForm.tsx:78 #: src/views/members/components/InviteMemberForm.tsx:78
#: src/views/members/components/InviteMemberForm.tsx:131 #: src/views/members/components/InviteMemberForm.tsx:131
#: src/views/settings/components/Avatar.tsx:40 #: src/views/settings/components/Avatar.tsx:81
#: src/views/settings/components/Avatar.tsx:98 #: src/views/settings/components/Avatar.tsx:222
#: src/views/settings/components/DeleteAccountConfirmation.tsx:40 #: src/views/settings/components/DeleteAccountConfirmation.tsx:40
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46 #: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:46
#: src/views/settings/components/UpdateDisplayNameForm.tsx:55 #: src/views/settings/components/UpdateDisplayNameForm.tsx:55
@@ -1387,7 +1400,7 @@ msgstr "Профессиональный план"
msgid "Pro Plan ∞" msgid "Pro Plan ∞"
msgstr "Профессиональный план ∞" msgstr "Профессиональный план ∞"
#: src/views/settings/components/Avatar.tsx:26 #: src/views/settings/components/Avatar.tsx:67
msgid "Profile image updated" msgid "Profile image updated"
msgstr "Изображение профиля обновлено" msgstr "Изображение профиля обновлено"
@@ -1488,6 +1501,7 @@ msgid "Run on your own infrastructure"
msgstr "Запустите на своей инфраструктуре" msgstr "Запустите на своей инфраструктуре"
#: src/views/card/components/Comment.tsx:165 #: src/views/card/components/Comment.tsx:165
#: src/views/settings/components/Avatar.tsx:312
msgid "Save" msgid "Save"
msgstr "Сохранить" msgstr "Сохранить"
@@ -2114,7 +2128,7 @@ msgstr "Ваше отображаемое имя было обновлено."
msgid "Your password has been changed." msgid "Your password has been changed."
msgstr "Ваш пароль был изменён." msgstr "Ваш пароль был изменён."
#: src/views/settings/components/Avatar.tsx:27 #: src/views/settings/components/Avatar.tsx:68
msgid "Your profile image has been updated." msgid "Your profile image has been updated."
msgstr "Ваше изображение профиля было обновлено." msgstr "Ваше изображение профиля было обновлено."

File diff suppressed because one or more lines are too long

View File

@@ -7,6 +7,7 @@ import type { ReactElement, ReactNode } from "react";
import { Plus_Jakarta_Sans } from "next/font/google"; import { Plus_Jakarta_Sans } from "next/font/google";
import Script from "next/script"; import Script from "next/script";
import { env } from "next-runtime-env"; import { env } from "next-runtime-env";
import { ThemeProvider } from "next-themes";
import posthog from "posthog-js"; import posthog from "posthog-js";
import { PostHogProvider } from "posthog-js/react"; import { PostHogProvider } from "posthog-js/react";
import { useEffect } from "react"; import { useEffect } from "react";
@@ -14,7 +15,6 @@ import { useEffect } from "react";
import { LinguiProviderWrapper } from "~/providers/lingui"; import { LinguiProviderWrapper } from "~/providers/lingui";
import { ModalProvider } from "~/providers/modal"; import { ModalProvider } from "~/providers/modal";
import { PopupProvider } from "~/providers/popup"; import { PopupProvider } from "~/providers/popup";
import { ThemeProvider } from "next-themes";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
const jakarta = Plus_Jakarta_Sans({ const jakarta = Plus_Jakarta_Sans({
@@ -82,8 +82,8 @@ const MyApp: AppType = ({ Component, pageProps }: AppPropsWithLayout) => {
<main className="font-sans"> <main className="font-sans">
<LinguiProviderWrapper> <LinguiProviderWrapper>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem> <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<ModalProvider> <ModalProvider>
<PopupProvider> <PopupProvider>
{posthogKey ? ( {posthogKey ? (
<PostHogProvider client={posthog}> <PostHogProvider client={posthog}>
{getLayout(<Component {...pageProps} />)} {getLayout(<Component {...pageProps} />)}
@@ -91,8 +91,8 @@ const MyApp: AppType = ({ Component, pageProps }: AppPropsWithLayout) => {
) : ( ) : (
getLayout(<Component {...pageProps} />) getLayout(<Component {...pageProps} />)
)} )}
</PopupProvider> </PopupProvider>
</ModalProvider> </ModalProvider>
</ThemeProvider> </ThemeProvider>
</LinguiProviderWrapper> </LinguiProviderWrapper>
</main> </main>

View File

@@ -1,14 +1,45 @@
import Image from "next/image"; import Image from "next/image";
import { t } from "@lingui/core/macro"; import { t } from "@lingui/core/macro";
import { env } from "next-runtime-env"; import { env } from "next-runtime-env";
import { useState } from "react"; import { useCallback, useRef, useState } from "react";
import ReactCrop from "react-image-crop";
import "react-image-crop/dist/ReactCrop.css";
import { generateUID } from "@kan/shared/utils"; import { generateUID } from "@kan/shared/utils";
import Button from "~/components/Button";
import Modal from "~/components/modal";
import { usePopup } from "~/providers/popup"; import { usePopup } from "~/providers/popup";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
import { getAvatarUrl } from "~/utils/helpers"; import { getAvatarUrl } from "~/utils/helpers";
interface PercentCrop {
unit: "%";
x: number;
y: number;
width: number;
height: number;
}
interface LocalPixelCrop {
x: number;
y: number;
width: number;
height: number;
}
interface ReactCropProps {
crop: PercentCrop | undefined;
onChange: (crop: LocalPixelCrop, percentCrop: PercentCrop) => void;
aspect?: number;
className?: string;
circularCrop?: boolean;
children: React.ReactNode;
}
const AnyReactCrop = ReactCrop as unknown as React.FC<ReactCropProps>;
export default function Avatar({ export default function Avatar({
userId, userId,
userImage, userImage,
@@ -19,6 +50,13 @@ export default function Avatar({
const utils = api.useUtils(); const utils = api.useUtils();
const { showPopup } = usePopup(); const { showPopup } = usePopup();
const [uploading, setUploading] = useState(false); const [uploading, setUploading] = useState(false);
const [cropDialogOpen, setCropDialogOpen] = useState(false);
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [selectedPreviewUrl, setSelectedPreviewUrl] = useState<string | null>(
null,
);
const [crop, setCrop] = useState<PercentCrop>();
const imgRef = useRef<HTMLImageElement | null>(null);
const updateUser = api.user.update.useMutation({ const updateUser = api.user.update.useMutation({
onSuccess: async () => { onSuccess: async () => {
@@ -45,24 +83,109 @@ export default function Avatar({
const avatarUrl = userImage ? getAvatarUrl(userImage) : undefined; const avatarUrl = userImage ? getAvatarUrl(userImage) : undefined;
const uploadAvatar = async (event: React.ChangeEvent<HTMLInputElement>) => { const onFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
try { event.preventDefault();
event.preventDefault(); const file = event.target.files?.[0] ?? null;
if (!file || !userId) {
return showPopup({
header: t`Error uploading profile image`,
message: t`Please select a file to upload.`,
icon: "error",
});
}
// Open crop dialog with preview
setSelectedFile(file);
const objUrl = URL.createObjectURL(file);
setSelectedPreviewUrl(objUrl);
setCropDialogOpen(true);
};
const file = event.target.files?.[0]; const onImageLoad = useCallback(
(e: React.SyntheticEvent<HTMLImageElement>) => {
if (!file || !userId) { const { naturalWidth, naturalHeight } = e.currentTarget;
return showPopup({ // Create a centered square crop at ~90% of the smaller dimension
header: t`Error uploading profile image`, // Compute width% so that the square fits within the image
message: t`Please select a file to upload.`, let widthPercent: number;
icon: "error", let heightPercent: number;
}); if (naturalWidth >= naturalHeight) {
// landscape: height is limiting
heightPercent = 90;
widthPercent = (naturalHeight / naturalWidth) * heightPercent;
} else {
// portrait: width is limiting
widthPercent = 90;
heightPercent = (naturalWidth / naturalHeight) * widthPercent;
} }
const x = (100 - widthPercent) / 2;
const y = (100 - heightPercent) / 2;
setCrop({ unit: "%", x, y, width: widthPercent, height: heightPercent });
},
[],
);
const fileExt = file.name.split(".").pop(); const getCroppedBlob = useCallback(async (): Promise<Blob> => {
const fileName = `${userId}/avatar-${generateUID()}.${fileExt}`; if (!imgRef.current || !crop) throw new Error("No crop to save");
const image = imgRef.current;
const canvas = document.createElement("canvas");
const cropXpx = (crop.x / 100) * image.naturalWidth;
const cropYpx = (crop.y / 100) * image.naturalHeight;
const cropWpx = (crop.width / 100) * image.naturalWidth;
const cropHpx = (crop.height / 100) * image.naturalHeight;
canvas.width = Math.max(1, Math.floor(cropWpx));
canvas.height = Math.max(1, Math.floor(cropHpx));
const ctx = canvas.getContext("2d");
if (!ctx) throw new Error("Canvas not supported");
// For better quality on HiDPI screens
const pixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.width * pixelRatio;
canvas.height = canvas.height * pixelRatio;
ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
ctx.imageSmoothingQuality = "high";
ctx.drawImage(
image,
cropXpx,
cropYpx,
cropWpx,
cropHpx,
0,
0,
canvas.width / pixelRatio,
canvas.height / pixelRatio,
);
const mime = selectedFile?.type ?? "image/jpeg";
const blob: Blob = await new Promise((resolve, reject) => {
canvas.toBlob(
(b) => (b ? resolve(b) : reject(new Error("toBlob failed"))),
mime,
);
});
return blob;
}, [crop, selectedFile]);
const resetCropState = useCallback(() => {
setCrop(undefined);
setSelectedFile(null);
if (selectedPreviewUrl) URL.revokeObjectURL(selectedPreviewUrl);
setSelectedPreviewUrl(null);
}, [selectedPreviewUrl]);
const handleCancelCrop = useCallback(() => {
setCropDialogOpen(false);
resetCropState();
}, [resetCropState]);
const handleSaveCrop = useCallback(async () => {
try {
if (!userId || !selectedFile) return;
setUploading(true); setUploading(true);
const blob = await getCroppedBlob();
const originalExt = selectedFile.name.split(".").pop() ?? "jpg";
const fileName = `${userId}/avatar-${generateUID()}.${originalExt}`;
const response = await fetch( const response = await fetch(
env("NEXT_PUBLIC_BASE_URL") + "/api/upload/image", env("NEXT_PUBLIC_BASE_URL") + "/api/upload/image",
@@ -71,26 +194,24 @@ export default function Avatar({
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ filename: fileName, contentType: file.type }), body: JSON.stringify({ filename: fileName, contentType: blob.type }),
}, },
); );
if (!response.ok) throw new Error("Failed to get pre-signed URL"); if (!response.ok) throw new Error("Failed to get pre-signed URL");
const { url } = (await response.json()) as { const { url } = (await response.json()) as { url: string };
url: string;
};
const uploadResponse = await fetch(url, { const uploadResponse = await fetch(url, {
method: "PUT", method: "PUT",
body: file, body: blob,
}); });
if (!uploadResponse.ok) throw new Error("Failed to upload profile image"); if (!uploadResponse.ok) throw new Error("Failed to upload profile image");
updateUser.mutate({ updateUser.mutate({ image: fileName });
image: fileName, setCropDialogOpen(false);
}); resetCropState();
} catch (error) { } catch (error) {
console.error(error); console.error(error);
showPopup({ showPopup({
@@ -101,7 +222,14 @@ export default function Avatar({
} finally { } finally {
setUploading(false); setUploading(false);
} }
}; }, [
getCroppedBlob,
resetCropState,
selectedFile,
showPopup,
updateUser,
userId,
]);
return ( return (
<div> <div>
@@ -111,7 +239,7 @@ export default function Avatar({
type="file" type="file"
id="single" id="single"
accept="image/*" accept="image/*"
onChange={uploadAvatar} onChange={onFileChange}
disabled={uploading} disabled={uploading}
/> />
{avatarUrl ? ( {avatarUrl ? (
@@ -134,6 +262,56 @@ export default function Avatar({
</span> </span>
)} )}
</div> </div>
{/* Crop Dialog */}
{cropDialogOpen && (
<Modal modalSize="md" positionFromTop="sm" isVisible>
<div className="p-4 sm:p-6">
<div className="mb-4">
<h3 className="text-base font-semibold text-light-1000 dark:text-dark-1000">
{t`Crop your avatar`}
</h3>
<p className="mt-1 text-sm text-light-800 dark:text-dark-800">
{t`Adjust the square crop to fit your avatar.`}
</p>
</div>
<div className="max-h-[80vh]">
<div className="rounded-md border border-light-600 p-2 dark:border-dark-600">
<AnyReactCrop
crop={crop}
onChange={(_crop: LocalPixelCrop, percentCrop: PercentCrop) =>
setCrop(percentCrop)
}
aspect={1}
circularCrop
className="w-full"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
ref={imgRef}
src={selectedPreviewUrl ?? undefined}
alt="Avatar to crop"
onLoad={onImageLoad}
className="h-auto max-h-[50vh] w-full object-contain"
/>
</AnyReactCrop>
</div>
</div>
<div className="mt-6 flex items-center justify-end gap-2">
<Button
variant="ghost"
onClick={handleCancelCrop}
disabled={uploading}
>
{t`Cancel`}
</Button>
<Button onClick={handleSaveCrop} isLoading={uploading}>
{t`Save`}
</Button>
</div>
</div>
</Modal>
)}
</div> </div>
); );
} }

12
pnpm-lock.yaml generated
View File

@@ -205,6 +205,9 @@ importers:
react-icons: react-icons:
specifier: ^5.5.0 specifier: ^5.5.0
version: 5.5.0(react@18.3.1) version: 5.5.0(react@18.3.1)
react-image-crop:
specifier: ^11.0.10
version: 11.0.10(react@18.3.1)
react-lottie-player: react-lottie-player:
specifier: ^1.5.5 specifier: ^1.5.5
version: 1.5.6(react@18.3.1) version: 1.5.6(react@18.3.1)
@@ -6116,6 +6119,11 @@ packages:
peerDependencies: peerDependencies:
react: '*' react: '*'
react-image-crop@11.0.10:
resolution: {integrity: sha512-+5FfDXUgYLLqBh1Y/uQhIycpHCbXkI50a+nbfkB1C0xXXUTwkisHDo2QCB1SQJyHCqIuia4FeyReqXuMDKWQTQ==}
peerDependencies:
react: '>=16.13.1'
react-is@16.13.1: react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
@@ -13696,6 +13704,10 @@ snapshots:
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
react-image-crop@11.0.10(react@18.3.1):
dependencies:
react: 18.3.1
react-is@16.13.1: {} react-is@16.13.1: {}
react-is@17.0.2: {} react-is@17.0.2: {}