v4: every live update reaches every page that shows what it changed — the client kept each kind of event in one "latest" slot, so two arriving before a render lost the first (two notifications of one dump going public showed one); they now go through a subscription, useWSEvent, and each reaches every subscriber. A playlist made private sent its new title and description to everyone, and kept them on a visitor's page; playlists now follow the dumps' rule, broadcastChange: others get playlist_deleted, and playlist_created when it goes public again. A dump deleted or turned private sends its playlists' dumps again, so their counts and pages follow. Comments on a private dump reach its poster's other tabs. Reading the notifications clears the bell in every tab (notifications_read), and a category change makes every client fetch the categories again (categories_changed). The dump page gives way to a notice when its dump is deleted or made private. A profile gains the user's new dumps, the followed feed those of the users followed and the playlists followed, the search results follow edits and deletions, the index's category feed drops a dump edited out of it, and a renamed user's name follows on cards and comments. After a reconnection, every live list fetches the pages it holds again (usePagedList's resync), and the playlist, the profile, the dump, the categories and the follows are fetched again. The position memory of usePositionAwareSync is now inside the list sync hooks, so a returning item is put back without depending on the order the hooks are called.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
khannurien
2026-10-10 07:34:49 +00:00
parent 1c5a449d84
commit 308a8299f3
53 changed files with 1941 additions and 1044 deletions

View File

