diff --git a/API.md b/API.md index 356c1cf4..486f22fa 100644 --- a/API.md +++ b/API.md @@ -22,27 +22,28 @@ has one word, the same as in pages. ## Pages -| Path | Views | Access | Page | -| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | ------------------------------ | -| `/` | `/hot`, `/new`, `/journal`, `/follow`, `/follow/playlists`; the bare `/` is the viewer's default tab, the bare `/follow` the users followed | anyone, `/follow` signed in | `Index` | -| `/` | `//hot`, `/new`, `/journal`, `/follow`, `/follow/playlists` | anyone, `/follow` signed in | `Index` | -| `/@` | the overview: dumps beside upvoted | anyone | `UserPublicProfile` | -| `/@/dumps`, `/upvoted`, `/playlists`, `/invitees` | | anyone | `UserPublicProfile` | -| `/@/follow` | `/@/follow/playlists`; the bare tab lists users | anyone | `UserPublicProfile` | -| `/@/manage` | | `user:manage`, on others' profiles | `UserPublicProfile` | -| `/@/dumps/` | | anyone; a private dump, its poster | `Dump` | -| `/@/dumps//edit` | | its poster, `dump:moderate` | `DumpEdit` | -| `/@/playlists/` | | anyone; a private playlist, its owner | `PlaylistDetail` | -| `/@/playlists//edit` | | its owner, `playlist:moderate` | `PlaylistDetail` | -| `/search?q=` | `/search/users?q=`, `/search/playlists?q=` | anyone | `Search` | -| `/notifications` | | signed in | `Notifications` | -| `/community` | `/community/monthly`; the bare path is the week | signed in | `Community` | -| `/settings` | | signed in | `Settings` | -| `/manage` | | `category:manage`, `federation:manage` | `Manage` | -| `/login`, `/register?token=` | `/login?next=` comes back to a page | signed out | `UserLogin`, `UserRegister` | -| `/authorize?client_id=…` | | signed in, else via `/login?next=` | `Authorize` | -| `/federation/callback?code=&state=` | | anyone | `FederationCallback` | -| `/reset-password?token=`, `/unsubscribe?token=` | | anyone | `ResetPassword`, `Unsubscribe` | +| Path | Views | Access | Page | +| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | --------------------------- | +| `/` | `/hot`, `/new`, `/journal`, `/follow`, `/follow/playlists`; the bare `/` is the viewer's default tab, the bare `/follow` the users followed | anyone, `/follow` signed in | `Index` | +| `/` | `//hot`, `/new`, `/journal`, `/follow`, `/follow/playlists` | anyone, `/follow` signed in | `Index` | +| `/@` | the overview: dumps beside upvoted | anyone | `UserPublicProfile` | +| `/@/dumps`, `/upvoted`, `/playlists`, `/invitees` | | anyone | `UserPublicProfile` | +| `/@/follow` | `/@/follow/playlists`; the bare tab lists users | anyone | `UserPublicProfile` | +| `/@/manage` | | `user:manage`, on others' profiles | `UserPublicProfile` | +| `/@/dumps/` | | anyone; a private dump, its poster | `Dump` | +| `/@/dumps//edit` | | its poster, `dump:moderate` | `DumpEdit` | +| `/@/playlists/` | | anyone; a private playlist, its owner | `PlaylistDetail` | +| `/@/playlists//edit` | | its owner, `playlist:moderate` | `PlaylistDetail` | +| `/search?q=` | `/search/users?q=`, `/search/playlists?q=` | anyone | `Search` | +| `/notifications` | | signed in | `Notifications` | +| `/community` | `/community/monthly`; the bare path is the week | signed in | `Community` | +| `/settings` | | signed in | `Settings` | +| `/manage` | | `category:manage`, `federation:manage` | `Manage` | +| `/login`, `/register?token=` | `/login?next=` comes back to a page | signed out | `UserLogin`, `UserRegister` | +| `/authorize?client_id=…` | | signed in, else via `/login?next=` | `Authorize` | +| `/federation/callback?code=&state=` | | anyone | `FederationCallback` | +| `/reset-password` | `/reset-password?token=`, from the emailed link, sets the new password | anyone | `ResetPassword` | +| `/unsubscribe?token=` | | anyone | `Unsubscribe` | `/?share_url=` opens the create form on a link shared from Android, `/?chat=open` opens the chat over any page, and `#comment-` scrolls a dump's diff --git a/locales/en.po b/locales/en.po index 30fbc2c6..c5325ecd 100644 --- a/locales/en.po +++ b/locales/en.po @@ -206,14 +206,14 @@ msgstr "# Welcome to {site}!\n" "Your account has been created successfully. Welcome aboard!" #: src/components/dump/create/DumpCreateModal.tsx:736 -#: src/pages/PlaylistDetail.tsx:80 +#: src/pages/PlaylistDetail.tsx:98 #: src/pages/UserPublicProfile.tsx:125 msgid "← Back" msgstr "← Back" -#: src/pages/Dump.tsx:325 -#: src/pages/Dump.tsx:552 -#: src/pages/DumpEdit.tsx:233 +#: src/pages/Dump.tsx:330 +#: src/pages/Dump.tsx:557 +#: src/pages/DumpEdit.tsx:234 msgid "← Back to all dumps" msgstr "← Back to all dumps" @@ -225,7 +225,7 @@ msgstr "+ Invite someone" msgid "+ New playlist" msgstr "+ New playlist" -#: src/pages/Dump.tsx:399 +#: src/pages/Dump.tsx:404 msgid "+ Playlist" msgstr "+ Playlist" @@ -377,7 +377,7 @@ msgstr "Appearance" #. placeholder {0}: VALIDATION.PASSWORD_MIN #: src/components/profile/ChangePasswordModal.tsx:101 -#: src/pages/ResetPassword.tsx:124 +#: src/pages/ResetPassword.tsx:176 #: src/pages/UserRegister.tsx:168 msgid "At least {0} characters" msgstr "At least {0} characters" @@ -390,8 +390,8 @@ msgstr "At most {maxLength} characters." msgid "Auto" msgstr "Auto" -#: src/pages/ResetPassword.tsx:74 -#: src/pages/ResetPassword.tsx:147 +#: src/pages/ResetPassword.tsx:101 +#: src/pages/ResetPassword.tsx:199 msgid "Back to login" msgstr "Back to login" @@ -439,8 +439,8 @@ msgstr "Can't sign in there" #: src/components/profile/EmailEditor.tsx:83 #: src/components/shared/ConfirmModal.tsx:63 #: src/pages/Authorize.tsx:158 -#: src/pages/Dump.tsx:441 -#: src/pages/DumpEdit.tsx:560 +#: src/pages/Dump.tsx:446 +#: src/pages/DumpEdit.tsx:561 msgid "Cancel" msgstr "Cancel" @@ -546,7 +546,7 @@ msgid "digest.community" msgstr "Community" #: src/components/profile/ChangePasswordModal.tsx:108 -#: src/pages/ResetPassword.tsx:131 +#: src/pages/ResetPassword.tsx:183 msgid "Confirm new password" msgstr "Confirm new password" @@ -582,8 +582,8 @@ msgstr "Could not change password" 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:177 -#: src/pages/DumpEdit.tsx:554 +#: src/components/profile/ProfilePlaylistsTab.tsx:178 +#: src/pages/DumpEdit.tsx:555 msgid "Could not delete" msgstr "Could not delete" @@ -591,7 +591,7 @@ msgstr "Could not delete" msgid "Could not rename" msgstr "Could not rename" -#: src/pages/DumpEdit.tsx:506 +#: src/pages/DumpEdit.tsx:507 msgid "Could not save" msgstr "Could not save" @@ -668,20 +668,20 @@ msgstr "Delete category" msgid "Delete category \"{0}\"? This cannot be undone." msgstr "Delete category \"{0}\"? This cannot be undone." -#: src/pages/DumpEdit.tsx:315 -#: src/pages/DumpEdit.tsx:557 +#: src/pages/DumpEdit.tsx:316 +#: src/pages/DumpEdit.tsx:558 msgid "Delete dump" msgstr "Delete dump" #. placeholder {0}: res.status -#: src/pages/DumpEdit.tsx:194 +#: src/pages/DumpEdit.tsx:195 msgid "Delete failed ({0})" msgstr "Delete failed ({0})" #: src/components/playlist/PlaylistCard.tsx:149 #: src/components/playlist/PlaylistEditForm.tsx:213 -#: src/components/profile/ProfilePlaylistsTab.tsx:207 -#: src/pages/PlaylistDetail.tsx:141 +#: src/components/profile/ProfilePlaylistsTab.tsx:208 +#: src/pages/PlaylistDetail.tsx:172 msgid "Delete playlist" msgstr "Delete playlist" @@ -689,7 +689,7 @@ msgstr "Delete playlist" msgid "Delete this comment?" msgstr "Delete this comment?" -#: src/pages/DumpEdit.tsx:314 +#: src/pages/DumpEdit.tsx:315 msgid "Delete this dump? This cannot be undone." msgstr "Delete this dump? This cannot be undone." @@ -697,8 +697,8 @@ msgstr "Delete this dump? This cannot be undone." msgid "Delete this message?" msgstr "Delete this message?" -#: src/components/profile/ProfilePlaylistsTab.tsx:206 -#: src/pages/PlaylistDetail.tsx:140 +#: src/components/profile/ProfilePlaylistsTab.tsx:207 +#: src/pages/PlaylistDetail.tsx:171 msgid "Delete this playlist? This cannot be undone." msgstr "Delete this playlist? This cannot be undone." @@ -748,7 +748,7 @@ 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:497 +#: src/pages/DumpEdit.tsx:498 msgid "Drop a replacement here" msgstr "Drop a replacement here" @@ -788,7 +788,7 @@ msgstr "Earlier" #: src/components/chat/PendingItem.tsx:93 #: src/components/comment/CommentNode.tsx:256 #: src/components/playlist/PlaylistHeader.tsx:60 -#: src/pages/Dump.tsx:548 +#: src/pages/Dump.tsx:553 msgid "Edit" msgstr "Edit" @@ -806,7 +806,7 @@ msgid "Edit email" msgstr "Edit email" #: src/components/dump/create/TitleField.tsx:69 -#: src/pages/Dump.tsx:458 +#: src/pages/Dump.tsx:463 msgid "Edit title" msgstr "Edit title" @@ -820,7 +820,7 @@ msgstr "edited" #: src/components/chat/ChatMessageItem.tsx:132 #: src/components/comment/CommentNode.tsx:205 #: src/components/playlist/PlaylistHeader.tsx:95 -#: src/pages/Dump.tsx:501 +#: src/pages/Dump.tsx:506 msgid "edited {0}" msgstr "edited {0}" @@ -830,16 +830,16 @@ msgstr "edited {0}" #: src/components/chat/ChatMessageItem.tsx:128 #: src/components/comment/CommentNode.tsx:203 #: src/components/playlist/PlaylistHeader.tsx:93 -#: src/pages/Dump.tsx:499 +#: src/pages/Dump.tsx:504 msgid "Edited {0}" msgstr "Edited {0}" -#: src/pages/DumpEdit.tsx:258 +#: src/pages/DumpEdit.tsx:259 msgid "Editing" msgstr "Editing" #. placeholder {0}: state.dump.title -#: src/pages/DumpEdit.tsx:81 +#: src/pages/DumpEdit.tsx:82 msgid "Editing {0}" msgstr "Editing {0}" @@ -942,15 +942,15 @@ msgstr "Follow {targetUsername}" msgid "Follow playlist" msgstr "Follow playlist" -#: src/components/feed/FollowedFeed.tsx:151 +#: src/components/feed/FollowedFeed.tsx:164 msgid "Follow some public playlists to see their dumps here." msgstr "Follow some public playlists to see their dumps here." -#: src/components/feed/FollowedFeed.tsx:143 +#: src/components/feed/FollowedFeed.tsx:156 msgid "Follow some users to see their dumps here." msgstr "Follow some users to see their dumps here." -#: src/components/feed/FeedTabBar.tsx:44 +#: src/components/feed/FeedTabBar.tsx:61 #: src/components/profile/ProfileFollowTab.tsx:140 #: src/pages/Settings.tsx:57 #: src/pages/UserPublicProfile.tsx:163 @@ -967,11 +967,11 @@ msgstr "Following" msgid "email.digest.forYou" msgstr "For you" -#: src/pages/UserLogin.tsx:103 +#: src/pages/UserLogin.tsx:92 msgid "Forgot password?" msgstr "Forgot password?" -#: src/components/feed/FollowedFeed.tsx:132 +#: src/components/feed/FollowedFeed.tsx:137 msgid "From people" msgstr "From people" @@ -980,7 +980,7 @@ msgstr "From people" msgid "email.digest.network" msgstr "From people you follow" -#: src/components/feed/FollowedFeed.tsx:133 +#: src/components/feed/FollowedFeed.tsx:138 msgid "From playlists" msgstr "From playlists" @@ -992,7 +992,7 @@ msgstr "Fullscreen" msgid "Go home" msgstr "Go home" -#: src/pages/ResetPassword.tsx:96 +#: src/pages/ResetPassword.tsx:148 msgid "Go to login" msgstr "Go to login" @@ -1001,12 +1001,12 @@ msgstr "Go to login" msgid "email.reset.hi" msgstr "Hi {username}," -#: src/components/feed/FeedTabBar.tsx:40 +#: src/components/feed/FeedTabBar.tsx:57 #: src/pages/Settings.tsx:54 msgid "Hot" msgstr "Hot" -#: src/pages/UserLogin.tsx:144 +#: src/pages/ResetPassword.tsx:76 msgid "If that address is registered you'll receive a reset link shortly." msgstr "If that address is registered you'll receive a reset link shortly." @@ -1024,7 +1024,7 @@ msgstr "If you didn't ask for this, ignore this email. Your password stays the s msgid "image" msgstr "image" -#: src/pages/Dump.tsx:568 +#: src/pages/Dump.tsx:573 msgid "In collections" msgstr "In collections" @@ -1046,7 +1046,6 @@ msgstr "Instances" msgid "Invalid invite" msgstr "Invalid invite" -#: src/pages/ResetPassword.tsx:64 #: src/pages/Unsubscribe.tsx:66 msgid "Invalid link" msgstr "Invalid link" @@ -1075,7 +1074,7 @@ msgstr "invited by you" msgid "Invitees" msgstr "Invitees" -#: src/components/feed/FeedTabBar.tsx:42 +#: src/components/feed/FeedTabBar.tsx:59 #: src/pages/Settings.tsx:56 msgid "Journal" msgstr "Journal" @@ -1126,8 +1125,8 @@ msgstr "Load more" msgid "Load older messages" msgstr "Load older messages" -#: src/pages/Dump.tsx:301 -#: src/pages/DumpEdit.tsx:209 +#: src/pages/Dump.tsx:306 +#: src/pages/DumpEdit.tsx:210 msgid "Loading dump…" msgstr "Loading dump…" @@ -1139,7 +1138,7 @@ msgstr "Loading messages…" msgid "Loading more…" msgstr "Loading more…" -#: src/pages/PlaylistDetail.tsx:64 +#: src/pages/PlaylistDetail.tsx:82 msgid "Loading playlist…" msgstr "Loading playlist…" @@ -1161,9 +1160,9 @@ msgstr "Loading…" #: src/components/layout/AppHeader.tsx:208 #: src/pages/FederationCallback.tsx:32 -#: src/pages/UserLogin.tsx:46 -#: src/pages/UserLogin.tsx:73 -#: src/pages/UserLogin.tsx:92 +#: src/pages/UserLogin.tsx:41 +#: src/pages/UserLogin.tsx:66 +#: src/pages/UserLogin.tsx:85 msgid "Log in" msgstr "Log in" @@ -1185,12 +1184,12 @@ msgstr "Log in with {0}" msgid "Log out" msgstr "Log out" -#: src/pages/UserLogin.tsx:91 +#: src/pages/UserLogin.tsx:84 msgid "Logging in…" msgstr "Logging in…" #: src/pages/FederationCallback.tsx:69 -#: src/pages/UserLogin.tsx:78 +#: src/pages/UserLogin.tsx:71 msgid "Login failed" msgstr "Login failed" @@ -1228,7 +1227,7 @@ msgid "Name" msgstr "Name" #: src/components/chat/ChatModal.tsx:692 -#: src/components/feed/FeedTabBar.tsx:41 +#: src/components/feed/FeedTabBar.tsx:58 #: src/pages/Settings.tsx:55 msgid "New" msgstr "New" @@ -1246,7 +1245,7 @@ msgid "digest.newMembers" msgstr "New members" #: src/components/profile/ChangePasswordModal.tsx:94 -#: src/pages/ResetPassword.tsx:116 +#: src/pages/ResetPassword.tsx:168 msgid "New password" msgstr "New password" @@ -1306,7 +1305,7 @@ msgid "No playlists match \"{q}\"." msgstr "No playlists match \"{q}\"." #: src/components/playlist/PlaylistMembershipPanel.tsx:51 -#: src/components/profile/ProfilePlaylistsTab.tsx:184 +#: src/components/profile/ProfilePlaylistsTab.tsx:185 #: src/pages/Playlists.tsx:118 msgid "No playlists yet." msgstr "No playlists yet." @@ -1369,7 +1368,7 @@ msgstr "Once a week you'll get a digest of what happened here, and once a month msgid "Only images can be dropped here." msgstr "Only images can be dropped here." -#: src/pages/DumpEdit.tsx:119 +#: src/pages/DumpEdit.tsx:120 msgid "Only its poster or a moderator can edit this dump." msgstr "Only its poster or a moderator can edit this dump." @@ -1418,7 +1417,7 @@ msgstr "Page not found" #: src/pages/Settings.tsx:96 #: src/pages/Settings.tsx:106 -#: src/pages/UserLogin.tsx:88 +#: src/pages/UserLogin.tsx:81 msgid "Password" msgstr "Password" @@ -1431,12 +1430,12 @@ msgstr "Password (min. {0} characters)" msgid "Password changed successfully." msgstr "Password changed successfully." -#: src/pages/ResetPassword.tsx:86 +#: src/pages/ResetPassword.tsx:138 msgid "Password updated" msgstr "Password updated" #: src/components/profile/ChangePasswordModal.tsx:114 -#: src/pages/ResetPassword.tsx:136 +#: src/pages/ResetPassword.tsx:188 msgid "Passwords do not match" msgstr "Passwords do not match" @@ -1471,7 +1470,7 @@ msgstr "Playlist categories" #: src/components/layout/AppHeader.tsx:172 #: src/components/layout/UserMenu.tsx:92 #: src/components/profile/ProfileFollowTab.tsx:144 -#: src/components/profile/ProfilePlaylistsTab.tsx:155 +#: src/components/profile/ProfilePlaylistsTab.tsx:156 #: src/pages/Playlists.tsx:52 #: src/pages/Playlists.tsx:106 #: src/pages/Search.tsx:151 @@ -1502,7 +1501,7 @@ msgstr "Previous track" #: src/components/playlist/PlaylistCard.tsx:106 #: src/components/playlist/PlaylistHeader.tsx:77 #: src/components/playlist/PlaylistMembershipPanel.tsx:81 -#: src/pages/Dump.tsx:507 +#: src/pages/Dump.tsx:512 msgid "private" msgstr "private" @@ -1519,7 +1518,7 @@ msgstr "public" msgid "Public" msgstr "Public" -#: src/pages/DumpEdit.tsx:291 +#: src/pages/DumpEdit.tsx:292 msgid "Refresh metadata" msgstr "Refresh metadata" @@ -1527,7 +1526,7 @@ msgstr "Refresh metadata" msgid "Refreshing stream…" msgstr "Refreshing stream…" -#: src/pages/DumpEdit.tsx:290 +#: src/pages/DumpEdit.tsx:291 msgid "Refreshing…" msgstr "Refreshing…" @@ -1545,7 +1544,7 @@ msgstr "Registering…" msgid "Registration failed" msgstr "Registration failed" -#: src/pages/Dump.tsx:559 +#: src/pages/Dump.tsx:564 msgid "Related" msgstr "Related" @@ -1579,7 +1578,7 @@ msgstr "Rename" msgid "Renaming…" msgstr "Renaming…" -#: src/pages/DumpEdit.tsx:489 +#: src/pages/DumpEdit.tsx:490 msgid "Replace file" msgstr "Replace file" @@ -1593,11 +1592,11 @@ msgstr "Reply" msgid "Replying to" msgstr "Replying to" -#: src/pages/UserLogin.tsx:156 +#: src/pages/ResetPassword.tsx:85 msgid "Request failed" msgstr "Request failed" -#: src/pages/ResetPassword.tsx:112 +#: src/pages/ResetPassword.tsx:164 msgid "Reset failed" msgstr "Reset failed" @@ -1606,12 +1605,13 @@ msgstr "Reset failed" msgid "email.reset.button" msgstr "Reset password" -#: src/pages/ResetPassword.tsx:34 +#: src/pages/ResetPassword.tsx:40 +#: src/pages/ResetPassword.tsx:71 msgid "Reset password" msgstr "Reset password" -#: src/pages/DumpEdit.tsx:465 -#: src/pages/DumpEdit.tsx:520 +#: src/pages/DumpEdit.tsx:466 +#: src/pages/DumpEdit.tsx:521 msgid "Reset to default" msgstr "Reset to default" @@ -1631,8 +1631,8 @@ msgid "email.reset.title" msgstr "Reset your password" #: src/components/chat/PendingItem.tsx:86 -#: src/pages/Dump.tsx:318 -#: src/pages/DumpEdit.tsx:226 +#: src/pages/Dump.tsx:323 +#: src/pages/DumpEdit.tsx:227 msgid "Retry" msgstr "Retry" @@ -1646,8 +1646,8 @@ msgstr "Role" #: src/components/playlist/PlaylistEditForm.tsx:229 #: src/components/profile/DescriptionEditor.tsx:89 #: src/components/profile/EmailEditor.tsx:75 -#: src/pages/Dump.tsx:433 -#: src/pages/DumpEdit.tsx:563 +#: src/pages/Dump.tsx:438 +#: src/pages/DumpEdit.tsx:564 msgid "Save" msgstr "Save" @@ -1656,8 +1656,8 @@ msgstr "Save" #: src/components/profile/ChangePasswordModal.tsx:119 #: src/components/profile/DescriptionEditor.tsx:86 #: src/components/profile/EmailEditor.tsx:72 -#: src/pages/Dump.tsx:432 -#: src/pages/ResetPassword.tsx:139 +#: src/pages/Dump.tsx:437 +#: src/pages/ResetPassword.tsx:191 msgid "Saving…" msgstr "Saving…" @@ -1700,12 +1700,12 @@ msgstr "Seek" msgid "Send" msgstr "Send" -#: src/pages/UserLogin.tsx:165 +#: src/pages/ResetPassword.tsx:94 msgid "Send reset link" msgstr "Send reset link" #: src/components/chat/PendingItem.tsx:104 -#: src/pages/UserLogin.tsx:164 +#: src/pages/ResetPassword.tsx:93 msgid "Sending…" msgstr "Sending…" @@ -1713,8 +1713,8 @@ msgstr "Sending…" msgid "Server unreachable" msgstr "Server unreachable" -#: src/pages/ResetPassword.tsx:107 -#: src/pages/ResetPassword.tsx:140 +#: src/pages/ResetPassword.tsx:159 +#: src/pages/ResetPassword.tsx:192 msgid "Set new password" msgstr "Set new password" @@ -1766,7 +1766,7 @@ msgstr "Someone asked to reset the password of your {site} account. The button b #: src/components/form/FormError.tsx:31 #: src/components/layout/PageError.tsx:29 #: src/contexts/ws/WSProvider.tsx:732 -#: src/pages/PlaylistDetail.tsx:124 +#: src/pages/PlaylistDetail.tsx:155 msgid "Something went wrong" msgstr "Something went wrong" @@ -1799,7 +1799,7 @@ msgstr "the chat" msgid "the chat" msgstr "the chat" -#: src/hooks/playlist/usePlaylist.ts:179 +#: src/hooks/playlist/usePlaylist.ts:182 msgid "The dump couldn't be removed. Try again." msgstr "The dump couldn't be removed. Try again." @@ -1822,7 +1822,7 @@ msgstr "The month on {site}" msgid "email.digest.monthly.subject" msgstr "The month on {site}, {range}" -#: src/hooks/playlist/usePlaylist.ts:322 +#: src/hooks/playlist/usePlaylist.ts:325 msgid "The new order couldn't be saved. Try again." msgstr "The new order couldn't be saved. Try again." @@ -1834,7 +1834,7 @@ msgstr "This comment couldn't be deleted. Try again." msgid "This invite link is missing, expired, or already used." msgstr "This invite link is missing, expired, or already used." -#: src/pages/UserLogin.tsx:112 +#: src/pages/UserLogin.tsx:99 msgid "This is a mirage." msgstr "This is a mirage." @@ -1846,10 +1846,6 @@ msgstr "This month" msgid "This page does not exist." msgstr "This page does not exist." -#: src/pages/ResetPassword.tsx:67 -msgid "This reset link is missing or malformed." -msgstr "This reset link is missing or malformed." - #: src/pages/FederationCallback.tsx:40 msgid "This sign-in link is incomplete." msgstr "This sign-in link is incomplete." @@ -1870,14 +1866,14 @@ msgstr "This unsubscribe link is missing or malformed." msgid "This week" msgstr "This week" -#: src/pages/DumpEdit.tsx:449 +#: src/pages/DumpEdit.tsx:450 msgid "Thumbnail" msgstr "Thumbnail" #: src/components/dump/create/TitleField.tsx:45 #: src/components/playlist/PlaylistCreateForm.tsx:100 #: src/components/playlist/PlaylistEditForm.tsx:175 -#: src/pages/DumpEdit.tsx:510 +#: src/pages/DumpEdit.tsx:511 msgid "Title" msgstr "Title" @@ -2007,7 +2003,7 @@ msgstr "Upvoted" msgid "Upvoted ({0})" msgstr "Upvoted ({0})" -#: src/pages/DumpEdit.tsx:481 +#: src/pages/DumpEdit.tsx:482 msgid "URL" msgstr "URL" @@ -2023,7 +2019,7 @@ msgstr "URL slug" msgid "User" msgstr "User" -#: src/components/profile/ProfileManageTab.tsx:54 +#: src/components/profile/ProfileManageTab.tsx:56 msgid "User management" msgstr "User management" @@ -2031,10 +2027,10 @@ msgstr "User management" msgid "User menu" msgstr "User menu" -#: src/components/profile/ProfileManageTab.tsx:61 +#: src/components/profile/ProfileManageTab.tsx:63 #: src/components/profile/UsernameField.tsx:51 #: src/pages/Settings.tsx:91 -#: src/pages/UserLogin.tsx:81 +#: src/pages/UserLogin.tsx:74 #: src/pages/UserRegister.tsx:141 msgid "Username" msgstr "Username" @@ -2079,7 +2075,7 @@ msgid "email.welcome.subject" msgstr "Welcome to {site}" #: src/components/dump/create/DumpCreateModal.tsx:705 -#: src/pages/DumpEdit.tsx:538 +#: src/pages/DumpEdit.tsx:539 msgid "What makes it worth it?" msgstr "What makes it worth it?" @@ -2097,7 +2093,7 @@ msgid "Why & where" msgstr "Why & where" #: src/components/dump/create/DumpCreateModal.tsx:704 -#: src/pages/DumpEdit.tsx:537 +#: src/pages/DumpEdit.tsx:538 msgid "Why?" msgstr "Why?" @@ -2171,7 +2167,7 @@ msgstr "Your account lives on {home}: sign in to other instances from there." msgid "Your account lives on {home}: your password, email address, avatar and username change there." msgstr "Your account lives on {home}: your password, email address, avatar and username change there." -#: src/pages/UserLogin.tsx:160 +#: src/pages/ResetPassword.tsx:89 msgid "Your email address" msgstr "Your email address" @@ -2179,7 +2175,7 @@ msgstr "Your email address" msgid "Your gerbeur's URL" msgstr "Your gerbeur's URL" -#: src/pages/ResetPassword.tsx:89 +#: src/pages/ResetPassword.tsx:141 msgid "Your password has been changed. You can now log in." msgstr "Your password has been changed. You can now log in." diff --git a/locales/fr.po b/locales/fr.po index 863efee2..3a8b39e9 100644 --- a/locales/fr.po +++ b/locales/fr.po @@ -206,14 +206,14 @@ msgstr "# Bienvenue sur {site} !\n" "Votre compte a bien été créé. Bienvenue à bord !" #: src/components/dump/create/DumpCreateModal.tsx:736 -#: src/pages/PlaylistDetail.tsx:80 +#: src/pages/PlaylistDetail.tsx:98 #: src/pages/UserPublicProfile.tsx:125 msgid "← Back" msgstr "← Retour" -#: src/pages/Dump.tsx:325 -#: src/pages/Dump.tsx:552 -#: src/pages/DumpEdit.tsx:233 +#: src/pages/Dump.tsx:330 +#: src/pages/Dump.tsx:557 +#: src/pages/DumpEdit.tsx:234 msgid "← Back to all dumps" msgstr "← Retour à toutes les recos" @@ -225,7 +225,7 @@ msgstr "+ Inviter quelqu'un" msgid "+ New playlist" msgstr "+ Nouvelle collection" -#: src/pages/Dump.tsx:399 +#: src/pages/Dump.tsx:404 msgid "+ Playlist" msgstr "+ Collection" @@ -377,7 +377,7 @@ msgstr "Apparence" #. placeholder {0}: VALIDATION.PASSWORD_MIN #: src/components/profile/ChangePasswordModal.tsx:101 -#: src/pages/ResetPassword.tsx:124 +#: src/pages/ResetPassword.tsx:176 #: src/pages/UserRegister.tsx:168 msgid "At least {0} characters" msgstr "Au moins {0} caractères" @@ -390,8 +390,8 @@ msgstr "{maxLength} caractères au maximum." msgid "Auto" msgstr "Auto" -#: src/pages/ResetPassword.tsx:74 -#: src/pages/ResetPassword.tsx:147 +#: src/pages/ResetPassword.tsx:101 +#: src/pages/ResetPassword.tsx:199 msgid "Back to login" msgstr "Retour à la connexion" @@ -439,8 +439,8 @@ msgstr "Connexion impossible" #: src/components/profile/EmailEditor.tsx:83 #: src/components/shared/ConfirmModal.tsx:63 #: src/pages/Authorize.tsx:158 -#: src/pages/Dump.tsx:441 -#: src/pages/DumpEdit.tsx:560 +#: src/pages/Dump.tsx:446 +#: src/pages/DumpEdit.tsx:561 msgid "Cancel" msgstr "Annuler" @@ -546,7 +546,7 @@ msgid "digest.community" msgstr "Communauté" #: src/components/profile/ChangePasswordModal.tsx:108 -#: src/pages/ResetPassword.tsx:131 +#: src/pages/ResetPassword.tsx:183 msgid "Confirm new password" msgstr "Confirmer le nouveau mot de passe" @@ -582,8 +582,8 @@ msgstr "Impossible de changer le mot de passe" 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:177 -#: src/pages/DumpEdit.tsx:554 +#: src/components/profile/ProfilePlaylistsTab.tsx:178 +#: src/pages/DumpEdit.tsx:555 msgid "Could not delete" msgstr "Suppression impossible" @@ -591,7 +591,7 @@ msgstr "Suppression impossible" msgid "Could not rename" msgstr "Renommage impossible" -#: src/pages/DumpEdit.tsx:506 +#: src/pages/DumpEdit.tsx:507 msgid "Could not save" msgstr "Sauvegarde impossible" @@ -668,20 +668,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:315 -#: src/pages/DumpEdit.tsx:557 +#: src/pages/DumpEdit.tsx:316 +#: src/pages/DumpEdit.tsx:558 msgid "Delete dump" msgstr "Supprimer la reco" #. placeholder {0}: res.status -#: src/pages/DumpEdit.tsx:194 +#: src/pages/DumpEdit.tsx:195 msgid "Delete failed ({0})" msgstr "Échec de la suppression ({0})" #: src/components/playlist/PlaylistCard.tsx:149 #: src/components/playlist/PlaylistEditForm.tsx:213 -#: src/components/profile/ProfilePlaylistsTab.tsx:207 -#: src/pages/PlaylistDetail.tsx:141 +#: src/components/profile/ProfilePlaylistsTab.tsx:208 +#: src/pages/PlaylistDetail.tsx:172 msgid "Delete playlist" msgstr "Supprimer la collection" @@ -689,7 +689,7 @@ msgstr "Supprimer la collection" msgid "Delete this comment?" msgstr "Supprimer ce commentaire ?" -#: src/pages/DumpEdit.tsx:314 +#: src/pages/DumpEdit.tsx:315 msgid "Delete this dump? This cannot be undone." msgstr "Supprimer cette reco ? Cette action est irréversible." @@ -697,8 +697,8 @@ msgstr "Supprimer cette reco ? Cette action est irréversible." msgid "Delete this message?" msgstr "Supprimer ce message ?" -#: src/components/profile/ProfilePlaylistsTab.tsx:206 -#: src/pages/PlaylistDetail.tsx:140 +#: src/components/profile/ProfilePlaylistsTab.tsx:207 +#: src/pages/PlaylistDetail.tsx:171 msgid "Delete this playlist? This cannot be undone." msgstr "Supprimer cette collection ? Cette action est irréversible." @@ -748,7 +748,7 @@ 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:497 +#: src/pages/DumpEdit.tsx:498 msgid "Drop a replacement here" msgstr "Déposez un fichier de remplacement ici" @@ -788,7 +788,7 @@ msgstr "Plus tôt" #: src/components/chat/PendingItem.tsx:93 #: src/components/comment/CommentNode.tsx:256 #: src/components/playlist/PlaylistHeader.tsx:60 -#: src/pages/Dump.tsx:548 +#: src/pages/Dump.tsx:553 msgid "Edit" msgstr "Modifier" @@ -806,7 +806,7 @@ msgid "Edit email" msgstr "Modifier l'e-mail" #: src/components/dump/create/TitleField.tsx:69 -#: src/pages/Dump.tsx:458 +#: src/pages/Dump.tsx:463 msgid "Edit title" msgstr "Modifier le titre" @@ -820,7 +820,7 @@ msgstr "modifié" #: src/components/chat/ChatMessageItem.tsx:132 #: src/components/comment/CommentNode.tsx:205 #: src/components/playlist/PlaylistHeader.tsx:95 -#: src/pages/Dump.tsx:501 +#: src/pages/Dump.tsx:506 msgid "edited {0}" msgstr "modifié {0}" @@ -830,16 +830,16 @@ msgstr "modifié {0}" #: src/components/chat/ChatMessageItem.tsx:128 #: src/components/comment/CommentNode.tsx:203 #: src/components/playlist/PlaylistHeader.tsx:93 -#: src/pages/Dump.tsx:499 +#: src/pages/Dump.tsx:504 msgid "Edited {0}" msgstr "Modifié le {0}" -#: src/pages/DumpEdit.tsx:258 +#: src/pages/DumpEdit.tsx:259 msgid "Editing" msgstr "Modification" #. placeholder {0}: state.dump.title -#: src/pages/DumpEdit.tsx:81 +#: src/pages/DumpEdit.tsx:82 msgid "Editing {0}" msgstr "Édition de {0}" @@ -942,15 +942,15 @@ msgstr "Suivre {targetUsername}" msgid "Follow playlist" msgstr "Suivre la collection" -#: src/components/feed/FollowedFeed.tsx:151 +#: src/components/feed/FollowedFeed.tsx:164 msgid "Follow some public playlists to see their dumps here." msgstr "Suivez des collections publiques pour voir leurs recos ici." -#: src/components/feed/FollowedFeed.tsx:143 +#: src/components/feed/FollowedFeed.tsx:156 msgid "Follow some users to see their dumps here." msgstr "Suivez des utilisateurs pour voir leurs recos ici." -#: src/components/feed/FeedTabBar.tsx:44 +#: src/components/feed/FeedTabBar.tsx:61 #: src/components/profile/ProfileFollowTab.tsx:140 #: src/pages/Settings.tsx:57 #: src/pages/UserPublicProfile.tsx:163 @@ -967,11 +967,11 @@ msgstr "Abonné" msgid "email.digest.forYou" msgstr "Pour vous" -#: src/pages/UserLogin.tsx:103 +#: src/pages/UserLogin.tsx:92 msgid "Forgot password?" msgstr "Mot de passe oublié ?" -#: src/components/feed/FollowedFeed.tsx:132 +#: src/components/feed/FollowedFeed.tsx:137 msgid "From people" msgstr "De personnes" @@ -980,7 +980,7 @@ msgstr "De personnes" msgid "email.digest.network" msgstr "De ceux que vous suivez" -#: src/components/feed/FollowedFeed.tsx:133 +#: src/components/feed/FollowedFeed.tsx:138 msgid "From playlists" msgstr "De collections" @@ -992,7 +992,7 @@ msgstr "Plein écran" msgid "Go home" msgstr "Accueil" -#: src/pages/ResetPassword.tsx:96 +#: src/pages/ResetPassword.tsx:148 msgid "Go to login" msgstr "Aller à la connexion" @@ -1001,12 +1001,12 @@ msgstr "Aller à la connexion" msgid "email.reset.hi" msgstr "Bonjour {username}," -#: src/components/feed/FeedTabBar.tsx:40 +#: src/components/feed/FeedTabBar.tsx:57 #: src/pages/Settings.tsx:54 msgid "Hot" msgstr "Tendances" -#: src/pages/UserLogin.tsx:144 +#: src/pages/ResetPassword.tsx:76 msgid "If that address is registered you'll receive a reset link shortly." msgstr "Si cette adresse est enregistrée, vous recevrez un lien de réinitialisation sous peu." @@ -1024,7 +1024,7 @@ msgstr "Si vous n'êtes pas à l'origine de cette demande, ignorez cet e-mail. V msgid "image" msgstr "image" -#: src/pages/Dump.tsx:568 +#: src/pages/Dump.tsx:573 msgid "In collections" msgstr "Dans les collections" @@ -1046,7 +1046,6 @@ msgstr "Instances" msgid "Invalid invite" msgstr "Invitation invalide" -#: src/pages/ResetPassword.tsx:64 #: src/pages/Unsubscribe.tsx:66 msgid "Invalid link" msgstr "Lien invalide" @@ -1075,7 +1074,7 @@ msgstr "sur votre invitation" msgid "Invitees" msgstr "Invités" -#: src/components/feed/FeedTabBar.tsx:42 +#: src/components/feed/FeedTabBar.tsx:59 #: src/pages/Settings.tsx:56 msgid "Journal" msgstr "Journal" @@ -1126,8 +1125,8 @@ msgstr "Charger plus" msgid "Load older messages" msgstr "Charger les messages plus anciens" -#: src/pages/Dump.tsx:301 -#: src/pages/DumpEdit.tsx:209 +#: src/pages/Dump.tsx:306 +#: src/pages/DumpEdit.tsx:210 msgid "Loading dump…" msgstr "Chargement de la reco…" @@ -1139,7 +1138,7 @@ msgstr "Chargement des messages…" msgid "Loading more…" msgstr "Chargement…" -#: src/pages/PlaylistDetail.tsx:64 +#: src/pages/PlaylistDetail.tsx:82 msgid "Loading playlist…" msgstr "Chargement de la collection…" @@ -1161,9 +1160,9 @@ msgstr "Chargement…" #: src/components/layout/AppHeader.tsx:208 #: src/pages/FederationCallback.tsx:32 -#: src/pages/UserLogin.tsx:46 -#: src/pages/UserLogin.tsx:73 -#: src/pages/UserLogin.tsx:92 +#: src/pages/UserLogin.tsx:41 +#: src/pages/UserLogin.tsx:66 +#: src/pages/UserLogin.tsx:85 msgid "Log in" msgstr "Se connecter" @@ -1185,12 +1184,12 @@ msgstr "Se connecter avec {0}" msgid "Log out" msgstr "Se déconnecter" -#: src/pages/UserLogin.tsx:91 +#: src/pages/UserLogin.tsx:84 msgid "Logging in…" msgstr "Connexion…" #: src/pages/FederationCallback.tsx:69 -#: src/pages/UserLogin.tsx:78 +#: src/pages/UserLogin.tsx:71 msgid "Login failed" msgstr "Connexion échouée" @@ -1228,7 +1227,7 @@ msgid "Name" msgstr "Nom" #: src/components/chat/ChatModal.tsx:692 -#: src/components/feed/FeedTabBar.tsx:41 +#: src/components/feed/FeedTabBar.tsx:58 #: src/pages/Settings.tsx:55 msgid "New" msgstr "Nouveau" @@ -1246,7 +1245,7 @@ msgid "digest.newMembers" msgstr "Nouveaux membres" #: src/components/profile/ChangePasswordModal.tsx:94 -#: src/pages/ResetPassword.tsx:116 +#: src/pages/ResetPassword.tsx:168 msgid "New password" msgstr "Nouveau mot de passe" @@ -1306,7 +1305,7 @@ msgid "No playlists match \"{q}\"." msgstr "Aucune collection ne correspond à « {q} »." #: src/components/playlist/PlaylistMembershipPanel.tsx:51 -#: src/components/profile/ProfilePlaylistsTab.tsx:184 +#: src/components/profile/ProfilePlaylistsTab.tsx:185 #: src/pages/Playlists.tsx:118 msgid "No playlists yet." msgstr "Pas encore de collections." @@ -1369,7 +1368,7 @@ msgstr "Chaque semaine, vous recevrez un résumé de ce qui s'est passé ici, et msgid "Only images can be dropped here." msgstr "Seules les images peuvent être déposées ici." -#: src/pages/DumpEdit.tsx:119 +#: src/pages/DumpEdit.tsx:120 msgid "Only its poster or a moderator can edit this dump." msgstr "Seuls son auteur et les modérateurs peuvent modifier ce dump." @@ -1418,7 +1417,7 @@ msgstr "Page introuvable" #: src/pages/Settings.tsx:96 #: src/pages/Settings.tsx:106 -#: src/pages/UserLogin.tsx:88 +#: src/pages/UserLogin.tsx:81 msgid "Password" msgstr "Mot de passe" @@ -1431,12 +1430,12 @@ msgstr "Mot de passe (min. {0} caractères)" msgid "Password changed successfully." msgstr "Mot de passe modifié avec succès." -#: src/pages/ResetPassword.tsx:86 +#: src/pages/ResetPassword.tsx:138 msgid "Password updated" msgstr "Mot de passe mis à jour" #: src/components/profile/ChangePasswordModal.tsx:114 -#: src/pages/ResetPassword.tsx:136 +#: src/pages/ResetPassword.tsx:188 msgid "Passwords do not match" msgstr "Les mots de passe ne correspondent pas" @@ -1471,7 +1470,7 @@ msgstr "Catégories de collections" #: src/components/layout/AppHeader.tsx:172 #: src/components/layout/UserMenu.tsx:92 #: src/components/profile/ProfileFollowTab.tsx:144 -#: src/components/profile/ProfilePlaylistsTab.tsx:155 +#: src/components/profile/ProfilePlaylistsTab.tsx:156 #: src/pages/Playlists.tsx:52 #: src/pages/Playlists.tsx:106 #: src/pages/Search.tsx:151 @@ -1502,7 +1501,7 @@ msgstr "Piste précédente" #: src/components/playlist/PlaylistCard.tsx:106 #: src/components/playlist/PlaylistHeader.tsx:77 #: src/components/playlist/PlaylistMembershipPanel.tsx:81 -#: src/pages/Dump.tsx:507 +#: src/pages/Dump.tsx:512 msgid "private" msgstr "privé" @@ -1519,7 +1518,7 @@ msgstr "public" msgid "Public" msgstr "Public" -#: src/pages/DumpEdit.tsx:291 +#: src/pages/DumpEdit.tsx:292 msgid "Refresh metadata" msgstr "Actualiser les métadonnées" @@ -1527,7 +1526,7 @@ msgstr "Actualiser les métadonnées" msgid "Refreshing stream…" msgstr "Actualisation du flux…" -#: src/pages/DumpEdit.tsx:290 +#: src/pages/DumpEdit.tsx:291 msgid "Refreshing…" msgstr "Actualisation…" @@ -1545,7 +1544,7 @@ msgstr "Inscription…" msgid "Registration failed" msgstr "Inscription échouée" -#: src/pages/Dump.tsx:559 +#: src/pages/Dump.tsx:564 msgid "Related" msgstr "Connexe" @@ -1579,7 +1578,7 @@ msgstr "Renommer" msgid "Renaming…" msgstr "Renommage…" -#: src/pages/DumpEdit.tsx:489 +#: src/pages/DumpEdit.tsx:490 msgid "Replace file" msgstr "Remplacer le fichier" @@ -1593,11 +1592,11 @@ msgstr "Répondre" msgid "Replying to" msgstr "En réponse à" -#: src/pages/UserLogin.tsx:156 +#: src/pages/ResetPassword.tsx:85 msgid "Request failed" msgstr "Échec de la demande" -#: src/pages/ResetPassword.tsx:112 +#: src/pages/ResetPassword.tsx:164 msgid "Reset failed" msgstr "Échec de la réinitialisation" @@ -1606,12 +1605,13 @@ msgstr "Échec de la réinitialisation" msgid "email.reset.button" msgstr "Choisir un nouveau mot de passe" -#: src/pages/ResetPassword.tsx:34 +#: src/pages/ResetPassword.tsx:40 +#: src/pages/ResetPassword.tsx:71 msgid "Reset password" msgstr "Réinitialiser le mot de passe" -#: src/pages/DumpEdit.tsx:465 -#: src/pages/DumpEdit.tsx:520 +#: src/pages/DumpEdit.tsx:466 +#: src/pages/DumpEdit.tsx:521 msgid "Reset to default" msgstr "Réinitialiser par défaut" @@ -1631,8 +1631,8 @@ msgid "email.reset.title" msgstr "Réinitialiser votre mot de passe" #: src/components/chat/PendingItem.tsx:86 -#: src/pages/Dump.tsx:318 -#: src/pages/DumpEdit.tsx:226 +#: src/pages/Dump.tsx:323 +#: src/pages/DumpEdit.tsx:227 msgid "Retry" msgstr "Réessayer" @@ -1646,8 +1646,8 @@ msgstr "Rôle" #: src/components/playlist/PlaylistEditForm.tsx:229 #: src/components/profile/DescriptionEditor.tsx:89 #: src/components/profile/EmailEditor.tsx:75 -#: src/pages/Dump.tsx:433 -#: src/pages/DumpEdit.tsx:563 +#: src/pages/Dump.tsx:438 +#: src/pages/DumpEdit.tsx:564 msgid "Save" msgstr "Enregistrer" @@ -1656,8 +1656,8 @@ msgstr "Enregistrer" #: src/components/profile/ChangePasswordModal.tsx:119 #: src/components/profile/DescriptionEditor.tsx:86 #: src/components/profile/EmailEditor.tsx:72 -#: src/pages/Dump.tsx:432 -#: src/pages/ResetPassword.tsx:139 +#: src/pages/Dump.tsx:437 +#: src/pages/ResetPassword.tsx:191 msgid "Saving…" msgstr "Enregistrement…" @@ -1700,12 +1700,12 @@ msgstr "Position" msgid "Send" msgstr "Envoyer" -#: src/pages/UserLogin.tsx:165 +#: src/pages/ResetPassword.tsx:94 msgid "Send reset link" msgstr "Envoyer le lien de réinitialisation" #: src/components/chat/PendingItem.tsx:104 -#: src/pages/UserLogin.tsx:164 +#: src/pages/ResetPassword.tsx:93 msgid "Sending…" msgstr "Envoi…" @@ -1713,8 +1713,8 @@ msgstr "Envoi…" msgid "Server unreachable" msgstr "Serveur inaccessible" -#: src/pages/ResetPassword.tsx:107 -#: src/pages/ResetPassword.tsx:140 +#: src/pages/ResetPassword.tsx:159 +#: src/pages/ResetPassword.tsx:192 msgid "Set new password" msgstr "Définir un nouveau mot de passe" @@ -1766,7 +1766,7 @@ msgstr "Quelqu'un a demandé à réinitialiser le mot de passe de votre compte { #: src/components/form/FormError.tsx:31 #: src/components/layout/PageError.tsx:29 #: src/contexts/ws/WSProvider.tsx:732 -#: src/pages/PlaylistDetail.tsx:124 +#: src/pages/PlaylistDetail.tsx:155 msgid "Something went wrong" msgstr "Une erreur est survenue" @@ -1799,7 +1799,7 @@ msgstr "la tribune" msgid "the chat" msgstr "la tribune" -#: src/hooks/playlist/usePlaylist.ts:179 +#: src/hooks/playlist/usePlaylist.ts:182 msgid "The dump couldn't be removed. Try again." msgstr "Le dump n'a pas pu être retiré. Réessayez." @@ -1822,7 +1822,7 @@ msgstr "Le mois sur {site}" msgid "email.digest.monthly.subject" msgstr "Le mois sur {site}, {range}" -#: src/hooks/playlist/usePlaylist.ts:322 +#: src/hooks/playlist/usePlaylist.ts:325 msgid "The new order couldn't be saved. Try again." msgstr "Le nouvel ordre n'a pas pu être enregistré. Réessayez." @@ -1834,7 +1834,7 @@ msgstr "Ce commentaire n'a pas pu être supprimé. Réessayez." msgid "This invite link is missing, expired, or already used." msgstr "Ce lien d'invitation est manquant, expiré ou déjà utilisé." -#: src/pages/UserLogin.tsx:112 +#: src/pages/UserLogin.tsx:99 msgid "This is a mirage." msgstr "C'est un mirage." @@ -1846,10 +1846,6 @@ msgstr "Ce mois-ci" msgid "This page does not exist." msgstr "Rien à voir, circulez." -#: src/pages/ResetPassword.tsx:67 -msgid "This reset link is missing or malformed." -msgstr "Ce lien de réinitialisation est absent ou malformé." - #: src/pages/FederationCallback.tsx:40 msgid "This sign-in link is incomplete." msgstr "Ce lien de connexion est incomplet." @@ -1870,14 +1866,14 @@ msgstr "Ce lien de désabonnement est absent ou mal formé." msgid "This week" msgstr "Cette semaine" -#: src/pages/DumpEdit.tsx:449 +#: src/pages/DumpEdit.tsx:450 msgid "Thumbnail" msgstr "Miniature" #: src/components/dump/create/TitleField.tsx:45 #: src/components/playlist/PlaylistCreateForm.tsx:100 #: src/components/playlist/PlaylistEditForm.tsx:175 -#: src/pages/DumpEdit.tsx:510 +#: src/pages/DumpEdit.tsx:511 msgid "Title" msgstr "Titre" @@ -2007,7 +2003,7 @@ msgstr "Validé" msgid "Upvoted ({0})" msgstr "Validé ({0})" -#: src/pages/DumpEdit.tsx:481 +#: src/pages/DumpEdit.tsx:482 msgid "URL" msgstr "URL" @@ -2023,7 +2019,7 @@ msgstr "Identifiant d’URL" msgid "User" msgstr "Utilisateur" -#: src/components/profile/ProfileManageTab.tsx:54 +#: src/components/profile/ProfileManageTab.tsx:56 msgid "User management" msgstr "Gestion utilisateur" @@ -2031,10 +2027,10 @@ msgstr "Gestion utilisateur" msgid "User menu" msgstr "Menu utilisateur" -#: src/components/profile/ProfileManageTab.tsx:61 +#: src/components/profile/ProfileManageTab.tsx:63 #: src/components/profile/UsernameField.tsx:51 #: src/pages/Settings.tsx:91 -#: src/pages/UserLogin.tsx:81 +#: src/pages/UserLogin.tsx:74 #: src/pages/UserRegister.tsx:141 msgid "Username" msgstr "Nom d'utilisateur" @@ -2079,7 +2075,7 @@ msgid "email.welcome.subject" msgstr "Bienvenue sur {site}" #: src/components/dump/create/DumpCreateModal.tsx:705 -#: src/pages/DumpEdit.tsx:538 +#: src/pages/DumpEdit.tsx:539 msgid "What makes it worth it?" msgstr "Pourquoi on en voudrait ?" @@ -2097,7 +2093,7 @@ msgid "Why & where" msgstr "Pourquoi & où" #: src/components/dump/create/DumpCreateModal.tsx:704 -#: src/pages/DumpEdit.tsx:537 +#: src/pages/DumpEdit.tsx:538 msgid "Why?" msgstr "Pourquoi ?" @@ -2171,7 +2167,7 @@ msgstr "Votre compte est sur {home} : connectez-vous aux autres instances depuis msgid "Your account lives on {home}: your password, email address, avatar and username change there." msgstr "Votre compte est sur {home} : votre mot de passe, votre adresse e-mail, votre avatar et votre nom d'utilisateur se changent là-bas." -#: src/pages/UserLogin.tsx:160 +#: src/pages/ResetPassword.tsx:89 msgid "Your email address" msgstr "Votre adresse e-mail" @@ -2179,7 +2175,7 @@ msgstr "Votre adresse e-mail" msgid "Your gerbeur's URL" msgstr "URL de votre gerbeur" -#: src/pages/ResetPassword.tsx:89 +#: src/pages/ResetPassword.tsx:141 msgid "Your password has been changed. You can now log in." msgstr "Votre mot de passe a été modifié. Vous pouvez maintenant vous connecter." diff --git a/src/App.css b/src/App.css index b477bcba..bffc8399 100644 --- a/src/App.css +++ b/src/App.css @@ -3316,34 +3316,6 @@ body.has-player .chat-fab { margin: 0; } -.auth-link-btn { - background: none; - border: none; - padding: 0; - cursor: pointer; - color: var(--color-accent); - font-size: inherit; - font-family: inherit; - text-decoration: underline; - text-underline-offset: 2px; -} - -.auth-link-btn:hover { - opacity: 0.8; -} - -.auth-reset-panel { - border-top: 1px solid var(--color-border-subtle); - padding-top: 1rem; - display: flex; - flex-direction: column; - gap: 0.75rem; -} - -.auth-reset-form { - margin: 0; -} - .auth-reset-sent { font-size: var(--text-md); text-align: center; diff --git a/src/App.tsx b/src/App.tsx index 3cf57e4a..0384dae0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -14,9 +14,9 @@ * - `/authorize` lets another gerbeur instance sign the user in with their * account here (`Authorize`), and `/federation/callback` finishes a sign-in * here with an account on another (`FederationCallback`). - * - `/reset-password` sets a new password from an emailed link - * (`ResetPassword`), and `/unsubscribe` turns off a digest from its emailed - * link (`Unsubscribe`). + * - `/reset-password` asks for a reset link by email, and sets a new password + * from it, `?token=` (`ResetPassword`), and `/unsubscribe` turns off a digest + * from its emailed link (`Unsubscribe`). * - `/notifications` (`Notifications`) and `/settings` (`Settings`), signed in * only, and `/manage`, the site's tools, for `category:manage` or * `federation:manage` (`Manage`). diff --git a/src/pages/ResetPassword.tsx b/src/pages/ResetPassword.tsx index d3ac74d7..0b5a39c8 100644 --- a/src/pages/ResetPassword.tsx +++ b/src/pages/ResetPassword.tsx @@ -1,6 +1,7 @@ /** - * Renders the page a password reset email links to, where the user sets a new - * password. + * Renders the reset of a forgotten password, both its steps on one page: the + * request for a link by email, which "Forgot password?" on the login page + * leads to, and the new password, which the link leads to. * * @module */ @@ -26,15 +27,88 @@ interface Values { confirm: string; } +interface RequestValues { + email: string; +} + /** - * Renders `/reset-password?token=`, for anyone holding a reset link. It doesn't - * sign the user in: a success links to `/login`. + * Renders `/reset-password`, for anyone: the request for a reset link, or, + * with the link's `?token=`, the new password. It doesn't sign the user in: a + * success links to `/login`. */ export function ResetPassword(): React.JSX.Element { useDocumentTitle(t`Reset password`); const [params] = useSearchParams(); - const navigate = useNavigate(); const token = params.get("token") ?? ""; + return token ? : ; +} + +/** + * Renders the form that asks the server to email a reset link, which leads + * back here with its token. + */ +function ResetRequest() { + const [sent, setSent] = useState(false); + const form = useApiForm({ defaultValues: { email: "" } }); + + const onSubmit = form.submit(async ({ email }) => { + // The server answers 200 whether or not the address is known, so as not + // to reveal which ones are. An error here means it failed. + await expectOk( + await fetch(`${API_URL}/api/password-resets`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ email: email.trim() }), + }), + ); + setSent(true); + }); + + return ( + +
+

