From 2c3a00b73d1d54479a10086a9798d6dc83b740e4 Mon Sep 17 00:00:00 2001 From: Blabla Linux Date: Sat, 8 Nov 2025 22:53:07 +0100 Subject: [PATCH 001/100] Update README.md Added a public community instance of Phanpy Blabla Linux. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 29187f6ee0..adf456fbd6 100644 --- a/README.md +++ b/README.md @@ -318,6 +318,7 @@ These are self-hosted by other wonderful folks. - [phanpy.tilde.zone](https://phanpy.tilde.zone) by [@ben@tilde.zone](https://tilde.zone/@ben) - [phanpy.vmst.io](https://phanpy.vmst.io/) by [@vmstan@vmst.io](https://vmst.io/@vmstan) - [phanpy.linuxusers.in](https://phanpy.linuxusers.in) by [@dharmik@linuxusers.in](https://linuxusers.in/dharmik) +- [phanpy.blablalinux.be](https://phanpy.blablalinux.be) by [@blablalinux@mastodon.blablalinux.be](https://mastodon.blablalinux.be/@blablalinux) > Note: Add yours by creating a pull request. From 0bb663c645d430eb352f27b364a51ec5ed48f90f Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Sat, 8 Nov 2025 10:31:30 +0800 Subject: [PATCH 002/100] Preserve states in Catch-up --- src/locales/en.po | 174 +++++++++++++++++++++--------------------- src/pages/catchup.jsx | 101 ++++++++++++++++++++++++ 2 files changed, 188 insertions(+), 87 deletions(-) diff --git a/src/locales/en.po b/src/locales/en.po index 9c33b1a765..0c12054dae 100644 --- a/src/locales/en.po +++ b/src/locales/en.po @@ -227,15 +227,15 @@ msgid "{0, plural, one {Last 1 post in the past year(s)} other {Last {1} posts i msgstr "{0, plural, one {Last 1 post in the past year(s)} other {Last {1} posts in the past year(s)}}" #: src/components/account-info.jsx:1008 -#: src/pages/catchup.jsx:70 +#: src/pages/catchup.jsx:73 msgid "Original" msgstr "" #: src/components/account-info.jsx:1012 #: src/components/status.jsx:2659 -#: src/pages/catchup.jsx:71 -#: src/pages/catchup.jsx:1463 -#: src/pages/catchup.jsx:2106 +#: src/pages/catchup.jsx:74 +#: src/pages/catchup.jsx:1564 +#: src/pages/catchup.jsx:2207 #: src/pages/status.jsx:1100 #: src/pages/status.jsx:1824 msgid "Replies" @@ -243,15 +243,15 @@ msgstr "" #: src/components/account-info.jsx:1017 #: src/components/quotes-modal.jsx:81 -#: src/pages/catchup.jsx:73 -#: src/pages/catchup.jsx:1466 +#: src/pages/catchup.jsx:76 +#: src/pages/catchup.jsx:1567 msgid "Quotes" msgstr "Quotes" #: src/components/account-info.jsx:1022 -#: src/pages/catchup.jsx:72 -#: src/pages/catchup.jsx:1465 -#: src/pages/catchup.jsx:2118 +#: src/pages/catchup.jsx:75 +#: src/pages/catchup.jsx:1566 +#: src/pages/catchup.jsx:2219 #: src/pages/settings.jsx:1249 msgid "Boosts" msgstr "" @@ -293,7 +293,7 @@ msgstr "View post stats" #: src/components/status.jsx:3444 #: src/components/translated-bio-sheet.jsx:21 #: src/pages/accounts.jsx:45 -#: src/pages/catchup.jsx:1600 +#: src/pages/catchup.jsx:1701 #: src/pages/filters.jsx:225 #: src/pages/list.jsx:302 #: src/pages/notifications.jsx:943 @@ -349,7 +349,7 @@ msgstr "More from <0/>" #: src/components/nav-menu.jsx:181 #: src/components/shortcuts-settings.jsx:139 #: src/components/timeline.jsx:464 -#: src/pages/catchup.jsx:899 +#: src/pages/catchup.jsx:1000 #: src/pages/filters.jsx:90 #: src/pages/followed-hashtags.jsx:41 #: src/pages/home.jsx:54 @@ -382,7 +382,7 @@ msgstr "Choice {0}" #: src/components/compose-poll.jsx:64 #: src/components/media-attachment.jsx:319 #: src/components/shortcuts-settings.jsx:726 -#: src/pages/catchup.jsx:1097 +#: src/pages/catchup.jsx:1198 #: src/pages/filters.jsx:413 msgid "Remove" msgstr "" @@ -712,7 +712,7 @@ msgid "No drafts found." msgstr "" #: src/components/drafts.jsx:263 -#: src/pages/catchup.jsx:1977 +#: src/pages/catchup.jsx:2078 msgid "Poll" msgstr "" @@ -878,7 +878,7 @@ msgstr "<0>{key1} then <1>{key2}" #: src/components/keyboard-shortcuts-help.jsx:56 #: src/components/nav-menu.jsx:368 -#: src/pages/catchup.jsx:1638 +#: src/pages/catchup.jsx:1739 msgid "Keyboard shortcuts" msgstr "" @@ -887,12 +887,12 @@ msgid "Keyboard shortcuts help" msgstr "" #: src/components/keyboard-shortcuts-help.jsx:68 -#: src/pages/catchup.jsx:1663 +#: src/pages/catchup.jsx:1764 msgid "Next post" msgstr "" #: src/components/keyboard-shortcuts-help.jsx:72 -#: src/pages/catchup.jsx:1671 +#: src/pages/catchup.jsx:1772 msgid "Previous post" msgstr "" @@ -917,7 +917,7 @@ msgid "Load new posts" msgstr "" #: src/components/keyboard-shortcuts-help.jsx:96 -#: src/pages/catchup.jsx:1695 +#: src/pages/catchup.jsx:1796 msgid "Open post details" msgstr "" @@ -1241,8 +1241,8 @@ msgstr "" #: src/components/status.jsx:3370 #: src/components/status.jsx:3448 #: src/components/timeline.jsx:979 -#: src/pages/catchup.jsx:76 -#: src/pages/catchup.jsx:1921 +#: src/pages/catchup.jsx:79 +#: src/pages/catchup.jsx:2022 msgid "Filtered" msgstr "" @@ -1295,7 +1295,7 @@ msgid "following.title" msgstr "Following" #: src/components/nav-menu.jsx:197 -#: src/pages/catchup.jsx:894 +#: src/pages/catchup.jsx:995 msgid "Catch-up" msgstr "" @@ -1345,8 +1345,8 @@ msgstr "" #: src/components/nav-menu.jsx:253 #: src/components/shortcuts-settings.jsx:55 #: src/components/shortcuts-settings.jsx:201 -#: src/pages/catchup.jsx:1464 -#: src/pages/catchup.jsx:2112 +#: src/pages/catchup.jsx:1565 +#: src/pages/catchup.jsx:2213 #: src/pages/favourites.jsx:12 #: src/pages/favourites.jsx:26 #: src/pages/settings.jsx:1245 @@ -2750,7 +2750,7 @@ msgstr "" #. placeholder {0}: filterInfo.titlesStr #. placeholder {0}: filterInfo?.titlesStr #: src/components/status.jsx:2553 -#: src/pages/catchup.jsx:1920 +#: src/pages/catchup.jsx:2021 msgid "Filtered: {0}" msgstr "Filtered: {0}" @@ -2822,7 +2822,7 @@ msgstr "<0/> <1/> boosted" #: src/components/thread-badge.jsx:22 #: src/components/thread-badge.jsx:37 #: src/components/thread-badge.jsx:52 -#: src/pages/catchup.jsx:1938 +#: src/pages/catchup.jsx:2039 msgid "Thread" msgstr "" @@ -3069,255 +3069,255 @@ msgstr "No bookmarks yet. Go bookmark something!" msgid "Unable to load bookmarks." msgstr "" -#: src/pages/catchup.jsx:54 +#: src/pages/catchup.jsx:57 msgid "last 1 hour" msgstr "" -#: src/pages/catchup.jsx:55 +#: src/pages/catchup.jsx:58 msgid "last 2 hours" msgstr "" -#: src/pages/catchup.jsx:56 +#: src/pages/catchup.jsx:59 msgid "last 3 hours" msgstr "" -#: src/pages/catchup.jsx:57 +#: src/pages/catchup.jsx:60 msgid "last 4 hours" msgstr "" -#: src/pages/catchup.jsx:58 +#: src/pages/catchup.jsx:61 msgid "last 5 hours" msgstr "" -#: src/pages/catchup.jsx:59 +#: src/pages/catchup.jsx:62 msgid "last 6 hours" msgstr "" -#: src/pages/catchup.jsx:60 +#: src/pages/catchup.jsx:63 msgid "last 7 hours" msgstr "" -#: src/pages/catchup.jsx:61 +#: src/pages/catchup.jsx:64 msgid "last 8 hours" msgstr "" -#: src/pages/catchup.jsx:62 +#: src/pages/catchup.jsx:65 msgid "last 9 hours" msgstr "" -#: src/pages/catchup.jsx:63 +#: src/pages/catchup.jsx:66 msgid "last 10 hours" msgstr "" -#: src/pages/catchup.jsx:64 +#: src/pages/catchup.jsx:67 msgid "last 11 hours" msgstr "" -#: src/pages/catchup.jsx:65 +#: src/pages/catchup.jsx:68 msgid "last 12 hours" msgstr "" -#: src/pages/catchup.jsx:66 +#: src/pages/catchup.jsx:69 msgid "beyond 12 hours" msgstr "" -#: src/pages/catchup.jsx:74 +#: src/pages/catchup.jsx:77 msgid "Followed tags" msgstr "" -#: src/pages/catchup.jsx:75 +#: src/pages/catchup.jsx:78 msgid "Groups" msgstr "" -#: src/pages/catchup.jsx:612 +#: src/pages/catchup.jsx:713 msgid "Showing {selectedFilterCategory, select, all {all posts} original {original posts} replies {replies} boosts {boosts} quotes {quotes} followedTags {followed tags} groups {groups} filtered {filtered posts}}, {sortBy, select, createdAt {{sortOrder, select, asc {oldest} desc {latest}}} reblogsCount {{sortOrder, select, asc {fewest boosts} desc {most boosts}}} favouritesCount {{sortOrder, select, asc {fewest likes} desc {most likes}}} repliesCount {{sortOrder, select, asc {fewest replies} desc {most replies}}} density {{sortOrder, select, asc {least dense} desc {most dense}}}} first{groupBy, select, account {, grouped by authors} other {}}" msgstr "Showing {selectedFilterCategory, select, all {all posts} original {original posts} replies {replies} boosts {boosts} quotes {quotes} followedTags {followed tags} groups {groups} filtered {filtered posts}}, {sortBy, select, createdAt {{sortOrder, select, asc {oldest} desc {latest}}} reblogsCount {{sortOrder, select, asc {fewest boosts} desc {most boosts}}} favouritesCount {{sortOrder, select, asc {fewest likes} desc {most likes}}} repliesCount {{sortOrder, select, asc {fewest replies} desc {most replies}}} density {{sortOrder, select, asc {least dense} desc {most dense}}}} first{groupBy, select, account {, grouped by authors} other {}}" -#: src/pages/catchup.jsx:905 -#: src/pages/catchup.jsx:929 +#: src/pages/catchup.jsx:1006 +#: src/pages/catchup.jsx:1030 msgid "Catch-up <0>beta" msgstr "" -#: src/pages/catchup.jsx:919 -#: src/pages/catchup.jsx:1604 +#: src/pages/catchup.jsx:1020 +#: src/pages/catchup.jsx:1705 msgid "Help" msgstr "" -#: src/pages/catchup.jsx:935 +#: src/pages/catchup.jsx:1036 msgid "What is this?" msgstr "" -#: src/pages/catchup.jsx:938 +#: src/pages/catchup.jsx:1039 msgid "Catch-up is a separate timeline for your followings, offering a high-level view at a glance, with a simple, email-inspired interface to effortlessly sort and filter through posts." msgstr "" -#: src/pages/catchup.jsx:949 +#: src/pages/catchup.jsx:1050 msgid "Preview of Catch-up UI" msgstr "Preview of Catch-up UI" -#: src/pages/catchup.jsx:958 +#: src/pages/catchup.jsx:1059 msgid "Let's catch up" msgstr "" -#: src/pages/catchup.jsx:963 +#: src/pages/catchup.jsx:1064 msgid "Let's catch up on the posts from your followings." msgstr "" -#: src/pages/catchup.jsx:967 +#: src/pages/catchup.jsx:1068 msgid "Show me all posts from…" msgstr "" -#: src/pages/catchup.jsx:990 +#: src/pages/catchup.jsx:1091 msgid "until the max" msgstr "until the max" -#: src/pages/catchup.jsx:1020 +#: src/pages/catchup.jsx:1121 msgid "Catch up" msgstr "" -#: src/pages/catchup.jsx:1026 +#: src/pages/catchup.jsx:1127 msgid "Overlaps with your last catch-up" msgstr "" #. placeholder {0}: dtf.format(new Date(lastCatchupEndAt)) -#: src/pages/catchup.jsx:1038 +#: src/pages/catchup.jsx:1139 msgid "Until the last catch-up ({0})" msgstr "" -#: src/pages/catchup.jsx:1047 +#: src/pages/catchup.jsx:1148 msgid "Note: your instance might only show a maximum of 800 posts in the Home timeline regardless of the time range. Could be less or more." msgstr "" -#: src/pages/catchup.jsx:1057 +#: src/pages/catchup.jsx:1158 msgid "Previously…" msgstr "" #. placeholder {0}: pc.count -#: src/pages/catchup.jsx:1075 +#: src/pages/catchup.jsx:1176 msgid "{0, plural, one {# post} other {# posts}}" msgstr "" -#: src/pages/catchup.jsx:1085 +#: src/pages/catchup.jsx:1186 msgid "Remove this catch-up?" msgstr "Remove this catch-up?" #. placeholder {0}: pc.id -#: src/pages/catchup.jsx:1088 +#: src/pages/catchup.jsx:1189 msgid "Removing Catch-up {0}" msgstr "Removing Catch-up {0}" #. placeholder {0}: pc.id -#: src/pages/catchup.jsx:1092 +#: src/pages/catchup.jsx:1193 msgid "Catch-up {0} removed" msgstr "Catch-up {0} removed" -#: src/pages/catchup.jsx:1106 +#: src/pages/catchup.jsx:1207 msgid "Note: Only max 3 will be stored. The rest will be automatically removed." msgstr "" -#: src/pages/catchup.jsx:1121 +#: src/pages/catchup.jsx:1222 msgid "Fetching posts…" msgstr "" -#: src/pages/catchup.jsx:1124 +#: src/pages/catchup.jsx:1225 msgid "This might take a while." msgstr "" -#: src/pages/catchup.jsx:1159 +#: src/pages/catchup.jsx:1260 msgid "Reset filters" msgstr "" -#: src/pages/catchup.jsx:1167 -#: src/pages/catchup.jsx:1610 +#: src/pages/catchup.jsx:1268 +#: src/pages/catchup.jsx:1711 msgid "Top links" msgstr "" #. placeholder {0}: sharers.map((s) => { const { avatarStatic, displayName } = s; return ( ); }) -#: src/pages/catchup.jsx:1280 +#: src/pages/catchup.jsx:1381 msgid "Shared by {0}" msgstr "" -#: src/pages/catchup.jsx:1335 +#: src/pages/catchup.jsx:1436 #: src/pages/mentions.jsx:154 #: src/pages/search.jsx:330 msgid "All" msgstr "" #. placeholder {0}: authorCountsList.length -#: src/pages/catchup.jsx:1420 +#: src/pages/catchup.jsx:1521 msgid "{0, plural, one {# author} other {# authors}}" msgstr "" -#: src/pages/catchup.jsx:1432 +#: src/pages/catchup.jsx:1533 msgid "Sort" msgstr "" -#: src/pages/catchup.jsx:1462 +#: src/pages/catchup.jsx:1563 msgid "Date" msgstr "Date" -#: src/pages/catchup.jsx:1467 +#: src/pages/catchup.jsx:1568 msgid "Density" msgstr "Density" #. js-lingui-explicit-id -#: src/pages/catchup.jsx:1490 +#: src/pages/catchup.jsx:1591 msgid "group.filter" msgstr "Group" -#: src/pages/catchup.jsx:1505 +#: src/pages/catchup.jsx:1606 msgid "Authors" msgstr "Authors" -#: src/pages/catchup.jsx:1506 +#: src/pages/catchup.jsx:1607 msgid "None" msgstr "None" -#: src/pages/catchup.jsx:1522 +#: src/pages/catchup.jsx:1623 msgid "Show all authors" msgstr "" -#: src/pages/catchup.jsx:1573 +#: src/pages/catchup.jsx:1674 msgid "You don't have to read everything." msgstr "You don't have to read everything." -#: src/pages/catchup.jsx:1574 +#: src/pages/catchup.jsx:1675 msgid "That's all." msgstr "That's all." -#: src/pages/catchup.jsx:1582 +#: src/pages/catchup.jsx:1683 msgid "Back to top" msgstr "" -#: src/pages/catchup.jsx:1613 +#: src/pages/catchup.jsx:1714 msgid "Links shared by followings, sorted by shared counts, boosts and likes." msgstr "" -#: src/pages/catchup.jsx:1619 +#: src/pages/catchup.jsx:1720 msgid "Sort: Density" msgstr "" -#: src/pages/catchup.jsx:1622 +#: src/pages/catchup.jsx:1723 msgid "Posts are sorted by information density or depth. Shorter posts are \"lighter\" while longer posts are \"heavier\". Posts with photos are \"heavier\" than posts without photos." msgstr "" -#: src/pages/catchup.jsx:1629 +#: src/pages/catchup.jsx:1730 msgid "Group: Authors" msgstr "" -#: src/pages/catchup.jsx:1632 +#: src/pages/catchup.jsx:1733 msgid "Posts are grouped by authors, sorted by posts count per author." msgstr "" -#: src/pages/catchup.jsx:1679 +#: src/pages/catchup.jsx:1780 msgid "Next author" msgstr "" -#: src/pages/catchup.jsx:1687 +#: src/pages/catchup.jsx:1788 msgid "Previous author" msgstr "" -#: src/pages/catchup.jsx:1703 +#: src/pages/catchup.jsx:1804 msgid "Scroll to top" msgstr "" diff --git a/src/pages/catchup.jsx b/src/pages/catchup.jsx index 6414f1936e..80fc298669 100644 --- a/src/pages/catchup.jsx +++ b/src/pages/catchup.jsx @@ -10,6 +10,7 @@ import { memo } from 'preact/compat'; import { useCallback, useEffect, + useLayoutEffect, useMemo, useReducer, useRef, @@ -43,12 +44,14 @@ import shortenNumber from '../utils/shorten-number'; import showToast from '../utils/show-toast'; import states, { statusKey } from '../utils/states'; import statusPeek from '../utils/status-peek'; +import store from '../utils/store'; import { getCurrentAccountID, getCurrentAccountNS } from '../utils/store-utils'; import supports from '../utils/supports'; import { assignFollowedTags } from '../utils/timeline-utils'; import useTitle from '../utils/useTitle'; const FILTER_CONTEXT = 'home'; +const CATCHUP_NS = 'catchup'; const RANGES = [ { label: msg`last 1 hour`, value: 1 }, @@ -247,6 +250,20 @@ function Catchup() { const [reloadCatchupsCount, reloadCatchups] = useReducer((c) => c + 1, 0); const [lastCatchupEndAt, setLastCatchupEndAt] = useState(null); const [prevCatchups, setPrevCatchups] = useState([]); + + useEffect(() => { + const catchupIds = new Set(prevCatchups.map((pc) => pc.id)); + for (let i = sessionStorage.length - 1; i >= 0; i--) { + const key = sessionStorage.key(i); + if (key?.startsWith(`${CATCHUP_NS}-`)) { + const catchupId = key.replace(`${CATCHUP_NS}-`, ''); + if (!catchupIds.has(catchupId)) { + store.session.del(key); + } + } + } + }, [prevCatchups]); + useEffect(() => { (async () => { try { @@ -430,6 +447,53 @@ function Catchup() { const [sortOrder, setSortOrder] = useState('asc'); const [groupBy, setGroupBy] = useState(null); + useEffect(() => { + if (!id) return; + const savedState = store.session.getJSON(`${CATCHUP_NS}-${id}`); + if (savedState) { + if (savedState.selectedFilterCategory !== undefined) { + setSelectedFilterCategory(savedState.selectedFilterCategory); + } + if (savedState.selectedAuthor !== undefined) { + setSelectedAuthor(savedState.selectedAuthor); + } + if (savedState.sortBy !== undefined) { + setSortBy(savedState.sortBy); + } + if (savedState.sortOrder !== undefined) { + setSortOrder(savedState.sortOrder); + } + if (savedState.groupBy !== undefined) { + setGroupBy(savedState.groupBy); + } + if (savedState.showTopLinks !== undefined) { + setShowTopLinks(savedState.showTopLinks); + } + } + }, [id]); + + useEffect(() => { + if (!id || uiState !== 'results') return; + const state = { + selectedFilterCategory, + selectedAuthor, + sortBy, + sortOrder, + groupBy, + showTopLinks, + }; + store.session.setJSON(`${CATCHUP_NS}-${id}`, state); + }, [ + id, + uiState, + selectedFilterCategory, + selectedAuthor, + sortBy, + sortOrder, + groupBy, + showTopLinks, + ]); + const [filteredPosts, authors, authorCounts] = useMemo(() => { const authorsHash = {}; const authorCountsMap = new Map(); @@ -589,6 +653,43 @@ function Catchup() { const scrollableRef = useRef(null); + useLayoutEffect(() => { + if (!id || uiState !== 'results' || !scrollableRef.current) return; + if (!sortedFilteredPosts.length) return; + + const savedState = store.session.getJSON(`${CATCHUP_NS}-${id}`); + if (savedState?.scrollTop !== undefined && savedState.scrollTop > 0) { + const timeoutId = setTimeout(() => { + if (scrollableRef.current) { + scrollableRef.current.scrollTo({ + top: savedState.scrollTop, + behavior: 'instant', + }); + } + }, 100); + + return () => clearTimeout(timeoutId); + } + }, [id, uiState, sortedFilteredPosts.length]); + + useEffect(() => { + if (!id || uiState !== 'results' || !scrollableRef.current) return; + + const handleScroll = () => { + if (!scrollableRef.current) return; + const savedState = store.session.getJSON(`${CATCHUP_NS}-${id}`) || {}; + savedState.scrollTop = scrollableRef.current.scrollTop; + store.session.setJSON(`${CATCHUP_NS}-${id}`, savedState); + }; + + const scrollElement = scrollableRef.current; + scrollElement.addEventListener('scroll', handleScroll, { passive: true }); + + return () => { + scrollElement.removeEventListener('scroll', handleScroll); + }; + }, [id, uiState]); + // if range value exceeded lastCatchupEndAt, show error const lastCatchupRange = useMemo(() => { // return hour, not ms From d7a53aa5593d2a0b7e0b876670a2198b189b35a2 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Sun, 9 Nov 2025 08:53:01 +0800 Subject: [PATCH 003/100] Update changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e1d2761ef..943578127d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -369,6 +369,14 @@ Recap: Mastodon v4.3 features (https://github.com/mastodon/mastodon/releases/tag - 💬 More support for (upcoming) Mastodon v4.5's native quote posts - 🐛 Bug fixes +## November 8, 2025 + +- 🗣️ Reply/Reply all +- ⌨️ Sequential hotkeys, only g>h and g>n for now +- 💈 Decal patterns for posting stats +- 💬 Slightly more support for Mastodon v4.5's native quote posts +- 🐛 Bug fixes +