From 5acdf79c8d43a2d73b9e52da9b94103732e9c0c5 Mon Sep 17 00:00:00 2001 From: khannurien Date: Thu, 8 Oct 2026 22:05:43 +0000 Subject: [PATCH] =?UTF-8?q?v4:=20the=20playlist=20and=20dump=20edit=20form?= =?UTF-8?q?s=20end=20in=20one=20bar=20of=20actions,=20a=20panel=20of=20its?= =?UTF-8?q?=20own=20=E2=80=94=20the=20playlist=20editor=20drew=20rules=20b?= =?UTF-8?q?etween=20its=20fields=20and=20its=20actions,=20and=20on=20a=20p?= =?UTF-8?q?hone=20its=20Delete,=20Cancel=20and=20Save=20wrapped=20into=20a?= =?UTF-8?q?=20staircase,=20then=20stacked=20(a0c8b1d),=20neither=20of=20wh?= =?UTF-8?q?ich=20held=20together.=20Both=20forms=20are=20now=20built=20as?= =?UTF-8?q?=20DumpEdit=20was:=20surface=20panels=203px=20apart=20(.form-pa?= =?UTF-8?q?nel,=20from=20.dump-edit-panel),=20the=20last=20a=20bar=20(.for?= =?UTF-8?q?m-panel--bar,=20from=20.dump-edit-footer)=20holding=20Delete=20?= =?UTF-8?q?on=20the=20left=20and=20Cancel=20and=20Save=20on=20the=20right,?= =?UTF-8?q?=20compact=20(btn-sm),=20on=20one=20line.=20The=20new=20DeleteB?= =?UTF-8?q?utton=20says=20"Delete"=20and=20names=20what=20goes=20to=20assi?= =?UTF-8?q?stive=20tech=20("Delete=20playlist",=20"Delete=20dump");=20in?= =?UTF-8?q?=20a=20bar=20too=20narrow=20for=20the=20three=20labels=20in=20e?= =?UTF-8?q?very=20face=20and=20language=20(a=20container=20query,=20under?= =?UTF-8?q?=2018rem),=20it=20shows=20=F0=9F=97=91=20instead.=20While=20edi?= =?UTF-8?q?ted,=20the=20playlist's=20header=20drops=20its=20own=20card=20f?= =?UTF-8?q?or=20the=20form's=20panels.=20The=20phone=20stacking=20rule=20i?= =?UTF-8?q?s=20gone.=20An=20auto-sized=20editor=20also=20re-fits=20when=20?= =?UTF-8?q?its=20width=20changes=20with=20its=20text=20unchanged:=20openin?= =?UTF-8?q?g=20the=20form=20makes=20the=20page=20tall=20enough=20for=20a?= =?UTF-8?q?=20scrollbar,=20which=20narrowed=20the=20description=20after=20?= =?UTF-8?q?it=20was=20measured,=20so=20it=20overflowed;=20and=20it=20hides?= =?UTF-8?q?=20its=20overflow=20below=20its=20max-height,=20where=20a=20scr?= =?UTF-8?q?ollbar=20could=20only=20come=20of=20rounding,=20and=20drops=20t?= =?UTF-8?q?he=20resize=20grip,=20which=20the=20next=20keystroke=20would=20?= =?UTF-8?q?undo.=20669=20frontend=20tests=20pass,=20and=20tsc,=20eslint,?= =?UTF-8?q?=20deno=20fmt,=20doc:lint=20and=20i18n:compile=20--strict=20are?= =?UTF-8?q?=20clean;=20checked=20in=20screenshots=20in=20Kanagawa=20dark?= =?UTF-8?q?=20(French,=20385=20and=20360px),=20Smooth=20light=20at=201000p?= =?UTF-8?q?x=20and=20DumpEdit=20in=20Smooth=20at=20390px.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- locales/en.po | 107 +++++++------- locales/fr.po | 107 +++++++------- src/App.css | 67 +++++---- src/components/editor/TextEditor.tsx | 43 ++++-- src/components/form/DeleteButton.tsx | 40 +++++ src/components/playlist/PlaylistEditForm.tsx | 145 ++++++++++--------- src/pages/DumpEdit.tsx | 17 +-- src/pages/PlaylistDetail.tsx | 7 +- src/test/pages/PlaylistDetail.test.tsx | 4 +- 9 files changed, 313 insertions(+), 224 deletions(-) create mode 100644 src/components/form/DeleteButton.tsx diff --git a/locales/en.po b/locales/en.po index ef3cc7b0..0b23add8 100644 --- a/locales/en.po +++ b/locales/en.po @@ -427,7 +427,7 @@ msgstr "← Back" #: src/pages/Dump.tsx:326 #: src/pages/Dump.tsx:568 -#: src/pages/DumpEdit.tsx:231 +#: src/pages/DumpEdit.tsx:232 msgid "← Back to all dumps" msgstr "← Back to all dumps" @@ -589,12 +589,12 @@ msgstr "Can't connect to the live updates server. Upvotes and notifications may #: src/components/comment/CommentForm.tsx:127 #: src/components/dump/create/DumpCreateModal.tsx:752 #: src/components/form/FormActions.tsx:42 -#: src/components/playlist/PlaylistEditForm.tsx:194 +#: src/components/playlist/PlaylistEditForm.tsx:199 #: src/components/profile/DescriptionEditor.tsx:97 #: src/components/profile/EmailEditor.tsx:83 #: src/components/shared/ConfirmModal.tsx:63 #: src/pages/Dump.tsx:445 -#: src/pages/DumpEdit.tsx:570 +#: src/pages/DumpEdit.tsx:565 msgid "Cancel" msgstr "Cancel" @@ -607,7 +607,7 @@ msgstr "Cancel removal" msgid "Cancel reply" msgstr "Cancel reply" -#: src/components/layout/AppHeader.tsx:164 +#: src/components/layout/AppHeader.tsx:190 msgid "Cancel search" msgstr "Cancel search" @@ -642,13 +642,13 @@ msgid "Change skin tone" msgstr "Change skin tone" #: src/components/chat/ChatModal.tsx:716 -#: src/components/layout/ChatButton.tsx:27 +#: src/components/layout/ChatButton.tsx:30 #: src/components/layout/ChatFab.tsx:54 #: src/components/layout/ChatFab.tsx:55 msgid "Chat" msgstr "Chat" -#: src/components/layout/ChatButton.tsx:26 +#: src/components/layout/ChatButton.tsx:29 #: src/components/layout/ChatFab.tsx:53 msgid "Chat ({unreadChatCount} unread)" msgstr "Chat ({unreadChatCount} unread)" @@ -712,7 +712,7 @@ msgid "Could not connect to the server. Check your connection and try again." msgstr "Could not connect to the server. Check your connection and try again." #: src/components/profile/ProfilePlaylistsTab.tsx:126 -#: src/pages/DumpEdit.tsx:558 +#: src/pages/DumpEdit.tsx:559 msgid "Could not delete" msgstr "Could not delete" @@ -720,7 +720,7 @@ msgstr "Could not delete" msgid "Could not rename" msgstr "Could not rename" -#: src/pages/DumpEdit.tsx:511 +#: src/pages/DumpEdit.tsx:512 msgid "Could not save" msgstr "Could not save" @@ -740,7 +740,7 @@ msgstr "Couldn't unsubscribe" msgid "Couldn't update. Try again." msgstr "Couldn't update. Try again." -#: src/components/playlist/PlaylistEditForm.tsx:133 +#: src/components/playlist/PlaylistEditForm.tsx:135 msgid "Cover" msgstr "Cover" @@ -775,7 +775,7 @@ msgstr "Default tab" #: src/components/chat/ChatMessageItem.tsx:214 #: src/components/comment/CommentNode.tsx:265 #: src/components/comment/CommentNode.tsx:271 -#: src/components/playlist/PlaylistEditForm.tsx:190 +#: src/components/form/DeleteButton.tsx:36 #: src/components/shared/ConfirmModal.tsx:34 msgid "Delete" msgstr "Delete" @@ -789,19 +789,20 @@ msgstr "Delete category" msgid "Delete category \"{0}\"? This cannot be undone." msgstr "Delete category \"{0}\"? This cannot be undone." -#: src/pages/DumpEdit.tsx:313 -#: src/pages/DumpEdit.tsx:566 +#: src/pages/DumpEdit.tsx:314 +#: src/pages/DumpEdit.tsx:562 msgid "Delete dump" msgstr "Delete dump" #. placeholder {0}: res.status -#: src/pages/DumpEdit.tsx:192 +#: src/pages/DumpEdit.tsx:193 msgid "Delete failed ({0})" msgstr "Delete failed ({0})" #: src/components/playlist/PlaylistCard.tsx:142 +#: src/components/playlist/PlaylistEditForm.tsx:190 #: src/components/profile/ProfilePlaylistsTab.tsx:156 -#: src/pages/PlaylistDetail.tsx:136 +#: src/pages/PlaylistDetail.tsx:141 msgid "Delete playlist" msgstr "Delete playlist" @@ -809,7 +810,7 @@ msgstr "Delete playlist" msgid "Delete this comment?" msgstr "Delete this comment?" -#: src/pages/DumpEdit.tsx:312 +#: src/pages/DumpEdit.tsx:313 msgid "Delete this dump? This cannot be undone." msgstr "Delete this dump? This cannot be undone." @@ -818,7 +819,7 @@ msgid "Delete this message?" msgstr "Delete this message?" #: src/components/profile/ProfilePlaylistsTab.tsx:155 -#: src/pages/PlaylistDetail.tsx:135 +#: src/pages/PlaylistDetail.tsx:140 msgid "Delete this playlist? This cannot be undone." msgstr "Delete this playlist? This cannot be undone." @@ -826,7 +827,7 @@ msgstr "Delete this playlist? This cannot be undone." msgid "deleted message" msgstr "deleted message" -#: src/components/playlist/PlaylistEditForm.tsx:173 +#: src/components/playlist/PlaylistEditForm.tsx:175 msgid "Description" msgstr "Description" @@ -864,11 +865,11 @@ msgstr "Drop a file here" msgid "Drop a file here, or paste one" msgstr "Drop a file here, or paste one" -#: src/pages/DumpEdit.tsx:502 +#: src/pages/DumpEdit.tsx:503 msgid "Drop a replacement here" msgstr "Drop a replacement here" -#: src/components/layout/AppHeader.tsx:203 +#: src/components/layout/AppHeader.tsx:209 msgid "Dump" msgstr "Dump" @@ -946,12 +947,12 @@ msgstr "edited {0}" msgid "Edited {0}" msgstr "Edited {0}" -#: src/pages/DumpEdit.tsx:256 +#: src/pages/DumpEdit.tsx:257 msgid "Editing" msgstr "Editing" #. placeholder {0}: state.dump.title -#: src/pages/DumpEdit.tsx:79 +#: src/pages/DumpEdit.tsx:80 msgid "Editing {0}" msgstr "Editing {0}" @@ -1005,7 +1006,7 @@ msgstr "Failed to post comment" msgid "Failed to post reply" msgstr "Failed to post reply" -#: src/components/playlist/PlaylistEditForm.tsx:182 +#: src/components/playlist/PlaylistEditForm.tsx:184 #: src/components/profile/DescriptionEditor.tsx:99 #: src/components/profile/EmailEditor.tsx:86 msgid "Failed to save" @@ -1113,8 +1114,8 @@ msgstr "image" msgid "In collections" msgstr "In collections" -#: src/components/editor/TextEditor.tsx:544 -#: src/components/editor/TextEditor.tsx:546 +#: src/components/editor/TextEditor.tsx:573 +#: src/components/editor/TextEditor.tsx:575 msgid "Insert emoji" msgstr "Insert emoji" @@ -1175,7 +1176,7 @@ msgstr "Link or file" msgid "Live updates are temporarily disconnected. Trying to reconnect…" msgstr "Live updates are temporarily disconnected. Trying to reconnect…" -#: src/components/layout/AppHeader.tsx:238 +#: src/components/layout/AppHeader.tsx:242 msgid "Live updates unavailable." msgstr "Live updates unavailable." @@ -1188,7 +1189,7 @@ msgid "Load older messages" msgstr "Load older messages" #: src/pages/Dump.tsx:302 -#: src/pages/DumpEdit.tsx:207 +#: src/pages/DumpEdit.tsx:208 msgid "Loading dump…" msgstr "Loading dump…" @@ -1218,7 +1219,7 @@ msgstr "Loading profile…" msgid "Loading…" msgstr "Loading…" -#: src/components/layout/AppHeader.tsx:211 +#: src/components/layout/AppHeader.tsx:216 #: src/pages/UserLogin.tsx:41 #: src/pages/UserLogin.tsx:67 #: src/pages/UserLogin.tsx:86 @@ -1366,14 +1367,14 @@ msgstr "Not following anyone yet." msgid "Nothing here yet." msgstr "Nothing here yet." -#: src/components/layout/NotificationBell.tsx:55 +#: src/components/layout/NotificationBell.tsx:57 #: src/pages/Notifications.tsx:376 #: src/pages/Notifications.tsx:494 #: src/pages/Settings.tsx:128 msgid "Notifications" msgstr "Notifications" -#: src/components/layout/NotificationBell.tsx:54 +#: src/components/layout/NotificationBell.tsx:56 msgid "Notifications ({unreadNotificationCount} unread)" msgstr "Notifications ({unreadNotificationCount} unread)" @@ -1385,11 +1386,11 @@ msgstr "Off" msgid "On" msgstr "On" -#: src/components/editor/TextEditor.tsx:359 +#: src/components/editor/TextEditor.tsx:385 msgid "Only images can be dropped here." msgstr "Only images can be dropped here." -#: src/pages/DumpEdit.tsx:117 +#: src/pages/DumpEdit.tsx:118 msgid "Only its poster or a moderator can edit this dump." msgstr "Only its poster or a moderator can edit this dump." @@ -1463,7 +1464,7 @@ msgid "Play" msgstr "Play" #: src/components/dump/create/StepIndicator.tsx:21 -#: src/components/layout/AppHeader.tsx:184 +#: src/components/layout/AppHeader.tsx:178 #: src/components/layout/UserMenu.tsx:81 #: src/components/profile/ProfileFollowTab.tsx:167 #: src/components/profile/ProfilePlaylistsTab.tsx:118 @@ -1512,7 +1513,7 @@ msgstr "public" msgid "Public" msgstr "Public" -#: src/pages/DumpEdit.tsx:289 +#: src/pages/DumpEdit.tsx:290 msgid "Refresh metadata" msgstr "Refresh metadata" @@ -1520,7 +1521,7 @@ msgstr "Refresh metadata" msgid "Refreshing stream…" msgstr "Refreshing stream…" -#: src/pages/DumpEdit.tsx:288 +#: src/pages/DumpEdit.tsx:289 msgid "Refreshing…" msgstr "Refreshing…" @@ -1566,7 +1567,7 @@ msgstr "Rename" msgid "Renaming…" msgstr "Renaming…" -#: src/pages/DumpEdit.tsx:494 +#: src/pages/DumpEdit.tsx:495 msgid "Replace file" msgstr "Replace file" @@ -1592,8 +1593,8 @@ msgstr "Reset failed" msgid "Reset password" msgstr "Reset password" -#: src/pages/DumpEdit.tsx:470 -#: src/pages/DumpEdit.tsx:525 +#: src/pages/DumpEdit.tsx:471 +#: src/pages/DumpEdit.tsx:526 msgid "Reset to default" msgstr "Reset to default" @@ -1604,7 +1605,7 @@ msgstr "Reset to the suggested title" #: src/components/chat/PendingItem.tsx:86 #: src/pages/Dump.tsx:319 -#: src/pages/DumpEdit.tsx:224 +#: src/pages/DumpEdit.tsx:225 msgid "Retry" msgstr "Retry" @@ -1615,16 +1616,16 @@ msgstr "Role" #: src/components/category/CategoryManager.tsx:216 #: src/components/chat/ChatEditBox.tsx:85 #: src/components/comment/CommentNode.tsx:216 -#: src/components/playlist/PlaylistEditForm.tsx:200 +#: src/components/playlist/PlaylistEditForm.tsx:206 #: src/components/profile/DescriptionEditor.tsx:89 #: src/components/profile/EmailEditor.tsx:75 #: src/pages/Dump.tsx:437 -#: src/pages/DumpEdit.tsx:573 +#: src/pages/DumpEdit.tsx:568 msgid "Save" msgstr "Save" #: src/components/comment/CommentNode.tsx:217 -#: src/components/playlist/PlaylistEditForm.tsx:197 +#: src/components/playlist/PlaylistEditForm.tsx:203 #: src/components/profile/ChangePasswordModal.tsx:119 #: src/components/profile/DescriptionEditor.tsx:86 #: src/components/profile/EmailEditor.tsx:72 @@ -1633,7 +1634,7 @@ msgstr "Save" msgid "Saving…" msgstr "Saving…" -#: src/components/layout/AppHeader.tsx:164 +#: src/components/layout/AppHeader.tsx:190 #: src/components/layout/SearchBar.tsx:83 #: src/pages/Search.tsx:69 msgid "Search" @@ -1676,7 +1677,7 @@ msgstr "Send reset link" msgid "Sending…" msgstr "Sending…" -#: src/components/layout/AppHeader.tsx:200 +#: src/components/layout/AppHeader.tsx:206 msgid "Server unreachable" msgstr "Server unreachable" @@ -1704,14 +1705,14 @@ msgstr "Single use, valid for 7 days." msgid "slug" msgstr "slug" -#: src/components/editor/TextEditor.tsx:317 +#: src/components/editor/TextEditor.tsx:343 msgid "Some images couldn't be uploaded." msgstr "Some images couldn't be uploaded." #: src/components/form/FormError.tsx:31 #: src/components/layout/PageError.tsx:29 #: src/contexts/ws/WSProvider.tsx:729 -#: src/pages/PlaylistDetail.tsx:119 +#: src/pages/PlaylistDetail.tsx:124 msgid "Something went wrong" msgstr "Something went wrong" @@ -1743,7 +1744,7 @@ msgstr "the chat" msgid "The dump couldn't be removed. Try again." msgstr "The dump couldn't be removed. Try again." -#: src/components/editor/TextEditor.tsx:318 +#: src/components/editor/TextEditor.tsx:344 msgid "The image couldn't be uploaded." msgstr "The image couldn't be uploaded." @@ -1779,14 +1780,14 @@ msgstr "This site doesn't send email, so no digest goes out." msgid "This unsubscribe link is missing or malformed." msgstr "This unsubscribe link is missing or malformed." -#: src/pages/DumpEdit.tsx:454 +#: src/pages/DumpEdit.tsx:455 msgid "Thumbnail" msgstr "Thumbnail" #: src/components/dump/create/TitleField.tsx:45 #: src/components/playlist/PlaylistCreateForm.tsx:96 -#: src/components/playlist/PlaylistEditForm.tsx:157 -#: src/pages/DumpEdit.tsx:515 +#: src/components/playlist/PlaylistEditForm.tsx:159 +#: src/pages/DumpEdit.tsx:516 msgid "Title" msgstr "Title" @@ -1861,7 +1862,7 @@ msgstr "Upload failed" msgid "Uploading {0}%" msgstr "Uploading {0}%" -#: src/components/editor/TextEditor.tsx:566 +#: src/components/editor/TextEditor.tsx:595 msgid "Uploading image…" msgstr "Uploading image…" @@ -1883,7 +1884,7 @@ msgstr "Upvoted" msgid "Upvoted ({0})" msgstr "Upvoted ({0})" -#: src/pages/DumpEdit.tsx:486 +#: src/pages/DumpEdit.tsx:487 msgid "URL" msgstr "URL" @@ -1933,7 +1934,7 @@ msgid "Volume" msgstr "Volume" #: src/components/dump/create/DumpCreateModal.tsx:712 -#: src/pages/DumpEdit.tsx:543 +#: src/pages/DumpEdit.tsx:544 msgid "What makes it worth it?" msgstr "What makes it worth it?" @@ -1951,7 +1952,7 @@ msgid "Why & where" msgstr "Why & where" #: src/components/dump/create/DumpCreateModal.tsx:711 -#: src/pages/DumpEdit.tsx:542 +#: src/pages/DumpEdit.tsx:543 msgid "Why?" msgstr "Why?" diff --git a/locales/fr.po b/locales/fr.po index ee92fa6a..4b92ff7c 100644 --- a/locales/fr.po +++ b/locales/fr.po @@ -427,7 +427,7 @@ msgstr "← Retour" #: src/pages/Dump.tsx:326 #: src/pages/Dump.tsx:568 -#: src/pages/DumpEdit.tsx:231 +#: src/pages/DumpEdit.tsx:232 msgid "← Back to all dumps" msgstr "← Retour à toutes les recos" @@ -589,12 +589,12 @@ msgstr "Impossible de se connecter au serveur de mises à jour en direct. Les vo #: src/components/comment/CommentForm.tsx:127 #: src/components/dump/create/DumpCreateModal.tsx:752 #: src/components/form/FormActions.tsx:42 -#: src/components/playlist/PlaylistEditForm.tsx:194 +#: src/components/playlist/PlaylistEditForm.tsx:199 #: src/components/profile/DescriptionEditor.tsx:97 #: src/components/profile/EmailEditor.tsx:83 #: src/components/shared/ConfirmModal.tsx:63 #: src/pages/Dump.tsx:445 -#: src/pages/DumpEdit.tsx:570 +#: src/pages/DumpEdit.tsx:565 msgid "Cancel" msgstr "Annuler" @@ -607,7 +607,7 @@ msgstr "Annuler la suppression" msgid "Cancel reply" msgstr "Annuler la réponse" -#: src/components/layout/AppHeader.tsx:164 +#: src/components/layout/AppHeader.tsx:190 msgid "Cancel search" msgstr "Annuler la recherche" @@ -642,13 +642,13 @@ msgid "Change skin tone" msgstr "Changer la couleur de peau" #: src/components/chat/ChatModal.tsx:716 -#: src/components/layout/ChatButton.tsx:27 +#: src/components/layout/ChatButton.tsx:30 #: src/components/layout/ChatFab.tsx:54 #: src/components/layout/ChatFab.tsx:55 msgid "Chat" msgstr "Tribune" -#: src/components/layout/ChatButton.tsx:26 +#: src/components/layout/ChatButton.tsx:29 #: src/components/layout/ChatFab.tsx:53 msgid "Chat ({unreadChatCount} unread)" msgstr "{unreadChatCount} messages non lus" @@ -712,7 +712,7 @@ msgid "Could not connect to the server. Check your connection and try again." msgstr "Impossible de joindre le serveur. Vérifiez votre connexion et réessayez." #: src/components/profile/ProfilePlaylistsTab.tsx:126 -#: src/pages/DumpEdit.tsx:558 +#: src/pages/DumpEdit.tsx:559 msgid "Could not delete" msgstr "Suppression impossible" @@ -720,7 +720,7 @@ msgstr "Suppression impossible" msgid "Could not rename" msgstr "Renommage impossible" -#: src/pages/DumpEdit.tsx:511 +#: src/pages/DumpEdit.tsx:512 msgid "Could not save" msgstr "Sauvegarde impossible" @@ -740,7 +740,7 @@ msgstr "Désabonnement impossible" msgid "Couldn't update. Try again." msgstr "La mise à jour a échoué. Réessayez." -#: src/components/playlist/PlaylistEditForm.tsx:133 +#: src/components/playlist/PlaylistEditForm.tsx:135 msgid "Cover" msgstr "Couverture" @@ -775,7 +775,7 @@ msgstr "Onglet par défaut" #: src/components/chat/ChatMessageItem.tsx:214 #: src/components/comment/CommentNode.tsx:265 #: src/components/comment/CommentNode.tsx:271 -#: src/components/playlist/PlaylistEditForm.tsx:190 +#: src/components/form/DeleteButton.tsx:36 #: src/components/shared/ConfirmModal.tsx:34 msgid "Delete" msgstr "Supprimer" @@ -789,19 +789,20 @@ msgstr "Supprimer la catégorie" msgid "Delete category \"{0}\"? This cannot be undone." msgstr "Supprimer la catégorie \"{0}\" ? Cette action est irréversible." -#: src/pages/DumpEdit.tsx:313 -#: src/pages/DumpEdit.tsx:566 +#: src/pages/DumpEdit.tsx:314 +#: src/pages/DumpEdit.tsx:562 msgid "Delete dump" msgstr "Supprimer la reco" #. placeholder {0}: res.status -#: src/pages/DumpEdit.tsx:192 +#: src/pages/DumpEdit.tsx:193 msgid "Delete failed ({0})" msgstr "Échec de la suppression ({0})" #: src/components/playlist/PlaylistCard.tsx:142 +#: src/components/playlist/PlaylistEditForm.tsx:190 #: src/components/profile/ProfilePlaylistsTab.tsx:156 -#: src/pages/PlaylistDetail.tsx:136 +#: src/pages/PlaylistDetail.tsx:141 msgid "Delete playlist" msgstr "Supprimer la collection" @@ -809,7 +810,7 @@ msgstr "Supprimer la collection" msgid "Delete this comment?" msgstr "Supprimer ce commentaire ?" -#: src/pages/DumpEdit.tsx:312 +#: src/pages/DumpEdit.tsx:313 msgid "Delete this dump? This cannot be undone." msgstr "Supprimer cette reco ? Cette action est irréversible." @@ -818,7 +819,7 @@ msgid "Delete this message?" msgstr "Supprimer ce message ?" #: src/components/profile/ProfilePlaylistsTab.tsx:155 -#: src/pages/PlaylistDetail.tsx:135 +#: src/pages/PlaylistDetail.tsx:140 msgid "Delete this playlist? This cannot be undone." msgstr "Supprimer cette collection ? Cette action est irréversible." @@ -826,7 +827,7 @@ msgstr "Supprimer cette collection ? Cette action est irréversible." msgid "deleted message" msgstr "message supprimé" -#: src/components/playlist/PlaylistEditForm.tsx:173 +#: src/components/playlist/PlaylistEditForm.tsx:175 msgid "Description" msgstr "Description" @@ -864,11 +865,11 @@ msgstr "Déposez un fichier ici" msgid "Drop a file here, or paste one" msgstr "Déposez un fichier ici, ou collez-en un" -#: src/pages/DumpEdit.tsx:502 +#: src/pages/DumpEdit.tsx:503 msgid "Drop a replacement here" msgstr "Déposez un fichier de remplacement ici" -#: src/components/layout/AppHeader.tsx:203 +#: src/components/layout/AppHeader.tsx:209 msgid "Dump" msgstr "Reco" @@ -946,12 +947,12 @@ msgstr "modifié {0}" msgid "Edited {0}" msgstr "Modifié le {0}" -#: src/pages/DumpEdit.tsx:256 +#: src/pages/DumpEdit.tsx:257 msgid "Editing" msgstr "Modification" #. placeholder {0}: state.dump.title -#: src/pages/DumpEdit.tsx:79 +#: src/pages/DumpEdit.tsx:80 msgid "Editing {0}" msgstr "Édition de {0}" @@ -1005,7 +1006,7 @@ msgstr "Impossible de publier le commentaire" msgid "Failed to post reply" msgstr "Impossible de publier la réponse" -#: src/components/playlist/PlaylistEditForm.tsx:182 +#: src/components/playlist/PlaylistEditForm.tsx:184 #: src/components/profile/DescriptionEditor.tsx:99 #: src/components/profile/EmailEditor.tsx:86 msgid "Failed to save" @@ -1113,8 +1114,8 @@ msgstr "image" msgid "In collections" msgstr "Dans les collections" -#: src/components/editor/TextEditor.tsx:544 -#: src/components/editor/TextEditor.tsx:546 +#: src/components/editor/TextEditor.tsx:573 +#: src/components/editor/TextEditor.tsx:575 msgid "Insert emoji" msgstr "Insérer un emoji" @@ -1175,7 +1176,7 @@ msgstr "Lien ou fichier" msgid "Live updates are temporarily disconnected. Trying to reconnect…" msgstr "Les mises à jour en direct sont temporairement interrompues. Tentative de reconnexion…" -#: src/components/layout/AppHeader.tsx:238 +#: src/components/layout/AppHeader.tsx:242 msgid "Live updates unavailable." msgstr "Mises à jour en direct indisponibles." @@ -1188,7 +1189,7 @@ msgid "Load older messages" msgstr "Charger les messages plus anciens" #: src/pages/Dump.tsx:302 -#: src/pages/DumpEdit.tsx:207 +#: src/pages/DumpEdit.tsx:208 msgid "Loading dump…" msgstr "Chargement de la reco…" @@ -1218,7 +1219,7 @@ msgstr "Chargement du profil…" msgid "Loading…" msgstr "Chargement…" -#: src/components/layout/AppHeader.tsx:211 +#: src/components/layout/AppHeader.tsx:216 #: src/pages/UserLogin.tsx:41 #: src/pages/UserLogin.tsx:67 #: src/pages/UserLogin.tsx:86 @@ -1366,14 +1367,14 @@ msgstr "Aucun abonnement pour le moment." msgid "Nothing here yet." msgstr "Rien ici pour l'instant." -#: src/components/layout/NotificationBell.tsx:55 +#: src/components/layout/NotificationBell.tsx:57 #: src/pages/Notifications.tsx:376 #: src/pages/Notifications.tsx:494 #: src/pages/Settings.tsx:128 msgid "Notifications" msgstr "Notifications" -#: src/components/layout/NotificationBell.tsx:54 +#: src/components/layout/NotificationBell.tsx:56 msgid "Notifications ({unreadNotificationCount} unread)" msgstr "Notifications ({unreadNotificationCount} non lues)" @@ -1385,11 +1386,11 @@ msgstr "Désactivés" msgid "On" msgstr "Activés" -#: src/components/editor/TextEditor.tsx:359 +#: src/components/editor/TextEditor.tsx:385 msgid "Only images can be dropped here." msgstr "Seules les images peuvent être déposées ici." -#: src/pages/DumpEdit.tsx:117 +#: src/pages/DumpEdit.tsx:118 msgid "Only its poster or a moderator can edit this dump." msgstr "Seuls son auteur et les modérateurs peuvent modifier ce dump." @@ -1463,7 +1464,7 @@ msgid "Play" msgstr "Lecture" #: src/components/dump/create/StepIndicator.tsx:21 -#: src/components/layout/AppHeader.tsx:184 +#: src/components/layout/AppHeader.tsx:178 #: src/components/layout/UserMenu.tsx:81 #: src/components/profile/ProfileFollowTab.tsx:167 #: src/components/profile/ProfilePlaylistsTab.tsx:118 @@ -1512,7 +1513,7 @@ msgstr "public" msgid "Public" msgstr "Public" -#: src/pages/DumpEdit.tsx:289 +#: src/pages/DumpEdit.tsx:290 msgid "Refresh metadata" msgstr "Actualiser les métadonnées" @@ -1520,7 +1521,7 @@ msgstr "Actualiser les métadonnées" msgid "Refreshing stream…" msgstr "Actualisation du flux…" -#: src/pages/DumpEdit.tsx:288 +#: src/pages/DumpEdit.tsx:289 msgid "Refreshing…" msgstr "Actualisation…" @@ -1566,7 +1567,7 @@ msgstr "Renommer" msgid "Renaming…" msgstr "Renommage…" -#: src/pages/DumpEdit.tsx:494 +#: src/pages/DumpEdit.tsx:495 msgid "Replace file" msgstr "Remplacer le fichier" @@ -1592,8 +1593,8 @@ msgstr "Échec de la réinitialisation" msgid "Reset password" msgstr "Réinitialiser le mot de passe" -#: src/pages/DumpEdit.tsx:470 -#: src/pages/DumpEdit.tsx:525 +#: src/pages/DumpEdit.tsx:471 +#: src/pages/DumpEdit.tsx:526 msgid "Reset to default" msgstr "Réinitialiser par défaut" @@ -1604,7 +1605,7 @@ msgstr "Rétablir le titre suggéré" #: src/components/chat/PendingItem.tsx:86 #: src/pages/Dump.tsx:319 -#: src/pages/DumpEdit.tsx:224 +#: src/pages/DumpEdit.tsx:225 msgid "Retry" msgstr "Réessayer" @@ -1615,16 +1616,16 @@ msgstr "Rôle" #: src/components/category/CategoryManager.tsx:216 #: src/components/chat/ChatEditBox.tsx:85 #: src/components/comment/CommentNode.tsx:216 -#: src/components/playlist/PlaylistEditForm.tsx:200 +#: src/components/playlist/PlaylistEditForm.tsx:206 #: src/components/profile/DescriptionEditor.tsx:89 #: src/components/profile/EmailEditor.tsx:75 #: src/pages/Dump.tsx:437 -#: src/pages/DumpEdit.tsx:573 +#: src/pages/DumpEdit.tsx:568 msgid "Save" msgstr "Enregistrer" #: src/components/comment/CommentNode.tsx:217 -#: src/components/playlist/PlaylistEditForm.tsx:197 +#: src/components/playlist/PlaylistEditForm.tsx:203 #: src/components/profile/ChangePasswordModal.tsx:119 #: src/components/profile/DescriptionEditor.tsx:86 #: src/components/profile/EmailEditor.tsx:72 @@ -1633,7 +1634,7 @@ msgstr "Enregistrer" msgid "Saving…" msgstr "Enregistrement…" -#: src/components/layout/AppHeader.tsx:164 +#: src/components/layout/AppHeader.tsx:190 #: src/components/layout/SearchBar.tsx:83 #: src/pages/Search.tsx:69 msgid "Search" @@ -1676,7 +1677,7 @@ msgstr "Envoyer le lien de réinitialisation" msgid "Sending…" msgstr "Envoi…" -#: src/components/layout/AppHeader.tsx:200 +#: src/components/layout/AppHeader.tsx:206 msgid "Server unreachable" msgstr "Serveur inaccessible" @@ -1704,14 +1705,14 @@ msgstr "Usage unique, valable 7 jours." msgid "slug" msgstr "identifiant" -#: src/components/editor/TextEditor.tsx:317 +#: src/components/editor/TextEditor.tsx:343 msgid "Some images couldn't be uploaded." msgstr "Certaines images n'ont pas pu être envoyées." #: src/components/form/FormError.tsx:31 #: src/components/layout/PageError.tsx:29 #: src/contexts/ws/WSProvider.tsx:729 -#: src/pages/PlaylistDetail.tsx:119 +#: src/pages/PlaylistDetail.tsx:124 msgid "Something went wrong" msgstr "Une erreur est survenue" @@ -1743,7 +1744,7 @@ msgstr "la tribune" msgid "The dump couldn't be removed. Try again." msgstr "Le dump n'a pas pu être retiré. Réessayez." -#: src/components/editor/TextEditor.tsx:318 +#: src/components/editor/TextEditor.tsx:344 msgid "The image couldn't be uploaded." msgstr "L'image n'a pas pu être envoyée." @@ -1779,14 +1780,14 @@ msgstr "Ce site n'envoie pas d'e-mails, aucun résumé ne part donc." msgid "This unsubscribe link is missing or malformed." msgstr "Ce lien de désabonnement est absent ou mal formé." -#: src/pages/DumpEdit.tsx:454 +#: src/pages/DumpEdit.tsx:455 msgid "Thumbnail" msgstr "Miniature" #: src/components/dump/create/TitleField.tsx:45 #: src/components/playlist/PlaylistCreateForm.tsx:96 -#: src/components/playlist/PlaylistEditForm.tsx:157 -#: src/pages/DumpEdit.tsx:515 +#: src/components/playlist/PlaylistEditForm.tsx:159 +#: src/pages/DumpEdit.tsx:516 msgid "Title" msgstr "Titre" @@ -1861,7 +1862,7 @@ msgstr "Envoi échoué" msgid "Uploading {0}%" msgstr "Envoi {0} %" -#: src/components/editor/TextEditor.tsx:566 +#: src/components/editor/TextEditor.tsx:595 msgid "Uploading image…" msgstr "Envoi de l'image…" @@ -1883,7 +1884,7 @@ msgstr "Voté" msgid "Upvoted ({0})" msgstr "Voté ({0})" -#: src/pages/DumpEdit.tsx:486 +#: src/pages/DumpEdit.tsx:487 msgid "URL" msgstr "URL" @@ -1933,7 +1934,7 @@ msgid "Volume" msgstr "Volume" #: src/components/dump/create/DumpCreateModal.tsx:712 -#: src/pages/DumpEdit.tsx:543 +#: src/pages/DumpEdit.tsx:544 msgid "What makes it worth it?" msgstr "Pourquoi on en voudrait ?" @@ -1951,7 +1952,7 @@ msgid "Why & where" msgstr "Pourquoi & où" #: src/components/dump/create/DumpCreateModal.tsx:711 -#: src/pages/DumpEdit.tsx:542 +#: src/pages/DumpEdit.tsx:543 msgid "Why?" msgstr "Pourquoi ?" diff --git a/src/App.css b/src/App.css index 00a3d9c8..c2f564e5 100644 --- a/src/App.css +++ b/src/App.css @@ -164,8 +164,7 @@ .dump-post-header, .dump-rich-content, .form-page-header, -.dump-edit-panel, -.dump-edit-footer, +.form-panel, .playlist-detail-header, .comment-node-inner { box-shadow: var(--panel-ring), var(--card-shadow); @@ -3374,7 +3373,7 @@ body.has-player .chat-fab { } .form-page--two-col .form-page-header, .dump-edit-form, - .dump-edit-footer { + .dump-edit-form > .form-panel--bar { grid-column: 1 / -1; } /* "Why?" soaks up whatever height the source column adds, so a tall @@ -3422,7 +3421,10 @@ body.has-player .chat-fab { word-break: break-word; } -.dump-edit-panel { +/* A form split into panels, a few pixels apart (as on the page's grid), in + place of rules between its parts: the fields, then a bar of actions, which + ends the card. */ +.form-panel { display: flex; flex-direction: column; gap: 1rem; @@ -3435,18 +3437,35 @@ body.has-player .chat-fab { overflow: hidden; } -.dump-edit-footer { +.form-panel--bar { padding: 0.875rem 1.25rem; - background: var(--color-surface); border-radius: 0 0 var(--radius-xl) var(--radius-xl); + container: form-bar / inline-size; } -.dump-edit-footer .form-actions { +.form-panel--bar .form-actions { + flex-wrap: nowrap; padding-top: 0; border-top: 0; margin-top: 0; } +/* Too narrow for Delete, Cancel and Save side by side in every face and + language, the bar shows Delete as its icon. */ +.form-delete-icon { + display: none; +} + +@container form-bar (max-width: 18rem) { + .form-delete-icon { + display: inline; + } + + .form-delete-label { + display: none; + } +} + .dump-edit-refresh { margin-top: 0.75rem; } @@ -3481,25 +3500,6 @@ body.has-player .chat-fab { margin-left: auto; } -/* A destructive action, Cancel and Save don't fit a phone side by side in - every face, and wrapped they would make a staircase. On a phone they stack: - Cancel and Save across the top, Save taking the room left, the destructive - action the full width under them. */ -@media (max-width: 512px) { - .form-actions:has(> .btn-danger) { - flex-direction: column-reverse; - align-items: stretch; - } - - .form-actions:has(> .btn-danger) > .form-actions-right { - margin-left: 0; - } - - .form-actions:has(> .btn-danger) > .form-actions-right > :last-child { - flex: 1; - } -} - /* Subtle text action. Resets the global + ); +} diff --git a/src/components/playlist/PlaylistEditForm.tsx b/src/components/playlist/PlaylistEditForm.tsx index 08e1782a..647e522d 100644 --- a/src/components/playlist/PlaylistEditForm.tsx +++ b/src/components/playlist/PlaylistEditForm.tsx @@ -26,6 +26,7 @@ import { ImagePicker } from "../shared/ImagePicker.tsx"; import { TextField } from "../form/TextField.tsx"; import { RichTextField } from "../form/RichTextField.tsx"; import { VisibilityToggle } from "../form/SegmentedField.tsx"; +import { DeleteButton } from "../form/DeleteButton.tsx"; import { FormError } from "../form/FormError.tsx"; import { SubmitButton } from "../form/SubmitButton.tsx"; import { SlugField } from "../form/SlugField.tsx"; @@ -121,84 +122,90 @@ export function PlaylistEditForm( return (
{ // The editor's popups take their own Escape and prevent it. if (e.key === "Escape" && !e.defaultPrevented) onCancel(); }} > -
- - Cover - - ( - { - field.onChange(file); - setImagePreview(URL.createObjectURL(file)); - }} - /> - )} +
+
+ + Cover + + ( + { + field.onChange(file); + setImagePreview(URL.createObjectURL(file)); + }} + /> + )} + /> +
+ + + name="title" + label={t`Title`} + autoFocus + rules={{ required: true }} + maxLength={VALIDATION.PLAYLIST_TITLE_MAX} + showCount /> + + + name="slug" + titleName="title" + prefix={`${userPath(playlist.ownerUsername, "playlists")}/`} + saved={playlist} + /> + + + name="description" + label={t`Description`} + rows={2} + autoResize + maxLength={VALIDATION.PLAYLIST_DESCRIPTION_MAX} + onSubmit={() => void onSubmit()} + /> + + name="isPublic" /> + +
- - name="title" - label={t`Title`} - autoFocus - rules={{ required: true }} - maxLength={VALIDATION.PLAYLIST_TITLE_MAX} - showCount - /> - - - name="slug" - titleName="title" - prefix={`${userPath(playlist.ownerUsername, "playlists")}/`} - saved={playlist} - /> - - - name="description" - label={t`Description`} - rows={2} - autoResize - maxLength={VALIDATION.PLAYLIST_DESCRIPTION_MAX} - onSubmit={() => void onSubmit()} - /> - - name="isPublic" /> - - - -
- -
- - Saving…} - disabled={!title.trim()} - > - Save - +
+
+ +
+ + Saving…} + disabled={!title.trim()} + > + Save + +
diff --git a/src/pages/DumpEdit.tsx b/src/pages/DumpEdit.tsx index 7f3c33de..f08a5380 100644 --- a/src/pages/DumpEdit.tsx +++ b/src/pages/DumpEdit.tsx @@ -47,6 +47,7 @@ import { SubmitButton } from "../components/form/SubmitButton.tsx"; import { TextField } from "../components/form/TextField.tsx"; import { useApiForm } from "../hooks/form/useApiForm.ts"; import { VisibilityToggle } from "../components/form/SegmentedField.tsx"; +import { DeleteButton } from "../components/form/DeleteButton.tsx"; import { SlugField } from "../components/form/SlugField.tsx"; import { useCanonicalPath } from "../hooks/shared/useCanonicalPath.ts"; import { userPath } from "../../shared/paths.ts"; @@ -446,7 +447,7 @@ function DumpEditForm({ /* The source panel holds what was dumped, the details panel how it is presented and who sees it. */ } -
+
{preview}
@@ -507,7 +508,7 @@ function DumpEditForm({ )}
-
+
@@ -553,23 +554,17 @@ function DumpEditForm({ name="isPublic" />
-
+
{deleteError && ( )}
- +
Cancel - + Save
diff --git a/src/pages/PlaylistDetail.tsx b/src/pages/PlaylistDetail.tsx index 4d5bdfd9..3f8b8ffb 100644 --- a/src/pages/PlaylistDetail.tsx +++ b/src/pages/PlaylistDetail.tsx @@ -90,7 +90,12 @@ export function PlaylistDetail(): React.JSX.Element { return ( -
+
{editOpen ? ( { ); const { user } = open(); await user.click(await screen.findByRole("button", { name: "Edit" })); - await user.click(screen.getByRole("button", { name: "Delete" })); + await user.click(screen.getByRole("button", { name: "Delete playlist" })); await user.click( within(screen.getByRole("alertdialog")).getByRole("button", { name: "Delete playlist", @@ -379,7 +379,7 @@ describe("PlaylistDetail", () => { route("DELETE /api/playlists/:id", () => fail("Forbidden", 403)); const { user } = open(); await user.click(await screen.findByRole("button", { name: "Edit" })); - await user.click(screen.getByRole("button", { name: "Delete" })); + await user.click(screen.getByRole("button", { name: "Delete playlist" })); await user.click( within(screen.getByRole("alertdialog")).getByRole("button", { name: "Delete playlist",