@@ -60,7 +60,7 @@ msgstr "{0}–{1} characters: letters, numbers, or underscores"
msgid "email.digest.totals"
msgstr "{dumps, plural, one {# dump} other {# dumps}}, {upvotes, plural, one {# upvote} other {# upvotes}} and {comments, plural, one {# comment} other {# comments}}."
#: src/pages/Search.tsx:152
#: src/pages/Search.tsx:178
msgid "{label} ({count})"
msgstr "{label} ({count})"
@@ -144,7 +144,7 @@ msgstr "{n, plural, one {upvote} other {upvotes}}"
msgid "email.digest.more"
msgstr "{n} more on your Followed feed"
#: src/pages/Notifications.tsx:508
#: src/pages/Notifications.tsx:499
msgid "{totalUnread, plural, one {# new} other {# new}}"
msgstr "{totalUnread, plural, one {# new} other {# new}}"
@@ -211,8 +211,9 @@ msgstr "# Welcome to {site}!\n"
msgid "← Back"
msgstr "← Back"
#: src/pages/Dump.tsx:330
#: src/pages/Dump.tsx:557
#: src/pages/Dump.tsx:353
#: src/pages/Dump.tsx:378
#: src/pages/Dump.tsx:605
#: src/pages/DumpEdit.tsx:234
msgid "← Back to all dumps"
msgstr "← Back to all dumps"
@@ -225,7 +226,7 @@ msgstr "+ Invite someone"
msgid "+ New playlist"
msgstr "+ New playlist"
#: src/pages/Dump.tsx:404
#: src/pages/Dump.tsx:452
msgid "+ Playlist"
msgstr "+ Playlist"
@@ -418,8 +419,8 @@ msgstr "by @{username}"
msgid "email.digest.playlistMeta"
msgstr "by @{username} · {n, plural, one {# dump} other {# dumps}}"
#: src/contexts/ws/WSProvider.tsx:395
#: src/contexts/ws/WSProvider.tsx:764
#: src/contexts/ws/WSProvider.tsx:376
#: src/contexts/ws/WSProvider.tsx:765
msgid "Can't connect to the live updates server. Upvotes and notifications may not sync until it reconnects."
msgstr "Can't connect to the live updates server. Upvotes and notifications may not sync until it reconnects."
@@ -439,7 +440,7 @@ 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:446
#: src/pages/Dump.tsx:494
#: src/pages/DumpEdit.tsx:561
msgid "Cancel"
msgstr "Cancel"
@@ -554,7 +555,7 @@ msgstr "Confirm new password"
msgid "Connecting…"
msgstr "Connecting…"
#: src/contexts/ws/WSProvider.tsx:757
#: src/contexts/ws/WSProvider.tsx:758
msgid "Connection lost — this message may not have been sent"
msgstr "Connection lost — this message may not have been sent"
@@ -582,7 +583,7 @@ 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:178
#: src/components/profile/ProfilePlaylistsTab.tsx:171
#: src/pages/DumpEdit.tsx:555
msgid "Could not delete"
msgstr "Could not delete"
@@ -680,7 +681,7 @@ msgstr "Delete failed ({0})"
#: src/components/playlist/PlaylistCard.tsx:149
#: src/components/playlist/PlaylistEditForm.tsx:213
#: src/components/profile/ProfilePlaylistsTab.tsx:208
#: src/components/profile/ProfilePlaylistsTab.tsx:201
#: src/pages/PlaylistDetail.tsx:172
msgid "Delete playlist"
msgstr "Delete playlist"
@@ -697,7 +698,7 @@ msgstr "Delete this dump? This cannot be undone."
msgid "Delete this message?"
msgstr "Delete this message?"
#: src/components/profile/ProfilePlaylistsTab.tsx:207
#: src/components/profile/ProfilePlaylistsTab.tsx:200
#: src/pages/PlaylistDetail.tsx:171
msgid "Delete this playlist? This cannot be undone."
msgstr "Delete this playlist? This cannot be undone."
@@ -769,7 +770,7 @@ msgid "Dumped!"
msgstr "Dumped!"
#: src/components/profile/ProfileDumpsTab.tsx:46
#: src/pages/Search.tsx:148
#: src/pages/Search.tsx:174
#: src/pages/UserPublicProfile.tsx:160
msgid "Dumps"
msgstr "Dumps"
@@ -788,7 +789,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:553
#: src/pages/Dump.tsx:601
msgid "Edit"
msgstr "Edit"
@@ -806,7 +807,7 @@ msgid "Edit email"
msgstr "Edit email"
#: src/components/dump/create/TitleField.tsx:69
#: src/pages/Dump.tsx:463
#: src/pages/Dump.tsx:511
msgid "Edit title"
msgstr "Edit title"
@@ -820,7 +821,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:506
#: src/pages/Dump.tsx:554
msgid "edited {0}"
msgstr "edited {0}"
@@ -830,7 +831,7 @@ 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:504
#: src/pages/Dump.tsx:552
msgid "Edited {0}"
msgstr "Edited {0}"
@@ -851,7 +852,7 @@ msgstr "Email"
msgid "Email address"
msgstr "Email address"
#: src/pages/Search.tsx:204
#: src/pages/Search.tsx:230
msgid "Enter a query to search."
msgstr "Enter a query to search."
@@ -942,16 +943,16 @@ msgstr "Follow {targetUsername}"
msgid "Follow playlist"
msgstr "Follow playlist"
#: src/components/feed/FollowedFeed.tsx:164
#: src/components/feed/FollowedFeed.tsx:192
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:156
#: src/components/feed/FollowedFeed.tsx:184
msgid "Follow some users to see their dumps here."
msgstr "Follow some users to see their dumps here."
#: src/components/feed/FeedTabBar.tsx:61
#: src/components/profile/ProfileFollowTab.tsx:140
#: src/components/profile/ProfileFollowTab.tsx:144
#: src/pages/Settings.tsx:57
#: src/pages/UserPublicProfile.tsx:163
msgid "Followed"
@@ -971,7 +972,7 @@ msgstr "For you"
msgid "Forgot password?"
msgstr "Forgot password?"
#: src/components/feed/FollowedFeed.tsx:137
#: src/components/feed/FollowedFeed.tsx:165
msgid "From people"
msgstr "From people"
@@ -980,7 +981,7 @@ msgstr "From people"
msgid "email.digest.network"
msgstr "From people you follow"
#: src/components/feed/FollowedFeed.tsx:138
#: src/components/feed/FollowedFeed.tsx:166
msgid "From playlists"
msgstr "From playlists"
@@ -1024,7 +1025,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:573
#: src/pages/Dump.tsx:621
msgid "In collections"
msgstr "In collections"
@@ -1109,7 +1110,7 @@ msgstr "Link"
msgid "Link or file"
msgstr "Link or file"
#: src/contexts/ws/WSProvider.tsx:763
#: src/contexts/ws/WSProvider.tsx:764
msgid "Live updates are temporarily disconnected. Trying to reconnect…"
msgstr "Live updates are temporarily disconnected. Trying to reconnect…"
@@ -1125,7 +1126,7 @@ msgstr "Load more"
msgid "Load older messages"
msgstr "Load older messages"
#: src/pages/Dump.tsx:306
#: src/pages/Dump.tsx:337
#: src/pages/DumpEdit.tsx:210
msgid "Loading dump…"
msgstr "Loading dump…"
@@ -1271,7 +1272,7 @@ msgstr "Next track"
msgid "No dumps in this playlist yet."
msgstr "No dumps in this playlist yet."
#: src/pages/Search.tsx:220
#: src/pages/Search.tsx:246
msgid "No dumps match \"{q}\"."
msgstr "No dumps match \"{q}\"."
@@ -1284,7 +1285,7 @@ msgstr "No dumps yet. Be the first!"
msgid "No emoji found."
msgstr "No emoji found."
#: src/components/profile/ProfileFollowTab.tsx:113
#: src/components/profile/ProfileFollowTab.tsx:117
msgid "No followed playlists yet."
msgstr "No followed playlists yet."
@@ -1300,21 +1301,21 @@ msgstr "No messages yet. Say hello!"
msgid "No one yet."
msgstr "No one yet."
#: src/pages/Search.tsx:261
#: src/pages/Search.tsx:287
msgid "No playlists match \"{q}\"."
msgstr "No playlists match \"{q}\"."
#: src/components/playlist/PlaylistMembershipPanel.tsx:51
#: src/components/profile/ProfilePlaylistsTab.tsx:185
#: src/pages/Playlists.tsx:118
#: src/components/profile/ProfilePlaylistsTab.tsx:178
#: src/pages/Playlists.tsx:126
msgid "No playlists yet."
msgstr "No playlists yet."
#: src/contexts/ws/WSProvider.tsx:932
#: src/contexts/ws/WSProvider.tsx:934
msgid "No reply from the server — this message may not have been sent"
msgstr "No reply from the server — this message may not have been sent"
#: src/pages/Search.tsx:235
#: src/pages/Search.tsx:261
msgid "No users match \"{q}\"."
msgstr "No users match \"{q}\"."
@@ -1336,18 +1337,18 @@ msgstr "Nothing happened this week."
#: src/components/profile/ProfileDumpsTab.tsx:97
#: src/components/profile/ProfileOverviewTab.tsx:47
#: src/pages/Notifications.tsx:522
#: src/pages/Notifications.tsx:513
msgid "Nothing here yet."
msgstr "Nothing here yet."
#: src/components/layout/NotificationBell.tsx:57
#: src/components/layout/NotificationBell.tsx:49
#: src/pages/Notifications.tsx:387
#: src/pages/Notifications.tsx:505
#: src/pages/Notifications.tsx:496
#: src/pages/Settings.tsx:163
msgid "Notifications"
msgstr "Notifications"
#: src/components/layout/NotificationBell.tsx:56
#: src/components/layout/NotificationBell.tsx:48
msgid "Notifications ({unreadNotificationCount} unread)"
msgstr "Notifications ({unreadNotificationCount} unread)"
@@ -1469,11 +1470,11 @@ msgstr "Playlist categories"
#: src/components/dump/create/StepIndicator.tsx:21
#: src/components/layout/AppHeader.tsx:172
#: src/components/layout/UserMenu.tsx:92
#: src/components/profile/ProfileFollowTab.tsx:144
#: src/components/profile/ProfilePlaylistsTab.tsx:156
#: src/pages/Playlists.tsx:52
#: src/pages/Playlists.tsx:106
#: src/pages/Search.tsx:151
#: src/components/profile/ProfileFollowTab.tsx:148
#: src/components/profile/ProfilePlaylistsTab.tsx:149
#: src/pages/Playlists.tsx:53
#: src/pages/Playlists.tsx:114
#: src/pages/Search.tsx:177
#: src/pages/UserPublicProfile.tsx:162
msgid "Playlists"
msgstr "Playlists"
@@ -1501,7 +1502,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:512
#: src/pages/Dump.tsx:560
msgid "private"
msgstr "private"
@@ -1544,7 +1545,7 @@ msgstr "Registering…"
msgid "Registration failed"
msgstr "Registration failed"
#: src/pages/Dump.tsx:564
#: src/pages/Dump.tsx:612
msgid "Related"
msgstr "Related"
@@ -1631,7 +1632,7 @@ msgid "email.reset.title"
msgstr "Reset your password"
#: src/components/chat/PendingItem.tsx:86
#: src/pages/Dump.tsx:323
#: src/pages/Dump.tsx:371
#: src/pages/DumpEdit.tsx:227
msgid "Retry"
msgstr "Retry"
@@ -1646,7 +1647,7 @@ msgstr "Role"
#: src/components/playlist/PlaylistEditForm.tsx:229
#: src/components/profile/DescriptionEditor.tsx:89
#: src/components/profile/EmailEditor.tsx:75
#: src/pages/Dump.tsx:438
#: src/pages/Dump.tsx:486
#: src/pages/DumpEdit.tsx:564
msgid "Save"
msgstr "Save"
@@ -1656,14 +1657,14 @@ msgstr "Save"
#: src/components/profile/ChangePasswordModal.tsx:119
#: src/components/profile/DescriptionEditor.tsx:86
#: src/components/profile/EmailEditor.tsx:72
#: src/pages/Dump.tsx:437
#: src/pages/Dump.tsx:485
#: src/pages/ResetPassword.tsx:191
msgid "Saving…"
msgstr "Saving…"
#: src/components/layout/AppHeader.tsx:182
#: src/components/layout/SearchBar.tsx:83
#: src/pages/Search.tsx:87
#: src/pages/Search.tsx:90
msgid "Search"
msgstr "Search"
@@ -1679,11 +1680,11 @@ msgstr "Search emoji"
msgid "Search emoji…"
msgstr "Search emoji…"
#: src/pages/Search.tsx:215
#: src/pages/Search.tsx:241
msgid "Search failed"
msgstr "Search failed"
#: src/pages/Search.tsx:210
#: src/pages/Search.tsx:236
msgid "Searching…"
msgstr "Searching…"
@@ -1765,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/contexts/ws/WSProvider.tsx:733
#: src/pages/PlaylistDetail.tsx:155
msgid "Something went wrong"
msgstr "Something went wrong"
@@ -1799,7 +1800,7 @@ msgstr "the chat"
msgid "the chat"
msgstr "the chat"
#: src/hooks/playlist/usePlaylist.ts:182
#: src/hooks/playlist/usePlaylist.ts:177
msgid "The dump couldn't be removed. Try again."
msgstr "The dump couldn't be removed. Try again."
@@ -1822,7 +1823,7 @@ msgstr "The month on {site}"
msgid "email.digest.monthly.subject"
msgstr "The month on {site}, {range}"
#: src/hooks/playlist/usePlaylist.ts:325
#: src/hooks/playlist/usePlaylist.ts:317
msgid "The new order couldn't be saved. Try again."
msgstr "The new order couldn't be saved. Try again."
@@ -1830,6 +1831,10 @@ msgstr "The new order couldn't be saved. Try again."
msgid "This comment couldn't be deleted. Try again."
msgstr "This comment couldn't be deleted. Try again."
#: src/pages/Dump.tsx:346
msgid "This dump was deleted, or made private."
msgstr "This dump was deleted, or made private."
#: src/pages/UserRegister.tsx:122
msgid "This invite link is missing, expired, or already used."
msgstr "This invite link is missing, expired, or already used."
@@ -2035,8 +2040,8 @@ msgstr "User menu"
msgid "Username"
msgstr "Username"
#: src/components/profile/ProfileFollowTab.tsx:143
#: src/pages/Search.tsx:150
#: src/components/profile/ProfileFollowTab.tsx:147
#: src/pages/Search.tsx:176
msgid "Users"
msgstr "Users"
@@ -2122,7 +2127,7 @@ msgstr "You won't get the monthly recap any more. You can turn it back on in you
msgid "You won't get the weekly digest any more. You can turn it back on in your settings."
msgstr "You won't get the weekly digest any more. You can turn it back on in your settings."
#: src/pages/Notifications.tsx:525
#: src/pages/Notifications.tsx:516
msgid "You'll be notified when someone follows your playlists, upvotes your dumps, or posts new content."
msgstr "You'll be notified when someone follows your playlists, upvotes your dumps, or posts new content."
@@ -2146,7 +2151,7 @@ msgstr "You're getting this email because a password reset was requested for thi
msgid "email.welcome.reason"
msgstr "You're getting this email because an account was created on {site} with this address."
#: src/contexts/ws/WSProvider.tsx:913
#: src/contexts/ws/WSProvider.tsx:915
msgid "You're offline — not sent"
msgstr "You're offline — not sent"