+ Reset password +

+ {sent + ? ( +

+ + If that address is registered you'll receive a reset link + shortly. + +

+ ) + : ( + +
+ + + name="email" + type="email" + placeholder={t`Your email address`} + autoFocus + rules={{ required: true }} + /> + Sending…}> + Send reset link + + +
+ )} +

+ + Back to login + +

+
+
+ ); +} + +/** Renders the form that sets a new password with the link's `token`. */ +function NewPassword({ token }: { token: string }) { + const navigate = useNavigate(); const [done, setDone] = useState(false); const form = useApiForm({ @@ -56,28 +130,6 @@ export function ResetPassword(): React.JSX.Element { setDone(true); }); - if (!token) { - return ( - -
-

- Invalid link -

-

- This reset link is missing or malformed. -

- - Back to login - -
-
- ); - } - if (done) { return ( diff --git a/src/pages/UserLogin.tsx b/src/pages/UserLogin.tsx index 8ff13eaa..4129e847 100644 --- a/src/pages/UserLogin.tsx +++ b/src/pages/UserLogin.tsx @@ -1,11 +1,10 @@ /** - * Renders the sign-in page, which also requests password reset links. + * Renders the sign-in page. * * @module */ -import { useState } from "react"; -import { useNavigate, useSearchParams } from "react-router"; +import { Link, useNavigate, useSearchParams } from "react-router"; import { t } from "@lingui/core/macro"; import { Trans } from "@lingui/react/macro"; @@ -15,7 +14,6 @@ import type { AuthResponse, LoginUserRequest } from "../../shared/user.ts"; import type { Wire } from "../../shared/api.ts"; import { useAuth } from "../hooks/auth/useAuth.ts"; import { useDocumentTitle } from "../hooks/shared/useDocumentTitle.ts"; -import { useHeightTransition } from "../hooks/shared/useHeightTransition.ts"; import { PageShell } from "../components/layout/PageShell.tsx"; import { expectOk } from "../utils/shared/api.ts"; import { FormError } from "../components/form/FormError.tsx"; @@ -32,13 +30,10 @@ interface LoginValues { password: string; } -interface ResetValues { - email: string; -} - /** * Renders `/login`, for the signed out. A sign-in lands on the page `?next=` - * names, or `/`, and "Forgot password?" unfolds the reset request form below. + * names, or `/`, and "Forgot password?" leads to `/reset-password`, which asks + * for a reset link. * Users of another instance sign in through {@link FederatedSignIn}, unless * the instance takes none. */ @@ -47,8 +42,6 @@ export function UserLogin(): React.JSX.Element { const navigate = useNavigate(); const [params] = useSearchParams(); const { login } = useAuth(); - const [showReset, setShowReset] = useState(false); - const cardRef = useHeightTransition(showReset); const form = useApiForm({ defaultValues: { username: "", password: "" }, @@ -68,7 +61,7 @@ export function UserLogin(): React.JSX.Element { return ( -
+

Log in

@@ -95,17 +88,11 @@ export function UserLogin(): React.JSX.Element {

- +

- {showReset && } - {FEDERATION_INCOMING && }

@@ -115,57 +102,3 @@ export function UserLogin(): React.JSX.Element { ); } - -/** - * Renders the form that asks the server to email a password reset link, which - * leads to `/reset-password`. - */ -function ResetRequestPanel() { - const [sent, setSent] = useState(false); - const form = useApiForm({ defaultValues: { email: "" } }); - - const onSubmit = form.submit(async ({ email }) => { - // The server answers 200 whether or not the address is known, so as not - // to reveal which ones are. An error here means it failed. - await expectOk( - await fetch(`${API_URL}/api/password-resets`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ email: email.trim() }), - }), - ); - setSent(true); - }); - - if (sent) { - return ( -

-

- - If that address is registered you'll receive a reset link shortly. - -

-
- ); - } - - return ( -
- -
- - - name="email" - type="email" - placeholder={t`Your email address`} - autoFocus - rules={{ required: true }} - /> - Sending…}> - Send reset link - - -
-
- ); -} diff --git a/src/test/pages/ResetPassword.test.tsx b/src/test/pages/ResetPassword.test.tsx index 17ed52a5..4038ce63 100644 --- a/src/test/pages/ResetPassword.test.tsx +++ b/src/test/pages/ResetPassword.test.tsx @@ -17,16 +17,37 @@ describe("ResetPassword", () => { return user; } - test("no token: an invalid link", () => { - setup(""); - expect(screen.getByRole("heading", { name: "Invalid link" })) - .toBeInTheDocument(); + test("without a token, it asks for a link by email", async () => { + route("POST /api/password-resets", () => ({})); + const user = setup(""); + await user.type( + screen.getByPlaceholderText("Your email address"), + " a@b.c {Enter}", + ); + await screen.findByText(/you'll receive a reset link/); + expect(calls("POST /api/password-resets")[0].body).toEqual({ + email: "a@b.c", + }); expect(screen.getByRole("link", { name: "Back to login" })).toHaveAttribute( "href", "/login", ); }); + test("a failed request is reported, not claimed as sent", async () => { + route("POST /api/password-resets", () => fail("Internal error", 500)); + const user = setup(""); + await user.type( + screen.getByPlaceholderText("Your email address"), + "a@b.c{Enter}", + ); + expect(await screen.findByRole("alert")).toHaveTextContent( + "Request failed", + ); + expect(screen.queryByText(/you'll receive a reset link/)).not + .toBeInTheDocument(); + }); + test("the two passwords must match", async () => { const user = setup(); await user.type(screen.getByPlaceholderText("New password"), "longenough"); diff --git a/src/test/pages/UserLogin.test.tsx b/src/test/pages/UserLogin.test.tsx index eb3ded51..1ed2205d 100644 --- a/src/test/pages/UserLogin.test.tsx +++ b/src/test/pages/UserLogin.test.tsx @@ -97,36 +97,10 @@ describe("UserLogin", () => { await screen.findByText("home page"); }); - test("password reset request", async () => { - route("POST /api/password-resets", () => ({})); - const user = setup(); - await user.click(screen.getByRole("button", { name: "Forgot password?" })); - await user.type( - screen.getByPlaceholderText("Your email address"), - " a@b.c {Enter}", - ); - await screen.findByText(/you'll receive a reset link/); - expect(calls("POST /api/password-resets")[0].body).toEqual({ - email: "a@b.c", - }); - }); - - test("a failed reset request is reported, not claimed as sent", async () => { - route( - "POST /api/password-resets", - () => fail("Internal error", 500), - ); - const user = setup(); - await user.click(screen.getByRole("button", { name: "Forgot password?" })); - await user.type( - screen.getByPlaceholderText("Your email address"), - "a@b.c{Enter}", - ); - expect(await screen.findByRole("alert")).toHaveTextContent( - "Request failed", - ); - expect(screen.queryByText(/you'll receive a reset link/)).not - .toBeInTheDocument(); + test("Forgot password? leads to the reset page", () => { + setup(); + expect(screen.getByRole("link", { name: "Forgot password?" })) + .toHaveAttribute("href", "/reset-password"); }); test("a sign-in follows ?next= on this site, and only there", async () => { diff --git a/src/themes/brutalist.css b/src/themes/brutalist.css index 7fd41256..4d657842 100644 --- a/src/themes/brutalist.css +++ b/src/themes/brutalist.css @@ -107,7 +107,6 @@ [data-style="brutalist"] .rich-content-thumbnail-btn, [data-style="brutalist"] .user-menu-trigger, [data-style="brutalist"] .user-menu-item, -[data-style="brutalist"] .auth-link-btn, [data-style="brutalist"] .form-cancel, [data-style="brutalist"] .form-label-action { border: none !important; @@ -118,8 +117,6 @@ [data-style="brutalist"] .user-menu-trigger:active, [data-style="brutalist"] .user-menu-item:hover:not(:disabled), [data-style="brutalist"] .user-menu-item:active, -[data-style="brutalist"] .auth-link-btn:hover:not(:disabled), -[data-style="brutalist"] .auth-link-btn:active, [data-style="brutalist"] .form-cancel:hover:not(:disabled), [data-style="brutalist"] .form-cancel:active, [data-style="brutalist"] .form-label-action:hover:not(:disabled), diff --git a/src/themes/geocities.css b/src/themes/geocities.css index 0509b349..a678e2c1 100644 --- a/src/themes/geocities.css +++ b/src/themes/geocities.css @@ -218,7 +218,6 @@ [data-style="geocities"] .rich-content-thumbnail-btn, [data-style="geocities"] .user-menu-trigger, [data-style="geocities"] .user-menu-item, -[data-style="geocities"] .auth-link-btn, [data-style="geocities"] .form-cancel, [data-style="geocities"] .form-label-action, [data-style="geocities"] .category-editor-btn {