diff --git a/package-lock.json b/package-lock.json
index daa61fd942..44b8cfc776 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,33 +10,33 @@
"hasInstallScript": true,
"dependencies": {
"@formatjs/intl-localematcher": "~0.8.8",
- "@formatjs/intl-segmenter": "~12.2.7",
+ "@formatjs/intl-segmenter": "~12.2.8",
"@formkit/auto-animate": "~0.9.0",
"@github/text-expander-element": "~2.9.4",
"@iconify-json/mingcute": "~1.2.7",
"@justinribeiro/lite-youtube": "~1.9.0",
- "@lingui/detect-locale": "~6.0.1",
- "@lingui/react": "~6.0.1",
+ "@lingui/detect-locale": "~6.1.0",
+ "@lingui/react": "~6.1.0",
"@szhsin/react-menu": "~4.5.1",
"chroma-js": "~3.2.0",
"compare-versions": "~6.1.1",
- "exifreader": "~4.38.1",
+ "exifreader": "~4.39.1",
"fast-blurhash": "~1.1.4",
"fast-equals": "~6.0.0",
"flexsearch": "~0.8.212",
"fuse.js": "~7.3.0",
"gifuct-js": "~2.1.2",
"html-prettify": "~1.0.7",
- "idb-keyval": "~6.2.2",
+ "idb-keyval": "~6.2.4",
"intl-locale-textinfo-polyfill": "~3.0.0",
- "js-cookie": "~3.0.5",
+ "js-cookie": "~3.0.7",
"just-debounce-it": "~3.2.0",
"lz-string": "~1.5.0",
"masto": "~7.11.1",
"micro-memoize": "~5.1.1",
- "p-queue": "~9.2.0",
+ "p-queue": "~9.3.0",
"p-retry": "~8.0.0",
- "preact": "10.29.1",
+ "preact": "10.29.2",
"punycode": "~2.3.1",
"qr": "~0.6.0",
"react-hotkeys-hook": "~5.2.4",
@@ -44,7 +44,7 @@
"react-quick-pinch-zoom": "~5.1.1",
"react-router-dom": "6.6.2",
"swiped-events": "~1.2.0",
- "temml": "~0.13.2",
+ "temml": "~0.13.3",
"tinyld": "~1.3.4",
"toastify-js": "~1.12.0",
"uid": "~2.0.2",
@@ -58,20 +58,20 @@
"@emnapi/core": "~1.10.0",
"@emnapi/runtime": "~1.10.0",
"@iconify/utils": "~3.1.3",
- "@lingui/babel-plugin-lingui-macro": "~6.0.1",
- "@lingui/cli": "~6.0.1",
- "@lingui/vite-plugin": "~6.0.1",
+ "@lingui/babel-plugin-lingui-macro": "~6.1.0",
+ "@lingui/cli": "~6.1.0",
+ "@lingui/vite-plugin": "~6.1.0",
"@playwright/test": "~1.60.0",
"@preact/preset-vite": "~2.10.5",
- "@types/node": "~25.8.0",
- "oxfmt": "~0.49.0",
- "postcss": "~8.5.14",
+ "@types/node": "~25.9.1",
+ "oxfmt": "~0.52.0",
+ "postcss": "~8.5.15",
"postcss-dark-theme-class": "~2.0.0",
"postcss-preset-env": "~11.3.0",
"prop-types": "^15.8.1",
"sonda": "~0.11.1",
"twitter-text": "~3.1.0",
- "vite": "~8.0.13",
+ "vite": "~8.0.14",
"vite-plugin-generate-file": "~0.3.1",
"vite-plugin-html-config": "~2.0.2",
"vite-plugin-pwa": "~1.3.0",
@@ -85,6 +85,7 @@
"workbox-strategies": "~7.4.1"
},
"engines": {
+ "node": ">=22.19.0",
"npm": ">=10.3.0 <11.5.0"
}
},
@@ -3201,9 +3202,9 @@
}
},
"node_modules/@formatjs/intl-segmenter": {
- "version": "12.2.7",
- "resolved": "https://registry.npmjs.org/@formatjs/intl-segmenter/-/intl-segmenter-12.2.7.tgz",
- "integrity": "sha512-fukQs4CP7pUM2km4mn7laHNNJewS3RB0v0wP50gV43THf1I3yRECyehDqQHxpj/kmOAYOdCmJs8Tw60grmSs+w==",
+ "version": "12.2.8",
+ "resolved": "https://registry.npmjs.org/@formatjs/intl-segmenter/-/intl-segmenter-12.2.8.tgz",
+ "integrity": "sha512-zQPS2yENJA2Snpx3RmZd1eMt+gFc9y3IibtFxzhhXvcGA0oDr350eJZA+jMt18rEBZ2P5exEqhTA9xKEb1c7Ig==",
"license": "MIT",
"dependencies": {
"@formatjs/intl-localematcher": "0.8.8"
@@ -3366,9 +3367,9 @@
"license": "MIT"
},
"node_modules/@lingui/babel-plugin-extract-messages": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-6.0.1.tgz",
- "integrity": "sha512-E9quPJxYZFz2f1t8lRyPILWKrqrUI32EYBQMjC9CcneKh9ZLtvm7K1IAM+tPMYW5BDDqlXIVr8XHhGrkv/3OSA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-6.1.0.tgz",
+ "integrity": "sha512-CRlWvISWj9WTS42j0Kz4suNSC8yP45kcmlnaes9vL2Y3hKeh1Uds74KZVIblHpEDSKxxQTQJdgGG37xxKfKcYw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3376,24 +3377,24 @@
}
},
"node_modules/@lingui/babel-plugin-lingui-macro": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-lingui-macro/-/babel-plugin-lingui-macro-6.0.1.tgz",
- "integrity": "sha512-ZVsi04ZeqkvOfLn+fVZPEv6//SKHvrJlD+T0oJWDdymMKQVGsuFUSHFq3eFBpKilPMzYSCCj0wHgmljdUQionw==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-lingui-macro/-/babel-plugin-lingui-macro-6.1.0.tgz",
+ "integrity": "sha512-f0ZIdt4ia01fr3Zjn8b7z3+LLGArNudY/t4rLkz4nFWzDKaIRgv/dHABdSnjTU6w5DtGcwU8ijbPIv6dGG2rag==",
"license": "MIT",
"dependencies": {
"@babel/core": "^7.20.12",
"@babel/types": "^7.20.7",
- "@lingui/conf": "6.0.1",
- "@lingui/message-utils": "6.0.1"
+ "@lingui/conf": "6.1.0",
+ "@lingui/message-utils": "6.1.0"
},
"engines": {
"node": ">=22.19.0"
}
},
"node_modules/@lingui/cli": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@lingui/cli/-/cli-6.0.1.tgz",
- "integrity": "sha512-xojK0f0JjgcZArNU4m3vydhG+ngQOxbovV8wDav3TT1R8PXSvKrmGfCoPffQczpbl86/0NOSdvteN8Da5MQlqg==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@lingui/cli/-/cli-6.1.0.tgz",
+ "integrity": "sha512-v1YA86vZMUyFG7Gbo2dKBLY6HX2aAoKwCGdXbtscFD0rAhHbs3UkzMwa3lWxiZHY2LpgZK7CCI3npKiBUTgrOg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3401,12 +3402,12 @@
"@babel/generator": "^7.28.5",
"@babel/parser": "^7.22.0",
"@babel/types": "^7.21.2",
- "@lingui/babel-plugin-extract-messages": "6.0.1",
- "@lingui/babel-plugin-lingui-macro": "6.0.1",
- "@lingui/conf": "6.0.1",
- "@lingui/core": "6.0.1",
- "@lingui/format-po": "6.0.1",
- "@lingui/message-utils": "6.0.1",
+ "@lingui/babel-plugin-extract-messages": "6.1.0",
+ "@lingui/babel-plugin-lingui-macro": "6.1.0",
+ "@lingui/conf": "6.1.0",
+ "@lingui/core": "6.1.0",
+ "@lingui/format-po": "6.1.0",
+ "@lingui/message-utils": "6.1.0",
"chokidar": "5.0.0",
"cli-table3": "^0.6.5",
"commander": "^14.0.2",
@@ -3912,9 +3913,9 @@
}
},
"node_modules/@lingui/conf": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-6.0.1.tgz",
- "integrity": "sha512-6NJIOTh7Pt1MXMNkUsxjA6tlKX7LB1QLh/A5H3a1SmZTSZgcbes/BvF4lEh7zAfhNIU5A5Y8PljX+n4fBGO7Hg==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-6.1.0.tgz",
+ "integrity": "sha512-GkgtaoersJxlTUsYLIHNbQIJuPEdtV/RcLAefT+0XZhVSn55CJRL9H0eYdOBNJtev0k7YuAKG+dPnFRaI7sYlg==",
"license": "MIT",
"dependencies": {
"jest-validate": "^29.4.3",
@@ -3927,13 +3928,13 @@
}
},
"node_modules/@lingui/core": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@lingui/core/-/core-6.0.1.tgz",
- "integrity": "sha512-3dtvQmPv7qpu6j4SwX8h/TQu3ADujdw9/ZV3qb6OwsYa0AhBUPaydVGOEDvkNA7v/fQh6CNUc6qqZrBbDBvdHA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@lingui/core/-/core-6.1.0.tgz",
+ "integrity": "sha512-5ZUR809ODdQ6DGyAyrIw/iPNCbhnknhWI/4w9S9BCtf1fx3LoqtBdb4ADSJ6OHz7kTvIgOZQPIAdPW/FtZui9w==",
"license": "MIT",
"dependencies": {
- "@lingui/babel-plugin-lingui-macro": "6.0.1",
- "@lingui/message-utils": "6.0.1"
+ "@lingui/babel-plugin-lingui-macro": "6.1.0",
+ "@lingui/message-utils": "6.1.0"
},
"engines": {
"node": ">=22.19.0"
@@ -3948,23 +3949,23 @@
}
},
"node_modules/@lingui/detect-locale": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@lingui/detect-locale/-/detect-locale-6.0.1.tgz",
- "integrity": "sha512-pQS8Y2Ho09llqs9YvFXUkouxQZd7VNl9F77a7PpOWd/pKKrJZyCzgPu7Kw3mr+zcbg2owBTzdIfoXfv1BXQUmg==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@lingui/detect-locale/-/detect-locale-6.1.0.tgz",
+ "integrity": "sha512-hkhBwwyxDJbsc2/iUzxj1acDMfBkiVJOLF+e1D1L/UhbtELx2eDwpgr2HMZ3pPzbgzZUDGymzgW6HDsZ4lJPzA==",
"license": "MIT",
"engines": {
"node": ">=22.19.0"
}
},
"node_modules/@lingui/format-po": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@lingui/format-po/-/format-po-6.0.1.tgz",
- "integrity": "sha512-kt3naP/2kpAPJ4dwwFnkhbvR5XkGaNdbK8W6ofpIJFhY3MvGZJ9rYY0KMp++3DAaXf7r6tHq0W0To3akSDejvg==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@lingui/format-po/-/format-po-6.1.0.tgz",
+ "integrity": "sha512-oMpd7l82xxpMPAnfw8Hk8x/GG4IDSlonYlhlqIWhTWbV0lpAtrmlCDq0TXeTO43MvAm53jkpwWzIKBI14seZZw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@lingui/conf": "6.0.1",
- "@lingui/message-utils": "6.0.1",
+ "@lingui/conf": "6.1.0",
+ "@lingui/message-utils": "6.1.0",
"pofile": "^1.1.4"
},
"engines": {
@@ -3972,9 +3973,9 @@
}
},
"node_modules/@lingui/message-utils": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-6.0.1.tgz",
- "integrity": "sha512-cw1X5mqDODbYDkwvA9i6/4j7Ix0ptl+E9RfhBRLI2NsoLzHHX+ePryGkShFdUHYsDL+C9qkq8W0drgRVEl9LgA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-6.1.0.tgz",
+ "integrity": "sha512-AYbUVx/1CnLLFHQWAU/ljczknIqepUZuYChcNJCOd/LzFM0jASgXRmzieP156V8EctBXNNIR145rw0HtJ1jmew==",
"license": "MIT",
"dependencies": {
"@messageformat/date-skeleton": "^1.1.0",
@@ -3986,13 +3987,13 @@
}
},
"node_modules/@lingui/react": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@lingui/react/-/react-6.0.1.tgz",
- "integrity": "sha512-Pjj77gdZEINsqTvnNtHZTtU+xlgCK3lFKUd4fXMcIo8q7snkdmD8SB/EBJB28s+e5ZEcmFi5dfS4ekc5scQvPA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@lingui/react/-/react-6.1.0.tgz",
+ "integrity": "sha512-PKTMyXgIfcmjURONBQmWV7U3IwxWA9gSRqh9gxP2Pr84Kslcyly+4ov7uqJNg/sy3L0qegsjReAXc9bR7Q73Kw==",
"license": "MIT",
"dependencies": {
- "@lingui/babel-plugin-lingui-macro": "6.0.1",
- "@lingui/core": "6.0.1"
+ "@lingui/babel-plugin-lingui-macro": "6.1.0",
+ "@lingui/core": "6.1.0"
},
"engines": {
"node": ">=22.19.0"
@@ -4008,14 +4009,14 @@
}
},
"node_modules/@lingui/vite-plugin": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@lingui/vite-plugin/-/vite-plugin-6.0.1.tgz",
- "integrity": "sha512-RgHkaC76p8NLj2DqA4JqC1/+pFIZWSkv4dJm/D8O+GSoJlst7WMl4h08qpPpAdTKgZpDZB8d22O6ejFohe6PTw==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@lingui/vite-plugin/-/vite-plugin-6.1.0.tgz",
+ "integrity": "sha512-kIm8Z6QfYOQjbN+Gxx3JnGqR57VKq1xn/bD2ybtH8jtrzYqFJXOw2oAtXMl1Q+tOSkpOYNMB/w/OYCYpwXwgkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@lingui/cli": "6.0.1",
- "@lingui/conf": "6.0.1"
+ "@lingui/cli": "6.1.0",
+ "@lingui/conf": "6.1.0"
},
"engines": {
"node": ">=22.19.0"
@@ -4086,9 +4087,9 @@
}
},
"node_modules/@oxc-project/types": {
- "version": "0.130.0",
- "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz",
- "integrity": "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==",
+ "version": "0.132.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.132.0.tgz",
+ "integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==",
"dev": true,
"license": "MIT",
"funding": {
@@ -4096,9 +4097,9 @@
}
},
"node_modules/@oxfmt/binding-android-arm-eabi": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.49.0.tgz",
- "integrity": "sha512-HbifJ84prIh9+55CTPAU35JdRQrwg47y16cGerCC+iejSKOuHXYo2WDql6l7cQlzrYVtc3f4UWY+dBj2lRmOeA==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.52.0.tgz",
+ "integrity": "sha512-17EMSJnQ9g+upVHrAUYDMfH5lvRKQ9Nvg8WtEoH72oDr1VpWz+7/o3tD97U1EToen2YAQ/68JmtDYkQUi20dfQ==",
"cpu": [
"arm"
],
@@ -4113,9 +4114,9 @@
}
},
"node_modules/@oxfmt/binding-android-arm64": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.49.0.tgz",
- "integrity": "sha512-Ef7SKJqAaH2d7E6eXZZa2OffIShbhFMxnGK0zd93p4qiyTJr75B0qf7lrPD+qQOwcf04BrjYJ0JUxq8d5+yZwg==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.52.0.tgz",
+ "integrity": "sha512-A2G1IdwGEW2lLJkIxcvuirRH1CzSl/e0NX11zTlW1gvxJThfwbI/BEoaKrTNpm7M2FchvIf6guvIQU7d5iz+OQ==",
"cpu": [
"arm64"
],
@@ -4130,9 +4131,9 @@
}
},
"node_modules/@oxfmt/binding-darwin-arm64": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.49.0.tgz",
- "integrity": "sha512-8x5DN9CsFfb432sHa9NyqX5XisGUdA53LPEGSdv/VniS+v4uEOR8Orv7A9QSB98Xxgp0t6r31DzQA/wpIobGqQ==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.52.0.tgz",
+ "integrity": "sha512-f9+bLvOYxy7NttCLFTvQ7afmqDOWY4wIP9xdvfj5trQ1qj6f2UFAGwZESlfsMjvJNTyRpXfIlOanCI9FOvoeQA==",
"cpu": [
"arm64"
],
@@ -4147,9 +4148,9 @@
}
},
"node_modules/@oxfmt/binding-darwin-x64": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.49.0.tgz",
- "integrity": "sha512-e0+DSVzk4ewhMVKNYDaRTmP81jNMBWR1X9al0cVKWS+hDM/dElNqD5zjTOCuLOZc4oOdp2Gx2ldrVL+yYo9TZQ==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.52.0.tgz",
+ "integrity": "sha512-YSTB9sJ5nnQd/Q0ddHkgof0ZCHPAnWZT1IW2SJ8omz7CP7KluJhO1fNHrpqdxCtpztJwSs4hY1uAee35wKxxaw==",
"cpu": [
"x64"
],
@@ -4164,9 +4165,9 @@
}
},
"node_modules/@oxfmt/binding-freebsd-x64": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.49.0.tgz",
- "integrity": "sha512-W+mjtYtrQvFbXT/uNT+221OBhGRZ8UqNsLxjTWsjZ4GsQnRdvRC/N2NCK86BcamWr7lsTxwpwN3PULnr78sgcQ==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.52.0.tgz",
+ "integrity": "sha512-NIrRNTTPCs4UbmVs0bxLSCDlLCtIRMJIXklNKaXa5Oj2/K1UIMBvgE8+uPVo01Io3N9HF0+GAX+aAHjUgZS7vA==",
"cpu": [
"x64"
],
@@ -4181,9 +4182,9 @@
}
},
"node_modules/@oxfmt/binding-linux-arm-gnueabihf": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.49.0.tgz",
- "integrity": "sha512-Rtv6UevV7czDlLqil+NZUe4d8gs8jQo/zScSpumwyf7I+fSdLc+hc8AF3MQC7ymxSMMD9+vfiqQlsIf7wOAzXA==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.52.0.tgz",
+ "integrity": "sha512-JXUCde8mn3GpgQouz2PXUokgy/uT1QrRJBL2s983VWcSQp62wTFYiNXgTKdeo1Jgbr0IgUnKKvzIk/YBlj/nVQ==",
"cpu": [
"arm"
],
@@ -4198,9 +4199,9 @@
}
},
"node_modules/@oxfmt/binding-linux-arm-musleabihf": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.49.0.tgz",
- "integrity": "sha512-sBi+8C/Q/MdKa5FL8ibAUCdhFBGFH7HFN/Qoyd5xQbZ/0ky3NMPpKfIBpaH0lhK2dXkGLczVQUoZ+xuNSerCdQ==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.52.0.tgz",
+ "integrity": "sha512-psbUXaRZ+V8DaXz10Qf7LSHtdtdKAmC8fxXgeU608jjzrmWK4quamZMOpl6sf+dikoFHA85uE93Q0BqxrCdQrQ==",
"cpu": [
"arm"
],
@@ -4215,9 +4216,9 @@
}
},
"node_modules/@oxfmt/binding-linux-arm64-gnu": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.49.0.tgz",
- "integrity": "sha512-JIfWenFhlzx+O8YygyZhoHFzTsdgDhxhbDRnE2iJLnnM5pWKScFvPECO2vOlA7JqJ/9S1g3uzEKuRCkHFwTjvA==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.52.0.tgz",
+ "integrity": "sha512-Jw7MgWUU9lcLCcy82updISP3EthTlfvAwR6gWNxPzqly7+fLvOi2gHQE9xXQjpqaVLm/8P+gOzlv9ODuoVlaaw==",
"cpu": [
"arm64"
],
@@ -4235,9 +4236,9 @@
}
},
"node_modules/@oxfmt/binding-linux-arm64-musl": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.49.0.tgz",
- "integrity": "sha512-iNzkMPG18jPkwBOZ4/HEjwqfzAjq4RrUQ0CgId/fC1ENvYD5jLVAaU/gWgpiqP1ys07kxSsSggDd1fp3E7mQHw==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.52.0.tgz",
+ "integrity": "sha512-wZg6bLjDvh2KibyI3QFUYo8GTXneIFsd0JvehtvJiUmQ8WRPERgxd/VM4ctWb86U5FT1FkqgS8/wZKVB+AZScg==",
"cpu": [
"arm64"
],
@@ -4255,9 +4256,9 @@
}
},
"node_modules/@oxfmt/binding-linux-ppc64-gnu": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.49.0.tgz",
- "integrity": "sha512-BPHA/NN3LvoIXiid+iz3BHt5V0Rzx0tXAqRUovwE1NsbDaLG9e8mtv7evDGRIkVQacqTDBv0XL25THHsxSJosQ==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.52.0.tgz",
+ "integrity": "sha512-IngE8uxhNvxcMrLjZNDo9xNLY7rEK33AKnaMd2B46he1e/mz2CfcW6If/U1wUjdRZddm1QzQaciqZkuMkdh1FA==",
"cpu": [
"ppc64"
],
@@ -4275,9 +4276,9 @@
}
},
"node_modules/@oxfmt/binding-linux-riscv64-gnu": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.49.0.tgz",
- "integrity": "sha512-3Eroshe+s69htC9JIL0+zLGQczLtRKezkMhwqQC21VC5Z/fuLvzLfbAOLgJLUq601H8gDYjy7deYycfOBjCvWg==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.52.0.tgz",
+ "integrity": "sha512-H3+DdFMv/efN3Efmhsv18jDrpiWWqKG7wsfAlQBqAt6z/E2Bx+TwEj2Nowe51CPOWB8/mFBC2dAMSgVFLvvowA==",
"cpu": [
"riscv64"
],
@@ -4295,9 +4296,9 @@
}
},
"node_modules/@oxfmt/binding-linux-riscv64-musl": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.49.0.tgz",
- "integrity": "sha512-fnaERGgsxGm0lKAmO72EYR4BA3qBnzBTJBTi6EtUMq1D4R7EexRBMU4voXnx4TXla3SEDl9x4uNp/18SbkPjGg==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.52.0.tgz",
+ "integrity": "sha512-zji+1kb7lJKohSDjzC1IsS+K/cKRs1hdVf0ZH0VbdbiakmtLvN9twBoXo/k8VdjFax7kfo+DyPxS7vv52br1aw==",
"cpu": [
"riscv64"
],
@@ -4315,9 +4316,9 @@
}
},
"node_modules/@oxfmt/binding-linux-s390x-gnu": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.49.0.tgz",
- "integrity": "sha512-rBwasMl1Uul1MCCeTGEFKnOTL7VUxHf+634jWStrQAbzpBJgd5Yz5m4F7exVCsoI8PHn57dNjssXagXLCLB5yA==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.52.0.tgz",
+ "integrity": "sha512-hcLBYedpCy7ToUvvBidWk7+11Yhg1oAZ4+6hKPic/mQI6NaqXJSXMps5nFlwUuX2ewhtLZZDPg63TI042qGKBg==",
"cpu": [
"s390x"
],
@@ -4335,9 +4336,9 @@
}
},
"node_modules/@oxfmt/binding-linux-x64-gnu": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.49.0.tgz",
- "integrity": "sha512-BoC/F9xHe2y/deuBGA5Aw7bes07OD2gcL2wlpzTrfImR92vPP7S/k3LBTyspQZCNIVNdagkELcqKELwMLGIfAg==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.52.0.tgz",
+ "integrity": "sha512-IDO2loXK2OtTOhSPchU9MW25mWL2QCDGdJbjN8MXKZVS80qXe5gMTwQWu/gMJ3juoBHbkuUZNB2N1LHzNT7DoA==",
"cpu": [
"x64"
],
@@ -4355,9 +4356,9 @@
}
},
"node_modules/@oxfmt/binding-linux-x64-musl": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.49.0.tgz",
- "integrity": "sha512-umY6jFADAo/oztFKl8D/S6vSrG6oBpEskcentiRuz42kZVU2kfDXMWCYavxyZR2bwPjqkHpcHZ6EZFiH3Qj9ZA==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.52.0.tgz",
+ "integrity": "sha512-mAV2Hjn0SatJ+KoAzKUC3eJhdJ8wv+3m1KyuS0dTsbF0c5weq+QrCt/DRZZM+uj/XiKzCDEUKYsBF30e2qkcyw==",
"cpu": [
"x64"
],
@@ -4375,9 +4376,9 @@
}
},
"node_modules/@oxfmt/binding-openharmony-arm64": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.49.0.tgz",
- "integrity": "sha512-J85zQMiw2pXiGPK+OusmDvSnJ/dgpgN7VgmB2zOBtgS8F+nsOUfSg9ZEBrwbQscjZ7tkPbm38CG4VF5f53MsiA==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.52.0.tgz",
+ "integrity": "sha512-vd4npaUIwChxp7XzkqmepBWTT9YMcSe/NBApVGPC30/lLyOVaV3dvma1SKo03t8O73BPRAG7EyJzGlN5cJM5hQ==",
"cpu": [
"arm64"
],
@@ -4392,9 +4393,9 @@
}
},
"node_modules/@oxfmt/binding-win32-arm64-msvc": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.49.0.tgz",
- "integrity": "sha512-38K67XR++CoFFORDd4sMFwUVAnD6msYBdGTei+qvKGrRPO6S2PbrYPNL/eQQ1RgnnxOegNba0YQwg6uRkNcw6A==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.52.0.tgz",
+ "integrity": "sha512-k2sz6gWQdMfh5HPpIS+Bw/0UEV/kaK2xuqJRrWL233sEHx9WLlsmvlPFM4HUNThkYbSN0U0vPW7LVKZWDS8hPQ==",
"cpu": [
"arm64"
],
@@ -4409,9 +4410,9 @@
}
},
"node_modules/@oxfmt/binding-win32-ia32-msvc": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.49.0.tgz",
- "integrity": "sha512-rXVe0HICwQF0dBgbQtBCoYf8x/SidPIdhyQl+iPuJlV7suV+qDv7yUEB3wQ4qC3nOeNxz287SwFXKzyr0kWgEg==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.52.0.tgz",
+ "integrity": "sha512-rhke69GTcArodLHpjMTfNnvjTEBryDeZcUCKK/VjXDMtfTULl6QRh0ymX5/hbCUv2WjYm9h/QbW++q2vE15gWQ==",
"cpu": [
"ia32"
],
@@ -4426,9 +4427,9 @@
}
},
"node_modules/@oxfmt/binding-win32-x64-msvc": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.49.0.tgz",
- "integrity": "sha512-gwWLwSEmBBfIK/Wh7GGd658161o4RKAvHWRaRQbJm571iQXGKfyr7UKsI1vsWvDlNLc30CxJDc8mMmCvJ/kczQ==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.52.0.tgz",
+ "integrity": "sha512-q5xL7oeXkZdEtNZWBdvehJcmt+GRu9l2bK40yJs1jJXlqq+r0Hygb1rTjq+FM2o/2xyt4cufH6KRplHp3Jjsvw==",
"cpu": [
"x64"
],
@@ -4560,9 +4561,9 @@
}
},
"node_modules/@rolldown/binding-android-arm64": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.1.tgz",
- "integrity": "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz",
+ "integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==",
"cpu": [
"arm64"
],
@@ -4577,9 +4578,9 @@
}
},
"node_modules/@rolldown/binding-darwin-arm64": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.1.tgz",
- "integrity": "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz",
+ "integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==",
"cpu": [
"arm64"
],
@@ -4594,9 +4595,9 @@
}
},
"node_modules/@rolldown/binding-darwin-x64": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.1.tgz",
- "integrity": "sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz",
+ "integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==",
"cpu": [
"x64"
],
@@ -4611,9 +4612,9 @@
}
},
"node_modules/@rolldown/binding-freebsd-x64": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.1.tgz",
- "integrity": "sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz",
+ "integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==",
"cpu": [
"x64"
],
@@ -4628,9 +4629,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.1.tgz",
- "integrity": "sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz",
+ "integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==",
"cpu": [
"arm"
],
@@ -4645,9 +4646,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-gnu": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.1.tgz",
- "integrity": "sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz",
+ "integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==",
"cpu": [
"arm64"
],
@@ -4665,9 +4666,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-musl": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.1.tgz",
- "integrity": "sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz",
+ "integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==",
"cpu": [
"arm64"
],
@@ -4685,9 +4686,9 @@
}
},
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.1.tgz",
- "integrity": "sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz",
+ "integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==",
"cpu": [
"ppc64"
],
@@ -4705,9 +4706,9 @@
}
},
"node_modules/@rolldown/binding-linux-s390x-gnu": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.1.tgz",
- "integrity": "sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz",
+ "integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==",
"cpu": [
"s390x"
],
@@ -4725,9 +4726,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-gnu": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz",
- "integrity": "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz",
+ "integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==",
"cpu": [
"x64"
],
@@ -4745,9 +4746,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-musl": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.1.tgz",
- "integrity": "sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz",
+ "integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==",
"cpu": [
"x64"
],
@@ -4765,9 +4766,9 @@
}
},
"node_modules/@rolldown/binding-openharmony-arm64": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.1.tgz",
- "integrity": "sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz",
+ "integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==",
"cpu": [
"arm64"
],
@@ -4782,9 +4783,9 @@
}
},
"node_modules/@rolldown/binding-wasm32-wasi": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.1.tgz",
- "integrity": "sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz",
+ "integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==",
"cpu": [
"wasm32"
],
@@ -4801,9 +4802,9 @@
}
},
"node_modules/@rolldown/binding-win32-arm64-msvc": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.1.tgz",
- "integrity": "sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz",
+ "integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==",
"cpu": [
"arm64"
],
@@ -4818,9 +4819,9 @@
}
},
"node_modules/@rolldown/binding-win32-x64-msvc": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.1.tgz",
- "integrity": "sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz",
+ "integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==",
"cpu": [
"x64"
],
@@ -5428,9 +5429,9 @@
}
},
"node_modules/@types/node": {
- "version": "25.8.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz",
- "integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==",
+ "version": "25.9.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz",
+ "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==",
"license": "MIT",
"dependencies": {
"undici-types": ">=7.24.0 <7.24.7"
@@ -6713,9 +6714,9 @@
"license": "MIT"
},
"node_modules/exifreader": {
- "version": "4.38.1",
- "resolved": "https://registry.npmjs.org/exifreader/-/exifreader-4.38.1.tgz",
- "integrity": "sha512-VUQ8pnWJHpnQXPQLgx4XBwjhj+eE0f5t4KhVFn6BnnTYKLf79DfjVRntR5061qE9NZgx2ohvE+JLXe/FWfCaAA==",
+ "version": "4.39.1",
+ "resolved": "https://registry.npmjs.org/exifreader/-/exifreader-4.39.1.tgz",
+ "integrity": "sha512-mQyOcAXK/mE+5rdzeqv/6tK431Vv8HCIVMYIJZJgJ+1ydd6nmg13awWcaEAzj/3M+Ii7A5v1gMokDOiK6RDcpw==",
"hasInstallScript": true,
"license": "MPL-2.0",
"optionalDependencies": {
@@ -7298,9 +7299,9 @@
"license": "ISC"
},
"node_modules/idb-keyval": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz",
- "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==",
+ "version": "6.2.4",
+ "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.4.tgz",
+ "integrity": "sha512-D/NzHWUmYJGXi++z67aMSrnisb9A3621CyRK5G89JyTlN13C8xf0g04DLxUKMufPem3e3L2JAXR6Z00OWy183Q==",
"license": "Apache-2.0"
},
"node_modules/import-meta-resolve": {
@@ -7955,12 +7956,12 @@
"license": "MIT"
},
"node_modules/js-cookie": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
- "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.7.tgz",
+ "integrity": "sha512-z/wZZgDrkNV1eA0ULjM/F9/50Ya8fbzgKneSpoPsXSGd0KnpdtHfOZWK+GcwLk+EZbS4F9RBhU+K2RgzuDaItw==",
"license": "MIT",
"engines": {
- "node": ">=14"
+ "node": ">=20"
}
},
"node_modules/js-sha256": {
@@ -8810,9 +8811,9 @@
}
},
"node_modules/oxfmt": {
- "version": "0.49.0",
- "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.49.0.tgz",
- "integrity": "sha512-IAHFMdlJSWe+oAr65dx22UvjCtV9DBMisAuLnKpDqMQrctzCkGnj3QRwNHm0d+uwSWPalsDF8ZYLz9rh6nH2IQ==",
+ "version": "0.52.0",
+ "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.52.0.tgz",
+ "integrity": "sha512-nJlYM35F64zTDMecCNhoHNkf+D/eHv7xcjj9XDSj+bFAVtN93m7v8DQMdHd6nDG6Akf/kEYYHmDUBs2Dz27Sug==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8828,39 +8829,43 @@
"url": "https://github.com/sponsors/Boshen"
},
"optionalDependencies": {
- "@oxfmt/binding-android-arm-eabi": "0.49.0",
- "@oxfmt/binding-android-arm64": "0.49.0",
- "@oxfmt/binding-darwin-arm64": "0.49.0",
- "@oxfmt/binding-darwin-x64": "0.49.0",
- "@oxfmt/binding-freebsd-x64": "0.49.0",
- "@oxfmt/binding-linux-arm-gnueabihf": "0.49.0",
- "@oxfmt/binding-linux-arm-musleabihf": "0.49.0",
- "@oxfmt/binding-linux-arm64-gnu": "0.49.0",
- "@oxfmt/binding-linux-arm64-musl": "0.49.0",
- "@oxfmt/binding-linux-ppc64-gnu": "0.49.0",
- "@oxfmt/binding-linux-riscv64-gnu": "0.49.0",
- "@oxfmt/binding-linux-riscv64-musl": "0.49.0",
- "@oxfmt/binding-linux-s390x-gnu": "0.49.0",
- "@oxfmt/binding-linux-x64-gnu": "0.49.0",
- "@oxfmt/binding-linux-x64-musl": "0.49.0",
- "@oxfmt/binding-openharmony-arm64": "0.49.0",
- "@oxfmt/binding-win32-arm64-msvc": "0.49.0",
- "@oxfmt/binding-win32-ia32-msvc": "0.49.0",
- "@oxfmt/binding-win32-x64-msvc": "0.49.0"
- },
- "peerDependencies": {
- "svelte": "^5.0.0"
+ "@oxfmt/binding-android-arm-eabi": "0.52.0",
+ "@oxfmt/binding-android-arm64": "0.52.0",
+ "@oxfmt/binding-darwin-arm64": "0.52.0",
+ "@oxfmt/binding-darwin-x64": "0.52.0",
+ "@oxfmt/binding-freebsd-x64": "0.52.0",
+ "@oxfmt/binding-linux-arm-gnueabihf": "0.52.0",
+ "@oxfmt/binding-linux-arm-musleabihf": "0.52.0",
+ "@oxfmt/binding-linux-arm64-gnu": "0.52.0",
+ "@oxfmt/binding-linux-arm64-musl": "0.52.0",
+ "@oxfmt/binding-linux-ppc64-gnu": "0.52.0",
+ "@oxfmt/binding-linux-riscv64-gnu": "0.52.0",
+ "@oxfmt/binding-linux-riscv64-musl": "0.52.0",
+ "@oxfmt/binding-linux-s390x-gnu": "0.52.0",
+ "@oxfmt/binding-linux-x64-gnu": "0.52.0",
+ "@oxfmt/binding-linux-x64-musl": "0.52.0",
+ "@oxfmt/binding-openharmony-arm64": "0.52.0",
+ "@oxfmt/binding-win32-arm64-msvc": "0.52.0",
+ "@oxfmt/binding-win32-ia32-msvc": "0.52.0",
+ "@oxfmt/binding-win32-x64-msvc": "0.52.0"
+ },
+ "peerDependencies": {
+ "svelte": "^5.0.0",
+ "vite-plus": "*"
},
"peerDependenciesMeta": {
"svelte": {
"optional": true
+ },
+ "vite-plus": {
+ "optional": true
}
}
},
"node_modules/p-queue": {
- "version": "9.2.0",
- "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.2.0.tgz",
- "integrity": "sha512-dWgLE8AH0HjQ9fe74pUkKkvzzYT18Inp4zra3lKHnnwqGvcfcUBrvF2EAVX+envufDNBOzpPq/IBUONDbI7+3g==",
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.0.tgz",
+ "integrity": "sha512-7NED7xhQ74Ngp4JP/2e0VZHp7vSWfJfqeiR92jPgxsz6m0Se4P03YoTKa9dDXyZ3r6P616gUXttrB6nnHYKang==",
"license": "MIT",
"dependencies": {
"eventemitter3": "^5.0.4",
@@ -9027,9 +9032,9 @@
}
},
"node_modules/postcss": {
- "version": "8.5.14",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
- "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
+ "version": "8.5.15",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
+ "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
"dev": true,
"funding": [
{
@@ -9047,7 +9052,7 @@
],
"license": "MIT",
"dependencies": {
- "nanoid": "^3.3.11",
+ "nanoid": "^3.3.12",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
@@ -9827,9 +9832,9 @@
}
},
"node_modules/preact": {
- "version": "10.29.1",
- "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.1.tgz",
- "integrity": "sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==",
+ "version": "10.29.2",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.2.tgz",
+ "integrity": "sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ==",
"license": "MIT",
"funding": {
"type": "opencollective",
@@ -10235,13 +10240,13 @@
}
},
"node_modules/rolldown": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.1.tgz",
- "integrity": "sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.2.tgz",
+ "integrity": "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@oxc-project/types": "=0.130.0",
+ "@oxc-project/types": "=0.132.0",
"@rolldown/pluginutils": "^1.0.0"
},
"bin": {
@@ -10251,21 +10256,21 @@
"node": "^20.19.0 || >=22.12.0"
},
"optionalDependencies": {
- "@rolldown/binding-android-arm64": "1.0.1",
- "@rolldown/binding-darwin-arm64": "1.0.1",
- "@rolldown/binding-darwin-x64": "1.0.1",
- "@rolldown/binding-freebsd-x64": "1.0.1",
- "@rolldown/binding-linux-arm-gnueabihf": "1.0.1",
- "@rolldown/binding-linux-arm64-gnu": "1.0.1",
- "@rolldown/binding-linux-arm64-musl": "1.0.1",
- "@rolldown/binding-linux-ppc64-gnu": "1.0.1",
- "@rolldown/binding-linux-s390x-gnu": "1.0.1",
- "@rolldown/binding-linux-x64-gnu": "1.0.1",
- "@rolldown/binding-linux-x64-musl": "1.0.1",
- "@rolldown/binding-openharmony-arm64": "1.0.1",
- "@rolldown/binding-wasm32-wasi": "1.0.1",
- "@rolldown/binding-win32-arm64-msvc": "1.0.1",
- "@rolldown/binding-win32-x64-msvc": "1.0.1"
+ "@rolldown/binding-android-arm64": "1.0.2",
+ "@rolldown/binding-darwin-arm64": "1.0.2",
+ "@rolldown/binding-darwin-x64": "1.0.2",
+ "@rolldown/binding-freebsd-x64": "1.0.2",
+ "@rolldown/binding-linux-arm-gnueabihf": "1.0.2",
+ "@rolldown/binding-linux-arm64-gnu": "1.0.2",
+ "@rolldown/binding-linux-arm64-musl": "1.0.2",
+ "@rolldown/binding-linux-ppc64-gnu": "1.0.2",
+ "@rolldown/binding-linux-s390x-gnu": "1.0.2",
+ "@rolldown/binding-linux-x64-gnu": "1.0.2",
+ "@rolldown/binding-linux-x64-musl": "1.0.2",
+ "@rolldown/binding-openharmony-arm64": "1.0.2",
+ "@rolldown/binding-wasm32-wasi": "1.0.2",
+ "@rolldown/binding-win32-arm64-msvc": "1.0.2",
+ "@rolldown/binding-win32-x64-msvc": "1.0.2"
}
},
"node_modules/rollup": {
@@ -10865,9 +10870,9 @@
"license": "MIT"
},
"node_modules/temml": {
- "version": "0.13.2",
- "resolved": "https://registry.npmjs.org/temml/-/temml-0.13.2.tgz",
- "integrity": "sha512-n8fDRSsLscq9nh9j6z+FgkCvFMT0IJm6GCgwfzh+7AHT3Sfb4jFTQlsA6hVcF2dYYr3b66oDBVES95RfoukyrA==",
+ "version": "0.13.3",
+ "resolved": "https://registry.npmjs.org/temml/-/temml-0.13.3.tgz",
+ "integrity": "sha512-GLNEdf5qBWux3adbOxFus4jlds8nCdEIkkKq99m/4GGTfqnsjlVlK/i371Ux7yYSg/WNmOyAkNT/GJlZoJ0v+w==",
"license": "MIT",
"engines": {
"node": ">=18.13.0"
@@ -11353,16 +11358,16 @@
}
},
"node_modules/vite": {
- "version": "8.0.13",
- "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.13.tgz",
- "integrity": "sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==",
+ "version": "8.0.14",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.14.tgz",
+ "integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==",
"dev": true,
"license": "MIT",
"dependencies": {
"lightningcss": "^1.32.0",
"picomatch": "^4.0.4",
- "postcss": "^8.5.14",
- "rolldown": "1.0.1",
+ "postcss": "^8.5.15",
+ "rolldown": "1.0.2",
"tinyglobby": "^0.2.16"
},
"bin": {
diff --git a/package.json b/package.json
index 090c9b99b3..7816d38d39 100644
--- a/package.json
+++ b/package.json
@@ -30,33 +30,33 @@
},
"dependencies": {
"@formatjs/intl-localematcher": "~0.8.8",
- "@formatjs/intl-segmenter": "~12.2.7",
+ "@formatjs/intl-segmenter": "~12.2.8",
"@formkit/auto-animate": "~0.9.0",
"@github/text-expander-element": "~2.9.4",
"@iconify-json/mingcute": "~1.2.7",
"@justinribeiro/lite-youtube": "~1.9.0",
- "@lingui/detect-locale": "~6.0.1",
- "@lingui/react": "~6.0.1",
+ "@lingui/detect-locale": "~6.1.0",
+ "@lingui/react": "~6.1.0",
"@szhsin/react-menu": "~4.5.1",
"chroma-js": "~3.2.0",
"compare-versions": "~6.1.1",
- "exifreader": "~4.38.1",
+ "exifreader": "~4.39.1",
"fast-blurhash": "~1.1.4",
"fast-equals": "~6.0.0",
"flexsearch": "~0.8.212",
"fuse.js": "~7.3.0",
"gifuct-js": "~2.1.2",
"html-prettify": "~1.0.7",
- "idb-keyval": "~6.2.2",
+ "idb-keyval": "~6.2.4",
"intl-locale-textinfo-polyfill": "~3.0.0",
- "js-cookie": "~3.0.5",
+ "js-cookie": "~3.0.7",
"just-debounce-it": "~3.2.0",
"lz-string": "~1.5.0",
"masto": "~7.11.1",
"micro-memoize": "~5.1.1",
- "p-queue": "~9.2.0",
+ "p-queue": "~9.3.0",
"p-retry": "~8.0.0",
- "preact": "10.29.1",
+ "preact": "10.29.2",
"punycode": "~2.3.1",
"qr": "~0.6.0",
"react-hotkeys-hook": "~5.2.4",
@@ -64,7 +64,7 @@
"react-quick-pinch-zoom": "~5.1.1",
"react-router-dom": "6.6.2",
"swiped-events": "~1.2.0",
- "temml": "~0.13.2",
+ "temml": "~0.13.3",
"tinyld": "~1.3.4",
"toastify-js": "~1.12.0",
"uid": "~2.0.2",
@@ -78,20 +78,20 @@
"@emnapi/core": "~1.10.0",
"@emnapi/runtime": "~1.10.0",
"@iconify/utils": "~3.1.3",
- "@lingui/babel-plugin-lingui-macro": "~6.0.1",
- "@lingui/cli": "~6.0.1",
- "@lingui/vite-plugin": "~6.0.1",
+ "@lingui/babel-plugin-lingui-macro": "~6.1.0",
+ "@lingui/cli": "~6.1.0",
+ "@lingui/vite-plugin": "~6.1.0",
"@playwright/test": "~1.60.0",
"@preact/preset-vite": "~2.10.5",
- "@types/node": "~25.8.0",
- "oxfmt": "~0.49.0",
- "postcss": "~8.5.14",
+ "@types/node": "~25.9.1",
+ "oxfmt": "~0.52.0",
+ "postcss": "~8.5.15",
"postcss-dark-theme-class": "~2.0.0",
"postcss-preset-env": "~11.3.0",
"prop-types": "^15.8.1",
"sonda": "~0.11.1",
"twitter-text": "~3.1.0",
- "vite": "~8.0.13",
+ "vite": "~8.0.14",
"vite-plugin-generate-file": "~0.3.1",
"vite-plugin-html-config": "~2.0.2",
"vite-plugin-pwa": "~1.3.0",
diff --git a/src/components/background-service.jsx b/src/components/background-service.jsx
index bbc9273e56..89ad817308 100644
--- a/src/components/background-service.jsx
+++ b/src/components/background-service.jsx
@@ -66,24 +66,30 @@ export default memo(function BackgroundService() {
let sub;
let streamTimeout;
let pollNotifications;
+ let cancelled = false;
if (isLoggedIn && visible) {
const { masto, streaming, instance } = api();
(async () => {
// 1. Get the latest notification
await checkLatestNotification(masto, instance);
- let hasStreaming = false;
- // 2. Start streaming
+ const startPolling = () => {
+ if (cancelled) return;
+ console.log('🎏 Fallback to polling');
+ pollNotifications = setInterval(() => {
+ checkLatestNotification(masto, instance, true);
+ }, POLL_INTERVAL);
+ };
+
+ // 2. Start streaming or fall back to polling
if (streaming) {
streamTimeout = setTimeout(() => {
(async () => {
try {
- hasStreaming = true;
sub = streaming.user.notification.subscribe();
console.log('🎏 Streaming notification', sub);
for await (const entry of sub) {
- if (!sub) break;
- if (!visible) break;
+ if (cancelled || !sub) break;
console.log('🔔🔔 Notification entry', entry);
if (entry.event === 'notification') {
console.log('🔔🔔 Notification', entry);
@@ -95,22 +101,20 @@ export default memo(function BackgroundService() {
}
console.log('💥 Streaming notification loop STOPPED');
} catch (e) {
- hasStreaming = false;
- console.error(e);
+ console.error('💥 Streaming error', e);
}
- if (!hasStreaming) {
- console.log('🎏 Streaming failed, fallback to polling');
- pollNotifications = setInterval(() => {
- checkLatestNotification(masto, instance, true);
- }, POLL_INTERVAL);
- }
+ startPolling();
})();
}, STREAMING_TIMEOUT);
+ } else {
+ console.log('🎏 No streaming available, polling directly');
+ startPolling();
}
})();
}
return () => {
+ cancelled = true;
sub?.unsubscribe?.();
sub = null;
clearTimeout(streamTimeout);
diff --git a/src/components/media-modal.jsx b/src/components/media-modal.jsx
index 5b5d1097ee..4c9e730d92 100644
--- a/src/components/media-modal.jsx
+++ b/src/components/media-modal.jsx
@@ -113,6 +113,27 @@ function MediaModal({
};
}, []);
+ const prevIndexRef = useRef(currentIndex);
+ useEffect(() => {
+ const prevIndex = prevIndexRef.current;
+ prevIndexRef.current = currentIndex;
+ if (prevIndex === currentIndex) return;
+
+ const carousel = carouselRef.current;
+ if (!carousel) return;
+
+ carousel.querySelectorAll('video, audio').forEach((el) => {
+ if (el.muted) return;
+ const item = el.closest('.carousel-item');
+ if (item) {
+ const idx = Array.from(item.parentNode.children).indexOf(item);
+ if (idx !== currentIndex) {
+ el.pause();
+ }
+ }
+ });
+ }, [currentIndex]);
+
useEffect(() => {
let timer = setTimeout(() => {
carouselRef.current?.focus?.();
@@ -319,7 +340,12 @@ function MediaModal({
)}
- {
@@ -303,7 +306,8 @@ function Timeline({
if (!value.length) done = true;
setShowMore(!done);
} else {
- // Iterator error state returns undefined - treat as error, not end of list
+ // Iterator returned unexpected data type
+ console.warn('Unexpected iterator result', { done, value });
throw new Error('Timeline load failed');
}
setUIState('default');
@@ -703,26 +707,16 @@ export const TimelineItem = memo(
const filteredItemsIDs = new Set();
// Here, we don't hide filtered posts, but we sort them last
fItems.sort((a, b) => {
- // if (a._filtered && !b._filtered) {
- // return 1;
- // }
- // if (!a._filtered && b._filtered) {
- // return -1;
- // }
const aFiltered = isFiltered(a.filtered, filterContext);
const bFiltered = isFiltered(b.filtered, filterContext);
- if (aFiltered && aFiltered?.action !== 'blur') {
- filteredItemsIDs.add(a.id);
- }
- if (bFiltered && bFiltered?.action !== 'blur') {
- filteredItemsIDs.add(b.id);
- }
- if (aFiltered && !bFiltered) {
- return 1;
- }
- if (!aFiltered && bFiltered) {
- return -1;
- }
+ const aShouldSort = aFiltered && aFiltered.action !== 'blur';
+ const bShouldSort = bFiltered && bFiltered.action !== 'blur';
+
+ if (aShouldSort) filteredItemsIDs.add(a.id);
+ if (bShouldSort) filteredItemsIDs.add(b.id);
+
+ if (aShouldSort && !bShouldSort) return 1;
+ if (!aShouldSort && bShouldSort) return -1;
return 0;
});
diff --git a/src/components/timeline2.jsx b/src/components/timeline2.jsx
index 8803f3d93f..bad10e5a66 100644
--- a/src/components/timeline2.jsx
+++ b/src/components/timeline2.jsx
@@ -283,8 +283,14 @@ function Timeline2({
const { max_id, min_id } = params;
let { value, originalValue, done } = result;
- // Iterator error state returns undefined - treat as error, not end of list
- if (value === undefined || value === null) {
+ if (done && (value === undefined || value === null)) {
+ // Iterator has completed (no more pages)
+ setShowOlder(false);
+ setShowNewer(false);
+ setUIState('default');
+ __BENCHMARK.end(`timeline-${id}-load`);
+ return;
+ } else if (value === undefined || value === null) {
throw new Error('Timeline load failed');
}
diff --git a/src/locales/ca-ES.po b/src/locales/ca-ES.po
index 1cb52e1dab..5ca9f6a2d3 100644
--- a/src/locales/ca-ES.po
+++ b/src/locales/ca-ES.po
@@ -8,7 +8,7 @@ msgstr ""
"Language: ca\n"
"Project-Id-Version: phanpy\n"
"Report-Msgid-Bugs-To: \n"
-"PO-Revision-Date: 2026-05-19 09:37\n"
+"PO-Revision-Date: 2026-05-21 20:52\n"
"Last-Translator: \n"
"Language-Team: Catalan\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -4200,7 +4200,7 @@ msgstr "Ajudeu a traduir"
#: src/pages/settings.jsx:255
msgid "Keep navigation bars visible while scrolling"
-msgstr ""
+msgstr "Manté les barres de navegació visibles en desplaçar-se"
#: src/pages/settings.jsx:263
msgid "Posting"
diff --git a/src/locales/en.po b/src/locales/en.po
index 9dbd4d6d56..0d3a1df775 100644
--- a/src/locales/en.po
+++ b/src/locales/en.po
@@ -43,17 +43,17 @@ msgid "Mutual"
msgstr ""
#: src/components/account-block.jsx:193
-#: src/components/related-actions.jsx:957
+#: src/components/related-actions.jsx:962
msgid "Requested"
msgstr ""
#: src/components/account-block.jsx:197
-#: src/components/related-actions.jsx:948
+#: src/components/related-actions.jsx:953
msgid "Following"
msgstr ""
#: src/components/account-block.jsx:201
-#: src/components/related-actions.jsx:200
+#: src/components/related-actions.jsx:205
msgid "Follows you"
msgstr ""
@@ -135,8 +135,8 @@ msgid "Go to account page"
msgstr "Go to account page"
#: src/components/account-info.jsx:417
-#: src/components/timeline.jsx:659
-#: src/components/timeline2.jsx:695
+#: src/components/timeline.jsx:663
+#: src/components/timeline2.jsx:701
#: src/pages/home.jsx:237
#: src/pages/notifications.jsx:1035
#: src/pages/status.jsx:1270
@@ -149,23 +149,23 @@ msgid "<0>{displayName}0> has indicated that their new account is now:"
msgstr "<0>{displayName}0> has indicated that their new account is now:"
#: src/components/account-info.jsx:627
-#: src/components/related-actions.jsx:513
+#: src/components/related-actions.jsx:518
msgid "Handle copied"
msgstr "Handle copied"
#: src/components/account-info.jsx:630
-#: src/components/related-actions.jsx:516
+#: src/components/related-actions.jsx:521
msgid "Unable to copy handle"
msgstr "Unable to copy handle"
#: src/components/account-info.jsx:636
-#: src/components/related-actions.jsx:522
+#: src/components/related-actions.jsx:527
msgid "Copy handle"
msgstr ""
#: src/components/account-info.jsx:654
-#: src/components/related-actions.jsx:587
-#: src/components/related-actions.jsx:862
+#: src/components/related-actions.jsx:592
+#: src/components/related-actions.jsx:867
#: src/components/shortcuts-settings.jsx:1099
msgid "QR code"
msgstr "QR code"
@@ -184,7 +184,7 @@ msgstr "View profile header"
#: src/components/account-info.jsx:714
#: src/components/edit-profile-sheet.jsx:267
-#: src/components/related-actions.jsx:876
+#: src/components/related-actions.jsx:881
msgid "Edit profile"
msgstr ""
@@ -284,7 +284,7 @@ msgstr "View post stats"
#: src/components/list-add-edit.jsx:37
#: src/components/media-alt-modal.jsx:43
#: src/components/media-attachment.jsx:420
-#: src/components/media-modal.jsx:336
+#: src/components/media-modal.jsx:362
#: src/components/mention-modal.jsx:162
#: src/components/notification-service.jsx:157
#: src/components/open-link-sheet.jsx:51
@@ -314,8 +314,8 @@ msgid "Close"
msgstr ""
#: src/components/add-remove-lists-sheet.jsx:50
-#: src/components/related-actions.jsx:463
-#: src/components/related-actions.jsx:473
+#: src/components/related-actions.jsx:468
+#: src/components/related-actions.jsx:478
msgid "Add/Remove from Lists"
msgstr ""
@@ -342,11 +342,11 @@ msgstr ""
msgid "New list"
msgstr ""
-#: src/components/background-service.jsx:160
+#: src/components/background-service.jsx:164
msgid "Cloak mode disabled"
msgstr ""
-#: src/components/background-service.jsx:160
+#: src/components/background-service.jsx:164
msgid "Cloak mode enabled"
msgstr ""
@@ -362,8 +362,8 @@ msgstr "Collection by <0>@{username}0>"
#: src/components/columns.jsx:29
#: src/components/nav-menu.jsx:187
#: src/components/shortcuts-settings.jsx:142
-#: src/components/timeline.jsx:542
-#: src/components/timeline2.jsx:574
+#: src/components/timeline.jsx:546
+#: src/components/timeline2.jsx:580
#: src/pages/catchup.jsx:1027
#: src/pages/filters.jsx:90
#: src/pages/followed-hashtags.jsx:41
@@ -525,7 +525,7 @@ msgstr "Attachment #{i} failed"
#: src/components/compose.jsx:1514
#: src/components/status.jsx:2555
-#: src/components/timeline.jsx:1068
+#: src/components/timeline.jsx:1062
msgid "Content warning"
msgstr ""
@@ -755,15 +755,15 @@ msgstr "Edit History Snapshots"
#: src/components/edit-history-controls.jsx:35
#: src/components/gif-picker-modal.jsx:208
-#: src/components/media-modal.jsx:478
-#: src/components/timeline.jsx:981
+#: src/components/media-modal.jsx:504
+#: src/components/timeline.jsx:975
msgid "Previous"
msgstr ""
#: src/components/edit-history-controls.jsx:47
#: src/components/gif-picker-modal.jsx:226
-#: src/components/media-modal.jsx:497
-#: src/components/timeline.jsx:998
+#: src/components/media-modal.jsx:523
+#: src/components/timeline.jsx:992
msgid "Next"
msgstr ""
@@ -774,8 +774,8 @@ msgstr "Exit"
#: src/components/edit-profile-sheet.jsx:87
#: src/components/media-alt-modal.jsx:55
#: src/components/media-attachment.jsx:465
-#: src/components/media-modal.jsx:372
-#: src/components/related-actions.jsx:256
+#: src/components/media-modal.jsx:398
+#: src/components/related-actions.jsx:261
#: src/components/status.jsx:2211
#: src/components/status.jsx:2228
#: src/components/status.jsx:2360
@@ -935,7 +935,7 @@ msgstr ""
#: src/components/generic-accounts.jsx:214
#: src/components/quotes-modal.jsx:129
-#: src/components/timeline.jsx:624
+#: src/components/timeline.jsx:628
#: src/pages/list.jsx:321
#: src/pages/notifications.jsx:1059
#: src/pages/search.jsx:576
@@ -946,8 +946,8 @@ msgstr ""
#: src/components/generic-accounts.jsx:219
#: src/components/quote-chain-modal.jsx:169
#: src/components/quotes-modal.jsx:133
-#: src/components/timeline.jsx:629
-#: src/components/timeline2.jsx:673
+#: src/components/timeline.jsx:633
+#: src/components/timeline2.jsx:679
#: src/pages/search.jsx:581
msgid "The end."
msgstr ""
@@ -1370,27 +1370,27 @@ msgstr ""
msgid "Done"
msgstr ""
-#: src/components/media-modal.jsx:383
+#: src/components/media-modal.jsx:409
msgid "Open original media in new window"
msgstr ""
-#: src/components/media-modal.jsx:387
+#: src/components/media-modal.jsx:413
msgid "Open original media"
msgstr ""
-#: src/components/media-modal.jsx:403
+#: src/components/media-modal.jsx:429
msgid "Attempting to describe image. Please wait…"
msgstr ""
-#: src/components/media-modal.jsx:418
+#: src/components/media-modal.jsx:444
msgid "Failed to describe image"
msgstr ""
-#: src/components/media-modal.jsx:428
+#: src/components/media-modal.jsx:454
msgid "Describe image…"
msgstr ""
-#: src/components/media-modal.jsx:452
+#: src/components/media-modal.jsx:478
msgid "View post"
msgstr ""
@@ -1406,13 +1406,13 @@ msgstr ""
#: src/components/status-compact.jsx:74
#: src/components/status.jsx:3618
#: src/components/status.jsx:3696
-#: src/components/timeline.jsx:1057
+#: src/components/timeline.jsx:1051
#: src/pages/catchup.jsx:79
#: src/pages/catchup.jsx:2052
msgid "Filtered"
msgstr ""
-#: src/components/media.jsx:532
+#: src/components/media.jsx:533
msgid "Open file"
msgstr "Open file"
@@ -1774,13 +1774,13 @@ msgid "Read more →"
msgstr ""
#: src/components/open-link-sheet.jsx:30
-#: src/components/related-actions.jsx:539
+#: src/components/related-actions.jsx:544
#: src/components/status.jsx:1489
msgid "Link copied"
msgstr ""
#: src/components/open-link-sheet.jsx:33
-#: src/components/related-actions.jsx:542
+#: src/components/related-actions.jsx:547
#: src/components/status.jsx:1492
msgid "Unable to copy link"
msgstr ""
@@ -1791,14 +1791,14 @@ msgstr "Open link?"
#: src/components/open-link-sheet.jsx:78
#: src/components/post-embed-modal.jsx:232
-#: src/components/related-actions.jsx:548
+#: src/components/related-actions.jsx:553
#: src/components/shortcuts-settings.jsx:1175
#: src/components/status.jsx:1498
msgid "Copy"
msgstr ""
#: src/components/open-link-sheet.jsx:82
-#: src/components/related-actions.jsx:569
+#: src/components/related-actions.jsx:574
#: src/components/status.jsx:1520
msgid "Share…"
msgstr ""
@@ -1940,7 +1940,7 @@ msgid "Note: This preview is lightly styled."
msgstr ""
#: src/components/private-note-sheet.jsx:41
-#: src/components/related-actions.jsx:232
+#: src/components/related-actions.jsx:237
msgid "Notes"
msgstr "Notes"
@@ -2037,195 +2037,195 @@ msgid "Forever"
msgstr ""
#. placeholder {0}: niceDateTime(lastStatusAt, { hideTime: true, })
-#: src/components/related-actions.jsx:204
+#: src/components/related-actions.jsx:209
msgid "Last post: <0>{0}0>"
msgstr ""
-#: src/components/related-actions.jsx:218
+#: src/components/related-actions.jsx:223
msgid "Muted"
msgstr ""
-#: src/components/related-actions.jsx:223
+#: src/components/related-actions.jsx:228
msgid "Blocked"
msgstr ""
-#: src/components/related-actions.jsx:289
+#: src/components/related-actions.jsx:294
msgid "Mention <0>@{username}0>"
msgstr ""
-#: src/components/related-actions.jsx:302
+#: src/components/related-actions.jsx:307
msgid "Search <0>@{username}0>'s posts"
msgstr "Search <0>@{username}0>'s posts"
-#: src/components/related-actions.jsx:316
+#: src/components/related-actions.jsx:321
msgid "Translate bio"
msgstr ""
-#: src/components/related-actions.jsx:326
+#: src/components/related-actions.jsx:331
msgid "Edit notes"
msgstr "Edit notes"
-#: src/components/related-actions.jsx:326
+#: src/components/related-actions.jsx:331
msgid "Add notes"
msgstr "Add notes"
-#: src/components/related-actions.jsx:345
+#: src/components/related-actions.jsx:350
msgid "Notifications enabled for @{username}'s posts."
msgstr "Notifications enabled for @{username}'s posts."
-#: src/components/related-actions.jsx:346
+#: src/components/related-actions.jsx:351
msgid " Notifications disabled for @{username}'s posts."
msgstr " Notifications disabled for @{username}'s posts."
-#: src/components/related-actions.jsx:358
+#: src/components/related-actions.jsx:363
msgid "Disable notifications"
msgstr "Disable notifications"
-#: src/components/related-actions.jsx:359
+#: src/components/related-actions.jsx:364
msgid "Enable notifications"
msgstr "Enable notifications"
-#: src/components/related-actions.jsx:376
+#: src/components/related-actions.jsx:381
msgid "Boosts from @{username} enabled."
msgstr "Boosts from @{username} enabled."
-#: src/components/related-actions.jsx:377
+#: src/components/related-actions.jsx:382
msgid "Boosts from @{username} disabled."
msgstr "Boosts from @{username} disabled."
-#: src/components/related-actions.jsx:388
+#: src/components/related-actions.jsx:393
msgid "Disable boosts"
msgstr "Disable boosts"
-#: src/components/related-actions.jsx:388
+#: src/components/related-actions.jsx:393
msgid "Enable boosts"
msgstr "Enable boosts"
-#: src/components/related-actions.jsx:407
+#: src/components/related-actions.jsx:412
msgid "@{username} is no longer featured on your profile."
msgstr "@{username} is no longer featured on your profile."
-#: src/components/related-actions.jsx:417
+#: src/components/related-actions.jsx:422
msgid "@{username} is now featured on your profile."
msgstr "@{username} is now featured on your profile."
-#: src/components/related-actions.jsx:425
+#: src/components/related-actions.jsx:430
msgid "Unable to unfeature @{username} on your profile."
msgstr "Unable to unfeature @{username} on your profile."
-#: src/components/related-actions.jsx:429
+#: src/components/related-actions.jsx:434
msgid "Unable to feature @{username} on your profile."
msgstr "Unable to feature @{username} on your profile."
-#: src/components/related-actions.jsx:438
+#: src/components/related-actions.jsx:443
msgid "Don't feature on profile"
msgstr "Don't feature on profile"
-#: src/components/related-actions.jsx:439
+#: src/components/related-actions.jsx:444
#: src/pages/hashtag.jsx:362
msgid "Feature on profile"
msgstr ""
-#: src/components/related-actions.jsx:448
-#: src/components/related-actions.jsx:498
+#: src/components/related-actions.jsx:453
+#: src/components/related-actions.jsx:503
msgid "Show featured profiles"
msgstr "Show featured profiles"
-#: src/components/related-actions.jsx:490
+#: src/components/related-actions.jsx:495
#: src/pages/account-statuses.jsx:578
msgid "Search my posts"
msgstr "Search my posts"
-#: src/components/related-actions.jsx:563
+#: src/components/related-actions.jsx:568
#: src/components/shortcuts-settings.jsx:1193
#: src/components/status.jsx:1514
msgid "Sharing doesn't seem to work."
msgstr ""
-#: src/components/related-actions.jsx:605
+#: src/components/related-actions.jsx:610
msgid "Unmuted @{username}"
msgstr "Unmuted @{username}"
-#: src/components/related-actions.jsx:617
+#: src/components/related-actions.jsx:622
msgid "Unmute <0>@{username}0>"
msgstr "Unmute <0>@{username}0>"
-#: src/components/related-actions.jsx:633
+#: src/components/related-actions.jsx:638
msgid "Mute <0>@{username}0>…"
msgstr ""
#. placeholder {0}: typeof MUTE_DURATIONS_LABELS[duration] === 'function' ? MUTE_DURATIONS_LABELS[duration]() : _(MUTE_DURATIONS_LABELS[duration])
-#: src/components/related-actions.jsx:665
+#: src/components/related-actions.jsx:670
msgid "Muted @{username} for {0}"
msgstr "Muted @{username} for {0}"
-#: src/components/related-actions.jsx:677
+#: src/components/related-actions.jsx:682
msgid "Unable to mute @{username}"
msgstr "Unable to mute @{username}"
-#: src/components/related-actions.jsx:698
+#: src/components/related-actions.jsx:703
msgid "Remove <0>@{username}0> from followers?"
msgstr ""
-#: src/components/related-actions.jsx:718
+#: src/components/related-actions.jsx:723
msgid "@{username} removed from followers"
msgstr "@{username} removed from followers"
-#: src/components/related-actions.jsx:730
+#: src/components/related-actions.jsx:735
msgid "Remove follower…"
msgstr ""
-#: src/components/related-actions.jsx:741
+#: src/components/related-actions.jsx:746
msgid "Block <0>@{username}0>?"
msgstr ""
-#: src/components/related-actions.jsx:765
+#: src/components/related-actions.jsx:770
msgid "Unblocked @{username}"
msgstr "Unblocked @{username}"
-#: src/components/related-actions.jsx:773
+#: src/components/related-actions.jsx:778
msgid "Blocked @{username}"
msgstr "Blocked @{username}"
-#: src/components/related-actions.jsx:781
+#: src/components/related-actions.jsx:786
msgid "Unable to unblock @{username}"
msgstr "Unable to unblock @{username}"
-#: src/components/related-actions.jsx:783
+#: src/components/related-actions.jsx:788
msgid "Unable to block @{username}"
msgstr "Unable to block @{username}"
-#: src/components/related-actions.jsx:793
+#: src/components/related-actions.jsx:798
msgid "Unblock <0>@{username}0>"
msgstr ""
-#: src/components/related-actions.jsx:802
+#: src/components/related-actions.jsx:807
msgid "Block <0>@{username}0>…"
msgstr ""
-#: src/components/related-actions.jsx:819
+#: src/components/related-actions.jsx:824
msgid "Report <0>@{username}0>…"
msgstr ""
-#: src/components/related-actions.jsx:887
+#: src/components/related-actions.jsx:892
msgid "Withdraw follow request?"
msgstr "Withdraw follow request?"
#. placeholder {0}: info.acct || info.username
-#: src/components/related-actions.jsx:888
+#: src/components/related-actions.jsx:893
msgid "Unfollow @{0}?"
msgstr "Unfollow @{0}?"
-#: src/components/related-actions.jsx:951
+#: src/components/related-actions.jsx:956
msgid "Unfollow…"
msgstr ""
-#: src/components/related-actions.jsx:960
+#: src/components/related-actions.jsx:965
msgid "Withdraw…"
msgstr ""
-#: src/components/related-actions.jsx:967
-#: src/components/related-actions.jsx:971
+#: src/components/related-actions.jsx:972
+#: src/components/related-actions.jsx:976
#: src/pages/hashtag.jsx:294
msgid "Follow"
msgstr ""
@@ -3051,22 +3051,22 @@ msgstr "{index}/{total}"
msgid "{index}/X"
msgstr "{index}/X"
-#: src/components/timeline.jsx:558
+#: src/components/timeline.jsx:562
#: src/pages/settings.jsx:1373
msgid "New posts"
msgstr ""
#. placeholder {0}: fItems.length
-#: src/components/timeline.jsx:694
+#: src/components/timeline.jsx:698
msgid "{0, plural, one {# Boost} other {# Boosts}}"
msgstr "{0, plural, one {# Boost} other {# Boosts}}"
-#: src/components/timeline.jsx:699
+#: src/components/timeline.jsx:703
msgid "Pinned posts"
msgstr "Pinned posts"
#. placeholder {0}: filterInfo.titlesStr
-#: src/components/timeline.jsx:1052
+#: src/components/timeline.jsx:1046
msgid "<0>Filtered0>: <1>{0}1>"
msgstr ""
diff --git a/src/locales/it-IT.po b/src/locales/it-IT.po
index 7690aaef81..68db6dc733 100644
--- a/src/locales/it-IT.po
+++ b/src/locales/it-IT.po
@@ -8,7 +8,7 @@ msgstr ""
"Language: it\n"
"Project-Id-Version: phanpy\n"
"Report-Msgid-Bugs-To: \n"
-"PO-Revision-Date: 2026-05-19 09:38\n"
+"PO-Revision-Date: 2026-05-25 21:28\n"
"Last-Translator: \n"
"Language-Team: Italian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -347,11 +347,11 @@ msgstr "Nessuna lista."
msgid "New list"
msgstr "Nuova lista"
-#: src/components/background-service.jsx:160
+#: src/components/background-service.jsx:164
msgid "Cloak mode disabled"
msgstr "Modalità mantello disattivata"
-#: src/components/background-service.jsx:160
+#: src/components/background-service.jsx:164
msgid "Cloak mode enabled"
msgstr "Modalità mantello attivata"
@@ -4199,7 +4199,7 @@ msgstr "Traduzioni volontarie"
#: src/pages/settings.jsx:255
msgid "Keep navigation bars visible while scrolling"
-msgstr ""
+msgstr "Mantieni le barre di navigazione visibili durante lo scorrimento"
#: src/pages/settings.jsx:263
msgid "Posting"
diff --git a/src/locales/pl-PL.po b/src/locales/pl-PL.po
index de78bcf975..9de2f88038 100644
--- a/src/locales/pl-PL.po
+++ b/src/locales/pl-PL.po
@@ -8,7 +8,7 @@ msgstr ""
"Language: pl\n"
"Project-Id-Version: phanpy\n"
"Report-Msgid-Bugs-To: \n"
-"PO-Revision-Date: 2026-05-19 09:38\n"
+"PO-Revision-Date: 2026-06-03 09:14\n"
"Last-Translator: \n"
"Language-Team: Polish\n"
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
@@ -48,17 +48,17 @@ msgid "Mutual"
msgstr "Znajomi"
#: src/components/account-block.jsx:193
-#: src/components/related-actions.jsx:957
+#: src/components/related-actions.jsx:962
msgid "Requested"
msgstr "Oczekująca prośba"
#: src/components/account-block.jsx:197
-#: src/components/related-actions.jsx:948
+#: src/components/related-actions.jsx:953
msgid "Following"
msgstr "Obserwujesz"
#: src/components/account-block.jsx:201
-#: src/components/related-actions.jsx:200
+#: src/components/related-actions.jsx:205
msgid "Follows you"
msgstr "Obserwuje cię"
@@ -140,8 +140,8 @@ msgid "Go to account page"
msgstr "Przejdź na stronę konta"
#: src/components/account-info.jsx:417
-#: src/components/timeline.jsx:659
-#: src/components/timeline2.jsx:695
+#: src/components/timeline.jsx:663
+#: src/components/timeline2.jsx:701
#: src/pages/home.jsx:237
#: src/pages/notifications.jsx:1035
#: src/pages/status.jsx:1270
@@ -154,23 +154,23 @@ msgid "<0>{displayName}0> has indicated that their new account is now:"
msgstr "<0>{displayName}0> używa teraz nowego konta:"
#: src/components/account-info.jsx:627
-#: src/components/related-actions.jsx:513
+#: src/components/related-actions.jsx:518
msgid "Handle copied"
msgstr "Skopiowano identyfikator"
#: src/components/account-info.jsx:630
-#: src/components/related-actions.jsx:516
+#: src/components/related-actions.jsx:521
msgid "Unable to copy handle"
msgstr "Nie udało się skopiować identyfikatora"
#: src/components/account-info.jsx:636
-#: src/components/related-actions.jsx:522
+#: src/components/related-actions.jsx:527
msgid "Copy handle"
msgstr "Kopiuj identyfikator"
#: src/components/account-info.jsx:654
-#: src/components/related-actions.jsx:587
-#: src/components/related-actions.jsx:862
+#: src/components/related-actions.jsx:592
+#: src/components/related-actions.jsx:867
#: src/components/shortcuts-settings.jsx:1099
msgid "QR code"
msgstr "Kod QR"
@@ -189,7 +189,7 @@ msgstr "Pokaż baner profilu"
#: src/components/account-info.jsx:714
#: src/components/edit-profile-sheet.jsx:267
-#: src/components/related-actions.jsx:876
+#: src/components/related-actions.jsx:881
msgid "Edit profile"
msgstr "Edytuj profil"
@@ -289,7 +289,7 @@ msgstr "Pokaż statystyki wpisów"
#: src/components/list-add-edit.jsx:37
#: src/components/media-alt-modal.jsx:43
#: src/components/media-attachment.jsx:420
-#: src/components/media-modal.jsx:336
+#: src/components/media-modal.jsx:362
#: src/components/mention-modal.jsx:162
#: src/components/notification-service.jsx:157
#: src/components/open-link-sheet.jsx:51
@@ -319,8 +319,8 @@ msgid "Close"
msgstr "Zamknij"
#: src/components/add-remove-lists-sheet.jsx:50
-#: src/components/related-actions.jsx:463
-#: src/components/related-actions.jsx:473
+#: src/components/related-actions.jsx:468
+#: src/components/related-actions.jsx:478
msgid "Add/Remove from Lists"
msgstr "Dodaj/usuń z list"
@@ -347,11 +347,11 @@ msgstr "Brak list."
msgid "New list"
msgstr "Nowa lista"
-#: src/components/background-service.jsx:160
+#: src/components/background-service.jsx:164
msgid "Cloak mode disabled"
msgstr "Tryb \"maskowanie\" jest wyłączony"
-#: src/components/background-service.jsx:160
+#: src/components/background-service.jsx:164
msgid "Cloak mode enabled"
msgstr "Tryb \"maskowanie\" jest włączony"
@@ -367,8 +367,8 @@ msgstr "Kolekcja autorstwa: <0>@{username}0>"
#: src/components/columns.jsx:29
#: src/components/nav-menu.jsx:187
#: src/components/shortcuts-settings.jsx:142
-#: src/components/timeline.jsx:542
-#: src/components/timeline2.jsx:574
+#: src/components/timeline.jsx:546
+#: src/components/timeline2.jsx:580
#: src/pages/catchup.jsx:1027
#: src/pages/filters.jsx:90
#: src/pages/followed-hashtags.jsx:41
@@ -530,7 +530,7 @@ msgstr "Załączenie #{i} nie powiodło się"
#: src/components/compose.jsx:1514
#: src/components/status.jsx:2555
-#: src/components/timeline.jsx:1068
+#: src/components/timeline.jsx:1062
msgid "Content warning"
msgstr "Ostrzeżenie o zawartości"
@@ -760,15 +760,15 @@ msgstr "Historia edytowania"
#: src/components/edit-history-controls.jsx:35
#: src/components/gif-picker-modal.jsx:208
-#: src/components/media-modal.jsx:478
-#: src/components/timeline.jsx:981
+#: src/components/media-modal.jsx:504
+#: src/components/timeline.jsx:975
msgid "Previous"
msgstr "Poprzednie"
#: src/components/edit-history-controls.jsx:47
#: src/components/gif-picker-modal.jsx:226
-#: src/components/media-modal.jsx:497
-#: src/components/timeline.jsx:998
+#: src/components/media-modal.jsx:523
+#: src/components/timeline.jsx:992
msgid "Next"
msgstr "Następne"
@@ -779,8 +779,8 @@ msgstr "Wyjdź"
#: src/components/edit-profile-sheet.jsx:87
#: src/components/media-alt-modal.jsx:55
#: src/components/media-attachment.jsx:465
-#: src/components/media-modal.jsx:372
-#: src/components/related-actions.jsx:256
+#: src/components/media-modal.jsx:398
+#: src/components/related-actions.jsx:261
#: src/components/status.jsx:2211
#: src/components/status.jsx:2228
#: src/components/status.jsx:2360
@@ -940,7 +940,7 @@ msgstr "Konta"
#: src/components/generic-accounts.jsx:214
#: src/components/quotes-modal.jsx:129
-#: src/components/timeline.jsx:624
+#: src/components/timeline.jsx:628
#: src/pages/list.jsx:321
#: src/pages/notifications.jsx:1059
#: src/pages/search.jsx:576
@@ -951,8 +951,8 @@ msgstr "Pokaż więcej…"
#: src/components/generic-accounts.jsx:219
#: src/components/quote-chain-modal.jsx:169
#: src/components/quotes-modal.jsx:133
-#: src/components/timeline.jsx:629
-#: src/components/timeline2.jsx:673
+#: src/components/timeline.jsx:633
+#: src/components/timeline2.jsx:679
#: src/pages/search.jsx:581
msgid "The end."
msgstr "Koniec."
@@ -1375,27 +1375,27 @@ msgstr "({0}) <0>— eksperymentalne0>"
msgid "Done"
msgstr "Zrobione"
-#: src/components/media-modal.jsx:383
+#: src/components/media-modal.jsx:409
msgid "Open original media in new window"
msgstr "Otwórz oryginalny plik w nowym oknie"
-#: src/components/media-modal.jsx:387
+#: src/components/media-modal.jsx:413
msgid "Open original media"
msgstr "Otwórz oryginalny plik"
-#: src/components/media-modal.jsx:403
+#: src/components/media-modal.jsx:429
msgid "Attempting to describe image. Please wait…"
msgstr "Próba opisania obrazka. Proszę czekać..."
-#: src/components/media-modal.jsx:418
+#: src/components/media-modal.jsx:444
msgid "Failed to describe image"
msgstr "Błąd podczas opisywania obrazka"
-#: src/components/media-modal.jsx:428
+#: src/components/media-modal.jsx:454
msgid "Describe image…"
msgstr "Opisz obrazek"
-#: src/components/media-modal.jsx:452
+#: src/components/media-modal.jsx:478
msgid "View post"
msgstr "Zobacz wpis"
@@ -1411,13 +1411,13 @@ msgstr "Odfiltrowano: {filterTitleStr}"
#: src/components/status-compact.jsx:74
#: src/components/status.jsx:3618
#: src/components/status.jsx:3696
-#: src/components/timeline.jsx:1057
+#: src/components/timeline.jsx:1051
#: src/pages/catchup.jsx:79
#: src/pages/catchup.jsx:2052
msgid "Filtered"
msgstr "Odfiltrowane"
-#: src/components/media.jsx:532
+#: src/components/media.jsx:533
msgid "Open file"
msgstr "Otwórz plik"
@@ -1779,13 +1779,13 @@ msgid "Read more →"
msgstr "Więcej →"
#: src/components/open-link-sheet.jsx:30
-#: src/components/related-actions.jsx:539
+#: src/components/related-actions.jsx:544
#: src/components/status.jsx:1489
msgid "Link copied"
msgstr "Skopiowano odnośnik"
#: src/components/open-link-sheet.jsx:33
-#: src/components/related-actions.jsx:542
+#: src/components/related-actions.jsx:547
#: src/components/status.jsx:1492
msgid "Unable to copy link"
msgstr "Nie udało się skopiować odnośnika"
@@ -1796,14 +1796,14 @@ msgstr "Otworzyć link?"
#: src/components/open-link-sheet.jsx:78
#: src/components/post-embed-modal.jsx:232
-#: src/components/related-actions.jsx:548
+#: src/components/related-actions.jsx:553
#: src/components/shortcuts-settings.jsx:1175
#: src/components/status.jsx:1498
msgid "Copy"
msgstr "Kopiuj"
#: src/components/open-link-sheet.jsx:82
-#: src/components/related-actions.jsx:569
+#: src/components/related-actions.jsx:574
#: src/components/status.jsx:1520
msgid "Share…"
msgstr "Udostępnij…"
@@ -1945,7 +1945,7 @@ msgid "Note: This preview is lightly styled."
msgstr "Uwaga: podgląd jest lekko stylizowany."
#: src/components/private-note-sheet.jsx:41
-#: src/components/related-actions.jsx:232
+#: src/components/related-actions.jsx:237
msgid "Notes"
msgstr "Notki"
@@ -2042,195 +2042,195 @@ msgid "Forever"
msgstr "Na zawsze"
#. placeholder {0}: niceDateTime(lastStatusAt, { hideTime: true, })
-#: src/components/related-actions.jsx:204
+#: src/components/related-actions.jsx:209
msgid "Last post: <0>{0}0>"
msgstr "Ostatni wpis: <0>{0}0>"
-#: src/components/related-actions.jsx:218
+#: src/components/related-actions.jsx:223
msgid "Muted"
msgstr "Wyciszono"
-#: src/components/related-actions.jsx:223
+#: src/components/related-actions.jsx:228
msgid "Blocked"
msgstr "Zablokowano"
-#: src/components/related-actions.jsx:289
+#: src/components/related-actions.jsx:294
msgid "Mention <0>@{username}0>"
msgstr "Wspomnij o <0>@{username}0>"
-#: src/components/related-actions.jsx:302
+#: src/components/related-actions.jsx:307
msgid "Search <0>@{username}0>'s posts"
msgstr "Znajdź wpisy <0>@{username}0>"
-#: src/components/related-actions.jsx:316
+#: src/components/related-actions.jsx:321
msgid "Translate bio"
msgstr "Przetłumacz biogram"
-#: src/components/related-actions.jsx:326
+#: src/components/related-actions.jsx:331
msgid "Edit notes"
msgstr "Edytuj notkę"
-#: src/components/related-actions.jsx:326
+#: src/components/related-actions.jsx:331
msgid "Add notes"
msgstr "Dodaj notkę"
-#: src/components/related-actions.jsx:345
+#: src/components/related-actions.jsx:350
msgid "Notifications enabled for @{username}'s posts."
msgstr "Włączono powiadomienia dla wpisów od @{username}."
-#: src/components/related-actions.jsx:346
+#: src/components/related-actions.jsx:351
msgid " Notifications disabled for @{username}'s posts."
msgstr " Wyłączono powiadomienia dla wpisów od @{username}."
-#: src/components/related-actions.jsx:358
+#: src/components/related-actions.jsx:363
msgid "Disable notifications"
msgstr "Wyłącz powiadomienia"
-#: src/components/related-actions.jsx:359
+#: src/components/related-actions.jsx:364
msgid "Enable notifications"
msgstr "Włącz powiadomienia"
-#: src/components/related-actions.jsx:376
+#: src/components/related-actions.jsx:381
msgid "Boosts from @{username} enabled."
msgstr "Włączono podbicia od @{username}."
-#: src/components/related-actions.jsx:377
+#: src/components/related-actions.jsx:382
msgid "Boosts from @{username} disabled."
msgstr "Wyłączono podbicia od @{username}."
-#: src/components/related-actions.jsx:388
+#: src/components/related-actions.jsx:393
msgid "Disable boosts"
msgstr "Wyłącz podbicia"
-#: src/components/related-actions.jsx:388
+#: src/components/related-actions.jsx:393
msgid "Enable boosts"
msgstr "Włącz podbicia"
-#: src/components/related-actions.jsx:407
+#: src/components/related-actions.jsx:412
msgid "@{username} is no longer featured on your profile."
msgstr "Cofnięto wyróżnienie @{username} na Twoim profilu."
-#: src/components/related-actions.jsx:417
+#: src/components/related-actions.jsx:422
msgid "@{username} is now featured on your profile."
msgstr "Wyróżniono @{username} na Twoim profilu."
-#: src/components/related-actions.jsx:425
+#: src/components/related-actions.jsx:430
msgid "Unable to unfeature @{username} on your profile."
msgstr "Nie udało się cofnąć wyróżnienia @{username} na Twoim profilu."
-#: src/components/related-actions.jsx:429
+#: src/components/related-actions.jsx:434
msgid "Unable to feature @{username} on your profile."
msgstr "Nie udało się wyróżnić @{username} na Twoim profilu."
-#: src/components/related-actions.jsx:438
+#: src/components/related-actions.jsx:443
msgid "Don't feature on profile"
msgstr "Nie wyróżniaj na profilu"
-#: src/components/related-actions.jsx:439
+#: src/components/related-actions.jsx:444
#: src/pages/hashtag.jsx:362
msgid "Feature on profile"
msgstr "Wyróżnij na profilu"
-#: src/components/related-actions.jsx:448
-#: src/components/related-actions.jsx:498
+#: src/components/related-actions.jsx:453
+#: src/components/related-actions.jsx:503
msgid "Show featured profiles"
msgstr "Pokaż wyróżnione profile"
-#: src/components/related-actions.jsx:490
+#: src/components/related-actions.jsx:495
#: src/pages/account-statuses.jsx:578
msgid "Search my posts"
msgstr "Przeszukaj swoje wpisy"
-#: src/components/related-actions.jsx:563
+#: src/components/related-actions.jsx:568
#: src/components/shortcuts-settings.jsx:1193
#: src/components/status.jsx:1514
msgid "Sharing doesn't seem to work."
msgstr "Udostępnianie zdaje się nie działać."
-#: src/components/related-actions.jsx:605
+#: src/components/related-actions.jsx:610
msgid "Unmuted @{username}"
msgstr "Wyłączono wyciszenie @{username}"
-#: src/components/related-actions.jsx:617
+#: src/components/related-actions.jsx:622
msgid "Unmute <0>@{username}0>"
msgstr "Wyłącz wyciszenie <0>@{username}0>"
-#: src/components/related-actions.jsx:633
+#: src/components/related-actions.jsx:638
msgid "Mute <0>@{username}0>…"
msgstr "Wycisz <0>@{username}0>…"
#. placeholder {0}: typeof MUTE_DURATIONS_LABELS[duration] === 'function' ? MUTE_DURATIONS_LABELS[duration]() : _(MUTE_DURATIONS_LABELS[duration])
-#: src/components/related-actions.jsx:665
+#: src/components/related-actions.jsx:670
msgid "Muted @{username} for {0}"
msgstr "Wyciszono @{username} na {0}"
-#: src/components/related-actions.jsx:677
+#: src/components/related-actions.jsx:682
msgid "Unable to mute @{username}"
msgstr "Nie udało się wyciszyć @{username}"
-#: src/components/related-actions.jsx:698
+#: src/components/related-actions.jsx:703
msgid "Remove <0>@{username}0> from followers?"
msgstr "Usunąć <0>@{username}0> z obserwujących?"
-#: src/components/related-actions.jsx:718
+#: src/components/related-actions.jsx:723
msgid "@{username} removed from followers"
msgstr "Usunięto @{username} z obserwujących"
-#: src/components/related-actions.jsx:730
+#: src/components/related-actions.jsx:735
msgid "Remove follower…"
msgstr "Usuń z obserwujących…"
-#: src/components/related-actions.jsx:741
+#: src/components/related-actions.jsx:746
msgid "Block <0>@{username}0>?"
msgstr "Zablokować <0>@{username}0>?"
-#: src/components/related-actions.jsx:765
+#: src/components/related-actions.jsx:770
msgid "Unblocked @{username}"
msgstr "Odblokowano @{username}"
-#: src/components/related-actions.jsx:773
+#: src/components/related-actions.jsx:778
msgid "Blocked @{username}"
msgstr "Zablokowano @{username}"
-#: src/components/related-actions.jsx:781
+#: src/components/related-actions.jsx:786
msgid "Unable to unblock @{username}"
msgstr "Nie udało się odblokować @{username}"
-#: src/components/related-actions.jsx:783
+#: src/components/related-actions.jsx:788
msgid "Unable to block @{username}"
msgstr "Nie udało się zablokować @{username}"
-#: src/components/related-actions.jsx:793
+#: src/components/related-actions.jsx:798
msgid "Unblock <0>@{username}0>"
msgstr "Odblokuj <0>@{username}0>"
-#: src/components/related-actions.jsx:802
+#: src/components/related-actions.jsx:807
msgid "Block <0>@{username}0>…"
msgstr "Zablokuj <0>@{username}0>…"
-#: src/components/related-actions.jsx:819
+#: src/components/related-actions.jsx:824
msgid "Report <0>@{username}0>…"
msgstr "Zgłoś <0>@{username}0>…"
-#: src/components/related-actions.jsx:887
+#: src/components/related-actions.jsx:892
msgid "Withdraw follow request?"
msgstr "Wycofać prośbę o obserwację?"
#. placeholder {0}: info.acct || info.username
-#: src/components/related-actions.jsx:888
+#: src/components/related-actions.jsx:893
msgid "Unfollow @{0}?"
msgstr "Przestać obserwować @{0}?"
-#: src/components/related-actions.jsx:951
+#: src/components/related-actions.jsx:956
msgid "Unfollow…"
msgstr "Nie obserwuj…"
-#: src/components/related-actions.jsx:960
+#: src/components/related-actions.jsx:965
msgid "Withdraw…"
msgstr "Wycofaj…"
-#: src/components/related-actions.jsx:967
-#: src/components/related-actions.jsx:971
+#: src/components/related-actions.jsx:972
+#: src/components/related-actions.jsx:976
#: src/pages/hashtag.jsx:294
msgid "Follow"
msgstr "Obserwuj"
@@ -3056,22 +3056,22 @@ msgstr "{index}/{total}"
msgid "{index}/X"
msgstr "{index}/X"
-#: src/components/timeline.jsx:558
+#: src/components/timeline.jsx:562
#: src/pages/settings.jsx:1373
msgid "New posts"
msgstr "Nowe wpisy"
#. placeholder {0}: fItems.length
-#: src/components/timeline.jsx:694
+#: src/components/timeline.jsx:698
msgid "{0, plural, one {# Boost} other {# Boosts}}"
msgstr "{0, plural, one {# podbicie} few {# podbicia} other{# podbić}}"
-#: src/components/timeline.jsx:699
+#: src/components/timeline.jsx:703
msgid "Pinned posts"
msgstr "Przypięte wpisy"
#. placeholder {0}: filterInfo.titlesStr
-#: src/components/timeline.jsx:1052
+#: src/components/timeline.jsx:1046
msgid "<0>Filtered0>: <1>{0}1>"
msgstr "<0>Odfiltrowane0>: <1>{0}1>"
@@ -4199,7 +4199,7 @@ msgstr "Pomóż w tłumaczeniu"
#: src/pages/settings.jsx:255
msgid "Keep navigation bars visible while scrolling"
-msgstr ""
+msgstr "Pozostaw pasek nawigacji widoczny podczas przewijania strony"
#: src/pages/settings.jsx:263
msgid "Posting"
diff --git a/src/locales/pt-BR.po b/src/locales/pt-BR.po
index 1010a49ab9..e2c6616f15 100644
--- a/src/locales/pt-BR.po
+++ b/src/locales/pt-BR.po
@@ -8,7 +8,7 @@ msgstr ""
"Language: pt\n"
"Project-Id-Version: phanpy\n"
"Report-Msgid-Bugs-To: \n"
-"PO-Revision-Date: 2026-05-19 15:00\n"
+"PO-Revision-Date: 2026-05-21 22:18\n"
"Last-Translator: \n"
"Language-Team: Portuguese, Brazilian\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -118,7 +118,7 @@ msgstr "Seguindo"
#: src/components/account-info-mini.jsx:106
#: src/components/account-info.jsx:879
msgid "{followingCount, plural, other {<0>{0}0> Following}}"
-msgstr "{followingCount, plural, one {}other {<0>{0}0> seguindo}}"
+msgstr "{followingCount, plural, other {<0>{0}0> seguindo}}"
#. placeholder {0}: shortenNumber(statusesCount)
#. placeholder {1}: shortenNumber(statusesCount)
@@ -203,7 +203,7 @@ msgstr "Em memória"
#. placeholder {3}: ( postingStats.boosts / postingStats.total ).toLocaleString(i18n.locale || undefined, { style: 'percent', })
#: src/components/account-info.jsx:960
msgid "{0} original posts, {1} replies, {2} quotes, {3} boosts"
-msgstr "{0} posts originais, {1} respostas, {2} citações, {3} impulsos"
+msgstr "{0} publicações originais, {1} respostas, {2} citações, {3} impulsos"
#. placeholder {0}: ( postingStats.originals / postingStats.total ).toLocaleString(i18n.locale || undefined, { style: 'percent', })
#. placeholder {1}: ( postingStats.replies / postingStats.total ).toLocaleString(i18n.locale || undefined, { style: 'percent', })
@@ -418,7 +418,7 @@ msgstr "Adicionar"
#: src/components/compose-poll.jsx:96
msgid "Multiple choice"
-msgstr "Múltipla escolha"
+msgstr "Múltiplas opções"
#: src/components/compose-poll.jsx:99
msgid "Duration"
@@ -1084,7 +1084,7 @@ msgstr "Detalhes da publicação"
#: src/components/keyboard-shortcuts-help.jsx:101
msgid "Open media or post details"
-msgstr "Abrir detalhes do post ou mídia"
+msgstr "Abrir detalhes da publicação ou mídia"
#: src/components/keyboard-shortcuts-help.jsx:106
msgid "Expand content warning or<0/>toggle expanded/collapsed thread"
@@ -1188,23 +1188,23 @@ msgstr "<0>Shift0> + <1>Alt1> + <2>k2>"
#: src/components/keyboard-shortcuts-help.jsx:210
msgid "Go to Home"
-msgstr "Ir para página inicial"
+msgstr "Página inicial"
#: src/components/keyboard-shortcuts-help.jsx:214
msgid "Go to Notifications"
-msgstr "Ir para notificações"
+msgstr "Notificações"
#: src/components/keyboard-shortcuts-help.jsx:218
msgid "Go to Settings"
-msgstr "Ir para configurações"
+msgstr "Opções"
#: src/components/keyboard-shortcuts-help.jsx:222
msgid "Go to Profile"
-msgstr "Ir para perfil"
+msgstr "Perfil"
#: src/components/keyboard-shortcuts-help.jsx:226
msgid "Go to Bookmarks"
-msgstr "Ir aos Favoritos"
+msgstr "Favoritos"
#: src/components/list-add-edit.jsx:41
msgid "Edit list"
@@ -1664,7 +1664,7 @@ msgstr "A enquete que você votou já acabou."
#: src/components/notification.jsx:204
msgid "{account} edited a post."
-msgstr "{account} editou um post."
+msgstr "{account} editou uma publicação."
#: src/components/notification.jsx:206
msgid "A post you interacted with has been edited."
@@ -1678,12 +1678,12 @@ msgstr "{count, plural, =1 {{postsCount, plural, =1 {{postType, select, reply {{
#: src/components/notification.jsx:258
msgid "{account} edited a post you have quoted."
-msgstr "{account} editou um post que você citou."
+msgstr "{account} editou uma publicação citada."
#. placeholder {0}: shortenNumber(count)
#: src/components/notification.jsx:261
msgid "{count, plural, =1 {{account} signed up.} other {<0><1>{0}1> people0> signed up.}}"
-msgstr "{count, plural, one {}=1 {{account} signed up.} other {<0><1>{0}1> people0> signed up.}}"
+msgstr "{count, plural, =1 {{account} registrou-se.} other {<0><1>{0}1>pessoas0> registraram-se.}}"
#: src/components/notification.jsx:275
msgid "{account} reported {targetAccount}"
@@ -1793,7 +1793,7 @@ msgstr "Impossível copiar o link"
#: src/components/open-link-sheet.jsx:56
msgid "Open link?"
-msgstr "Abrir link?"
+msgstr "Acessar link?"
#: src/components/open-link-sheet.jsx:78
#: src/components/post-embed-modal.jsx:232
@@ -1811,7 +1811,7 @@ msgstr "Compartilhar…"
#: src/components/open-link-sheet.jsx:92
msgid "Open"
-msgstr "Abrir"
+msgstr "Acessar"
#: src/components/poll.jsx:160
msgid "{optionVotesCount, plural, one {# vote} other {# votes}}"
@@ -1832,11 +1832,11 @@ msgstr "Ocultar resultado"
#: src/components/poll.jsx:290
#: src/components/poll.jsx:306
msgid "{0, plural, one {# choice} other {# choices}}"
-msgstr "{0, plural, one {# choice} other {# choices}}"
+msgstr "{0, plural, one {# opção} other {# opções}}"
#: src/components/poll.jsx:222
msgid "Unable to vote in poll"
-msgstr "Incapaz de votar na enquete"
+msgstr "Não foi possível votar na enquete"
#: src/components/poll.jsx:279
msgid "Vote"
@@ -1948,11 +1948,11 @@ msgstr "Nota: Esta prévia tem um estilo levemente padronizado."
#: src/components/private-note-sheet.jsx:41
#: src/components/related-actions.jsx:232
msgid "Notes"
-msgstr "Anotações"
+msgstr "Notas"
#: src/components/private-note-sheet.jsx:44
msgid "Only visible to you"
-msgstr "Apenas visível para você"
+msgstr "Somente visível para você"
#: src/components/private-note-sheet.jsx:69
msgid "Unable to update private note."
@@ -1965,33 +1965,33 @@ msgstr "Salvar e fechar"
#: src/components/qr-code-modal.jsx:26
#: src/components/shortcuts-settings.jsx:849
msgid "Scan QR code"
-msgstr "Escanear código QR"
+msgstr "Escanear QR code"
#: src/components/qr-scanner-modal.jsx:263
msgid "Unable to access camera. Please check permissions."
-msgstr "Incapaz de acessar a câmera. Por favor, cheque as permissões."
+msgstr "Não foi possível abrir a câmera. Verifique as permissões."
#: src/components/quote-chain-modal.jsx:107
msgid "Quote chain"
-msgstr "Sequência de citações"
+msgstr "Cadeia de citações"
#: src/components/quote-chain-modal.jsx:151
msgid "Failed to unwrap quote chain"
-msgstr "Falha ao desenrolar sequência de citações"
+msgstr "Falhou ao expandir cadeia de citações"
#: src/components/quote-chain-modal.jsx:165
msgid "Continue unwrapping…"
-msgstr "Continuar desenrolando…"
+msgstr "Expandir…"
#: src/components/quote-settings-sheet.jsx:37
#: src/pages/settings.jsx:341
msgid "Quote settings updated"
-msgstr "Configurações de citação atualizadas"
+msgstr "Opções de citação atualizadas"
#: src/components/quote-settings-sheet.jsx:47
#: src/pages/settings.jsx:343
msgid "Failed to update quote settings"
-msgstr "Falha na atualização de configurações de citação"
+msgstr "Falhou ao atualizar opções de citação"
#: src/components/quote-settings-sheet.jsx:66
msgid "Quote settings for this post"
diff --git a/tests/keyboard-shortcuts.spec.js b/tests/keyboard-shortcuts.spec.js
new file mode 100644
index 0000000000..f80034d634
--- /dev/null
+++ b/tests/keyboard-shortcuts.spec.js
@@ -0,0 +1,677 @@
+// @ts-check
+import { expect, test } from '@playwright/test';
+
+const MOCK_INSTANCE_RESPONSE = {
+ uri: 'test.social',
+ title: 'Test Social',
+ domain: 'test.social',
+ version: '4.0.0',
+ configuration: {
+ statuses: { maxCharacters: 500, maxMediaAttachments: 4 },
+ polls: {
+ maxOptions: 4,
+ maxCharactersPerOption: 50,
+ minExpiration: 300,
+ maxExpiration: 86400,
+ },
+ urls: { streaming: 'wss://test.social' },
+ },
+};
+
+const MOCK_ACCOUNT_INFO = {
+ id: '1',
+ username: 'testuser',
+ acct: 'testuser',
+ display_name: 'Test User',
+ locked: false,
+ bot: false,
+ discoverable: true,
+ created_at: '2024-01-01T00:00:00.000Z',
+ note: '
Test user
', + url: 'https://test.social/@testuser', + uri: 'https://test.social/users/testuser', + avatar: 'https://test.social/avatars/test.png', + avatar_static: 'https://test.social/avatars/test.png', + header: 'https://test.social/headers/test.png', + header_static: 'https://test.social/headers/test.png', + followers_count: 100, + following_count: 50, + statuses_count: 500, + last_status_at: '2024-06-01', + emojis: [], + roles: [], + fields: [], +}; + +function createMockPost(id, index) { + const i = index ?? 0; + return { + id: String(id), + created_at: new Date(Date.now() - i * 900000).toISOString(), + account: { + id: '1', + username: 'testuser', + acct: 'testuser', + display_name: 'Test User', + url: 'https://test.social/@testuser', + uri: 'https://test.social/users/testuser', + avatar: 'https://test.social/avatar.png', + avatar_static: 'https://test.social/avatar.png', + header: 'https://test.social/header.png', + header_static: 'https://test.social/header.png', + followers_count: 100, + following_count: 50, + statuses_count: 200, + last_status_at: '2024-06-01', + emojis: [], + fields: [], + }, + content: `Test post ${i}
`, + uri: `https://test.social/users/testuser/statuses/${id}`, + url: `https://test.social/@testuser/${id}`, + media_attachments: [], + mentions: [], + tags: [], + emojis: [], + reblogs_count: 0, + favourites_count: 0, + replies_count: 0, + sensitive: false, + spoiler_text: '', + visibility: 'public', + language: 'en', + favourited: false, + reblogged: false, + bookmarked: false, + muted: false, + pinned: false, + }; +} + +async function setupMockHomeEnv(page) { + await page.route('**/api/v2/instance', async (route) => { + await route.fulfill({ json: MOCK_INSTANCE_RESPONSE }); + }); + await page.route('**/api/v1/instance', async (route) => { + await route.fulfill({ json: MOCK_INSTANCE_RESPONSE }); + }); + await page.goto('/#/_mock/home'); + await page.waitForSelector('.timeline-item', { timeout: 15000 }); +} + +async function setupLoggedInEnv(page) { + await page.addInitScript(() => { + const account = { + info: { + id: '1', + username: 'testuser', + acct: 'testuser', + display_name: 'Test User', + avatar: 'https://test.social/avatar.png', + avatar_static: 'https://test.social/avatar.png', + header: 'https://test.social/header.png', + header_static: 'https://test.social/header.png', + }, + instanceURL: 'test.social', + accessToken: 'mock-access-token', + createdAt: Date.now(), + updatedAt: Date.now(), + lastAccessedAt: Date.now(), + }; + localStorage.setItem('accounts', JSON.stringify([account])); + sessionStorage.setItem('currentAccount', '1'); + localStorage.setItem( + 'preferences', + JSON.stringify({ + '1@test.social': { 'posting:default:visibility': 'public' }, + }), + ); + localStorage.setItem( + 'instances', + JSON.stringify({ + 'test.social': { + uri: 'test.social', + title: 'Test Social', + version: '4.0.0', + configuration: { + statuses: { maxCharacters: 500, maxMediaAttachments: 4 }, + polls: { + maxOptions: 4, + maxCharactersPerOption: 50, + minExpiration: 300, + maxExpiration: 86400, + }, + urls: { streaming: 'wss://test.social' }, + }, + }, + }), + ); + localStorage.setItem( + 'credentialApplications', + JSON.stringify({ + 'test.social': { + client_id: 'mock-client-id', + client_secret: 'mock-client-secret', + vapid_key: 'mock-vapid-key', + }, + }), + ); + }); + + await page.route('**/api/v2/instance', async (route) => { + await route.fulfill({ json: MOCK_INSTANCE_RESPONSE }); + }); + await page.route('**/api/v1/instance', async (route) => { + await route.fulfill({ json: MOCK_INSTANCE_RESPONSE }); + }); + await page.route('**/api/v1/preferences', async (route) => { + await route.fulfill({ json: {} }); + }); + await page.route('**/api/v1/accounts/verify_credentials', async (route) => { + await route.fulfill({ json: MOCK_ACCOUNT_INFO }); + }); + await page.route('**/api/v1/apps/verify_credentials', async (route) => { + await route.fulfill({ json: { name: 'Test App', website: null } }); + }); +} + +async function focusFirstStatus(page) { + await page.locator('.status').first().focus(); + await page.waitForTimeout(300); +} + +async function focusInput(page) { + await page.evaluate(() => { + const existing = document.getElementById('__test-input__'); + if (existing) existing.remove(); + const input = document.createElement('input'); + input.id = '__test-input__'; + input.style.position = 'fixed'; + input.style.top = '0'; + input.style.left = '0'; + input.style.opacity = '0.01'; + input.style.zIndex = '99999'; + document.body.prepend(input); + input.focus(); + }); + await page.waitForTimeout(100); +} + +async function cleanupInput(page) { + await page.evaluate(() => { + document.getElementById('__test-input__')?.remove(); + }); +} + +function overrideAlert(page) { + return page.evaluate(() => { + window.__alertCalled = false; + window.__alertCount = 0; + window.alert = () => { + window.__alertCalled = true; + window.__alertCount++; + }; + }); +} + +function wasAlertCalled(page) { + return page.evaluate(() => window.__alertCalled); +} + +function getAlertCount(page) { + return page.evaluate(() => window.__alertCount); +} + +function resetAlertCounter(page) { + return page.evaluate(() => { + window.__alertCalled = false; + window.__alertCount = 0; + }); +} + +test.describe('Keyboard Shortcuts', () => { + test.describe('Section 1: Status Interaction Shortcuts (via _mock/home)', () => { + test.beforeEach(async ({ page }) => { + await setupMockHomeEnv(page); + await focusFirstStatus(page); + await overrideAlert(page); + }); + + test('1.1 Reply (r) fires on focused status', async ({ page }) => { + await page.keyboard.press('r'); + await page.waitForTimeout(500); + expect(await wasAlertCalled(page)).toBe(true); + }); + + test('1.2 Favourite (f) fires on focused status', async ({ page }) => { + await page.keyboard.press('f'); + await page.waitForTimeout(500); + expect(await wasAlertCalled(page)).toBe(true); + }); + + test('1.3 Favourite (l) fires on focused status', async ({ page }) => { + await page.keyboard.press('l'); + await page.waitForTimeout(500); + expect(await wasAlertCalled(page)).toBe(true); + }); + + test('1.4 Bookmark (d) fires on focused status', async ({ page }) => { + await page.keyboard.press('d'); + await page.waitForTimeout(500); + expect(await wasAlertCalled(page)).toBe(true); + }); + + test('1.5 Quote (q) fires on focused status', async ({ page }) => { + await page.keyboard.press('q'); + await page.waitForTimeout(500); + expect(await wasAlertCalled(page)).toBe(true); + }); + + test('1.6 Scoping: input focus blocks status shortcuts', async ({ + page, + }) => { + await focusInput(page); + await page.keyboard.press('r'); + await page.waitForTimeout(500); + expect(await wasAlertCalled(page)).toBe(false); + await cleanupInput(page); + }); + + test('1.7 Scoping: modifier key blocks status shortcuts', async ({ + page, + }) => { + await page.keyboard.press('Meta+r'); + await page.waitForTimeout(500); + expect(await wasAlertCalled(page)).toBe(false); + }); + + test('1.8 Focus scoping: reply fires only for focused status, not multiple', async ({ + page, + }) => { + expect(await getAlertCount(page)).toBe(0); + await page.keyboard.press('r'); + await page.waitForTimeout(500); + const count = await getAlertCount(page); + expect(count).toBe(1); + }); + + test('1.9 Focus scoping: favourite fires only for newly focused status', async ({ + page, + }) => { + await page.keyboard.press('f'); + await page.waitForTimeout(500); + expect(await getAlertCount(page)).toBe(1); + await resetAlertCounter(page); + const items = page.locator('.status'); + const count = await items.count(); + if (count < 2) return; + await items.nth(1).focus(); + await page.waitForTimeout(300); + await page.keyboard.press('f'); + await page.waitForTimeout(500); + expect(await getAlertCount(page)).toBe(1); + }); + }); + + test.describe('Section 2: Compose Shortcuts (via _mock/home)', () => { + test.beforeEach(async ({ page }) => { + await setupMockHomeEnv(page); + }); + + test('2.1 Open compose (c) sets showCompose', async ({ page }) => { + await page.keyboard.press('c'); + await page.waitForTimeout(300); + const showCompose = await page.evaluate( + () => window.__STATES__?.showCompose, + ); + expect(showCompose).toBeTruthy(); + }); + + test('2.2 Scoping: input focus blocks compose', async ({ page }) => { + await focusInput(page); + await page.keyboard.press('c'); + await page.waitForTimeout(300); + const showCompose = await page.evaluate( + () => window.__STATES__?.showCompose, + ); + expect(showCompose).toBeFalsy(); + await cleanupInput(page); + }); + + test('2.3 Scoping: modifier key blocks compose', async ({ page }) => { + await page.keyboard.press('Meta+c'); + await page.waitForTimeout(300); + const showCompose = await page.evaluate( + () => window.__STATES__?.showCompose, + ); + expect(showCompose).toBeFalsy(); + }); + }); + + test.describe('Section 3: Number Shortcuts (via _mock/home)', () => { + test.beforeEach(async ({ page }) => { + await setupMockHomeEnv(page); + await page.waitForTimeout(500); + }); + + test('3.1 Number 1 navigates to home', async ({ page }) => { + await page.keyboard.press('1'); + await page.waitForTimeout(500); + const hash = await page.evaluate(() => location.hash); + expect(hash).toBe('#/'); + }); + + test('3.2 Scoping: modifier key blocks number shortcut', async ({ + page, + }) => { + const hashBefore = await page.evaluate(() => location.hash); + await page.keyboard.press('Meta+1'); + await page.waitForTimeout(500); + const hashAfter = await page.evaluate(() => location.hash); + expect(hashAfter).toBe(hashBefore); + }); + }); + + test.describe('Section 4: Help Shortcut (via _mock/home)', () => { + test.beforeEach(async ({ page }) => { + await setupMockHomeEnv(page); + }); + + test('4.1 Open help with ?', async ({ page }) => { + await page.keyboard.press('?'); + await page.waitForTimeout(500); + await expect( + page.locator('#keyboard-shortcuts-help-container'), + ).toBeVisible(); + }); + + test('4.2 Close help with Escape', async ({ page }) => { + await page.keyboard.press('?'); + await page.waitForTimeout(500); + await expect( + page.locator('#keyboard-shortcuts-help-container'), + ).toBeVisible(); + await page.keyboard.press('Escape'); + await page.waitForTimeout(500); + await expect( + page.locator('#keyboard-shortcuts-help-container'), + ).not.toBeVisible(); + }); + + test('4.3 Scoping: modifier key blocks help', async ({ page }) => { + await page.keyboard.press('Meta+?'); + await page.waitForTimeout(500); + await expect( + page.locator('#keyboard-shortcuts-help-container'), + ).not.toBeVisible(); + }); + }); + + test.describe('Section 5: Search Overlay (via _mock/home)', () => { + test.beforeEach(async ({ page }) => { + await setupMockHomeEnv(page); + }); + + test('5.1 Open search with / removes hidden attribute', async ({ + page, + }) => { + await page.keyboard.press('/'); + await page.waitForTimeout(500); + await expect( + page.locator('#search-command-container'), + ).not.toHaveAttribute('hidden', ''); + }); + + test('5.2 Close search with Escape adds hidden attribute', async ({ + page, + }) => { + await page.keyboard.press('/'); + await page.waitForTimeout(500); + const hiddenBefore = await page + .locator('#search-command-container') + .getAttribute('hidden'); + expect(hiddenBefore).toBeNull(); + await page.keyboard.press('Escape'); + await page.waitForTimeout(500); + await expect(page.locator('#search-command-container')).toHaveAttribute( + 'hidden', + '', + ); + }); + }); + + test.describe('Section 6: Cloak Mode (via _mock/home)', () => { + test.beforeEach(async ({ page }) => { + await setupMockHomeEnv(page); + }); + + test('6.1 Toggle cloak mode on', async ({ page }) => { + await page.keyboard.press('Shift+Alt+k'); + await page.waitForTimeout(300); + const hasCloak = await page.evaluate(() => + document.body.classList.contains('cloak'), + ); + expect(hasCloak).toBe(true); + }); + + test('6.2 Toggle cloak mode off', async ({ page }) => { + await page.keyboard.press('Shift+Alt+k'); + await page.waitForTimeout(300); + await page.keyboard.press('Shift+Alt+k'); + await page.waitForTimeout(300); + const hasCloak = await page.evaluate(() => + document.body.classList.contains('cloak'), + ); + expect(hasCloak).toBe(false); + }); + + test('6.3 Scoping: modifier key blocks cloak toggle', async ({ page }) => { + await page.keyboard.press('Meta+Shift+Alt+k'); + await page.waitForTimeout(300); + const hasCloak = await page.evaluate(() => + document.body.classList.contains('cloak'), + ); + expect(hasCloak).toBe(false); + }); + }); + + test.describe('Section 7: Navigation Commands (g> sequences) — needs auth', () => { + test.beforeEach(async ({ page }) => { + await setupLoggedInEnv(page); + await page.route('**/api/v1/timelines/home**', async (route) => { + await route.fulfill({ json: [] }); + }); + await page.goto('/#/test.social'); + await page.waitForTimeout(3000); + }); + + test('7.1 g then h navigates to home', async ({ page }) => { + await page.keyboard.press('g'); + await page.waitForTimeout(100); + await page.keyboard.press('h'); + await page.waitForTimeout(500); + const hash = await page.evaluate(() => location.hash); + expect(hash).toBe('#/'); + }); + + test('7.2 g then n navigates to notifications', async ({ page }) => { + await page.keyboard.press('g'); + await page.waitForTimeout(100); + await page.keyboard.press('n'); + await page.waitForTimeout(500); + const hash = await page.evaluate(() => location.hash); + expect(hash).toMatch(/notifications/); + }); + + test('7.3 g then s opens settings', async ({ page }) => { + await page.keyboard.press('g'); + await page.waitForTimeout(100); + await page.keyboard.press('s'); + await page.waitForTimeout(500); + const showSettings = await page.evaluate( + () => window.__STATES__?.showSettings, + ); + expect(showSettings).toBe(true); + }); + + test('7.4 g then b navigates to bookmarks', async ({ page }) => { + await page.keyboard.press('g'); + await page.waitForTimeout(100); + await page.keyboard.press('b'); + await page.waitForTimeout(500); + const hash = await page.evaluate(() => location.hash); + expect(hash).toMatch(/\/b$/); + }); + }); + + test.describe('Section 8: Timeline Navigation (j/k) — needs auth', () => { + test.beforeEach(async ({ page }) => { + await setupLoggedInEnv(page); + const mockPosts = Array.from({ length: 5 }, (_, i) => + createMockPost(100 + i, i), + ); + await page.route('**/api/v1/timelines/home**', async (route) => { + await route.fulfill({ json: mockPosts }); + }); + await page.goto('/#/test.social'); + await page.waitForSelector('.timeline-item', { timeout: 20000 }); + await page.waitForTimeout(1000); + }); + + test('8.1 j focuses next timeline item', async ({ page }) => { + await focusFirstStatus(page); + await page.keyboard.press('j'); + await page.waitForTimeout(300); + const activeItem = await page.evaluate(() => + document.activeElement?.closest('.timeline-item'), + ); + expect(activeItem).not.toBeNull(); + }); + + test('8.2 j then k navigates back to previous item', async ({ page }) => { + const count = await page.locator('.timeline-item').count(); + expect(count).toBeGreaterThanOrEqual(2); + await focusFirstStatus(page); + await page.keyboard.press('j'); + await page.waitForTimeout(200); + await page.keyboard.press('k'); + await page.waitForTimeout(200); + const activeItem = await page.evaluate(() => + document.activeElement?.closest('.timeline-item'), + ); + expect(activeItem).not.toBeNull(); + }); + + test('8.3 Scoping: input focus blocks j (default library behavior)', async ({ + page, + }) => { + await focusFirstStatus(page); + await focusInput(page); + await page.keyboard.press('j'); + await page.waitForTimeout(300); + const stillInInput = await page.evaluate( + () => document.activeElement?.id === '__test-input__', + ); + await cleanupInput(page); + expect(stillInInput).toBe(true); + }); + + test('8.4 Scoping: modifier key blocks j navigation', async ({ page }) => { + await focusFirstStatus(page); + await page.keyboard.press('Meta+j'); + await page.waitForTimeout(300); + const onFirstItem = await page.evaluate(() => { + const ae = document.activeElement; + return ( + ae?.closest('.timeline-item')?.classList.contains('timeline-item') === + true + ); + }); + expect(onFirstItem).toBe(true); + }); + }); + + test.describe('Section 9: Modal Escape (via _mock/home)', () => { + test.beforeEach(async ({ page }) => { + await setupMockHomeEnv(page); + }); + + test('9.1 Escape closes help modal', async ({ page }) => { + await page.keyboard.press('?'); + await page.waitForTimeout(500); + await expect( + page.locator('#keyboard-shortcuts-help-container'), + ).toBeVisible(); + await page.keyboard.press('Escape'); + await page.waitForTimeout(500); + await expect( + page.locator('#keyboard-shortcuts-help-container'), + ).not.toBeVisible(); + }); + + test('9.2 Scoping: modifier key does not close modal', async ({ page }) => { + await page.keyboard.press('?'); + await page.waitForTimeout(500); + await expect( + page.locator('#keyboard-shortcuts-help-container'), + ).toBeVisible(); + await page.keyboard.press('Meta+Escape'); + await page.waitForTimeout(500); + await expect( + page.locator('#keyboard-shortcuts-help-container'), + ).toBeVisible(); + }); + }); + + test.describe('Section 10: Status Detail Page — needs auth', () => { + test.beforeEach(async ({ page }) => { + await setupLoggedInEnv(page); + + const contextDescendants = Array.from({ length: 3 }, (_, i) => ({ + ...createMockPost(124 + i, i + 1), + descendant: true, + in_reply_to_id: '123', + in_reply_to_account_id: '1', + })); + + await page.route('**/api/v1/statuses/123', async (route) => { + await route.fulfill({ + json: { + ...createMockPost(123, 0), + content: 'Status detail test post
', + }, + }); + }); + await page.route('**/api/v1/statuses/123/context', async (route) => { + await route.fulfill({ + json: { ancestors: [], descendants: contextDescendants }, + }); + }); + + await page.route('**/api/v1/timelines/home**', async (route) => { + await route.fulfill({ json: [] }); + }); + + await page.goto('/#/test.social/s/123'); + await page.waitForSelector('article.status', { timeout: 15000 }); + await page.waitForTimeout(500); + }); + + test('10.1 Escape closes status detail', async ({ page }) => { + await page.keyboard.press('Escape'); + await page.waitForTimeout(500); + const hash = await page.evaluate(() => location.hash); + expect(hash).not.toMatch(/\/s\/123/); + }); + + test('10.2 j focuses next context status', async ({ page }) => { + await page.keyboard.press('j'); + await page.waitForTimeout(300); + const activeEl = await page.evaluate(() => { + const el = document.activeElement; + return el?.closest('.status-focus, .status-link'); + }); + expect(activeEl).not.toBeNull(); + }); + }); +});