Merge pull request #864 from bitsocialhq/development

Development
This commit is contained in:
Tom
2026-01-22 17:32:22 +01:00
committed by GitHub
12 changed files with 400 additions and 16 deletions
+165
View File
@@ -1,3 +1,168 @@
# [0.6.0](https://github.com/plebbit/plebchan/compare/v0.5.3...v0.6.0) (2026-01-22)
### Bug Fixes
* align asset-manifest generator output with prettier config ([4fd9a9c](https://github.com/plebbit/plebchan/commit/4fd9a9c1a98838dd9bbd05240905564fb6b6c85e))
* **android:** capacitor config was pointing to build instead of dist (legacy from CRA) ([436988e](https://github.com/plebbit/plebchan/commit/436988ee26f83c3c32c82a1a436006facec302de))
* **board buttons:** guard against undefined address ([2a521ad](https://github.com/plebbit/plebchan/commit/2a521ad8f82160b83f2d400c5a75f41bcb61f6d1))
* **board header:** limit clickable area of subscriptions counter to text only ([4f49ec6](https://github.com/plebbit/plebchan/commit/4f49ec666626b7711d9166fdb9933b83b2bec186))
* **boards-list:** hide Multiboards section when filtering for worksafe boards ([594be88](https://github.com/plebbit/plebchan/commit/594be882101cf849e172b90c0944b98a3629bad2))
* **board:** subscribe to transient state and error fields separately ([4c4e120](https://github.com/plebbit/plebchan/commit/4c4e1209aaa0b78f4ae8b3c0497a1d2c38e219fa))
* **catalog-row:** expand CatalogPost memo comparator to prevent stale renders ([d71d518](https://github.com/plebbit/plebchan/commit/d71d518e271840f1603a1d5e578cbece086855df))
* **challenge modal:** show board name in iframe confirmation message ([5963123](https://github.com/plebbit/plebchan/commit/596312357f51bfeefe745fd782c129fbc275a938))
* **challenge-modal:** improve mobile iframe challenge modal positioning and sizing ([76e0732](https://github.com/plebbit/plebchan/commit/76e073228f43568b3fd1f80b7d476d8e0d1e9fdf))
* **ci:** fix test workflow failures on all platforms ([26278f9](https://github.com/plebbit/plebchan/commit/26278f92c6fc83ec43bf256592c69ef14c233b77))
* **ci:** mac smoke tests can't use timeout command ([724b623](https://github.com/plebbit/plebchan/commit/724b62344b5f318366c001704296ffddb4a9fe63))
* **ci:** macOS test builds fail with hdiutil "Resource busy" error ([46f0f49](https://github.com/plebbit/plebchan/commit/46f0f494e99a5fe113f0e27f46e97dcc0be6a2eb))
* **ci:** remove redundant electron-rebuild from build scripts ([96a3068](https://github.com/plebbit/plebchan/commit/96a306892868993f000af9c1f8928acbd928e3b3))
* **ci:** update deprecated intel mac runner ([2d23f44](https://github.com/plebbit/plebchan/commit/2d23f44bd80df5db75677b829c3484878d7f8d7c))
* **comment-content:** ensure parent comment number is populated for nested replies ([c2bbe2d](https://github.com/plebbit/plebchan/commit/c2bbe2dd0b95d7e4b1fb1e3b988df0039d5e1684))
* **comment-content:** use correct banExpiresAt path for ban visibility ([476681c](https://github.com/plebbit/plebchan/commit/476681c689edba6fe0dbc052c9908649188cca60))
* correct horizontal centering of create board modal ([e863ddb](https://github.com/plebbit/plebchan/commit/e863ddb8b901191e7b5bb4f9527b0af994895a42))
* **deps:** add missing env-paths and progress dependencies ([a75eef7](https://github.com/plebbit/plebchan/commit/a75eef74959759d1c5a52ed31657d77bc58c91db))
* **deps:** resolve build dependency conflicts for Vercel deployment ([341fae9](https://github.com/plebbit/plebchan/commit/341fae91fc049c6cf518aaee2338e1eac52cb030))
* **deps:** resolve dependabot security alerts via yarn resolutions ([b93890b](https://github.com/plebbit/plebchan/commit/b93890b3bcf02a875a5e00f3f44ffeeb1f963987))
* **deps:** upgrade React to 19.1.2 to patch CVE-2025-55182 ([8e1bfa2](https://github.com/plebbit/plebchan/commit/8e1bfa2554fd9704a5f61148d1c8e8966ca82d85))
* **deps:** upgrade sharp to 0.34.5 to address security vulnerabilities ([8340953](https://github.com/plebbit/plebchan/commit/834095320375a4fe1d2596052c352f46356083ea))
* **directory-modal:** move to global layout and close on navigation ([ace4b0c](https://github.com/plebbit/plebchan/commit/ace4b0c8db0ee3dcc9e435a2988134932bfd325b))
* **disclaimer-modal:** correct CSS positioning and remove invalid HTML ([3aaa28f](https://github.com/plebbit/plebchan/commit/3aaa28f7430aeaf0158980765590f870cfaa376d))
* **disclaimer-modal:** update copy to reference "Accept" button ([7e1fe00](https://github.com/plebbit/plebchan/commit/7e1fe00dbf645fdb012b50bca0013bd0004065c9))
* **edit-menu:** use correct banExpiresAt path in commentModeration.author ([a959f14](https://github.com/plebbit/plebchan/commit/a959f14290f7262483ab3058dd2d3431be1b682e))
* **electron:** force GTK 3 on Linux to avoid GTK 2/3 vs GTK 4 crash ([547fc4d](https://github.com/plebbit/plebchan/commit/547fc4df814a22026d7bb9b614e2d4bcb3acb1df))
* **electron:** upgrade cacache for Node.js 22 compatibility ([ec2fb14](https://github.com/plebbit/plebchan/commit/ec2fb14cad9470898c9637fc1d83f70c753604e8))
* **error-display:** add delay to prevent false positive error displays ([341e72a](https://github.com/plebbit/plebchan/commit/341e72ad5b5a03152273c0060363579cbffc8cd3))
* **hooks:** fix usePopularPosts loading state and change detection ([a7614db](https://github.com/plebbit/plebchan/commit/a7614db743c3eff052b48a1401f427b38dbd03d2))
* **hooks:** remove postCid requirement from isAccountCommentAuthor check ([6175744](https://github.com/plebbit/plebchan/commit/6175744e7b4f9f56e562265751ac3bf5bcad6f2b))
* **hooks:** use structural equality for roles comparison in useStableSubplebbit ([647139c](https://github.com/plebbit/plebchan/commit/647139c0ec4a23f21fb4d7830285cc5123f9202a))
* limit vite-plugin-eslint to src/ files only ([f65635b](https://github.com/plebbit/plebchan/commit/f65635b549a7c73f31b52c7f5656fc20b6f02a1c))
* **lint:** use correct oxlint rule names and enable react plugin in config ([9fd41f2](https://github.com/plebbit/plebchan/commit/9fd41f2f9f8099fd23d2341371d6168b204c97fe))
* **markdown:** embedded media in comment.content shouldn't be expandable and should be already expanded ([fcd8838](https://github.com/plebbit/plebchan/commit/fcd8838045a8ba66852b2f69904f939d3a8c6153))
* **media-utils:** ignore blacklisted thumbnails ([f01a1dc](https://github.com/plebbit/plebchan/commit/f01a1dcaa96e2e009a310c2055c92eb49910bb68))
* memory leak in ModQueueButtonContent statusMap ([056096a](https://github.com/plebbit/plebchan/commit/056096aacecd64f79c57bbfc35ad381dec0aea7d))
* **mod queue:** adjust styling ([4fd0820](https://github.com/plebbit/plebchan/commit/4fd0820d94041bc625427cd1bdbaf4185dba3738))
* **mod queue:** alert threshold returns NaN when migrating from old localStorage format ([4a9f468](https://github.com/plebbit/plebchan/commit/4a9f4685cbedba4819404e4262cf2d00a08b077b))
* **mod queue:** button counter doesn't update when navigating between boards ([ca53fb4](https://github.com/plebbit/plebchan/commit/ca53fb4728f64a6847ebf34456a0d63e5b76e657))
* **mod queue:** CSS Modules not exporting rowOdd and alert classes ([6827aaa](https://github.com/plebbit/plebchan/commit/6827aaa141a22890932ac700ec66a954bb7b3ad7))
* **mod queue:** items shouldn't disappear from feed unless api removes them ([99596d3](https://github.com/plebbit/plebchan/commit/99596d3a54a81fd3439731951854681d2991df25))
* **mod queue:** ModQueueButton shows incomplete pending count without postsPerPage ([823731c](https://github.com/plebbit/plebchan/commit/823731cb2d38e811c0975b41934f1e386d9fb4be))
* **mod queue:** show mod queue button in /mod/ multiboard view ([6f9e3b2](https://github.com/plebbit/plebchan/commit/6f9e3b2330f506976cd9143c7261a744768daf91))
* **mod-queue:** alert animation and counter only for pending items ([a23f5bc](https://github.com/plebbit/plebchan/commit/a23f5bc2388f3ceae6d9bdbe9b7f24247c094d4b))
* **mod-queue:** button counter includes already approved/rejected items ([02fc6a3](https://github.com/plebbit/plebchan/commit/02fc6a3171517e06012138ad9f3ac6aa620d69dc))
* **mod-queue:** close CSS breakpoint gap and remove duplicate time-ago rendering ([ab98bd0](https://github.com/plebbit/plebchan/commit/ab98bd0a87f92af5ba70b88a360fd1132e0668bb))
* **mod-queue:** style action buttons to match board buttons and make status indicators bold/colored ([fbdfadc](https://github.com/plebbit/plebchan/commit/fbdfadc65cd0ad24eff28552570ef91fa89fcddf))
* **mod-queue:** use link as excerpt when post has no title/content and prevent empty strings ([410fd54](https://github.com/plebbit/plebchan/commit/410fd541b33655d2668f85c25d52a1392703e3d5))
* **p2p-options:** correct Solana chainId from 1 to 101 ([52fea38](https://github.com/plebbit/plebchan/commit/52fea3851e0fe3bccadd8cae8b02e2204c45e397))
* **package.json:** missing license field ([696f19f](https://github.com/plebbit/plebchan/commit/696f19fcc0758ca00ad911f4eac8c2aba7aa1ada))
* **package.json:** unpin dependencies, fix script conflict ([f896c7d](https://github.com/plebbit/plebchan/commit/f896c7d96ac7d684bab0e57d77d3dfa762f71360))
* **popular-threads:** update memo comparator to include multisub entry titles ([f5cf263](https://github.com/plebbit/plebchan/commit/f5cf2634817ae26c73bdc3bfa18ec9b1a3fb5486))
* **post form:** fix positioning and styling on mobile ([e84038f](https://github.com/plebbit/plebchan/commit/e84038f185cfeb5c461bd32104c11a17a82822bc))
* **post-menu:** add copy link and hide block board for /all description ([1b22711](https://github.com/plebbit/plebchan/commit/1b227117767bc7d71f1cebf7d9d2e1359f788b49))
* **post-menu:** await clipboard copy before closing menu ([6f1fcaf](https://github.com/plebbit/plebchan/commit/6f1fcafc2c795cd4a2a48dbc42a137d58048fe3b))
* **post:** don't render empty avatar space when image url is invalid ([e1f1f28](https://github.com/plebbit/plebchan/commit/e1f1f280cc9a71e36406740314040c2db94d50bb))
* **post:** OP thumbnail overlaps with replies when image has unusual dimensions ([5e1114e](https://github.com/plebbit/plebchan/commit/5e1114e08715f9729c17a7e2a189838c68e50134))
* **post:** redirect to 404 when thread URL specifies wrong board ([6724f91](https://github.com/plebbit/plebchan/commit/6724f91c795cb8e1d3c4e63861464712fcebc12a))
* prevent memory leak from unbounded setInterval in use-time-filter ([eedb0fa](https://github.com/plebbit/plebchan/commit/eedb0fa08eb71c98d51e1068e79df8a4a2f48f9a))
* prevent race conditions and memory leaks in useCommentMediaInfo hook ([fc48021](https://github.com/plebbit/plebchan/commit/fc4802186d06ed24b7410cc49c022da06a2afc80))
* remove duplicate .filterModal .separator CSS rule ([8de4fba](https://github.com/plebbit/plebchan/commit/8de4fba9ed92e9dcd2b506bef898f35e3129e507))
* remove unused variables from catalog and post views ([760e8d9](https://github.com/plebbit/plebchan/commit/760e8d900ef0a9dc91dae31949aba555c9624d9c))
* rename invalid identifiers starting with digit to fivechan ([3360a41](https://github.com/plebbit/plebchan/commit/3360a41b00bea9a1ae3dd2b837faf1df0777ae03))
* **replies:** reply permalink didn't auto-scroll to deep replies ([b8e3a02](https://github.com/plebbit/plebchan/commit/b8e3a0202ae360fc210badaf00c56174a5606b83))
* reset board scroll on link nav ([9e13292](https://github.com/plebbit/plebchan/commit/9e13292ae3f137fc1352379d2f4939414953140c))
* resolve typescript errors in post menu components ([0b573ac](https://github.com/plebbit/plebchan/commit/0b573acf1db1fe3d2bcc65e54e23549c73af81aa))
* resolve TypeScript overload error in CopyLinkButton ([55dc396](https://github.com/plebbit/plebchan/commit/55dc3961202514067d477bfeae95590ea77be3b9))
* **routes:** prevent malformed routes and fix cache invalidation ([93859ec](https://github.com/plebbit/plebchan/commit/93859ec2f140be3af85856b3625125034b2fc27c))
* **routing:** handle empty boardPath and resolve directory codes ([b886cbd](https://github.com/plebbit/plebchan/commit/b886cbdf3b8fe3a4564eb0455442c2439d36bb50))
* **security:** upgrade dependencies to address dependabot alerts ([a25d4bf](https://github.com/plebbit/plebchan/commit/a25d4bfa9968f7b5356933d2a7654126ed223ef9))
* **settings:** resolve theme persistence bug after hard refresh ([26d014b](https://github.com/plebbit/plebchan/commit/26d014b6964cc1bc5b86e4d057025ac2913ab4d0))
* show cached feed time filter in UI ([198b613](https://github.com/plebbit/plebchan/commit/198b6135da410a6b6296140d6b9aa4860fe34915))
* **subplebbit-stats:** revert broken useStableSubplebbitStats hook ([64ef0dd](https://github.com/plebbit/plebchan/commit/64ef0ddccf6def43abd123b33cb4c2c7b8af9eb2))
* synchronize blinking animation in moderation queue ([5f4856a](https://github.com/plebbit/plebchan/commit/5f4856ad3c7e49fc4923d1cb25aca4cf3c50a37c))
* **theme:** prevent theme flash on board load ([b1ebf0b](https://github.com/plebbit/plebchan/commit/b1ebf0b4ae4e4e9361f3a3603f9d40fece2d6ef6))
* **themes:** all and subscriptions multiboards should use yotsuba ([9cc7869](https://github.com/plebbit/plebchan/commit/9cc78694d8ac4ff12a4743de08b85fb6ff8c2eec))
* **topbar edit modal:** show subscription addresses instead of directory codes ([43956d4](https://github.com/plebbit/plebchan/commit/43956d44a172046ed0f3e60162c6564090b9590e))
* **topbar-edit-modal:** memoize subscriptions array ([f997365](https://github.com/plebbit/plebchan/commit/f99736581340362133644fc46c31fa049ba8ff39))
* **topbar:** correct mobile topbar select values for directory boards ([723ad9f](https://github.com/plebbit/plebchan/commit/723ad9fb58b6eaa19f03b48f9e1dd80303b670d3))
* **topbar:** didn't update when subscribing to a board ([e77dd53](https://github.com/plebbit/plebchan/commit/e77dd53e0ef6c123247af5ba0b7365f25533f661))
* **translations:** move purge keys to end of EN locale file ([db413ba](https://github.com/plebbit/plebchan/commit/db413baa1df773c9c3ca928c784e9c28052814fa))
* update Plebbit.getShortAddress calls to use object parameter ([4cb3bda](https://github.com/plebbit/plebchan/commit/4cb3bda38c2f46029b87c2f9a6d65a8b4f9c8d63))
* update Plebbit.getShortCid calls to use object parameter format ([a57cc1e](https://github.com/plebbit/plebchan/commit/a57cc1e4e70bd3fb96f6b94735d4749c0f074257))
* use stable time filter for virtuoso state key in cached feeds ([1a6ac4a](https://github.com/plebbit/plebchan/commit/1a6ac4a2bec7423c9e8ab43561d8b6402b839c70))
* **use-default-subplebbits:** prevent state updates after unmount ([e548198](https://github.com/plebbit/plebchan/commit/e548198d0e5369779ae628186c83dcf8e83a5318))
* validate thread share link cid ([23f2451](https://github.com/plebbit/plebchan/commit/23f245145ccbfb7d692bceddc69fdeacf76e3a66))
* **views:** display useSubplebbit and useComment errors in board, post, and mod-queue views ([122b177](https://github.com/plebbit/plebchan/commit/122b17790a67389f60d7b171aedf20a7223adc43))
* **views:** use directory codes in document titles and fix order ([5aa1eaf](https://github.com/plebbit/plebchan/commit/5aa1eaf13af842ebd78b4b7cfdbe8e563fc1e700))
### Features
* add iframe challenges (e.g. mintpass) ([a7dc46f](https://github.com/plebbit/plebchan/commit/a7dc46fe2e768a1b872304d9b9233dcca343fb29))
* add infinite scroll for replies ([882b7b4](https://github.com/plebbit/plebchan/commit/882b7b4a99627e4c0e85d8ab619ac3891f6c74c9))
* add Multiboards category with /subs/ and /all/ ([12101fe](https://github.com/plebbit/plebchan/commit/12101fe75ec81c43413dfe6677cbc7b46b87950b))
* add redirect for non-hash URLs to support HashRouter ([dba736e](https://github.com/plebbit/plebchan/commit/dba736efb486a4a2b992f7233afbc9bf82d2ee5f))
* add script to automate translations ([d82bb58](https://github.com/plebbit/plebchan/commit/d82bb58c3eebed3db6b115cdd21abbcb2a75adff))
* **all-feed:** add NSFW/SFW filter ([6523855](https://github.com/plebbit/plebchan/commit/652385561bdbc52fe6956be8da6ccc338a498687))
* **board buttons:** add vote button to mobile ([d30db40](https://github.com/plebbit/plebchan/commit/d30db401591460d3509ef78a69251d6afc1e7d9d))
* **board header:** add banners, add support to gif banners ([07831cb](https://github.com/plebbit/plebchan/commit/07831cb8b026c230841d7c70d62078c35aa7e84c))
* **board header:** make subscriptions subtitle clickable to go to subs settings ([cc28224](https://github.com/plebbit/plebchan/commit/cc28224c91bb0716dc41165cff44b806ef4ba4f8))
* **board-buttons:** add directory-specific vote button ([af14686](https://github.com/plebbit/plebchan/commit/af1468669c7db81c2a28bf37f2da6fb454730784))
* **board-header:** prioritize default subplebbit title over store title ([f44b9ae](https://github.com/plebbit/plebchan/commit/f44b9aefbb926ece4b432606a7f9f6ed1d9bcf39))
* **board-header:** show subscription count in subscriptions view ([1675ab7](https://github.com/plebbit/plebchan/commit/1675ab7d407889750cdab2a77cb4d49b3c73e1cb))
* **board:** add more_threads_last_year suggestion ([e3e2599](https://github.com/plebbit/plebchan/commit/e3e25995d6c38ba5f98128824d1c4fbc86cbcf9b))
* **boards-list:** mark Flash, Oekaki, Artwork/Critique, Wallpapers/General as NSFW ([36bd9c5](https://github.com/plebbit/plebchan/commit/36bd9c5c0f6044655ae99f9fa34b34615af2f644))
* **create-board-modal:** add focus styles for close button ([eb3d672](https://github.com/plebbit/plebchan/commit/eb3d6729452a7a6f391fa4695ef750e36828c872))
* **crypto wallets settings:** add timestamp field ([e2149ca](https://github.com/plebbit/plebchan/commit/e2149ca02caf729f6d01d328105f435122b8649f))
* **crypto-wallets-setting:** add CSS-based step numbering and reorganize delete button ([dbf67f5](https://github.com/plebbit/plebchan/commit/dbf67f55b649fcfc6f6c0dc0579b7273e9219beb))
* **directory-modal:** add modal explaining how to submit boards to directories ([e627b6b](https://github.com/plebbit/plebchan/commit/e627b6b619676fa877424bf53da971a99815ebab))
* **footer:** add feedback and contact links and update styling ([0d48838](https://github.com/plebbit/plebchan/commit/0d488389a5d4734bf47713e9ba08b70d7b7707c7))
* **home:** add disclaimer modal for board navigation ([2a25d73](https://github.com/plebbit/plebchan/commit/2a25d7353c37fe73bef9b66c3f4e1bdaa8deb505))
* **home:** redesign boards list to match 4chan with filtering and catalog support ([a9690ac](https://github.com/plebbit/plebchan/commit/a9690ac0befba357c41595c05900efe1aa5a337e))
* **i18n:** add translations for subscriptions subtitle ([bb596bf](https://github.com/plebbit/plebchan/commit/bb596bff0db280cbcac0363e0b16f813ab556b5a))
* implement 5chan-specific default board list ([bae6faa](https://github.com/plebbit/plebchan/commit/bae6faa9291a4633b6da0b3aa0e6ced3e46a6d20))
* implement mod queue ([70ba145](https://github.com/plebbit/plebchan/commit/70ba14591ab1d5b541727e5d4391315d260af933))
* implement post numbers ([7684541](https://github.com/plebbit/plebchan/commit/76845412e8b34c11fb70bf993a0aeaeda54a3ee4))
* **mod-queue:** add minutes support to alert threshold ([ab353b5](https://github.com/plebbit/plebchan/commit/ab353b59f62e94edd76e97e5c18cab1f3cfb2115))
* **mod-queue:** add number column, improve time display, and use edited comments ([a33b2e5](https://github.com/plebbit/plebchan/commit/a33b2e5a9aa04d3ae5daf418b51b13ce6d23d579))
* **modals:** use icon-close-red.png for close buttons on home view ([21d9c0c](https://github.com/plebbit/plebchan/commit/21d9c0c6163dcd3947d26bcf3bdc5e5d0aae52dc))
* **moderation:** add purge action to edit menu ([1abc841](https://github.com/plebbit/plebchan/commit/1abc8410cd09e8d1b79df6809a9fea0241a3ae4c))
* **p2p options:** add http routers field ([3d67606](https://github.com/plebbit/plebchan/commit/3d676062af3ed54942a5f92b0958ce3501616c8b))
* **post-form:** display directory names in board selector ([fc79eb6](https://github.com/plebbit/plebchan/commit/fc79eb68d2f9400175eece2c7a468ae765126b7f))
* **post-menu:** add copy content ID button ([a1de352](https://github.com/plebbit/plebchan/commit/a1de352da0c58c992199e569746ed2424dcdad8f))
* **post:** add moderator and administrator role indicators ([5de2587](https://github.com/plebbit/plebchan/commit/5de2587cf4dbec906acd7a5b2b2332cc7ef04276))
* **post:** add pending approval label ([4023131](https://github.com/plebbit/plebchan/commit/402313107c1ee81b1282fec2f2aabefe49c1db6b))
* rename plebchan to 5chan ([1360dd8](https://github.com/plebbit/plebchan/commit/1360dd8348d309f041b3ad78e3e6789f5da243fc))
* **reply modal:** add alert when attempting multiple quotes ([c0a1b67](https://github.com/plebbit/plebchan/commit/c0a1b671c85c2fb9e8035f56a686c71f4c93ec43))
* **routing:** add hooks and utilities for directory-based board routing ([f485656](https://github.com/plebbit/plebchan/commit/f4856563df136ca84e180483d132d1005c91abc3))
* **rules:** add rules page with board selector ([d800ee9](https://github.com/plebbit/plebchan/commit/d800ee9817a465842870ad94983be336f18e9e3e))
* **share-link:** add description and rules link types ([41ffd2f](https://github.com/plebbit/plebchan/commit/41ffd2f65b7561ebdd6f1663fde0c5ecf97d1121))
* **topbar:** add customizable visibility controls for directories and subscriptions ([669bb5b](https://github.com/plebbit/plebchan/commit/669bb5b1815b403a4343eb507429ebfb159c44e2))
* **topbar:** add temporary show-all button for hidden directories ([5792fcd](https://github.com/plebbit/plebchan/commit/5792fcd31eca9c1e07eebcbae37de1ee67d1d0d8))
* **ui:** add context-aware directory modal with different content for placeholder vs create board ([5f06fdf](https://github.com/plebbit/plebchan/commit/5f06fdf461788453c02293c9b9b6457f5f52c786))
* **update-translations.js:** remove unused translations, add translation cleanup audit with dynamic key safety ([96c5dff](https://github.com/plebbit/plebchan/commit/96c5dff794bc32d14f4524bf3274afc8fba41201))
* **url-utils:** replace p/ syntax with >>> cross-board references ([c984e56](https://github.com/plebbit/plebchan/commit/c984e562495e58b30ec1971a14ae637ea4d4d6f8))
### Performance Improvements
* **components:** memoize post menus with minimal props ([698df59](https://github.com/plebbit/plebchan/commit/698df59f197eefc4f5da63fa4f98b6d7a7714ea9))
* **components:** prevent rerenders from updatingState ([fa32833](https://github.com/plebbit/plebchan/commit/fa32833b2a03b299196218e60c35911072f9ae80))
* eliminate redundant derived state in board and post views ([b10ada5](https://github.com/plebbit/plebchan/commit/b10ada55e7c7603a9d1680ee4240e120655e0798))
* **feeds:** use hasMore instead of length check for conditional virtualization ([c0c6e9e](https://github.com/plebbit/plebchan/commit/c0c6e9ee315e983cbe38491d7b40a231edd44e07))
* Fix unnecessary renders in useCurrentTime hook and ModQueueView footer ([404b613](https://github.com/plebbit/plebchan/commit/404b613b44c7a71511c08704dcec0a545234bfa1))
* **hooks:** document stable reference optimization in useDefaultSubplebbits ([e7e2a2f](https://github.com/plebbit/plebchan/commit/e7e2a2fda70230ea02d6ac6e184c8bc9ffb48373))
* implement LRU-cached persistent feed mounting to eliminate Virtuoso flash ([896ca4a](https://github.com/plebbit/plebchan/commit/896ca4ad13072f38fbb1e81e9f2147ed99cbe009))
* isolate IPFS state updates in board and catalog views to prevent excessive re-renders ([eb8e226](https://github.com/plebbit/plebchan/commit/eb8e226ff151e4c716297e81e0358e840195f5c9))
* migrate from vite to rolldown-vite for faster builds ([10a266c](https://github.com/plebbit/plebchan/commit/10a266ceaba05ee33bb10be573167a37b7637101))
* **mod queue:** conditionally virtualize table for large feeds ([951a8ff](https://github.com/plebbit/plebchan/commit/951a8ffd84223fd5ace0b71d196d55d8cb2522d3))
* **mod queue:** prevent re-renders from IPFS client state changes ([33943c3](https://github.com/plebbit/plebchan/commit/33943c3de9e53d444cb24d519b03d2c204c5e2f6))
* **mod queue:** skip animation sync when no items need blinking ([4900410](https://github.com/plebbit/plebchan/commit/49004109f8ab5f93d228687dd103e47b612e5574))
* only virtualize replies when count exceeds first page size ([2b8d6f4](https://github.com/plebbit/plebchan/commit/2b8d6f4fceea040daa6865fbab77cb2dcaa85671))
* pre-optimize workbox dependencies to prevent dev server reload ([ac19034](https://github.com/plebbit/plebchan/commit/ac19034ac4f94e015716938358d94482fa2b599a))
* preload theme button and background images on app startup ([d46d7ed](https://github.com/plebbit/plebchan/commit/d46d7edffe89e51d6972a9d8a82834b89140328f))
* prevent unnecessary re-renders from RPC client state changes ([3799dcc](https://github.com/plebbit/plebchan/commit/3799dccd88285cdee8c3bc9417f262c4aa1f53fb))
## [0.5.3](https://github.com/plebbit/plebchan/compare/v0.5.2...v0.5.3) (2025-07-29)
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "5chan",
"version": "0.5.3",
"version": "0.6.0",
"description": "A bitsocial client with a 4chan UI",
"type": "module",
"author": "Bitsocial Labs",
@@ -17,6 +17,7 @@
"@types/react": "18.2.25",
"@types/react-dom": "18.2.10",
"@use-gesture/react": "10.3.1",
"@vercel/analytics": "^1.6.1",
"cross-env": "7.0.3",
"electron-context-menu": "3.3.0",
"electron-is-dev": "2.0.0",
+1 -1
View File
@@ -17,7 +17,7 @@ let releaseChangelog =
// format
releaseChangelog = releaseChangelog.trim().replace(/\n\n+/g, '\n\n')
const releaseBody = `This version fixes a bug that prevented publishing.
const releaseBody = `This version rebrands the app to 5chan, introducing a set of new features and several performance improvements.
- Web app: https://5chan.app
- Decentralized web app: https://5chan.eth (only works on [Brave Browser](https://brave.com/) or via [IPFS Companion](https://docs.ipfs.tech/install/ipfs-companion/#prerequisites))
@@ -1,7 +1,7 @@
import { Fragment, useState } from 'react';
import { useLocation, useParams } from 'react-router-dom';
import { Trans, useTranslation } from 'react-i18next';
import { Comment } from '@plebbit/plebbit-react-hooks';
import { Comment, useComment } from '@plebbit/plebbit-react-hooks';
import useSubplebbitsPagesStore from '@plebbit/plebbit-react-hooks/dist/stores/subplebbits-pages';
import Plebbit from '@plebbit/plebbit-js';
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
@@ -35,7 +35,10 @@ const CommentContent = ({ comment: post }: { comment: Comment }) => {
? content.slice(0, 2000)
: content);
const quotelinkReply = useSubplebbitsPagesStore((state) => state.comments[parentCid]);
const quotelinkReplyFromStore = useSubplebbitsPagesStore((state) => state.comments[parentCid]);
const quotelinkReplyFromHook = useComment({ commentCid: parentCid, onlyIfCached: true });
// Prefer hook version to ensure 'number' property is populated for deeper nested replies in Virtuoso
const quotelinkReply = quotelinkReplyFromHook?.number !== undefined ? quotelinkReplyFromHook : quotelinkReplyFromStore;
const isReply = !!parentCid;
const isReplyingToReply = isReply && parentCid !== postCid;
+19 -3
View File
@@ -19,6 +19,7 @@ import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
import useHide from '../../hooks/use-hide';
import useStateString from '../../hooks/use-state-string';
import useScrollToReply from '../../hooks/use-scroll-to-reply';
import CommentContent from '../comment-content';
import CommentMedia from '../comment-media';
import EditMenu from '../edit-menu/edit-menu';
@@ -187,7 +188,7 @@ const PostInfo = ({ post, postReplyCount = 0, roles, isHidden, threadNumber }: P
</span>
) : (
<>
<span>CID:</span>
<span>No.</span>
<span className={styles.pendingCid}>
{state === 'failed' || stateString === 'Failed' ? _.capitalize(t('failed')) : state === 'pending' ? _.capitalize(t('pending')) : ''}
</span>
@@ -375,7 +376,7 @@ const Reply = ({ postReplyCount, reply, roles, threadNumber }: PostProps) => {
);
};
const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostProps) => {
const PostDesktop = ({ post, roles, showAllReplies, showReplies = true, targetReplyCid }: PostProps) => {
const { t } = useTranslation();
const { author, cid, content, deleted, link, linkHeight, linkWidth, pinned, postCid, removed, spoiler, state, subplebbitAddress, thumbnailUrl, parentCid } = post || {};
const params = useParams();
@@ -429,6 +430,16 @@ const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostPr
const lastVirtuosoState = navigationType === 'POP' ? lastVirtuosoStates?.[virtuosoStateKey] : undefined;
const shouldScrollToReply = showAllReplies && showReplies && !isInPendingPostView && !!targetReplyCid;
useScrollToReply({
targetReplyCid,
replies: filteredReplies,
hasMore,
loadMore,
virtuosoRef,
enabled: shouldScrollToReply,
});
// Footer component for Virtuoso showing loading state
const RepliesFooter = () =>
hasMore ? (
@@ -452,7 +463,12 @@ const PostDesktop = ({ post, roles, showAllReplies, showReplies = true }: PostPr
<span className={`${styles.hideButton} ${hidden ? styles.unhideThread : styles.hideThread}`} onClick={hidden ? unhide : hide} />
</span>
)}
<div data-cid={cid} data-author-address={author?.shortAddress} data-post-cid={postCid} className={shouldShowSnow() && hasThumbnail ? styles.xmasHatWrapper : ''}>
<div
data-cid={cid}
data-author-address={author?.shortAddress}
data-post-cid={postCid}
className={`${styles.opContainer} ${shouldShowSnow() && hasThumbnail ? styles.xmasHatWrapper : ''}`}
>
{shouldShowSnow() && hasThumbnail && <img src='assets/xmashat.gif' className={styles.xmasHat} alt='' />}
{link && !isHidden && !(deleted || removed) && isValidURL(link) && (
<PostMedia
+13 -2
View File
@@ -18,6 +18,7 @@ import { useCommentMediaInfo } from '../../hooks/use-comment-media-info';
import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
import useHide from '../../hooks/use-hide';
import useStateString from '../../hooks/use-state-string';
import useScrollToReply from '../../hooks/use-scroll-to-reply';
import CommentContent from '../comment-content';
import CommentMedia from '../comment-media';
import LoadingEllipsis from '../loading-ellipsis';
@@ -192,7 +193,7 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: Pos
</span>
) : (
<>
<span>CID:</span>
<span>No.</span>
<span className={styles.pendingCid}>
{state === 'failed' || stateString === 'Failed' ? _.capitalize(t('failed')) : state === 'pending' ? _.capitalize(t('pending')) : ''}
</span>
@@ -282,7 +283,7 @@ const Reply = ({ postReplyCount, reply, roles, threadNumber }: PostProps) => {
);
};
const PostMobile = ({ post, roles, showAllReplies, showReplies = true }: PostProps) => {
const PostMobile = ({ post, roles, showAllReplies, showReplies = true, targetReplyCid }: PostProps) => {
const { t } = useTranslation();
const { author, cid, pinned, postCid, replyCount, state, subplebbitAddress } = post || {};
const params = useParams();
@@ -324,6 +325,16 @@ const PostMobile = ({ post, roles, showAllReplies, showReplies = true }: PostPro
const lastVirtuosoState = navigationType === 'POP' ? lastVirtuosoStates?.[virtuosoStateKey] : undefined;
const shouldScrollToReply = showAllReplies && showReplies && !isInPendingPostView && !!targetReplyCid;
useScrollToReply({
targetReplyCid,
replies: filteredReplies,
hasMore,
loadMore,
virtuosoRef,
enabled: shouldScrollToReply,
});
// Footer component for Virtuoso showing loading state
const RepliesFooter = () =>
hasMore ? (
+165
View File
@@ -0,0 +1,165 @@
import { useEffect, useRef } from 'react';
import { VirtuosoHandle } from 'react-virtuoso';
type ReplyItem = {
cid?: string | null;
};
interface UseScrollToReplyParams {
targetReplyCid?: string;
replies: ReplyItem[];
hasMore: boolean;
loadMore: () => void;
virtuosoRef: React.RefObject<VirtuosoHandle | null>;
enabled?: boolean;
}
const DEFAULT_MAX_LOAD_ATTEMPTS = 500;
const MAX_LOAD_DURATION_MS = 120000;
const LOAD_MORE_THROTTLE_MS = 300;
const AUTO_SCROLL_INTERVAL_MS = 350;
const useScrollToReply = ({ targetReplyCid, replies, hasMore, loadMore, virtuosoRef, enabled = true }: UseScrollToReplyParams) => {
const hasScrolledRef = useRef(false);
const loadAttemptsRef = useRef(0);
const lastRepliesLengthRef = useRef(replies.length);
const loadMoreTimeoutRef = useRef<number | null>(null);
const lastLoadAtRef = useRef(0);
const loadStartAtRef = useRef(0);
const lastScrollIndexRef = useRef(-1);
const intervalRef = useRef<number | null>(null);
const latestTargetRef = useRef(targetReplyCid);
const latestRepliesRef = useRef(replies);
const latestHasMoreRef = useRef(hasMore);
const latestLoadMoreRef = useRef(loadMore);
// Only reset when the target changes, NOT when replies.length changes
// (replies.length changing is expected as we load more pages)
useEffect(() => {
hasScrolledRef.current = false;
loadAttemptsRef.current = 0;
lastRepliesLengthRef.current = replies.length;
lastLoadAtRef.current = 0;
loadStartAtRef.current = Date.now();
lastScrollIndexRef.current = -1;
if (intervalRef.current) {
window.clearInterval(intervalRef.current);
intervalRef.current = null;
}
if (loadMoreTimeoutRef.current) {
window.clearTimeout(loadMoreTimeoutRef.current);
loadMoreTimeoutRef.current = null;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [targetReplyCid]);
useEffect(() => {
latestTargetRef.current = targetReplyCid;
}, [targetReplyCid]);
useEffect(() => {
latestRepliesRef.current = replies;
}, [replies]);
useEffect(() => {
latestHasMoreRef.current = hasMore;
}, [hasMore]);
useEffect(() => {
latestLoadMoreRef.current = loadMore;
}, [loadMore]);
useEffect(() => {
if (replies.length !== lastRepliesLengthRef.current) {
lastRepliesLengthRef.current = replies.length;
}
}, [replies.length]);
useEffect(() => {
if (!enabled || !targetReplyCid || intervalRef.current) return;
intervalRef.current = window.setInterval(() => {
const latestTarget = latestTargetRef.current;
const latestReplies = latestRepliesRef.current;
const latestHasMore = latestHasMoreRef.current;
const latestLoadMore = latestLoadMoreRef.current;
if (!enabled || !latestTarget || hasScrolledRef.current) {
if (intervalRef.current) {
window.clearInterval(intervalRef.current);
intervalRef.current = null;
}
return;
}
if (!latestHasMore) {
const element = document.querySelector(`[data-cid="${latestTarget}"]`);
if (element) {
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
hasScrolledRef.current = true;
} else {
// Reply not found after loading all pages
console.warn(`[scroll-to-reply] Could not find reply with CID "${latestTarget}" in the feed.`);
hasScrolledRef.current = true; // Stop trying
}
if (intervalRef.current) {
window.clearInterval(intervalRef.current);
intervalRef.current = null;
}
return;
}
// Iteratively load pages until the target reply appears in the list.
const targetIndex = latestReplies.findIndex((reply) => reply?.cid === latestTarget);
if (targetIndex >= 0) {
hasScrolledRef.current = true;
if (loadMoreTimeoutRef.current) {
window.clearTimeout(loadMoreTimeoutRef.current);
loadMoreTimeoutRef.current = null;
}
if (intervalRef.current) {
window.clearInterval(intervalRef.current);
intervalRef.current = null;
}
virtuosoRef.current?.scrollToIndex({ index: targetIndex, align: 'center', behavior: 'smooth' });
return;
}
// Smoothly scroll to the latest loaded replies while loading more pages
const lastIndex = latestReplies.length - 1;
if (lastIndex >= 0 && lastIndex !== lastScrollIndexRef.current) {
lastScrollIndexRef.current = lastIndex;
virtuosoRef.current?.scrollToIndex({ index: lastIndex, align: 'end', behavior: 'smooth' });
}
const loadDuration = Date.now() - loadStartAtRef.current;
if (!latestHasMore || loadAttemptsRef.current >= DEFAULT_MAX_LOAD_ATTEMPTS || loadDuration >= MAX_LOAD_DURATION_MS) return;
const now = Date.now();
if (now - lastLoadAtRef.current < LOAD_MORE_THROTTLE_MS) return;
lastLoadAtRef.current = now;
loadAttemptsRef.current += 1;
if (loadMoreTimeoutRef.current) {
window.clearTimeout(loadMoreTimeoutRef.current);
}
loadMoreTimeoutRef.current = window.setTimeout(() => {
latestLoadMore();
}, LOAD_MORE_THROTTLE_MS);
}, AUTO_SCROLL_INTERVAL_MS);
return () => {
if (intervalRef.current) {
window.clearInterval(intervalRef.current);
intervalRef.current = null;
}
if (loadMoreTimeoutRef.current) {
window.clearTimeout(loadMoreTimeoutRef.current);
loadMoreTimeoutRef.current = null;
}
};
}, [enabled, targetReplyCid, virtuosoRef]);
};
export default useScrollToReply;
+7
View File
@@ -7,12 +7,19 @@ import './lib/init-translations';
import './index.css';
import './themes.css';
import { App as CapacitorApp } from '@capacitor/app';
import { Analytics } from '@vercel/analytics/react';
// Only enable analytics on 5chan.app (Vercel deployment)
// Exclude Electron (file:// or localhost), Capacitor/APK (capacitor:// or localhost), and IPFS (ipfs:// or different domain)
const isVercelDeployment =
typeof window !== 'undefined' && (window.location.hostname === '5chan.app' || window.location.hostname === 'www.5chan.app') && !window.isElectron;
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<React.StrictMode>
<Router>
<App />
{isVercelDeployment && <Analytics />}
</Router>
</React.StrictMode>,
);
+2 -2
View File
@@ -27,12 +27,12 @@ export async function copyShareLinkToClipboard(boardIdentifier: string, linkType
if (!cid) {
throw new Error('copyShareLinkToClipboard: thread links require a cid');
}
const shareLink = `https://5chan.app/${boardIdentifier}/thread/${cid}`;
const shareLink = `https://5chan.app/#/${boardIdentifier}/thread/${cid}`;
await copyToClipboard(shareLink);
return;
}
const shareLink = `https://5chan.app/${boardIdentifier}/${linkType}`;
const shareLink = `https://5chan.app/#/${boardIdentifier}/${linkType}`;
await copyToClipboard(shareLink);
}
+7
View File
@@ -79,6 +79,13 @@
clear: both;
}
/* clearfix for OP content to contain floated thumbnail before replies */
.opContainer::after {
content: "";
display: table;
clear: both;
}
.postDesktop .hideThread {
background-image: var(--post-hide-button-background-image);
}
+9 -5
View File
@@ -23,10 +23,11 @@ export interface PostProps {
roles?: Role[];
showAllReplies?: boolean;
showReplies?: boolean;
targetReplyCid?: string;
threadNumber?: number;
}
export const Post = ({ post, showAllReplies = false, showReplies = true }: PostProps) => {
export const Post = ({ post, showAllReplies = false, showReplies = true, targetReplyCid }: PostProps) => {
// Only subscribe to roles field to avoid rerenders from updatingState changes
const roles = useSubplebbitField(post?.subplebbitAddress, (subplebbit) => subplebbit?.roles);
const isMobile = useIsMobile();
@@ -43,9 +44,9 @@ export const Post = ({ post, showAllReplies = false, showReplies = true }: PostP
<div className={styles.thread}>
<div className={styles.postContainer}>
{isMobile ? (
<PostMobile post={comment} roles={roles} showAllReplies={showAllReplies} showReplies={showReplies} />
<PostMobile post={comment} roles={roles} showAllReplies={showAllReplies} showReplies={showReplies} targetReplyCid={targetReplyCid} />
) : (
<PostDesktop post={comment} roles={roles} showAllReplies={showAllReplies} showReplies={showReplies} />
<PostDesktop post={comment} roles={roles} showAllReplies={showAllReplies} showReplies={showReplies} targetReplyCid={targetReplyCid} />
)}
</div>
</div>
@@ -85,8 +86,9 @@ const PostPage = () => {
const { error } = post || {};
useEffect(() => {
if (!comment?.cid || comment.parentCid) return;
window.scrollTo(0, 0);
}, []);
}, [comment?.cid, comment?.parentCid]);
useEffect(() => {
const boardIdentifier = params.boardIdentifier;
@@ -110,6 +112,8 @@ const PostPage = () => {
const shouldShowPostError = post?.error && post?.replyCount > 0 && post?.replies?.length === 0;
const shouldShowSubplebbitError = subplebbitError?.message && !post?.cid;
const targetReplyCid = comment?.parentCid ? comment?.cid : undefined;
return (
<div className={styles.content}>
{shouldShowPostError && (
@@ -117,7 +121,7 @@ const PostPage = () => {
<ErrorDisplay error={error} />
</div>
)}
<Post post={post} showAllReplies={true} />
<Post post={post} showAllReplies={true} targetReplyCid={targetReplyCid} />
{shouldShowSubplebbitError && (
<div className={styles.error}>
<ErrorDisplay error={subplebbitError} />
+5
View File
@@ -5145,6 +5145,11 @@
dependencies:
"@use-gesture/core" "10.3.1"
"@vercel/analytics@^1.6.1":
version "1.6.1"
resolved "https://registry.yarnpkg.com/@vercel/analytics/-/analytics-1.6.1.tgz#b4e16daf445cf6cd365a91e43d86e9e5b3428ddc"
integrity sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==
"@vitejs/plugin-react@4.3.4":
version "4.3.4"
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz#c64be10b54c4640135a5b28a2432330e88ad7c20"