v4: the playlist and dump edit forms end in one bar of actions, a panel of its own — the playlist editor drew rules between its fields and its actions, and on a phone its Delete, Cancel and Save wrapped into a staircase, then stacked (a0c8b1d), neither of which held together. Both forms are now built as DumpEdit was: surface panels 3px apart (.form-panel, from .dump-edit-panel), the last a bar (.form-panel--bar, from .dump-edit-footer) holding Delete on the left and Cancel and Save on the right, compact (btn-sm), on one line. The new DeleteButton says "Delete" and names what goes to assistive tech ("Delete playlist", "Delete dump"); in a bar too narrow for the three labels in every face and language (a container query, under 18rem), it shows 🗑 instead. While edited, the playlist's header drops its own card for the form's panels. The phone stacking rule is gone. An auto-sized editor also re-fits when its width changes with its text unchanged: opening the form makes the page tall enough for a scrollbar, which narrowed the description after it was measured, so it overflowed; and it hides its overflow below its max-height, where a scrollbar could only come of rounding, and drops the resize grip, which the next keystroke would undo. 669 frontend tests pass, and tsc, eslint, deno fmt, doc:lint and i18n:compile --strict are clean; checked in screenshots in Kanagawa dark (French, 385 and 360px), Smooth light at 1000px and DumpEdit in Smooth at 390px.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
107
locales/en.po
107
locales/en.po
@@ -427,7 +427,7 @@ msgstr "← Back"
|
|||||||
|
|
||||||
#: src/pages/Dump.tsx:326
|
#: src/pages/Dump.tsx:326
|
||||||
#: src/pages/Dump.tsx:568
|
#: src/pages/Dump.tsx:568
|
||||||
#: src/pages/DumpEdit.tsx:231
|
#: src/pages/DumpEdit.tsx:232
|
||||||
msgid "← Back to all dumps"
|
msgid "← Back to all dumps"
|
||||||
msgstr "← 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/comment/CommentForm.tsx:127
|
||||||
#: src/components/dump/create/DumpCreateModal.tsx:752
|
#: src/components/dump/create/DumpCreateModal.tsx:752
|
||||||
#: src/components/form/FormActions.tsx:42
|
#: 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/DescriptionEditor.tsx:97
|
||||||
#: src/components/profile/EmailEditor.tsx:83
|
#: src/components/profile/EmailEditor.tsx:83
|
||||||
#: src/components/shared/ConfirmModal.tsx:63
|
#: src/components/shared/ConfirmModal.tsx:63
|
||||||
#: src/pages/Dump.tsx:445
|
#: src/pages/Dump.tsx:445
|
||||||
#: src/pages/DumpEdit.tsx:570
|
#: src/pages/DumpEdit.tsx:565
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Cancel"
|
msgstr "Cancel"
|
||||||
|
|
||||||
@@ -607,7 +607,7 @@ msgstr "Cancel removal"
|
|||||||
msgid "Cancel reply"
|
msgid "Cancel reply"
|
||||||
msgstr "Cancel reply"
|
msgstr "Cancel reply"
|
||||||
|
|
||||||
#: src/components/layout/AppHeader.tsx:164
|
#: src/components/layout/AppHeader.tsx:190
|
||||||
msgid "Cancel search"
|
msgid "Cancel search"
|
||||||
msgstr "Cancel search"
|
msgstr "Cancel search"
|
||||||
|
|
||||||
@@ -642,13 +642,13 @@ msgid "Change skin tone"
|
|||||||
msgstr "Change skin tone"
|
msgstr "Change skin tone"
|
||||||
|
|
||||||
#: src/components/chat/ChatModal.tsx:716
|
#: 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:54
|
||||||
#: src/components/layout/ChatFab.tsx:55
|
#: src/components/layout/ChatFab.tsx:55
|
||||||
msgid "Chat"
|
msgid "Chat"
|
||||||
msgstr "Chat"
|
msgstr "Chat"
|
||||||
|
|
||||||
#: src/components/layout/ChatButton.tsx:26
|
#: src/components/layout/ChatButton.tsx:29
|
||||||
#: src/components/layout/ChatFab.tsx:53
|
#: src/components/layout/ChatFab.tsx:53
|
||||||
msgid "Chat ({unreadChatCount} unread)"
|
msgid "Chat ({unreadChatCount} unread)"
|
||||||
msgstr "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."
|
msgstr "Could not connect to the server. Check your connection and try again."
|
||||||
|
|
||||||
#: src/components/profile/ProfilePlaylistsTab.tsx:126
|
#: src/components/profile/ProfilePlaylistsTab.tsx:126
|
||||||
#: src/pages/DumpEdit.tsx:558
|
#: src/pages/DumpEdit.tsx:559
|
||||||
msgid "Could not delete"
|
msgid "Could not delete"
|
||||||
msgstr "Could not delete"
|
msgstr "Could not delete"
|
||||||
|
|
||||||
@@ -720,7 +720,7 @@ msgstr "Could not delete"
|
|||||||
msgid "Could not rename"
|
msgid "Could not rename"
|
||||||
msgstr "Could not rename"
|
msgstr "Could not rename"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:511
|
#: src/pages/DumpEdit.tsx:512
|
||||||
msgid "Could not save"
|
msgid "Could not save"
|
||||||
msgstr "Could not save"
|
msgstr "Could not save"
|
||||||
|
|
||||||
@@ -740,7 +740,7 @@ msgstr "Couldn't unsubscribe"
|
|||||||
msgid "Couldn't update. Try again."
|
msgid "Couldn't update. Try again."
|
||||||
msgstr "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"
|
msgid "Cover"
|
||||||
msgstr "Cover"
|
msgstr "Cover"
|
||||||
|
|
||||||
@@ -775,7 +775,7 @@ msgstr "Default tab"
|
|||||||
#: src/components/chat/ChatMessageItem.tsx:214
|
#: src/components/chat/ChatMessageItem.tsx:214
|
||||||
#: src/components/comment/CommentNode.tsx:265
|
#: src/components/comment/CommentNode.tsx:265
|
||||||
#: src/components/comment/CommentNode.tsx:271
|
#: src/components/comment/CommentNode.tsx:271
|
||||||
#: src/components/playlist/PlaylistEditForm.tsx:190
|
#: src/components/form/DeleteButton.tsx:36
|
||||||
#: src/components/shared/ConfirmModal.tsx:34
|
#: src/components/shared/ConfirmModal.tsx:34
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Delete"
|
msgstr "Delete"
|
||||||
@@ -789,19 +789,20 @@ msgstr "Delete category"
|
|||||||
msgid "Delete category \"{0}\"? This cannot be undone."
|
msgid "Delete category \"{0}\"? This cannot be undone."
|
||||||
msgstr "Delete category \"{0}\"? This cannot be undone."
|
msgstr "Delete category \"{0}\"? This cannot be undone."
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:313
|
#: src/pages/DumpEdit.tsx:314
|
||||||
#: src/pages/DumpEdit.tsx:566
|
#: src/pages/DumpEdit.tsx:562
|
||||||
msgid "Delete dump"
|
msgid "Delete dump"
|
||||||
msgstr "Delete dump"
|
msgstr "Delete dump"
|
||||||
|
|
||||||
#. placeholder {0}: res.status
|
#. placeholder {0}: res.status
|
||||||
#: src/pages/DumpEdit.tsx:192
|
#: src/pages/DumpEdit.tsx:193
|
||||||
msgid "Delete failed ({0})"
|
msgid "Delete failed ({0})"
|
||||||
msgstr "Delete failed ({0})"
|
msgstr "Delete failed ({0})"
|
||||||
|
|
||||||
#: src/components/playlist/PlaylistCard.tsx:142
|
#: src/components/playlist/PlaylistCard.tsx:142
|
||||||
|
#: src/components/playlist/PlaylistEditForm.tsx:190
|
||||||
#: src/components/profile/ProfilePlaylistsTab.tsx:156
|
#: src/components/profile/ProfilePlaylistsTab.tsx:156
|
||||||
#: src/pages/PlaylistDetail.tsx:136
|
#: src/pages/PlaylistDetail.tsx:141
|
||||||
msgid "Delete playlist"
|
msgid "Delete playlist"
|
||||||
msgstr "Delete playlist"
|
msgstr "Delete playlist"
|
||||||
|
|
||||||
@@ -809,7 +810,7 @@ msgstr "Delete playlist"
|
|||||||
msgid "Delete this comment?"
|
msgid "Delete this comment?"
|
||||||
msgstr "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."
|
msgid "Delete this dump? This cannot be undone."
|
||||||
msgstr "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?"
|
msgstr "Delete this message?"
|
||||||
|
|
||||||
#: src/components/profile/ProfilePlaylistsTab.tsx:155
|
#: src/components/profile/ProfilePlaylistsTab.tsx:155
|
||||||
#: src/pages/PlaylistDetail.tsx:135
|
#: src/pages/PlaylistDetail.tsx:140
|
||||||
msgid "Delete this playlist? This cannot be undone."
|
msgid "Delete this playlist? This cannot be undone."
|
||||||
msgstr "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"
|
msgid "deleted message"
|
||||||
msgstr "deleted message"
|
msgstr "deleted message"
|
||||||
|
|
||||||
#: src/components/playlist/PlaylistEditForm.tsx:173
|
#: src/components/playlist/PlaylistEditForm.tsx:175
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Description"
|
msgstr "Description"
|
||||||
|
|
||||||
@@ -864,11 +865,11 @@ msgstr "Drop a file here"
|
|||||||
msgid "Drop a file here, or paste one"
|
msgid "Drop a file here, or paste one"
|
||||||
msgstr "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"
|
msgid "Drop a replacement here"
|
||||||
msgstr "Drop a replacement here"
|
msgstr "Drop a replacement here"
|
||||||
|
|
||||||
#: src/components/layout/AppHeader.tsx:203
|
#: src/components/layout/AppHeader.tsx:209
|
||||||
msgid "Dump"
|
msgid "Dump"
|
||||||
msgstr "Dump"
|
msgstr "Dump"
|
||||||
|
|
||||||
@@ -946,12 +947,12 @@ msgstr "edited {0}"
|
|||||||
msgid "Edited {0}"
|
msgid "Edited {0}"
|
||||||
msgstr "Edited {0}"
|
msgstr "Edited {0}"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:256
|
#: src/pages/DumpEdit.tsx:257
|
||||||
msgid "Editing"
|
msgid "Editing"
|
||||||
msgstr "Editing"
|
msgstr "Editing"
|
||||||
|
|
||||||
#. placeholder {0}: state.dump.title
|
#. placeholder {0}: state.dump.title
|
||||||
#: src/pages/DumpEdit.tsx:79
|
#: src/pages/DumpEdit.tsx:80
|
||||||
msgid "Editing {0}"
|
msgid "Editing {0}"
|
||||||
msgstr "Editing {0}"
|
msgstr "Editing {0}"
|
||||||
|
|
||||||
@@ -1005,7 +1006,7 @@ msgstr "Failed to post comment"
|
|||||||
msgid "Failed to post reply"
|
msgid "Failed to post reply"
|
||||||
msgstr "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/DescriptionEditor.tsx:99
|
||||||
#: src/components/profile/EmailEditor.tsx:86
|
#: src/components/profile/EmailEditor.tsx:86
|
||||||
msgid "Failed to save"
|
msgid "Failed to save"
|
||||||
@@ -1113,8 +1114,8 @@ msgstr "image"
|
|||||||
msgid "In collections"
|
msgid "In collections"
|
||||||
msgstr "In collections"
|
msgstr "In collections"
|
||||||
|
|
||||||
#: src/components/editor/TextEditor.tsx:544
|
#: src/components/editor/TextEditor.tsx:573
|
||||||
#: src/components/editor/TextEditor.tsx:546
|
#: src/components/editor/TextEditor.tsx:575
|
||||||
msgid "Insert emoji"
|
msgid "Insert emoji"
|
||||||
msgstr "Insert emoji"
|
msgstr "Insert emoji"
|
||||||
|
|
||||||
@@ -1175,7 +1176,7 @@ msgstr "Link or file"
|
|||||||
msgid "Live updates are temporarily disconnected. Trying to reconnect…"
|
msgid "Live updates are temporarily disconnected. Trying to reconnect…"
|
||||||
msgstr "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."
|
msgid "Live updates unavailable."
|
||||||
msgstr "Live updates unavailable."
|
msgstr "Live updates unavailable."
|
||||||
|
|
||||||
@@ -1188,7 +1189,7 @@ msgid "Load older messages"
|
|||||||
msgstr "Load older messages"
|
msgstr "Load older messages"
|
||||||
|
|
||||||
#: src/pages/Dump.tsx:302
|
#: src/pages/Dump.tsx:302
|
||||||
#: src/pages/DumpEdit.tsx:207
|
#: src/pages/DumpEdit.tsx:208
|
||||||
msgid "Loading dump…"
|
msgid "Loading dump…"
|
||||||
msgstr "Loading dump…"
|
msgstr "Loading dump…"
|
||||||
|
|
||||||
@@ -1218,7 +1219,7 @@ msgstr "Loading profile…"
|
|||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "Loading…"
|
msgstr "Loading…"
|
||||||
|
|
||||||
#: src/components/layout/AppHeader.tsx:211
|
#: src/components/layout/AppHeader.tsx:216
|
||||||
#: src/pages/UserLogin.tsx:41
|
#: src/pages/UserLogin.tsx:41
|
||||||
#: src/pages/UserLogin.tsx:67
|
#: src/pages/UserLogin.tsx:67
|
||||||
#: src/pages/UserLogin.tsx:86
|
#: src/pages/UserLogin.tsx:86
|
||||||
@@ -1366,14 +1367,14 @@ msgstr "Not following anyone yet."
|
|||||||
msgid "Nothing here yet."
|
msgid "Nothing here yet."
|
||||||
msgstr "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:376
|
||||||
#: src/pages/Notifications.tsx:494
|
#: src/pages/Notifications.tsx:494
|
||||||
#: src/pages/Settings.tsx:128
|
#: src/pages/Settings.tsx:128
|
||||||
msgid "Notifications"
|
msgid "Notifications"
|
||||||
msgstr "Notifications"
|
msgstr "Notifications"
|
||||||
|
|
||||||
#: src/components/layout/NotificationBell.tsx:54
|
#: src/components/layout/NotificationBell.tsx:56
|
||||||
msgid "Notifications ({unreadNotificationCount} unread)"
|
msgid "Notifications ({unreadNotificationCount} unread)"
|
||||||
msgstr "Notifications ({unreadNotificationCount} unread)"
|
msgstr "Notifications ({unreadNotificationCount} unread)"
|
||||||
|
|
||||||
@@ -1385,11 +1386,11 @@ msgstr "Off"
|
|||||||
msgid "On"
|
msgid "On"
|
||||||
msgstr "On"
|
msgstr "On"
|
||||||
|
|
||||||
#: src/components/editor/TextEditor.tsx:359
|
#: src/components/editor/TextEditor.tsx:385
|
||||||
msgid "Only images can be dropped here."
|
msgid "Only images can be dropped here."
|
||||||
msgstr "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."
|
msgid "Only its poster or a moderator can edit this dump."
|
||||||
msgstr "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"
|
msgstr "Play"
|
||||||
|
|
||||||
#: src/components/dump/create/StepIndicator.tsx:21
|
#: 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/layout/UserMenu.tsx:81
|
||||||
#: src/components/profile/ProfileFollowTab.tsx:167
|
#: src/components/profile/ProfileFollowTab.tsx:167
|
||||||
#: src/components/profile/ProfilePlaylistsTab.tsx:118
|
#: src/components/profile/ProfilePlaylistsTab.tsx:118
|
||||||
@@ -1512,7 +1513,7 @@ msgstr "public"
|
|||||||
msgid "Public"
|
msgid "Public"
|
||||||
msgstr "Public"
|
msgstr "Public"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:289
|
#: src/pages/DumpEdit.tsx:290
|
||||||
msgid "Refresh metadata"
|
msgid "Refresh metadata"
|
||||||
msgstr "Refresh metadata"
|
msgstr "Refresh metadata"
|
||||||
|
|
||||||
@@ -1520,7 +1521,7 @@ msgstr "Refresh metadata"
|
|||||||
msgid "Refreshing stream…"
|
msgid "Refreshing stream…"
|
||||||
msgstr "Refreshing stream…"
|
msgstr "Refreshing stream…"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:288
|
#: src/pages/DumpEdit.tsx:289
|
||||||
msgid "Refreshing…"
|
msgid "Refreshing…"
|
||||||
msgstr "Refreshing…"
|
msgstr "Refreshing…"
|
||||||
|
|
||||||
@@ -1566,7 +1567,7 @@ msgstr "Rename"
|
|||||||
msgid "Renaming…"
|
msgid "Renaming…"
|
||||||
msgstr "Renaming…"
|
msgstr "Renaming…"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:494
|
#: src/pages/DumpEdit.tsx:495
|
||||||
msgid "Replace file"
|
msgid "Replace file"
|
||||||
msgstr "Replace file"
|
msgstr "Replace file"
|
||||||
|
|
||||||
@@ -1592,8 +1593,8 @@ msgstr "Reset failed"
|
|||||||
msgid "Reset password"
|
msgid "Reset password"
|
||||||
msgstr "Reset password"
|
msgstr "Reset password"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:470
|
#: src/pages/DumpEdit.tsx:471
|
||||||
#: src/pages/DumpEdit.tsx:525
|
#: src/pages/DumpEdit.tsx:526
|
||||||
msgid "Reset to default"
|
msgid "Reset to default"
|
||||||
msgstr "Reset to default"
|
msgstr "Reset to default"
|
||||||
|
|
||||||
@@ -1604,7 +1605,7 @@ msgstr "Reset to the suggested title"
|
|||||||
|
|
||||||
#: src/components/chat/PendingItem.tsx:86
|
#: src/components/chat/PendingItem.tsx:86
|
||||||
#: src/pages/Dump.tsx:319
|
#: src/pages/Dump.tsx:319
|
||||||
#: src/pages/DumpEdit.tsx:224
|
#: src/pages/DumpEdit.tsx:225
|
||||||
msgid "Retry"
|
msgid "Retry"
|
||||||
msgstr "Retry"
|
msgstr "Retry"
|
||||||
|
|
||||||
@@ -1615,16 +1616,16 @@ msgstr "Role"
|
|||||||
#: src/components/category/CategoryManager.tsx:216
|
#: src/components/category/CategoryManager.tsx:216
|
||||||
#: src/components/chat/ChatEditBox.tsx:85
|
#: src/components/chat/ChatEditBox.tsx:85
|
||||||
#: src/components/comment/CommentNode.tsx:216
|
#: 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/DescriptionEditor.tsx:89
|
||||||
#: src/components/profile/EmailEditor.tsx:75
|
#: src/components/profile/EmailEditor.tsx:75
|
||||||
#: src/pages/Dump.tsx:437
|
#: src/pages/Dump.tsx:437
|
||||||
#: src/pages/DumpEdit.tsx:573
|
#: src/pages/DumpEdit.tsx:568
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Save"
|
msgstr "Save"
|
||||||
|
|
||||||
#: src/components/comment/CommentNode.tsx:217
|
#: 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/ChangePasswordModal.tsx:119
|
||||||
#: src/components/profile/DescriptionEditor.tsx:86
|
#: src/components/profile/DescriptionEditor.tsx:86
|
||||||
#: src/components/profile/EmailEditor.tsx:72
|
#: src/components/profile/EmailEditor.tsx:72
|
||||||
@@ -1633,7 +1634,7 @@ msgstr "Save"
|
|||||||
msgid "Saving…"
|
msgid "Saving…"
|
||||||
msgstr "Saving…"
|
msgstr "Saving…"
|
||||||
|
|
||||||
#: src/components/layout/AppHeader.tsx:164
|
#: src/components/layout/AppHeader.tsx:190
|
||||||
#: src/components/layout/SearchBar.tsx:83
|
#: src/components/layout/SearchBar.tsx:83
|
||||||
#: src/pages/Search.tsx:69
|
#: src/pages/Search.tsx:69
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
@@ -1676,7 +1677,7 @@ msgstr "Send reset link"
|
|||||||
msgid "Sending…"
|
msgid "Sending…"
|
||||||
msgstr "Sending…"
|
msgstr "Sending…"
|
||||||
|
|
||||||
#: src/components/layout/AppHeader.tsx:200
|
#: src/components/layout/AppHeader.tsx:206
|
||||||
msgid "Server unreachable"
|
msgid "Server unreachable"
|
||||||
msgstr "Server unreachable"
|
msgstr "Server unreachable"
|
||||||
|
|
||||||
@@ -1704,14 +1705,14 @@ msgstr "Single use, valid for 7 days."
|
|||||||
msgid "slug"
|
msgid "slug"
|
||||||
msgstr "slug"
|
msgstr "slug"
|
||||||
|
|
||||||
#: src/components/editor/TextEditor.tsx:317
|
#: src/components/editor/TextEditor.tsx:343
|
||||||
msgid "Some images couldn't be uploaded."
|
msgid "Some images couldn't be uploaded."
|
||||||
msgstr "Some images couldn't be uploaded."
|
msgstr "Some images couldn't be uploaded."
|
||||||
|
|
||||||
#: src/components/form/FormError.tsx:31
|
#: src/components/form/FormError.tsx:31
|
||||||
#: src/components/layout/PageError.tsx:29
|
#: src/components/layout/PageError.tsx:29
|
||||||
#: src/contexts/ws/WSProvider.tsx:729
|
#: src/contexts/ws/WSProvider.tsx:729
|
||||||
#: src/pages/PlaylistDetail.tsx:119
|
#: src/pages/PlaylistDetail.tsx:124
|
||||||
msgid "Something went wrong"
|
msgid "Something went wrong"
|
||||||
msgstr "Something went wrong"
|
msgstr "Something went wrong"
|
||||||
|
|
||||||
@@ -1743,7 +1744,7 @@ msgstr "the chat"
|
|||||||
msgid "The dump couldn't be removed. Try again."
|
msgid "The dump couldn't be removed. Try again."
|
||||||
msgstr "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."
|
msgid "The image couldn't be uploaded."
|
||||||
msgstr "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."
|
msgid "This unsubscribe link is missing or malformed."
|
||||||
msgstr "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"
|
msgid "Thumbnail"
|
||||||
msgstr "Thumbnail"
|
msgstr "Thumbnail"
|
||||||
|
|
||||||
#: src/components/dump/create/TitleField.tsx:45
|
#: src/components/dump/create/TitleField.tsx:45
|
||||||
#: src/components/playlist/PlaylistCreateForm.tsx:96
|
#: src/components/playlist/PlaylistCreateForm.tsx:96
|
||||||
#: src/components/playlist/PlaylistEditForm.tsx:157
|
#: src/components/playlist/PlaylistEditForm.tsx:159
|
||||||
#: src/pages/DumpEdit.tsx:515
|
#: src/pages/DumpEdit.tsx:516
|
||||||
msgid "Title"
|
msgid "Title"
|
||||||
msgstr "Title"
|
msgstr "Title"
|
||||||
|
|
||||||
@@ -1861,7 +1862,7 @@ msgstr "Upload failed"
|
|||||||
msgid "Uploading {0}%"
|
msgid "Uploading {0}%"
|
||||||
msgstr "Uploading {0}%"
|
msgstr "Uploading {0}%"
|
||||||
|
|
||||||
#: src/components/editor/TextEditor.tsx:566
|
#: src/components/editor/TextEditor.tsx:595
|
||||||
msgid "Uploading image…"
|
msgid "Uploading image…"
|
||||||
msgstr "Uploading image…"
|
msgstr "Uploading image…"
|
||||||
|
|
||||||
@@ -1883,7 +1884,7 @@ msgstr "Upvoted"
|
|||||||
msgid "Upvoted ({0})"
|
msgid "Upvoted ({0})"
|
||||||
msgstr "Upvoted ({0})"
|
msgstr "Upvoted ({0})"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:486
|
#: src/pages/DumpEdit.tsx:487
|
||||||
msgid "URL"
|
msgid "URL"
|
||||||
msgstr "URL"
|
msgstr "URL"
|
||||||
|
|
||||||
@@ -1933,7 +1934,7 @@ msgid "Volume"
|
|||||||
msgstr "Volume"
|
msgstr "Volume"
|
||||||
|
|
||||||
#: src/components/dump/create/DumpCreateModal.tsx:712
|
#: src/components/dump/create/DumpCreateModal.tsx:712
|
||||||
#: src/pages/DumpEdit.tsx:543
|
#: src/pages/DumpEdit.tsx:544
|
||||||
msgid "What makes it worth it?"
|
msgid "What makes it worth it?"
|
||||||
msgstr "What makes it worth it?"
|
msgstr "What makes it worth it?"
|
||||||
|
|
||||||
@@ -1951,7 +1952,7 @@ msgid "Why & where"
|
|||||||
msgstr "Why & where"
|
msgstr "Why & where"
|
||||||
|
|
||||||
#: src/components/dump/create/DumpCreateModal.tsx:711
|
#: src/components/dump/create/DumpCreateModal.tsx:711
|
||||||
#: src/pages/DumpEdit.tsx:542
|
#: src/pages/DumpEdit.tsx:543
|
||||||
msgid "Why?"
|
msgid "Why?"
|
||||||
msgstr "Why?"
|
msgstr "Why?"
|
||||||
|
|
||||||
|
|||||||
107
locales/fr.po
107
locales/fr.po
@@ -427,7 +427,7 @@ msgstr "← Retour"
|
|||||||
|
|
||||||
#: src/pages/Dump.tsx:326
|
#: src/pages/Dump.tsx:326
|
||||||
#: src/pages/Dump.tsx:568
|
#: src/pages/Dump.tsx:568
|
||||||
#: src/pages/DumpEdit.tsx:231
|
#: src/pages/DumpEdit.tsx:232
|
||||||
msgid "← Back to all dumps"
|
msgid "← Back to all dumps"
|
||||||
msgstr "← Retour à toutes les recos"
|
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/comment/CommentForm.tsx:127
|
||||||
#: src/components/dump/create/DumpCreateModal.tsx:752
|
#: src/components/dump/create/DumpCreateModal.tsx:752
|
||||||
#: src/components/form/FormActions.tsx:42
|
#: 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/DescriptionEditor.tsx:97
|
||||||
#: src/components/profile/EmailEditor.tsx:83
|
#: src/components/profile/EmailEditor.tsx:83
|
||||||
#: src/components/shared/ConfirmModal.tsx:63
|
#: src/components/shared/ConfirmModal.tsx:63
|
||||||
#: src/pages/Dump.tsx:445
|
#: src/pages/Dump.tsx:445
|
||||||
#: src/pages/DumpEdit.tsx:570
|
#: src/pages/DumpEdit.tsx:565
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Annuler"
|
msgstr "Annuler"
|
||||||
|
|
||||||
@@ -607,7 +607,7 @@ msgstr "Annuler la suppression"
|
|||||||
msgid "Cancel reply"
|
msgid "Cancel reply"
|
||||||
msgstr "Annuler la réponse"
|
msgstr "Annuler la réponse"
|
||||||
|
|
||||||
#: src/components/layout/AppHeader.tsx:164
|
#: src/components/layout/AppHeader.tsx:190
|
||||||
msgid "Cancel search"
|
msgid "Cancel search"
|
||||||
msgstr "Annuler la recherche"
|
msgstr "Annuler la recherche"
|
||||||
|
|
||||||
@@ -642,13 +642,13 @@ msgid "Change skin tone"
|
|||||||
msgstr "Changer la couleur de peau"
|
msgstr "Changer la couleur de peau"
|
||||||
|
|
||||||
#: src/components/chat/ChatModal.tsx:716
|
#: 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:54
|
||||||
#: src/components/layout/ChatFab.tsx:55
|
#: src/components/layout/ChatFab.tsx:55
|
||||||
msgid "Chat"
|
msgid "Chat"
|
||||||
msgstr "Tribune"
|
msgstr "Tribune"
|
||||||
|
|
||||||
#: src/components/layout/ChatButton.tsx:26
|
#: src/components/layout/ChatButton.tsx:29
|
||||||
#: src/components/layout/ChatFab.tsx:53
|
#: src/components/layout/ChatFab.tsx:53
|
||||||
msgid "Chat ({unreadChatCount} unread)"
|
msgid "Chat ({unreadChatCount} unread)"
|
||||||
msgstr "{unreadChatCount} messages non lus"
|
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."
|
msgstr "Impossible de joindre le serveur. Vérifiez votre connexion et réessayez."
|
||||||
|
|
||||||
#: src/components/profile/ProfilePlaylistsTab.tsx:126
|
#: src/components/profile/ProfilePlaylistsTab.tsx:126
|
||||||
#: src/pages/DumpEdit.tsx:558
|
#: src/pages/DumpEdit.tsx:559
|
||||||
msgid "Could not delete"
|
msgid "Could not delete"
|
||||||
msgstr "Suppression impossible"
|
msgstr "Suppression impossible"
|
||||||
|
|
||||||
@@ -720,7 +720,7 @@ msgstr "Suppression impossible"
|
|||||||
msgid "Could not rename"
|
msgid "Could not rename"
|
||||||
msgstr "Renommage impossible"
|
msgstr "Renommage impossible"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:511
|
#: src/pages/DumpEdit.tsx:512
|
||||||
msgid "Could not save"
|
msgid "Could not save"
|
||||||
msgstr "Sauvegarde impossible"
|
msgstr "Sauvegarde impossible"
|
||||||
|
|
||||||
@@ -740,7 +740,7 @@ msgstr "Désabonnement impossible"
|
|||||||
msgid "Couldn't update. Try again."
|
msgid "Couldn't update. Try again."
|
||||||
msgstr "La mise à jour a échoué. Réessayez."
|
msgstr "La mise à jour a échoué. Réessayez."
|
||||||
|
|
||||||
#: src/components/playlist/PlaylistEditForm.tsx:133
|
#: src/components/playlist/PlaylistEditForm.tsx:135
|
||||||
msgid "Cover"
|
msgid "Cover"
|
||||||
msgstr "Couverture"
|
msgstr "Couverture"
|
||||||
|
|
||||||
@@ -775,7 +775,7 @@ msgstr "Onglet par défaut"
|
|||||||
#: src/components/chat/ChatMessageItem.tsx:214
|
#: src/components/chat/ChatMessageItem.tsx:214
|
||||||
#: src/components/comment/CommentNode.tsx:265
|
#: src/components/comment/CommentNode.tsx:265
|
||||||
#: src/components/comment/CommentNode.tsx:271
|
#: src/components/comment/CommentNode.tsx:271
|
||||||
#: src/components/playlist/PlaylistEditForm.tsx:190
|
#: src/components/form/DeleteButton.tsx:36
|
||||||
#: src/components/shared/ConfirmModal.tsx:34
|
#: src/components/shared/ConfirmModal.tsx:34
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Supprimer"
|
msgstr "Supprimer"
|
||||||
@@ -789,19 +789,20 @@ msgstr "Supprimer la catégorie"
|
|||||||
msgid "Delete category \"{0}\"? This cannot be undone."
|
msgid "Delete category \"{0}\"? This cannot be undone."
|
||||||
msgstr "Supprimer la catégorie \"{0}\" ? Cette action est irréversible."
|
msgstr "Supprimer la catégorie \"{0}\" ? Cette action est irréversible."
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:313
|
#: src/pages/DumpEdit.tsx:314
|
||||||
#: src/pages/DumpEdit.tsx:566
|
#: src/pages/DumpEdit.tsx:562
|
||||||
msgid "Delete dump"
|
msgid "Delete dump"
|
||||||
msgstr "Supprimer la reco"
|
msgstr "Supprimer la reco"
|
||||||
|
|
||||||
#. placeholder {0}: res.status
|
#. placeholder {0}: res.status
|
||||||
#: src/pages/DumpEdit.tsx:192
|
#: src/pages/DumpEdit.tsx:193
|
||||||
msgid "Delete failed ({0})"
|
msgid "Delete failed ({0})"
|
||||||
msgstr "Échec de la suppression ({0})"
|
msgstr "Échec de la suppression ({0})"
|
||||||
|
|
||||||
#: src/components/playlist/PlaylistCard.tsx:142
|
#: src/components/playlist/PlaylistCard.tsx:142
|
||||||
|
#: src/components/playlist/PlaylistEditForm.tsx:190
|
||||||
#: src/components/profile/ProfilePlaylistsTab.tsx:156
|
#: src/components/profile/ProfilePlaylistsTab.tsx:156
|
||||||
#: src/pages/PlaylistDetail.tsx:136
|
#: src/pages/PlaylistDetail.tsx:141
|
||||||
msgid "Delete playlist"
|
msgid "Delete playlist"
|
||||||
msgstr "Supprimer la collection"
|
msgstr "Supprimer la collection"
|
||||||
|
|
||||||
@@ -809,7 +810,7 @@ msgstr "Supprimer la collection"
|
|||||||
msgid "Delete this comment?"
|
msgid "Delete this comment?"
|
||||||
msgstr "Supprimer ce commentaire ?"
|
msgstr "Supprimer ce commentaire ?"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:312
|
#: src/pages/DumpEdit.tsx:313
|
||||||
msgid "Delete this dump? This cannot be undone."
|
msgid "Delete this dump? This cannot be undone."
|
||||||
msgstr "Supprimer cette reco ? Cette action est irréversible."
|
msgstr "Supprimer cette reco ? Cette action est irréversible."
|
||||||
|
|
||||||
@@ -818,7 +819,7 @@ msgid "Delete this message?"
|
|||||||
msgstr "Supprimer ce message ?"
|
msgstr "Supprimer ce message ?"
|
||||||
|
|
||||||
#: src/components/profile/ProfilePlaylistsTab.tsx:155
|
#: src/components/profile/ProfilePlaylistsTab.tsx:155
|
||||||
#: src/pages/PlaylistDetail.tsx:135
|
#: src/pages/PlaylistDetail.tsx:140
|
||||||
msgid "Delete this playlist? This cannot be undone."
|
msgid "Delete this playlist? This cannot be undone."
|
||||||
msgstr "Supprimer cette collection ? Cette action est irréversible."
|
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"
|
msgid "deleted message"
|
||||||
msgstr "message supprimé"
|
msgstr "message supprimé"
|
||||||
|
|
||||||
#: src/components/playlist/PlaylistEditForm.tsx:173
|
#: src/components/playlist/PlaylistEditForm.tsx:175
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Description"
|
msgstr "Description"
|
||||||
|
|
||||||
@@ -864,11 +865,11 @@ msgstr "Déposez un fichier ici"
|
|||||||
msgid "Drop a file here, or paste one"
|
msgid "Drop a file here, or paste one"
|
||||||
msgstr "Déposez un fichier ici, ou collez-en un"
|
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"
|
msgid "Drop a replacement here"
|
||||||
msgstr "Déposez un fichier de remplacement ici"
|
msgstr "Déposez un fichier de remplacement ici"
|
||||||
|
|
||||||
#: src/components/layout/AppHeader.tsx:203
|
#: src/components/layout/AppHeader.tsx:209
|
||||||
msgid "Dump"
|
msgid "Dump"
|
||||||
msgstr "Reco"
|
msgstr "Reco"
|
||||||
|
|
||||||
@@ -946,12 +947,12 @@ msgstr "modifié {0}"
|
|||||||
msgid "Edited {0}"
|
msgid "Edited {0}"
|
||||||
msgstr "Modifié le {0}"
|
msgstr "Modifié le {0}"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:256
|
#: src/pages/DumpEdit.tsx:257
|
||||||
msgid "Editing"
|
msgid "Editing"
|
||||||
msgstr "Modification"
|
msgstr "Modification"
|
||||||
|
|
||||||
#. placeholder {0}: state.dump.title
|
#. placeholder {0}: state.dump.title
|
||||||
#: src/pages/DumpEdit.tsx:79
|
#: src/pages/DumpEdit.tsx:80
|
||||||
msgid "Editing {0}"
|
msgid "Editing {0}"
|
||||||
msgstr "Édition de {0}"
|
msgstr "Édition de {0}"
|
||||||
|
|
||||||
@@ -1005,7 +1006,7 @@ msgstr "Impossible de publier le commentaire"
|
|||||||
msgid "Failed to post reply"
|
msgid "Failed to post reply"
|
||||||
msgstr "Impossible de publier la réponse"
|
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/DescriptionEditor.tsx:99
|
||||||
#: src/components/profile/EmailEditor.tsx:86
|
#: src/components/profile/EmailEditor.tsx:86
|
||||||
msgid "Failed to save"
|
msgid "Failed to save"
|
||||||
@@ -1113,8 +1114,8 @@ msgstr "image"
|
|||||||
msgid "In collections"
|
msgid "In collections"
|
||||||
msgstr "Dans les collections"
|
msgstr "Dans les collections"
|
||||||
|
|
||||||
#: src/components/editor/TextEditor.tsx:544
|
#: src/components/editor/TextEditor.tsx:573
|
||||||
#: src/components/editor/TextEditor.tsx:546
|
#: src/components/editor/TextEditor.tsx:575
|
||||||
msgid "Insert emoji"
|
msgid "Insert emoji"
|
||||||
msgstr "Insérer un emoji"
|
msgstr "Insérer un emoji"
|
||||||
|
|
||||||
@@ -1175,7 +1176,7 @@ msgstr "Lien ou fichier"
|
|||||||
msgid "Live updates are temporarily disconnected. Trying to reconnect…"
|
msgid "Live updates are temporarily disconnected. Trying to reconnect…"
|
||||||
msgstr "Les mises à jour en direct sont temporairement interrompues. Tentative de reconnexion…"
|
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."
|
msgid "Live updates unavailable."
|
||||||
msgstr "Mises à jour en direct indisponibles."
|
msgstr "Mises à jour en direct indisponibles."
|
||||||
|
|
||||||
@@ -1188,7 +1189,7 @@ msgid "Load older messages"
|
|||||||
msgstr "Charger les messages plus anciens"
|
msgstr "Charger les messages plus anciens"
|
||||||
|
|
||||||
#: src/pages/Dump.tsx:302
|
#: src/pages/Dump.tsx:302
|
||||||
#: src/pages/DumpEdit.tsx:207
|
#: src/pages/DumpEdit.tsx:208
|
||||||
msgid "Loading dump…"
|
msgid "Loading dump…"
|
||||||
msgstr "Chargement de la reco…"
|
msgstr "Chargement de la reco…"
|
||||||
|
|
||||||
@@ -1218,7 +1219,7 @@ msgstr "Chargement du profil…"
|
|||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "Chargement…"
|
msgstr "Chargement…"
|
||||||
|
|
||||||
#: src/components/layout/AppHeader.tsx:211
|
#: src/components/layout/AppHeader.tsx:216
|
||||||
#: src/pages/UserLogin.tsx:41
|
#: src/pages/UserLogin.tsx:41
|
||||||
#: src/pages/UserLogin.tsx:67
|
#: src/pages/UserLogin.tsx:67
|
||||||
#: src/pages/UserLogin.tsx:86
|
#: src/pages/UserLogin.tsx:86
|
||||||
@@ -1366,14 +1367,14 @@ msgstr "Aucun abonnement pour le moment."
|
|||||||
msgid "Nothing here yet."
|
msgid "Nothing here yet."
|
||||||
msgstr "Rien ici pour l'instant."
|
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:376
|
||||||
#: src/pages/Notifications.tsx:494
|
#: src/pages/Notifications.tsx:494
|
||||||
#: src/pages/Settings.tsx:128
|
#: src/pages/Settings.tsx:128
|
||||||
msgid "Notifications"
|
msgid "Notifications"
|
||||||
msgstr "Notifications"
|
msgstr "Notifications"
|
||||||
|
|
||||||
#: src/components/layout/NotificationBell.tsx:54
|
#: src/components/layout/NotificationBell.tsx:56
|
||||||
msgid "Notifications ({unreadNotificationCount} unread)"
|
msgid "Notifications ({unreadNotificationCount} unread)"
|
||||||
msgstr "Notifications ({unreadNotificationCount} non lues)"
|
msgstr "Notifications ({unreadNotificationCount} non lues)"
|
||||||
|
|
||||||
@@ -1385,11 +1386,11 @@ msgstr "Désactivés"
|
|||||||
msgid "On"
|
msgid "On"
|
||||||
msgstr "Activés"
|
msgstr "Activés"
|
||||||
|
|
||||||
#: src/components/editor/TextEditor.tsx:359
|
#: src/components/editor/TextEditor.tsx:385
|
||||||
msgid "Only images can be dropped here."
|
msgid "Only images can be dropped here."
|
||||||
msgstr "Seules les images peuvent être déposées ici."
|
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."
|
msgid "Only its poster or a moderator can edit this dump."
|
||||||
msgstr "Seuls son auteur et les modérateurs peuvent modifier ce dump."
|
msgstr "Seuls son auteur et les modérateurs peuvent modifier ce dump."
|
||||||
|
|
||||||
@@ -1463,7 +1464,7 @@ msgid "Play"
|
|||||||
msgstr "Lecture"
|
msgstr "Lecture"
|
||||||
|
|
||||||
#: src/components/dump/create/StepIndicator.tsx:21
|
#: 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/layout/UserMenu.tsx:81
|
||||||
#: src/components/profile/ProfileFollowTab.tsx:167
|
#: src/components/profile/ProfileFollowTab.tsx:167
|
||||||
#: src/components/profile/ProfilePlaylistsTab.tsx:118
|
#: src/components/profile/ProfilePlaylistsTab.tsx:118
|
||||||
@@ -1512,7 +1513,7 @@ msgstr "public"
|
|||||||
msgid "Public"
|
msgid "Public"
|
||||||
msgstr "Public"
|
msgstr "Public"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:289
|
#: src/pages/DumpEdit.tsx:290
|
||||||
msgid "Refresh metadata"
|
msgid "Refresh metadata"
|
||||||
msgstr "Actualiser les métadonnées"
|
msgstr "Actualiser les métadonnées"
|
||||||
|
|
||||||
@@ -1520,7 +1521,7 @@ msgstr "Actualiser les métadonnées"
|
|||||||
msgid "Refreshing stream…"
|
msgid "Refreshing stream…"
|
||||||
msgstr "Actualisation du flux…"
|
msgstr "Actualisation du flux…"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:288
|
#: src/pages/DumpEdit.tsx:289
|
||||||
msgid "Refreshing…"
|
msgid "Refreshing…"
|
||||||
msgstr "Actualisation…"
|
msgstr "Actualisation…"
|
||||||
|
|
||||||
@@ -1566,7 +1567,7 @@ msgstr "Renommer"
|
|||||||
msgid "Renaming…"
|
msgid "Renaming…"
|
||||||
msgstr "Renommage…"
|
msgstr "Renommage…"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:494
|
#: src/pages/DumpEdit.tsx:495
|
||||||
msgid "Replace file"
|
msgid "Replace file"
|
||||||
msgstr "Remplacer le fichier"
|
msgstr "Remplacer le fichier"
|
||||||
|
|
||||||
@@ -1592,8 +1593,8 @@ msgstr "Échec de la réinitialisation"
|
|||||||
msgid "Reset password"
|
msgid "Reset password"
|
||||||
msgstr "Réinitialiser le mot de passe"
|
msgstr "Réinitialiser le mot de passe"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:470
|
#: src/pages/DumpEdit.tsx:471
|
||||||
#: src/pages/DumpEdit.tsx:525
|
#: src/pages/DumpEdit.tsx:526
|
||||||
msgid "Reset to default"
|
msgid "Reset to default"
|
||||||
msgstr "Réinitialiser par défaut"
|
msgstr "Réinitialiser par défaut"
|
||||||
|
|
||||||
@@ -1604,7 +1605,7 @@ msgstr "Rétablir le titre suggéré"
|
|||||||
|
|
||||||
#: src/components/chat/PendingItem.tsx:86
|
#: src/components/chat/PendingItem.tsx:86
|
||||||
#: src/pages/Dump.tsx:319
|
#: src/pages/Dump.tsx:319
|
||||||
#: src/pages/DumpEdit.tsx:224
|
#: src/pages/DumpEdit.tsx:225
|
||||||
msgid "Retry"
|
msgid "Retry"
|
||||||
msgstr "Réessayer"
|
msgstr "Réessayer"
|
||||||
|
|
||||||
@@ -1615,16 +1616,16 @@ msgstr "Rôle"
|
|||||||
#: src/components/category/CategoryManager.tsx:216
|
#: src/components/category/CategoryManager.tsx:216
|
||||||
#: src/components/chat/ChatEditBox.tsx:85
|
#: src/components/chat/ChatEditBox.tsx:85
|
||||||
#: src/components/comment/CommentNode.tsx:216
|
#: 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/DescriptionEditor.tsx:89
|
||||||
#: src/components/profile/EmailEditor.tsx:75
|
#: src/components/profile/EmailEditor.tsx:75
|
||||||
#: src/pages/Dump.tsx:437
|
#: src/pages/Dump.tsx:437
|
||||||
#: src/pages/DumpEdit.tsx:573
|
#: src/pages/DumpEdit.tsx:568
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Enregistrer"
|
msgstr "Enregistrer"
|
||||||
|
|
||||||
#: src/components/comment/CommentNode.tsx:217
|
#: 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/ChangePasswordModal.tsx:119
|
||||||
#: src/components/profile/DescriptionEditor.tsx:86
|
#: src/components/profile/DescriptionEditor.tsx:86
|
||||||
#: src/components/profile/EmailEditor.tsx:72
|
#: src/components/profile/EmailEditor.tsx:72
|
||||||
@@ -1633,7 +1634,7 @@ msgstr "Enregistrer"
|
|||||||
msgid "Saving…"
|
msgid "Saving…"
|
||||||
msgstr "Enregistrement…"
|
msgstr "Enregistrement…"
|
||||||
|
|
||||||
#: src/components/layout/AppHeader.tsx:164
|
#: src/components/layout/AppHeader.tsx:190
|
||||||
#: src/components/layout/SearchBar.tsx:83
|
#: src/components/layout/SearchBar.tsx:83
|
||||||
#: src/pages/Search.tsx:69
|
#: src/pages/Search.tsx:69
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
@@ -1676,7 +1677,7 @@ msgstr "Envoyer le lien de réinitialisation"
|
|||||||
msgid "Sending…"
|
msgid "Sending…"
|
||||||
msgstr "Envoi…"
|
msgstr "Envoi…"
|
||||||
|
|
||||||
#: src/components/layout/AppHeader.tsx:200
|
#: src/components/layout/AppHeader.tsx:206
|
||||||
msgid "Server unreachable"
|
msgid "Server unreachable"
|
||||||
msgstr "Serveur inaccessible"
|
msgstr "Serveur inaccessible"
|
||||||
|
|
||||||
@@ -1704,14 +1705,14 @@ msgstr "Usage unique, valable 7 jours."
|
|||||||
msgid "slug"
|
msgid "slug"
|
||||||
msgstr "identifiant"
|
msgstr "identifiant"
|
||||||
|
|
||||||
#: src/components/editor/TextEditor.tsx:317
|
#: src/components/editor/TextEditor.tsx:343
|
||||||
msgid "Some images couldn't be uploaded."
|
msgid "Some images couldn't be uploaded."
|
||||||
msgstr "Certaines images n'ont pas pu être envoyées."
|
msgstr "Certaines images n'ont pas pu être envoyées."
|
||||||
|
|
||||||
#: src/components/form/FormError.tsx:31
|
#: src/components/form/FormError.tsx:31
|
||||||
#: src/components/layout/PageError.tsx:29
|
#: src/components/layout/PageError.tsx:29
|
||||||
#: src/contexts/ws/WSProvider.tsx:729
|
#: src/contexts/ws/WSProvider.tsx:729
|
||||||
#: src/pages/PlaylistDetail.tsx:119
|
#: src/pages/PlaylistDetail.tsx:124
|
||||||
msgid "Something went wrong"
|
msgid "Something went wrong"
|
||||||
msgstr "Une erreur est survenue"
|
msgstr "Une erreur est survenue"
|
||||||
|
|
||||||
@@ -1743,7 +1744,7 @@ msgstr "la tribune"
|
|||||||
msgid "The dump couldn't be removed. Try again."
|
msgid "The dump couldn't be removed. Try again."
|
||||||
msgstr "Le dump n'a pas pu être retiré. Réessayez."
|
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."
|
msgid "The image couldn't be uploaded."
|
||||||
msgstr "L'image n'a pas pu être envoyée."
|
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."
|
msgid "This unsubscribe link is missing or malformed."
|
||||||
msgstr "Ce lien de désabonnement est absent ou mal formé."
|
msgstr "Ce lien de désabonnement est absent ou mal formé."
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:454
|
#: src/pages/DumpEdit.tsx:455
|
||||||
msgid "Thumbnail"
|
msgid "Thumbnail"
|
||||||
msgstr "Miniature"
|
msgstr "Miniature"
|
||||||
|
|
||||||
#: src/components/dump/create/TitleField.tsx:45
|
#: src/components/dump/create/TitleField.tsx:45
|
||||||
#: src/components/playlist/PlaylistCreateForm.tsx:96
|
#: src/components/playlist/PlaylistCreateForm.tsx:96
|
||||||
#: src/components/playlist/PlaylistEditForm.tsx:157
|
#: src/components/playlist/PlaylistEditForm.tsx:159
|
||||||
#: src/pages/DumpEdit.tsx:515
|
#: src/pages/DumpEdit.tsx:516
|
||||||
msgid "Title"
|
msgid "Title"
|
||||||
msgstr "Titre"
|
msgstr "Titre"
|
||||||
|
|
||||||
@@ -1861,7 +1862,7 @@ msgstr "Envoi échoué"
|
|||||||
msgid "Uploading {0}%"
|
msgid "Uploading {0}%"
|
||||||
msgstr "Envoi {0} %"
|
msgstr "Envoi {0} %"
|
||||||
|
|
||||||
#: src/components/editor/TextEditor.tsx:566
|
#: src/components/editor/TextEditor.tsx:595
|
||||||
msgid "Uploading image…"
|
msgid "Uploading image…"
|
||||||
msgstr "Envoi de l'image…"
|
msgstr "Envoi de l'image…"
|
||||||
|
|
||||||
@@ -1883,7 +1884,7 @@ msgstr "Voté"
|
|||||||
msgid "Upvoted ({0})"
|
msgid "Upvoted ({0})"
|
||||||
msgstr "Voté ({0})"
|
msgstr "Voté ({0})"
|
||||||
|
|
||||||
#: src/pages/DumpEdit.tsx:486
|
#: src/pages/DumpEdit.tsx:487
|
||||||
msgid "URL"
|
msgid "URL"
|
||||||
msgstr "URL"
|
msgstr "URL"
|
||||||
|
|
||||||
@@ -1933,7 +1934,7 @@ msgid "Volume"
|
|||||||
msgstr "Volume"
|
msgstr "Volume"
|
||||||
|
|
||||||
#: src/components/dump/create/DumpCreateModal.tsx:712
|
#: src/components/dump/create/DumpCreateModal.tsx:712
|
||||||
#: src/pages/DumpEdit.tsx:543
|
#: src/pages/DumpEdit.tsx:544
|
||||||
msgid "What makes it worth it?"
|
msgid "What makes it worth it?"
|
||||||
msgstr "Pourquoi on en voudrait ?"
|
msgstr "Pourquoi on en voudrait ?"
|
||||||
|
|
||||||
@@ -1951,7 +1952,7 @@ msgid "Why & where"
|
|||||||
msgstr "Pourquoi & où"
|
msgstr "Pourquoi & où"
|
||||||
|
|
||||||
#: src/components/dump/create/DumpCreateModal.tsx:711
|
#: src/components/dump/create/DumpCreateModal.tsx:711
|
||||||
#: src/pages/DumpEdit.tsx:542
|
#: src/pages/DumpEdit.tsx:543
|
||||||
msgid "Why?"
|
msgid "Why?"
|
||||||
msgstr "Pourquoi ?"
|
msgstr "Pourquoi ?"
|
||||||
|
|
||||||
|
|||||||
67
src/App.css
67
src/App.css
@@ -164,8 +164,7 @@
|
|||||||
.dump-post-header,
|
.dump-post-header,
|
||||||
.dump-rich-content,
|
.dump-rich-content,
|
||||||
.form-page-header,
|
.form-page-header,
|
||||||
.dump-edit-panel,
|
.form-panel,
|
||||||
.dump-edit-footer,
|
|
||||||
.playlist-detail-header,
|
.playlist-detail-header,
|
||||||
.comment-node-inner {
|
.comment-node-inner {
|
||||||
box-shadow: var(--panel-ring), var(--card-shadow);
|
box-shadow: var(--panel-ring), var(--card-shadow);
|
||||||
@@ -3374,7 +3373,7 @@ body.has-player .chat-fab {
|
|||||||
}
|
}
|
||||||
.form-page--two-col .form-page-header,
|
.form-page--two-col .form-page-header,
|
||||||
.dump-edit-form,
|
.dump-edit-form,
|
||||||
.dump-edit-footer {
|
.dump-edit-form > .form-panel--bar {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
/* "Why?" soaks up whatever height the source column adds, so a tall
|
/* "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;
|
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;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
@@ -3435,18 +3437,35 @@ body.has-player .chat-fab {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dump-edit-footer {
|
.form-panel--bar {
|
||||||
padding: 0.875rem 1.25rem;
|
padding: 0.875rem 1.25rem;
|
||||||
background: var(--color-surface);
|
|
||||||
border-radius: 0 0 var(--radius-xl) var(--radius-xl);
|
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;
|
padding-top: 0;
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
margin-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 {
|
.dump-edit-refresh {
|
||||||
margin-top: 0.75rem;
|
margin-top: 0.75rem;
|
||||||
}
|
}
|
||||||
@@ -3481,25 +3500,6 @@ body.has-player .chat-fab {
|
|||||||
margin-left: auto;
|
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 <button> chrome so it looks the same
|
/* Subtle text action. Resets the global <button> chrome so it looks the same
|
||||||
whether rendered as a <button> (modal/page forms) or a <Link> (DumpEdit). */
|
whether rendered as a <button> (modal/page forms) or a <Link> (DumpEdit). */
|
||||||
.form-cancel {
|
.form-cancel {
|
||||||
@@ -5327,6 +5327,21 @@ body.has-player .chat-fab {
|
|||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* While edited, the header gives way to the form's own panels. */
|
||||||
|
.playlist-detail-header--editing {
|
||||||
|
padding: 0;
|
||||||
|
background: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlist-edit-form {
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlist-edit-form > .form-panel:first-child {
|
||||||
|
border-radius: var(--radius-xl) var(--radius-xl) 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
.playlist-detail-header-top {
|
.playlist-detail-header-top {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|||||||
@@ -99,6 +99,20 @@ interface PendingInsert {
|
|||||||
focus: boolean;
|
focus: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sizes an `autoResize` textarea to its text. A border-box height counts the
|
||||||
|
* borders, which `scrollHeight` leaves out. Below its `max-height` the box
|
||||||
|
* holds all its text, so a scrollbar there could only come of sub-pixel
|
||||||
|
* rounding, and would narrow the text into more lines; overflow is hidden
|
||||||
|
* then, and left to the stylesheet once the box is capped.
|
||||||
|
*/
|
||||||
|
function fitHeight(el: HTMLTextAreaElement): void {
|
||||||
|
el.style.height = "auto";
|
||||||
|
const height = el.scrollHeight + el.offsetHeight - el.clientHeight;
|
||||||
|
el.style.height = `${height}px`;
|
||||||
|
el.style.overflowY = el.offsetHeight < height ? "" : "hidden";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a textarea that completes `@mentions` and `:emoji`, opens an emoji
|
* Renders a textarea that completes `@mentions` and `:emoji`, opens an emoji
|
||||||
* picker from its button, and counts characters near `maxLength`. A pasted or
|
* picker from its button, and counts characters near `maxLength`. A pasted or
|
||||||
@@ -274,17 +288,25 @@ export const TextEditor: React.ForwardRefExoticComponent<
|
|||||||
// Before paint, so that the first frame, and any layout effect measuring
|
// Before paint, so that the first frame, and any layout effect measuring
|
||||||
// it (such as a height transition), sees the final size.
|
// it (such as a height transition), sees the final size.
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (!autoResize) return;
|
if (autoResize && textareaRef.current) fitHeight(textareaRef.current);
|
||||||
const el = textareaRef.current;
|
|
||||||
if (!el) return;
|
|
||||||
el.style.height = "auto";
|
|
||||||
// A border-box height counts the borders, which scrollHeight leaves
|
|
||||||
// out; without them the text overflows by a few pixels and scrolls.
|
|
||||||
el.style.height = `${
|
|
||||||
el.scrollHeight + el.offsetHeight - el.clientHeight
|
|
||||||
}px`;
|
|
||||||
}, [value, autoResize]);
|
}, [value, autoResize]);
|
||||||
|
|
||||||
|
// The text rewraps when the width changes with the value unchanged: when
|
||||||
|
// the page's scrollbar shows as the editor makes it taller, or the window
|
||||||
|
// narrows.
|
||||||
|
useEffect(() => {
|
||||||
|
const el = textareaRef.current;
|
||||||
|
if (!autoResize || !el) return;
|
||||||
|
let width = el.clientWidth;
|
||||||
|
const observer = new ResizeObserver(() => {
|
||||||
|
if (el.clientWidth === width) return;
|
||||||
|
width = el.clientWidth;
|
||||||
|
fitHeight(el);
|
||||||
|
});
|
||||||
|
observer.observe(el);
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [autoResize]);
|
||||||
|
|
||||||
// The textarea is read-only while images upload, so the spot they go to
|
// The textarea is read-only while images upload, so the spot they go to
|
||||||
// can't move. They go in once it is writable again.
|
// can't move. They go in once it is writable again.
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@@ -534,6 +556,9 @@ export const TextEditor: React.ForwardRefExoticComponent<
|
|||||||
rows={rows}
|
rows={rows}
|
||||||
id={id}
|
id={id}
|
||||||
className={className}
|
className={className}
|
||||||
|
// Its height follows the text, so a grip to drag it would only
|
||||||
|
// be undone at the next keystroke.
|
||||||
|
style={autoResize ? { resize: "none" } : undefined}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
ref={emojiButtonRef}
|
ref={emojiButtonRef}
|
||||||
|
|||||||
40
src/components/form/DeleteButton.tsx
Normal file
40
src/components/form/DeleteButton.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Renders the destructive action of an edit form's bar, in `DumpEdit` and
|
||||||
|
* `PlaylistEditForm`.
|
||||||
|
*
|
||||||
|
* @module
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Trans } from "@lingui/react/macro";
|
||||||
|
|
||||||
|
/** Passed to {@link DeleteButton} by an edit form. */
|
||||||
|
export interface DeleteButtonProps {
|
||||||
|
/** Its accessible name, which names what goes, such as "Delete dump". */
|
||||||
|
label: string;
|
||||||
|
/** Opens the page's confirmation, which deletes. */
|
||||||
|
onClick: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a compact "Delete" button, at the start of the bar's
|
||||||
|
* `.form-actions`. A bar too narrow for it beside Cancel and Save shows its
|
||||||
|
* icon instead (`.form-delete-icon`).
|
||||||
|
*/
|
||||||
|
export function DeleteButton(
|
||||||
|
{ label, onClick }: DeleteButtonProps,
|
||||||
|
): React.JSX.Element {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn-danger btn-sm"
|
||||||
|
aria-label={label}
|
||||||
|
title={label}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
<span className="form-delete-icon" aria-hidden>🗑</span>
|
||||||
|
<span className="form-delete-label">
|
||||||
|
<Trans>Delete</Trans>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ import { ImagePicker } from "../shared/ImagePicker.tsx";
|
|||||||
import { TextField } from "../form/TextField.tsx";
|
import { TextField } from "../form/TextField.tsx";
|
||||||
import { RichTextField } from "../form/RichTextField.tsx";
|
import { RichTextField } from "../form/RichTextField.tsx";
|
||||||
import { VisibilityToggle } from "../form/SegmentedField.tsx";
|
import { VisibilityToggle } from "../form/SegmentedField.tsx";
|
||||||
|
import { DeleteButton } from "../form/DeleteButton.tsx";
|
||||||
import { FormError } from "../form/FormError.tsx";
|
import { FormError } from "../form/FormError.tsx";
|
||||||
import { SubmitButton } from "../form/SubmitButton.tsx";
|
import { SubmitButton } from "../form/SubmitButton.tsx";
|
||||||
import { SlugField } from "../form/SlugField.tsx";
|
import { SlugField } from "../form/SlugField.tsx";
|
||||||
@@ -121,13 +122,14 @@ export function PlaylistEditForm(
|
|||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<form
|
<form
|
||||||
className="form animate-in"
|
className="form playlist-edit-form animate-in"
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
// The editor's popups take their own Escape and prevent it.
|
// The editor's popups take their own Escape and prevent it.
|
||||||
if (e.key === "Escape" && !e.defaultPrevented) onCancel();
|
if (e.key === "Escape" && !e.defaultPrevented) onCancel();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<div className="form-panel">
|
||||||
<div className="form-field">
|
<div className="form-field">
|
||||||
<span className="form-label">
|
<span className="form-label">
|
||||||
<Trans>Cover</Trans>
|
<Trans>Cover</Trans>
|
||||||
@@ -180,20 +182,24 @@ export function PlaylistEditForm(
|
|||||||
<VisibilityToggle<EditValues> name="isPublic" />
|
<VisibilityToggle<EditValues> name="isPublic" />
|
||||||
|
|
||||||
<FormError title={t`Failed to save`} />
|
<FormError title={t`Failed to save`} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-panel form-panel--bar">
|
||||||
<div className="form-actions">
|
<div className="form-actions">
|
||||||
|
<DeleteButton
|
||||||
|
label={t`Delete playlist`}
|
||||||
|
onClick={onRequestDelete}
|
||||||
|
/>
|
||||||
|
<div className="form-actions-right">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn-danger"
|
className="form-cancel"
|
||||||
onClick={onRequestDelete}
|
onClick={onCancel}
|
||||||
>
|
>
|
||||||
<Trans>Delete</Trans>
|
|
||||||
</button>
|
|
||||||
<div className="form-actions-right">
|
|
||||||
<button type="button" className="form-cancel" onClick={onCancel}>
|
|
||||||
<Trans>Cancel</Trans>
|
<Trans>Cancel</Trans>
|
||||||
</button>
|
</button>
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
|
className="btn-primary btn-sm"
|
||||||
pendingLabel={<Trans>Saving…</Trans>}
|
pendingLabel={<Trans>Saving…</Trans>}
|
||||||
disabled={!title.trim()}
|
disabled={!title.trim()}
|
||||||
>
|
>
|
||||||
@@ -201,6 +207,7 @@ export function PlaylistEditForm(
|
|||||||
</SubmitButton>
|
</SubmitButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import { SubmitButton } from "../components/form/SubmitButton.tsx";
|
|||||||
import { TextField } from "../components/form/TextField.tsx";
|
import { TextField } from "../components/form/TextField.tsx";
|
||||||
import { useApiForm } from "../hooks/form/useApiForm.ts";
|
import { useApiForm } from "../hooks/form/useApiForm.ts";
|
||||||
import { VisibilityToggle } from "../components/form/SegmentedField.tsx";
|
import { VisibilityToggle } from "../components/form/SegmentedField.tsx";
|
||||||
|
import { DeleteButton } from "../components/form/DeleteButton.tsx";
|
||||||
import { SlugField } from "../components/form/SlugField.tsx";
|
import { SlugField } from "../components/form/SlugField.tsx";
|
||||||
import { useCanonicalPath } from "../hooks/shared/useCanonicalPath.ts";
|
import { useCanonicalPath } from "../hooks/shared/useCanonicalPath.ts";
|
||||||
import { userPath } from "../../shared/paths.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
|
/* The source panel holds what was dumped, the details panel how it
|
||||||
is presented and who sees it. */
|
is presented and who sees it. */
|
||||||
}
|
}
|
||||||
<div className="dump-edit-panel dump-edit-panel--source">
|
<div className="form-panel dump-edit-panel--source">
|
||||||
{preview}
|
{preview}
|
||||||
|
|
||||||
<div className="form-field">
|
<div className="form-field">
|
||||||
@@ -507,7 +508,7 @@ function DumpEditForm({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="dump-edit-panel dump-edit-panel--details">
|
<div className="form-panel dump-edit-panel--details">
|
||||||
<FormError title={t`Could not save`} />
|
<FormError title={t`Could not save`} />
|
||||||
|
|
||||||
<TextField<EditValues>
|
<TextField<EditValues>
|
||||||
@@ -553,23 +554,17 @@ function DumpEditForm({
|
|||||||
<VisibilityToggle<EditValues> name="isPublic" />
|
<VisibilityToggle<EditValues> name="isPublic" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="dump-edit-footer">
|
<div className="form-panel form-panel--bar">
|
||||||
{deleteError && (
|
{deleteError && (
|
||||||
<ErrorCard title={t`Could not delete`} message={deleteError} />
|
<ErrorCard title={t`Could not delete`} message={deleteError} />
|
||||||
)}
|
)}
|
||||||
<div className="form-actions">
|
<div className="form-actions">
|
||||||
<button
|
<DeleteButton label={t`Delete dump`} onClick={onRequestDelete} />
|
||||||
type="button"
|
|
||||||
onClick={onRequestDelete}
|
|
||||||
className="btn-danger"
|
|
||||||
>
|
|
||||||
<Trans>Delete dump</Trans>
|
|
||||||
</button>
|
|
||||||
<div className="form-actions-right">
|
<div className="form-actions-right">
|
||||||
<Link to={dumpUrl(dump)} className="form-cancel">
|
<Link to={dumpUrl(dump)} className="form-cancel">
|
||||||
<Trans>Cancel</Trans>
|
<Trans>Cancel</Trans>
|
||||||
</Link>
|
</Link>
|
||||||
<SubmitButton>
|
<SubmitButton className="btn-primary btn-sm">
|
||||||
<Trans>Save</Trans>
|
<Trans>Save</Trans>
|
||||||
</SubmitButton>
|
</SubmitButton>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -90,7 +90,12 @@ export function PlaylistDetail(): React.JSX.Element {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PageShell>
|
<PageShell>
|
||||||
<div className="playlist-detail-header" ref={headerRef}>
|
<div
|
||||||
|
className={`playlist-detail-header${
|
||||||
|
editOpen ? " playlist-detail-header--editing" : ""
|
||||||
|
}`}
|
||||||
|
ref={headerRef}
|
||||||
|
>
|
||||||
{editOpen
|
{editOpen
|
||||||
? (
|
? (
|
||||||
<PlaylistEditForm
|
<PlaylistEditForm
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ describe("PlaylistDetail", () => {
|
|||||||
);
|
);
|
||||||
const { user } = open();
|
const { user } = open();
|
||||||
await user.click(await screen.findByRole("button", { name: "Edit" }));
|
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(
|
await user.click(
|
||||||
within(screen.getByRole("alertdialog")).getByRole("button", {
|
within(screen.getByRole("alertdialog")).getByRole("button", {
|
||||||
name: "Delete playlist",
|
name: "Delete playlist",
|
||||||
@@ -379,7 +379,7 @@ describe("PlaylistDetail", () => {
|
|||||||
route("DELETE /api/playlists/:id", () => fail("Forbidden", 403));
|
route("DELETE /api/playlists/:id", () => fail("Forbidden", 403));
|
||||||
const { user } = open();
|
const { user } = open();
|
||||||
await user.click(await screen.findByRole("button", { name: "Edit" }));
|
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(
|
await user.click(
|
||||||
within(screen.getByRole("alertdialog")).getByRole("button", {
|
within(screen.getByRole("alertdialog")).getByRole("button", {
|
||||||
name: "Delete playlist",
|
name: "Delete playlist",
|
||||||
|
|||||||
Reference in New Issue
Block a user