From d82bada742c85ec2369806c2dadac1315c7c68af Mon Sep 17 00:00:00 2001 From: diondiondion Date: Mon, 20 Apr 2026 19:50:37 +0200 Subject: [PATCH 01/10] Add "Must follow" section to account suggestion dropdown menu (#38750) --- .../features/collections/editor/accounts.tsx | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/app/javascript/mastodon/features/collections/editor/accounts.tsx b/app/javascript/mastodon/features/collections/editor/accounts.tsx index ec6dbdac27..a51f58c236 100644 --- a/app/javascript/mastodon/features/collections/editor/accounts.tsx +++ b/app/javascript/mastodon/features/collections/editor/accounts.tsx @@ -4,6 +4,8 @@ import { FormattedMessage, useIntl } from 'react-intl'; import { useHistory } from 'react-router-dom'; +import type { Map as ImmutableMap } from 'immutable'; + import type { ApiMutedAccountJSON } from 'mastodon/api_types/accounts'; import type { ApiCollectionJSON } from 'mastodon/api_types/collections'; import { AccountListItem } from 'mastodon/components/account_list_item'; @@ -25,6 +27,7 @@ import { import { useAccount } from 'mastodon/hooks/useAccount'; import { useSearchAccounts } from 'mastodon/hooks/useSearchAccounts'; import { domain } from 'mastodon/initial_state'; +import type { Relationship } from 'mastodon/models/relationship'; import { addCollectionItem, getCollectionItemIds, @@ -85,19 +88,37 @@ const renderAccountItem = (account: ApiMutedAccountJSON) => ( type GroupKey = 'available' | 'mustFollow' | 'disabled'; -function groupSuggestions(accounts: ApiMutedAccountJSON[]) { - const { available, disabled } = Object.groupBy(accounts, (account) => { - if (getIsItemDisabled(account)) { +const canAccountBeAdded = (account: ApiMutedAccountJSON) => + ['automatic', 'manual'].includes(account.feature_approval.current_user); + +function groupSuggestions( + accounts: ApiMutedAccountJSON[], + relationships: ImmutableMap, +) { + const { available, mustFollow, disabled } = Object.groupBy( + accounts, + (account): GroupKey => { + if (canAccountBeAdded(account)) { + return 'available'; + } + + const canAccountBeAddedByFollowers = + account.feature_approval.automatic.includes('followers') || + account.feature_approval.manual.includes('followers'); + + if ( + canAccountBeAddedByFollowers && + !relationships.get(account.id)?.following + ) { + return 'mustFollow'; + } + return 'disabled'; - } - // if (account.locked && !relationship?.following) { - // return 'mustFollow'; - // } - return 'available'; - }); + }, + ); // Returning a new object ensures a fixed property order - return { available, disabled }; + return { available, mustFollow, disabled }; } const renderGroupTitle = (groupKey: GroupKey, titleId: string) => { @@ -146,10 +167,8 @@ const renderGroupTitle = (groupKey: GroupKey, titleId: string) => { }; const getItemId = (account: ApiMutedAccountJSON) => account.id; - -// Disable accounts who can't be added to a collection const getIsItemDisabled = (account: ApiMutedAccountJSON) => - !['automatic', 'manual'].includes(account.feature_approval.current_user); + !canAccountBeAdded(account); export const CollectionAccounts: React.FC<{ collection?: ApiCollectionJSON | null; @@ -189,6 +208,10 @@ export const CollectionAccounts: React.FC<{ filterResults: (account) => !accountIds.includes(account.id), }); + const relationships = useAppSelector((state) => state.relationships); + + const groupedItems = groupSuggestions(suggestedAccounts, relationships); + const handleSearchValueChange = useCallback( (e: React.ChangeEvent) => { setSearchValue(e.target.value); @@ -330,7 +353,7 @@ export const CollectionAccounts: React.FC<{ onKeyDown={handleSearchKeyDown} disabled={hasMaxAccounts} isLoading={isLoadingSuggestions} - items={groupSuggestions(suggestedAccounts)} + items={groupedItems} getItemId={getItemId} getIsItemDisabled={getIsItemDisabled} renderItem={renderAccountItem} From 055b739b882053b74a34a8e738593cd5d4791335 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 21 Apr 2026 05:59:04 -0400 Subject: [PATCH 02/10] Use `with_domain` scope in ReportService (#38758) --- app/services/report_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/report_service.rb b/app/services/report_service.rb index 9366a69e75..2bde022276 100644 --- a/app/services/report_service.rb +++ b/app/services/report_service.rb @@ -96,7 +96,7 @@ class ReportService < BaseService def domain_mentions(domain) Mention .joins(:account) - .where(Account.arel_table[:domain].lower.eq domain) + .merge(Account.with_domain(domain)) .select(1).arel.exists end From 6903d155596312f622d181b96bbff4aa48771378 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:02:33 +0200 Subject: [PATCH 03/10] Update formatjs monorepo (#38666) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 298 +++++++++++++++++++++++++++++------------------------- 1 file changed, 163 insertions(+), 135 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4340a3e0ec..e899af63b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2411,6 +2411,13 @@ __metadata: languageName: node linkType: hard +"@formatjs/bigdecimal@npm:0.2.1": + version: 0.2.1 + resolution: "@formatjs/bigdecimal@npm:0.2.1" + checksum: 10c0/04b72caf1608afe59f20313b73b80dba474b65485076c0f9a72b8145fcb0e04580a7a0592c2f88f739f4997b51326e2b9d6142e6c5b04c0c941d0294e2aa2f20 + languageName: node + linkType: hard + "@formatjs/cli@npm:^6.1.1": version: 6.7.4 resolution: "@formatjs/cli@npm:6.7.4" @@ -2461,6 +2468,13 @@ __metadata: languageName: node linkType: hard +"@formatjs/fast-memoize@npm:3.1.2": + version: 3.1.2 + resolution: "@formatjs/fast-memoize@npm:3.1.2" + checksum: 10c0/25af387ebb53146c8c09af34cda4ce82768f0855227ec854fb315d6dc2e7859e16724860fdea7991b3c7c5741154e3fcdd5169ef7a11ba1afb3ffd860613931c + languageName: node + linkType: hard + "@formatjs/icu-messageformat-parser@npm:3.5.3": version: 3.5.3 resolution: "@formatjs/icu-messageformat-parser@npm:3.5.3" @@ -2471,6 +2485,15 @@ __metadata: languageName: node linkType: hard +"@formatjs/icu-messageformat-parser@npm:3.5.4": + version: 3.5.4 + resolution: "@formatjs/icu-messageformat-parser@npm:3.5.4" + dependencies: + "@formatjs/icu-skeleton-parser": "npm:2.1.4" + checksum: 10c0/3ff5ab209b63113d6b1779a4e8de6ee2cf941f3ad3f3ede2c8e425953a25456b6a1d880d734845244615dc9887fad10b62e75dee38858c731e45812402110efb + languageName: node + linkType: hard + "@formatjs/icu-skeleton-parser@npm:2.1.3": version: 2.1.3 resolution: "@formatjs/icu-skeleton-parser@npm:2.1.3" @@ -2480,6 +2503,13 @@ __metadata: languageName: node linkType: hard +"@formatjs/icu-skeleton-parser@npm:2.1.4": + version: 2.1.4 + resolution: "@formatjs/icu-skeleton-parser@npm:2.1.4" + checksum: 10c0/9d6292443e4079c5718c50e32041a3bd192047449d181ae87e8cb6ef78c90f156f8b2d454008c9d0c2920c215daee5250c0eb214d13a105522a631f269e71b3c + languageName: node + linkType: hard + "@formatjs/intl-localematcher@npm:0.8.2": version: 0.8.2 resolution: "@formatjs/intl-localematcher@npm:0.8.2" @@ -2489,26 +2519,33 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-pluralrules@npm:^6.0.0": - version: 6.3.1 - resolution: "@formatjs/intl-pluralrules@npm:6.3.1" +"@formatjs/intl-localematcher@npm:0.8.3": + version: 0.8.3 + resolution: "@formatjs/intl-localematcher@npm:0.8.3" dependencies: - "@formatjs/bigdecimal": "npm:0.2.0" - "@formatjs/ecma402-abstract": "npm:3.2.0" - "@formatjs/intl-localematcher": "npm:0.8.2" - checksum: 10c0/8c0847d21d06276557316a01998528b79310b1c5411b0932b51dc88640a8ed6181c2221694d1d206a217f5a2be29227edfa52d1eca0873bc7c8c04b9a7dc2cc7 + "@formatjs/fast-memoize": "npm:3.1.2" + checksum: 10c0/4693548ee9df74deb5f548635242ede0254507a531e04bb52d0983a653e7103bd4bfa1024e0b5b784fce1dadab57a31062bd7412b142f954c6614a7c9ee4cae7 languageName: node linkType: hard -"@formatjs/intl@npm:4.1.5": - version: 4.1.5 - resolution: "@formatjs/intl@npm:4.1.5" +"@formatjs/intl-pluralrules@npm:^6.0.0": + version: 6.3.2 + resolution: "@formatjs/intl-pluralrules@npm:6.3.2" dependencies: - "@formatjs/ecma402-abstract": "npm:3.2.0" - "@formatjs/fast-memoize": "npm:3.1.1" - "@formatjs/icu-messageformat-parser": "npm:3.5.3" - intl-messageformat: "npm:11.2.0" - checksum: 10c0/2fd7c6211b38fd6178093e7358f015dc461bc80d428372064a0c144b1a32fce4050c34fa58b77af715b8dbf77909d408b59c7e714b0c612d1b573defe70828b2 + "@formatjs/bigdecimal": "npm:0.2.1" + "@formatjs/intl-localematcher": "npm:0.8.3" + checksum: 10c0/7ff9a9a48efc970d6ebcb0902dc28fcf6577fd53f07c2b775ac918858a08d934317c654f6e481a978eeea2146a0e84ab7604f991d8bbdb147b42a004f582bec8 + languageName: node + linkType: hard + +"@formatjs/intl@npm:4.1.6": + version: 4.1.6 + resolution: "@formatjs/intl@npm:4.1.6" + dependencies: + "@formatjs/fast-memoize": "npm:3.1.2" + "@formatjs/icu-messageformat-parser": "npm:3.5.4" + intl-messageformat: "npm:11.2.1" + checksum: 10c0/d1bdd4ba373efc249090970c54bb7b5373f88d4294b9e6c889f91c8214b047715578b4fde4c917f809fddd0d52d3ec360ddc9a96def9e7c237c4024161ca29a0 languageName: node linkType: hard @@ -2529,11 +2566,11 @@ __metadata: languageName: node linkType: hard -"@formatjs/ts-transformer@npm:4.4.3": - version: 4.4.3 - resolution: "@formatjs/ts-transformer@npm:4.4.3" +"@formatjs/ts-transformer@npm:4.4.4": + version: 4.4.4 + resolution: "@formatjs/ts-transformer@npm:4.4.4" dependencies: - "@formatjs/icu-messageformat-parser": "npm:3.5.3" + "@formatjs/icu-messageformat-parser": "npm:3.5.4" "@types/node": "npm:22 || 24" json-stable-stringify: "npm:^1.3.0" typescript: "npm:^5.6 || 6" @@ -2542,18 +2579,18 @@ __metadata: peerDependenciesMeta: ts-jest: optional: true - checksum: 10c0/f5a4b32098e2c37c7ab7b40a798b6fa8e24e23516384579a698175ab214e2052e45256cc39880891de8db583c326a2e9f8581e1d4f7a0dc5d4aaa2291dec058d + checksum: 10c0/88aecd69792c34d3dbe3da3866422c3c6668102d316dd0bad848ec56ac1cd11d011e4b9253b72e0241e934a68d6b0144dda85ab0e200019c572edab4b257d93b languageName: node linkType: hard "@formatjs/unplugin@npm:^1.1.5": - version: 1.1.6 - resolution: "@formatjs/unplugin@npm:1.1.6" + version: 1.1.7 + resolution: "@formatjs/unplugin@npm:1.1.7" dependencies: - "@formatjs/icu-messageformat-parser": "npm:3.5.3" - "@formatjs/ts-transformer": "npm:4.4.3" + "@formatjs/icu-messageformat-parser": "npm:3.5.4" + "@formatjs/ts-transformer": "npm:4.4.4" magic-string: "npm:^0.30.0" - oxc-parser: "npm:^0.120.0" + oxc-parser: "npm:^0.124.0" unplugin: "npm:^3.0.0" peerDependencies: "@rspack/core": ">=1" @@ -2572,7 +2609,7 @@ __metadata: optional: true webpack: optional: true - checksum: 10c0/9371206edfb7d0197a04fc64b6095eea759b04a135fc766a9fe49b9252a65c7fae1c487f40952e3ae6e82ca77ee0aae456c46e42ecc7753f1990bc95e673f064 + checksum: 10c0/4578e27f0063095ac11dc717c42a483bd5e29e8eeba5ddafe95238f7c124a1c3f86edf933591f7efa3af950e5031bda77dd639fc10a11e11aae88ccdee61a0d2 languageName: node linkType: hard @@ -3040,7 +3077,7 @@ __metadata: languageName: node linkType: hard -"@napi-rs/wasm-runtime@npm:^1.1.1, @napi-rs/wasm-runtime@npm:^1.1.3": +"@napi-rs/wasm-runtime@npm:^1.1.2, @napi-rs/wasm-runtime@npm:^1.1.3": version: 1.1.3 resolution: "@napi-rs/wasm-runtime@npm:1.1.3" dependencies: @@ -3154,162 +3191,155 @@ __metadata: languageName: node linkType: hard -"@oxc-parser/binding-android-arm-eabi@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-android-arm-eabi@npm:0.120.0" +"@oxc-parser/binding-android-arm-eabi@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-android-arm-eabi@npm:0.124.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@oxc-parser/binding-android-arm64@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-android-arm64@npm:0.120.0" +"@oxc-parser/binding-android-arm64@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-android-arm64@npm:0.124.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@oxc-parser/binding-darwin-arm64@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-darwin-arm64@npm:0.120.0" +"@oxc-parser/binding-darwin-arm64@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-darwin-arm64@npm:0.124.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@oxc-parser/binding-darwin-x64@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-darwin-x64@npm:0.120.0" +"@oxc-parser/binding-darwin-x64@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-darwin-x64@npm:0.124.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@oxc-parser/binding-freebsd-x64@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-freebsd-x64@npm:0.120.0" +"@oxc-parser/binding-freebsd-x64@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-freebsd-x64@npm:0.124.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@oxc-parser/binding-linux-arm-gnueabihf@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-linux-arm-gnueabihf@npm:0.120.0" +"@oxc-parser/binding-linux-arm-gnueabihf@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-linux-arm-gnueabihf@npm:0.124.0" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@oxc-parser/binding-linux-arm-musleabihf@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-linux-arm-musleabihf@npm:0.120.0" +"@oxc-parser/binding-linux-arm-musleabihf@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-linux-arm-musleabihf@npm:0.124.0" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@oxc-parser/binding-linux-arm64-gnu@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-linux-arm64-gnu@npm:0.120.0" +"@oxc-parser/binding-linux-arm64-gnu@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-linux-arm64-gnu@npm:0.124.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@oxc-parser/binding-linux-arm64-musl@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-linux-arm64-musl@npm:0.120.0" +"@oxc-parser/binding-linux-arm64-musl@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-linux-arm64-musl@npm:0.124.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@oxc-parser/binding-linux-ppc64-gnu@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-linux-ppc64-gnu@npm:0.120.0" +"@oxc-parser/binding-linux-ppc64-gnu@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-linux-ppc64-gnu@npm:0.124.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@oxc-parser/binding-linux-riscv64-gnu@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-linux-riscv64-gnu@npm:0.120.0" +"@oxc-parser/binding-linux-riscv64-gnu@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-linux-riscv64-gnu@npm:0.124.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@oxc-parser/binding-linux-riscv64-musl@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-linux-riscv64-musl@npm:0.120.0" +"@oxc-parser/binding-linux-riscv64-musl@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-linux-riscv64-musl@npm:0.124.0" conditions: os=linux & cpu=riscv64 & libc=musl languageName: node linkType: hard -"@oxc-parser/binding-linux-s390x-gnu@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-linux-s390x-gnu@npm:0.120.0" +"@oxc-parser/binding-linux-s390x-gnu@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-linux-s390x-gnu@npm:0.124.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@oxc-parser/binding-linux-x64-gnu@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-linux-x64-gnu@npm:0.120.0" +"@oxc-parser/binding-linux-x64-gnu@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-linux-x64-gnu@npm:0.124.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@oxc-parser/binding-linux-x64-musl@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-linux-x64-musl@npm:0.120.0" +"@oxc-parser/binding-linux-x64-musl@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-linux-x64-musl@npm:0.124.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@oxc-parser/binding-openharmony-arm64@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-openharmony-arm64@npm:0.120.0" +"@oxc-parser/binding-openharmony-arm64@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-openharmony-arm64@npm:0.124.0" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@oxc-parser/binding-wasm32-wasi@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-wasm32-wasi@npm:0.120.0" +"@oxc-parser/binding-wasm32-wasi@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-wasm32-wasi@npm:0.124.0" dependencies: - "@napi-rs/wasm-runtime": "npm:^1.1.1" + "@napi-rs/wasm-runtime": "npm:^1.1.2" conditions: cpu=wasm32 languageName: node linkType: hard -"@oxc-parser/binding-win32-arm64-msvc@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-win32-arm64-msvc@npm:0.120.0" +"@oxc-parser/binding-win32-arm64-msvc@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-win32-arm64-msvc@npm:0.124.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@oxc-parser/binding-win32-ia32-msvc@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-win32-ia32-msvc@npm:0.120.0" +"@oxc-parser/binding-win32-ia32-msvc@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-win32-ia32-msvc@npm:0.124.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@oxc-parser/binding-win32-x64-msvc@npm:0.120.0": - version: 0.120.0 - resolution: "@oxc-parser/binding-win32-x64-msvc@npm:0.120.0" +"@oxc-parser/binding-win32-x64-msvc@npm:0.124.0": + version: 0.124.0 + resolution: "@oxc-parser/binding-win32-x64-msvc@npm:0.124.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@oxc-project/types@npm:=0.124.0": +"@oxc-project/types@npm:=0.124.0, @oxc-project/types@npm:^0.124.0": version: 0.124.0 resolution: "@oxc-project/types@npm:0.124.0" checksum: 10c0/9564ee3ce41f4b87802ffd0d62a7602d27f4503fbd39c1bedab98d54fde06e2ac254a8f85d8f679af1281a26e8fc7aa053fadbb3e09e786b38178eb38a8e2fb3 languageName: node linkType: hard -"@oxc-project/types@npm:^0.120.0": - version: 0.120.0 - resolution: "@oxc-project/types@npm:0.120.0" - checksum: 10c0/3090ca95ed1467ae790a79cf7aa49d1ea4ac390dbfccb7afb914c138034d01e72115e2e137a3cc76f409ba424e4d2b160a599fe137c88033ad68ba2df1e40b29 - languageName: node - linkType: hard - "@oxfmt/binding-android-arm-eabi@npm:0.33.0": version: 0.33.0 resolution: "@oxfmt/binding-android-arm-eabi@npm:0.33.0" @@ -8785,14 +8815,13 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:11.2.0, intl-messageformat@npm:^11.0.0": - version: 11.2.0 - resolution: "intl-messageformat@npm:11.2.0" +"intl-messageformat@npm:11.2.1, intl-messageformat@npm:^11.0.0": + version: 11.2.1 + resolution: "intl-messageformat@npm:11.2.1" dependencies: - "@formatjs/ecma402-abstract": "npm:3.2.0" - "@formatjs/fast-memoize": "npm:3.1.1" - "@formatjs/icu-messageformat-parser": "npm:3.5.3" - checksum: 10c0/0f0a92324ef61c885902ff41c99754a65f0cc5cbe25d690c1771605117df4f97a786bb06dec50f12a7047e4cb2fab1f2516002df32e93be6ac02e1967e928e44 + "@formatjs/fast-memoize": "npm:3.1.2" + "@formatjs/icu-messageformat-parser": "npm:3.5.4" + checksum: 10c0/c4d2e43c2e7940a8dbd75d7a3b77d722c7ac8802707f7410067097e3a923243343bd36367edb4e922b13d1a10425a2f52c544c65c9368841d481816ed04c6c2b languageName: node linkType: hard @@ -10658,31 +10687,31 @@ __metadata: languageName: node linkType: hard -"oxc-parser@npm:^0.120.0": - version: 0.120.0 - resolution: "oxc-parser@npm:0.120.0" +"oxc-parser@npm:^0.124.0": + version: 0.124.0 + resolution: "oxc-parser@npm:0.124.0" dependencies: - "@oxc-parser/binding-android-arm-eabi": "npm:0.120.0" - "@oxc-parser/binding-android-arm64": "npm:0.120.0" - "@oxc-parser/binding-darwin-arm64": "npm:0.120.0" - "@oxc-parser/binding-darwin-x64": "npm:0.120.0" - "@oxc-parser/binding-freebsd-x64": "npm:0.120.0" - "@oxc-parser/binding-linux-arm-gnueabihf": "npm:0.120.0" - "@oxc-parser/binding-linux-arm-musleabihf": "npm:0.120.0" - "@oxc-parser/binding-linux-arm64-gnu": "npm:0.120.0" - "@oxc-parser/binding-linux-arm64-musl": "npm:0.120.0" - "@oxc-parser/binding-linux-ppc64-gnu": "npm:0.120.0" - "@oxc-parser/binding-linux-riscv64-gnu": "npm:0.120.0" - "@oxc-parser/binding-linux-riscv64-musl": "npm:0.120.0" - "@oxc-parser/binding-linux-s390x-gnu": "npm:0.120.0" - "@oxc-parser/binding-linux-x64-gnu": "npm:0.120.0" - "@oxc-parser/binding-linux-x64-musl": "npm:0.120.0" - "@oxc-parser/binding-openharmony-arm64": "npm:0.120.0" - "@oxc-parser/binding-wasm32-wasi": "npm:0.120.0" - "@oxc-parser/binding-win32-arm64-msvc": "npm:0.120.0" - "@oxc-parser/binding-win32-ia32-msvc": "npm:0.120.0" - "@oxc-parser/binding-win32-x64-msvc": "npm:0.120.0" - "@oxc-project/types": "npm:^0.120.0" + "@oxc-parser/binding-android-arm-eabi": "npm:0.124.0" + "@oxc-parser/binding-android-arm64": "npm:0.124.0" + "@oxc-parser/binding-darwin-arm64": "npm:0.124.0" + "@oxc-parser/binding-darwin-x64": "npm:0.124.0" + "@oxc-parser/binding-freebsd-x64": "npm:0.124.0" + "@oxc-parser/binding-linux-arm-gnueabihf": "npm:0.124.0" + "@oxc-parser/binding-linux-arm-musleabihf": "npm:0.124.0" + "@oxc-parser/binding-linux-arm64-gnu": "npm:0.124.0" + "@oxc-parser/binding-linux-arm64-musl": "npm:0.124.0" + "@oxc-parser/binding-linux-ppc64-gnu": "npm:0.124.0" + "@oxc-parser/binding-linux-riscv64-gnu": "npm:0.124.0" + "@oxc-parser/binding-linux-riscv64-musl": "npm:0.124.0" + "@oxc-parser/binding-linux-s390x-gnu": "npm:0.124.0" + "@oxc-parser/binding-linux-x64-gnu": "npm:0.124.0" + "@oxc-parser/binding-linux-x64-musl": "npm:0.124.0" + "@oxc-parser/binding-openharmony-arm64": "npm:0.124.0" + "@oxc-parser/binding-wasm32-wasi": "npm:0.124.0" + "@oxc-parser/binding-win32-arm64-msvc": "npm:0.124.0" + "@oxc-parser/binding-win32-ia32-msvc": "npm:0.124.0" + "@oxc-parser/binding-win32-x64-msvc": "npm:0.124.0" + "@oxc-project/types": "npm:^0.124.0" dependenciesMeta: "@oxc-parser/binding-android-arm-eabi": optional: true @@ -10724,7 +10753,7 @@ __metadata: optional: true "@oxc-parser/binding-win32-x64-msvc": optional: true - checksum: 10c0/12b717560645480f12954b2eaaabcf8043dfc7a8bc0105627ff11d7958d52a90eaf9f5cfb6af82f148d5e69ef7c57ac5a84f8834fc1edda695b2b09d6bb4e73d + checksum: 10c0/06bd6b937f0574f49b74112cf2af3fb9990e7445d40126fca2c6ceb950c7ba5e10fbb223d941341c8207376620f6ee37466779a4fbff78ed7a67e15df3459d9c languageName: node linkType: hard @@ -12036,17 +12065,16 @@ __metadata: linkType: hard "react-intl@npm:^10.0.0": - version: 10.1.1 - resolution: "react-intl@npm:10.1.1" + version: 10.1.2 + resolution: "react-intl@npm:10.1.2" dependencies: - "@formatjs/ecma402-abstract": "npm:3.2.0" - "@formatjs/icu-messageformat-parser": "npm:3.5.3" - "@formatjs/intl": "npm:4.1.5" - intl-messageformat: "npm:11.2.0" + "@formatjs/icu-messageformat-parser": "npm:3.5.4" + "@formatjs/intl": "npm:4.1.6" + intl-messageformat: "npm:11.2.1" peerDependencies: "@types/react": 19 react: 19 - checksum: 10c0/97ac04e5813d22bb0f7cbc7332c41a683b61deddd9f1e2720c72536bc74abb23713b02602bf69c1fbd99ab1d087ff1b334a1ef89b2332c867b9030187d128dd9 + checksum: 10c0/785a4c0d16a5cb64888b23f6f2d8a87296bde05f1f834c34c5f7f6a73dcab6115afbbb0d4e71471fb287a9c919f32b54ed4b6284e60d21368dec1244eaf3e736 languageName: node linkType: hard From ec855cbf59b0899a7bd5966b1701b5a16dc4830a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:02:36 +0200 Subject: [PATCH 04/10] Update opentelemetry-ruby (non-major) (#38682) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile | 26 ++++++++-------- Gemfile.lock | 86 ++++++++++++++++++++++++++-------------------------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Gemfile b/Gemfile index 302b634e82..6d22ed3e19 100644 --- a/Gemfile +++ b/Gemfile @@ -105,19 +105,19 @@ gem 'opentelemetry-api', '~> 1.9.0' group :opentelemetry do gem 'opentelemetry-exporter-otlp', '~> 0.33.0', require: false - gem 'opentelemetry-instrumentation-active_job', '~> 0.10.0', require: false - gem 'opentelemetry-instrumentation-active_model_serializers', '~> 0.24.0', require: false - gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.24.0', require: false - gem 'opentelemetry-instrumentation-excon', '~> 0.28.0', require: false - gem 'opentelemetry-instrumentation-faraday', '~> 0.32.0', require: false - gem 'opentelemetry-instrumentation-http', '~> 0.29.0', require: false - gem 'opentelemetry-instrumentation-http_client', '~> 0.28.0', require: false - gem 'opentelemetry-instrumentation-net_http', '~> 0.28.0', require: false - gem 'opentelemetry-instrumentation-pg', '~> 0.35.0', require: false - gem 'opentelemetry-instrumentation-rack', '~> 0.30.0', require: false - gem 'opentelemetry-instrumentation-rails', '~> 0.40.0', require: false - gem 'opentelemetry-instrumentation-redis', '~> 0.28.0', require: false - gem 'opentelemetry-instrumentation-sidekiq', '~> 0.28.0', require: false + gem 'opentelemetry-instrumentation-active_job', '~> 0.11.0', require: false + gem 'opentelemetry-instrumentation-active_model_serializers', '~> 0.25.0', require: false + gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.25.0', require: false + gem 'opentelemetry-instrumentation-excon', '~> 0.29.0', require: false + gem 'opentelemetry-instrumentation-faraday', '~> 0.33.0', require: false + gem 'opentelemetry-instrumentation-http', '~> 0.30.0', require: false + gem 'opentelemetry-instrumentation-http_client', '~> 0.29.0', require: false + gem 'opentelemetry-instrumentation-net_http', '~> 0.29.0', require: false + gem 'opentelemetry-instrumentation-pg', '~> 0.36.0', require: false + gem 'opentelemetry-instrumentation-rack', '~> 0.31.0', require: false + gem 'opentelemetry-instrumentation-rails', '~> 0.41.0', require: false + gem 'opentelemetry-instrumentation-redis', '~> 0.29.0', require: false + gem 'opentelemetry-instrumentation-sidekiq', '~> 0.29.0', require: false gem 'opentelemetry-sdk', '~> 1.4', require: false end diff --git a/Gemfile.lock b/Gemfile.lock index 5abc3b42ba..cdf1ca3c14 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -519,61 +519,61 @@ GEM opentelemetry-common (~> 0.20) opentelemetry-sdk (~> 1.10) opentelemetry-semantic_conventions - opentelemetry-helpers-sql (0.3.0) + opentelemetry-helpers-sql (0.4.0) opentelemetry-api (~> 1.7) - opentelemetry-helpers-sql-processor (0.4.0) + opentelemetry-helpers-sql-processor (0.5.0) opentelemetry-api (~> 1.0) opentelemetry-common (~> 0.21) - opentelemetry-instrumentation-action_mailer (0.6.1) + opentelemetry-instrumentation-action_mailer (0.7.0) opentelemetry-instrumentation-active_support (~> 0.10) - opentelemetry-instrumentation-action_pack (0.16.0) + opentelemetry-instrumentation-action_pack (0.17.0) opentelemetry-instrumentation-rack (~> 0.29) - opentelemetry-instrumentation-action_view (0.11.2) + opentelemetry-instrumentation-action_view (0.12.0) opentelemetry-instrumentation-active_support (~> 0.10) - opentelemetry-instrumentation-active_job (0.10.1) + opentelemetry-instrumentation-active_job (0.11.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-active_model_serializers (0.24.0) + opentelemetry-instrumentation-active_model_serializers (0.25.0) opentelemetry-instrumentation-active_support (>= 0.7.0) - opentelemetry-instrumentation-active_record (0.11.1) + opentelemetry-instrumentation-active_record (0.12.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-active_storage (0.3.1) + opentelemetry-instrumentation-active_storage (0.4.0) opentelemetry-instrumentation-active_support (~> 0.10) - opentelemetry-instrumentation-active_support (0.10.1) + opentelemetry-instrumentation-active_support (0.11.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-base (0.25.0) + opentelemetry-instrumentation-base (0.26.0) opentelemetry-api (~> 1.7) opentelemetry-common (~> 0.21) opentelemetry-registry (~> 0.1) - opentelemetry-instrumentation-concurrent_ruby (0.24.0) + opentelemetry-instrumentation-concurrent_ruby (0.25.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-excon (0.28.0) + opentelemetry-instrumentation-excon (0.29.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-faraday (0.32.0) + opentelemetry-instrumentation-faraday (0.33.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-http (0.29.0) + opentelemetry-instrumentation-http (0.30.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-http_client (0.28.0) + opentelemetry-instrumentation-http_client (0.29.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-net_http (0.28.0) + opentelemetry-instrumentation-net_http (0.29.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-pg (0.35.0) + opentelemetry-instrumentation-pg (0.36.0) opentelemetry-helpers-sql opentelemetry-helpers-sql-processor opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-rack (0.30.0) + opentelemetry-instrumentation-rack (0.31.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-rails (0.40.0) - opentelemetry-instrumentation-action_mailer (~> 0.6) - opentelemetry-instrumentation-action_pack (~> 0.15) - opentelemetry-instrumentation-action_view (~> 0.11) - opentelemetry-instrumentation-active_job (~> 0.10) - opentelemetry-instrumentation-active_record (~> 0.11) - opentelemetry-instrumentation-active_storage (~> 0.3) - opentelemetry-instrumentation-active_support (~> 0.10) - opentelemetry-instrumentation-concurrent_ruby (~> 0.23) - opentelemetry-instrumentation-redis (0.28.0) + opentelemetry-instrumentation-rails (0.41.0) + opentelemetry-instrumentation-action_mailer (~> 0.7) + opentelemetry-instrumentation-action_pack (~> 0.17) + opentelemetry-instrumentation-action_view (~> 0.12) + opentelemetry-instrumentation-active_job (~> 0.11) + opentelemetry-instrumentation-active_record (~> 0.12) + opentelemetry-instrumentation-active_storage (~> 0.4) + opentelemetry-instrumentation-active_support (~> 0.11) + opentelemetry-instrumentation-concurrent_ruby (~> 0.25) + opentelemetry-instrumentation-redis (0.29.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-sidekiq (0.28.1) + opentelemetry-instrumentation-sidekiq (0.29.0) opentelemetry-instrumentation-base (~> 0.25) opentelemetry-registry (0.5.0) opentelemetry-api (~> 1.1) @@ -1022,19 +1022,19 @@ DEPENDENCIES omniauth_openid_connect (~> 0.8.0) opentelemetry-api (~> 1.9.0) opentelemetry-exporter-otlp (~> 0.33.0) - opentelemetry-instrumentation-active_job (~> 0.10.0) - opentelemetry-instrumentation-active_model_serializers (~> 0.24.0) - opentelemetry-instrumentation-concurrent_ruby (~> 0.24.0) - opentelemetry-instrumentation-excon (~> 0.28.0) - opentelemetry-instrumentation-faraday (~> 0.32.0) - opentelemetry-instrumentation-http (~> 0.29.0) - opentelemetry-instrumentation-http_client (~> 0.28.0) - opentelemetry-instrumentation-net_http (~> 0.28.0) - opentelemetry-instrumentation-pg (~> 0.35.0) - opentelemetry-instrumentation-rack (~> 0.30.0) - opentelemetry-instrumentation-rails (~> 0.40.0) - opentelemetry-instrumentation-redis (~> 0.28.0) - opentelemetry-instrumentation-sidekiq (~> 0.28.0) + opentelemetry-instrumentation-active_job (~> 0.11.0) + opentelemetry-instrumentation-active_model_serializers (~> 0.25.0) + opentelemetry-instrumentation-concurrent_ruby (~> 0.25.0) + opentelemetry-instrumentation-excon (~> 0.29.0) + opentelemetry-instrumentation-faraday (~> 0.33.0) + opentelemetry-instrumentation-http (~> 0.30.0) + opentelemetry-instrumentation-http_client (~> 0.29.0) + opentelemetry-instrumentation-net_http (~> 0.29.0) + opentelemetry-instrumentation-pg (~> 0.36.0) + opentelemetry-instrumentation-rack (~> 0.31.0) + opentelemetry-instrumentation-rails (~> 0.41.0) + opentelemetry-instrumentation-redis (~> 0.29.0) + opentelemetry-instrumentation-sidekiq (~> 0.29.0) opentelemetry-sdk (~> 1.4) ox (~> 2.14) parslet From 27d92ede7e4a42f0c73248c869cc12ce892acf91 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:02:40 +0200 Subject: [PATCH 05/10] Update dependency pghero to v3.8.0 (#38706) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index cdf1ca3c14..86ab28d044 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -597,8 +597,8 @@ GEM pastel (0.8.0) tty-color (~> 0.5) pg (1.6.3) - pghero (3.7.0) - activerecord (>= 7.1) + pghero (3.8.0) + activerecord (>= 7.2) playwright-ruby-client (1.59.0) base64 concurrent-ruby (>= 1.1.6) From 5399d9761cc9e6693680b420593f2cb751d6385b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:02:44 +0200 Subject: [PATCH 06/10] Update dependency uuid to v14 (#38744) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- streaming/package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/streaming/package.json b/streaming/package.json index 947ad49bcf..8308c47032 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -27,7 +27,7 @@ "pino": "^10.0.0", "pino-http": "^11.0.0", "prom-client": "^15.0.0", - "uuid": "^13.0.0", + "uuid": "^14.0.0", "ws": "^8.12.1" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index e899af63b3..df1f4db459 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3030,7 +3030,7 @@ __metadata: typescript: "npm:~6.0.0" typescript-eslint: "npm:^8.55.0" utf-8-validate: "npm:^6.0.3" - uuid: "npm:^13.0.0" + uuid: "npm:^14.0.0" ws: "npm:^8.12.1" dependenciesMeta: bufferutil: @@ -14678,12 +14678,12 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^13.0.0": - version: 13.0.0 - resolution: "uuid@npm:13.0.0" +"uuid@npm:^14.0.0": + version: 14.0.0 + resolution: "uuid@npm:14.0.0" bin: uuid: dist-node/bin/uuid - checksum: 10c0/950e4c18d57fef6c69675344f5700a08af21e26b9eff2bf2180427564297368c538ea11ac9fb2e6528b17fc3966a9fd2c5049361b0b63c7d654f3c550c9b3d67 + checksum: 10c0/a57ae7794c45005c1a9208989196c5baf79a7679c30f43c1bee9033a2c4d113a2cea216fa6fcc9663b08b0d55635df1a7c6eb7e7f3d21c3e50688c698fa39a50 languageName: node linkType: hard From 9717dc64d0f263980bfaf9190ba705f99c68cf23 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:10:06 +0200 Subject: [PATCH 07/10] New Crowdin Translations (automated) (#38762) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/de.json | 2 ++ app/javascript/mastodon/locales/el.json | 2 +- app/javascript/mastodon/locales/en-GB.json | 21 ++++++++++++ app/javascript/mastodon/locales/et.json | 28 +++++++-------- app/javascript/mastodon/locales/lv.json | 40 ++++++++++++++++++++++ config/locales/doorkeeper.et.yml | 4 +++ config/locales/et.yml | 2 +- config/locales/simple_form.en-GB.yml | 3 ++ config/locales/simple_form.et.yml | 5 +++ 9 files changed, 91 insertions(+), 16 deletions(-) diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 6a1c63b921..31f9b5ecba 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -411,7 +411,9 @@ "collections.sensitive": "Inhaltswarnung", "collections.share_short": "Teilen", "collections.suggestions.can_not_add": "Kann nicht hinzugefügt werden", + "collections.suggestions.can_not_add_desc": "Diese Konten möchten möglicherweise nicht entdeckt werden oder deren Server unterstützt noch keine Sammlungen.", "collections.suggestions.must_follow": "Zuerst Profil folgen", + "collections.suggestions.must_follow_desc": "Diese Konten überprüfen ihre Follower-Anfragen manuell. Follower können sie zu Sammlungen hinzufügen.", "collections.topic_hint": "Ein Hashtag für diese Sammlung kann anderen dabei helfen, dein Anliegen besser einordnen zu können.", "collections.topic_special_chars_hint": "Sonderzeichen werden beim Speichern entfernt", "collections.unlisted_collections_description": "Die Sammlungen sind für andere nicht auf deinem Profil sichtbar. Ein direkter Zugriff ist per Link möglich.", diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index 3e0a48c7cc..863cb4f03c 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -666,7 +666,7 @@ "featured_carousel.header": "{count, plural, one {Καρφιτσωμένη Ανάρτηση} other {Καρφιτσωμένες Αναρτήσεις}}", "featured_carousel.slide": "Ανάρτηση {current, number} από {max, number}", "featured_tags.more_items": "+{count}", - "featured_tags.suggestions": "Τον τελευταίο καιρό έχετε δημοσιεύσει για {items}. Προσθέστε αυτά ως αναδεδειγμένες ετικέτες;", + "featured_tags.suggestions": "Τον τελευταίο καιρό έχεις δημοσιεύσει για {items}. Να προστεθούν αυτά ως αναδεδειγμένες ετικέτες;", "featured_tags.suggestions.add": "Προσθήκη", "featured_tags.suggestions.added": "Διαχειριστείτε τις αναδεδειγμένες ετικέτες σας οποιαδήποτε στιγμή κάτω από το Επεξεργασία προφίλ > Αναδεδειγμένες ετικέτες.", "featured_tags.suggestions.dismiss": "Όχι, ευχαριστώ", diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json index 43330f176e..0718725951 100644 --- a/app/javascript/mastodon/locales/en-GB.json +++ b/app/javascript/mastodon/locales/en-GB.json @@ -106,6 +106,7 @@ "account.name.copy": "Copy handle", "account.name.help.domain": "{domain} is the server that hosts the user’s profile and posts.", "account.name.help.domain_self": "{domain} is your server that hosts your profile and posts.", + "account.name.help.footer": "Just like you can send emails to people using different email providers, you can interact with people on other Mastodon servers, and with anyone on other Mastodon-compatible social apps.", "account.name.help.header": "A handle is like an email address", "account.name.help.username": "{username} is this account’s username on their server. Someone on another server might have the same username.", "account.name.help.username_self": "{username} is your username on this server. Someone on another server might have the same username.", @@ -350,6 +351,7 @@ "closed_registrations_modal.find_another_server": "Find another server", "closed_registrations_modal.preamble": "Mastodon is decentralised, so no matter where you create your account, you will be able to follow and interact with anyone on this server. You can even self-host it!", "closed_registrations_modal.title": "Signing up on Mastodon", + "collection.share_modal.share_link_label": "Share link", "collection.share_modal.share_via_post": "Post on Mastodon", "collection.share_modal.share_via_system": "Share to…", "collection.share_modal.title": "Share collection", @@ -357,7 +359,10 @@ "collection.share_template_other": "Check out this cool collection: {link}", "collection.share_template_own": "Check out my new collection: {link}", "collections.account_count": "{count, plural, one {# account} other {# accounts}}", + "collections.accounts.empty_description": "Add up to {count} accounts", + "collections.accounts.empty_editor_title": "No one is in this collection yet", "collections.accounts.empty_title": "This collection is empty", + "collections.block_collection_owner": "Block account", "collections.by_account": "Delete", "collections.collection_description": "Description", "collections.collection_language": "Language", @@ -367,6 +372,8 @@ "collections.confirm_account_removal": "Are you sure you want to remove this account from this collection?", "collections.content_warning": "Content warning", "collections.continue": "Continue", + "collections.copy_link": "Copy link", + "collections.copy_link_confirmation": "Copied collection link to clipboard", "collections.create.accounts_title": "Who will you feature in this collection?", "collections.create.basic_details_title": "Basic details", "collections.create.steps": "Step {step}/{total}", @@ -384,6 +391,9 @@ "collections.detail.you_are_in_this_collection": "You're featured in this collection", "collections.edit_details": "Edit details", "collections.error_loading_collections": "There was an error when trying to load your collections.", + "collections.hidden_accounts_description": "You’ve blocked or muted {count, plural, one {this user} other {these users}}", + "collections.hidden_accounts_link": "{count, plural, one {# hidden account} other {# hidden accounts}}", + "collections.hints.accounts_counter": "{count}/{max} accounts", "collections.last_updated_at": "Last updated: {date}", "collections.manage_accounts": "Manage accounts", "collections.mark_as_sensitive": "Mark as sensitive", @@ -391,14 +401,23 @@ "collections.name_length_hint": "40 characters limit", "collections.new_collection": "New collection", "collections.no_collections_yet": "No collections yet.", + "collections.remove_account": "Remove", "collections.report_collection": "Report this collection", "collections.revoke_collection_inclusion": "Remove myself from this collection", "collections.revoke_inclusion.confirmation": "You've been removed from \"{collection}\"", "collections.revoke_inclusion.error": "There was an error, please try again later.", + "collections.search_accounts_label": "Search for an account to add", "collections.search_accounts_max_reached": "You have added the maximum number of accounts", "collections.sensitive": "Sensitive", + "collections.share_short": "Share", + "collections.suggestions.can_not_add": "Can’t be added", + "collections.suggestions.can_not_add_desc": "These accounts may have opted out of discovery, or they might be on a server that doesn’t support collections.", + "collections.suggestions.must_follow": "Must follow first", + "collections.suggestions.must_follow_desc": "These accounts review all follow requests. Followers can add them to collections.", "collections.topic_hint": "Add a hashtag that helps others understand the main topic of this collection.", "collections.topic_special_chars_hint": "Special characters will be removed when saving", + "collections.unlisted_collections_description": "These don’t appear on your profile to others. Anyone with the link can discover them.", + "collections.unlisted_collections_with_count": "Unlisted collections ({count})", "collections.view_collection": "View collection", "collections.visibility_public": "Public", "collections.visibility_public_hint": "Discoverable in search results and other areas where recommendations appear.", @@ -891,6 +910,7 @@ "navigation_panel.expand_followed_tags": "Expand followed hashtags menu", "navigation_panel.expand_lists": "Expand list menu", "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", + "notification.added_to_collection": "{name} added you to a collection", "notification.admin.report": "{name} reported {target}", "notification.admin.report_account": "{name} reported {count, plural, one {one post} other {# posts}} from {target} for {category}", "notification.admin.report_account_other": "{name} reported {count, plural, one {one post} other {# posts}} from {target}", @@ -900,6 +920,7 @@ "notification.admin.sign_up.name_and_others": "{name} and {count, plural, one {# other} other {# others}} signed up", "notification.annual_report.message": "Your {year} #Wrapstodon awaits! Unveil your year's highlights and memorable moments on Mastodon!", "notification.annual_report.view": "View #Wrapstodon", + "notification.collection_update": "{name} edited a collection you’re in", "notification.favourite": "{name} favourited your post", "notification.favourite.name_and_others_with_link": "{name} and {count, plural, one {# other} other {# others}} favourited your post", "notification.favourite_pm": "{name} favourited your private mention", diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json index 5c79bccfae..b70fc916c0 100644 --- a/app/javascript/mastodon/locales/et.json +++ b/app/javascript/mastodon/locales/et.json @@ -141,8 +141,8 @@ "account.unmute_notifications_short": "Lõpeta teavituste summutamine", "account.unmute_short": "Lõpeta summutamine", "account_edit.advanced_settings.bot_hint": "Teavita teisi, et sel kontol tehakse peamiselt automatiseeritud toiminguid ja seda ei pruugita jälgida", - "account_edit.advanced_settings.bot_label": "Automatiseeritud konto", - "account_edit.advanced_settings.title": "Täpsemad seaded", + "account_edit.advanced_settings.bot_label": "Automatiseeritud kasutajakonto", + "account_edit.advanced_settings.title": "Täpsemad seadistused", "account_edit.bio.add_label": "Lisa elulugu", "account_edit.bio.edit_label": "Muuda elulugu", "account_edit.bio.placeholder": "Lisa lühike tutvustus, et aidata teistel sinust pilti luua.", @@ -158,7 +158,7 @@ "account_edit.custom_fields.tip_content": "Saad Mastodoni konto usaldusväärsust hõlpsasti suurendada, kinnitades lingid lehtedele, mis sulle kuuluvad.", "account_edit.custom_fields.tip_title": "Soovitus: Kinnitatud linkide lisamine", "account_edit.custom_fields.title": "Kohandatud väljad", - "account_edit.custom_fields.verified_hint": "Kuidas lisada kinnitatud link?", + "account_edit.custom_fields.verified_hint": "Kuidas lisada kinnitatud linki?", "account_edit.display_name.add_label": "Lisa kuvatav nimi", "account_edit.display_name.edit_label": "Muuda kuvatavat nime", "account_edit.display_name.placeholder": "Kuvatav nimi määrab, kuidas sinu nimi on näha sinu profiilis ja ajajoontel.", @@ -170,7 +170,7 @@ "account_edit.field_actions.edit": "Muuda välja", "account_edit.field_delete_modal.confirm": "Kas oled kindel, et soovid selle kohandatud välja kustutada? Seda toimingut ei saa tagasi võtta.", "account_edit.field_delete_modal.delete_button": "Kustuta", - "account_edit.field_delete_modal.title": "Kustutada kohandatud väli?", + "account_edit.field_delete_modal.title": "Kas kustutame kohandatud välja?", "account_edit.field_edit_modal.add_title": "Lisa kohandatud väli", "account_edit.field_edit_modal.discard_confirm": "Loobu", "account_edit.field_edit_modal.discard_message": "Sul on salvestamata muudatusi. Kas soovid tõesti neist loobuda?", @@ -211,14 +211,14 @@ "account_edit.profile_tab.button_label": "Kohanda", "account_edit.profile_tab.hint.description": "Need seaded määravad, mida kasutajad näevad {server} ametlikes rakendustes, kuid ei pruugi kehtida teiste serverite kasutajate ja kolmandate osapoolte rakenduste puhul.", "account_edit.profile_tab.hint.title": "Näitamine siiski erinev", - "account_edit.profile_tab.show_featured.description": "\"Esile tõstetud\" on valikuline taab, kus saad näidata teisi kontosid.", - "account_edit.profile_tab.show_featured.title": "Näita esiletõstetute taabi", - "account_edit.profile_tab.show_media.description": "\"Meedia\" on valikuline taab, mis näitab sinu piltide või videotega postitusi.", - "account_edit.profile_tab.show_media.title": "Näita meedia taabi", - "account_edit.profile_tab.show_media_replies.description": "Sisse lülitatuna näitab meedia taab mõlemat, nii sinu postitusi kui su vastuseid teiste postitustele.", - "account_edit.profile_tab.show_media_replies.title": "Kaasa meedia taabile ka vastused", + "account_edit.profile_tab.show_featured.description": "„Esiletõstetud“ on valikuline vahekaart, kus saad näidata teisi kontosid.", + "account_edit.profile_tab.show_featured.title": "Näita vahekaarti „Esiletõstetud“", + "account_edit.profile_tab.show_media.description": "„Meedium“ on valikuline vahekaart, mis näitab sinu piltide või videotega postitusi.", + "account_edit.profile_tab.show_media.title": "Näita multimeedia vahekaarti", + "account_edit.profile_tab.show_media_replies.description": "Sisselülitatuna näitab mediumi vahekaart, nii sinu postitusi kui su vastuseid teiste kasutajate postitustele.", + "account_edit.profile_tab.show_media_replies.title": "Kaasa vahekaardile „Meedium“ ka vastused", "account_edit.profile_tab.subtitle": "Kohanda oma profiili vahekaarte ja nende sisu.", - "account_edit.profile_tab.title": "Profiili taabide seaded", + "account_edit.profile_tab.title": "Profiili vahekaartide seadistused", "account_edit.save": "Salvesta", "account_edit.upload_modal.back": "Tagasi", "account_edit.upload_modal.done": "Valmis", @@ -511,10 +511,10 @@ "confirmations.follow_to_list.confirm": "Jälgi ja lisa loetellu", "confirmations.follow_to_list.message": "Pead jälgima kasutajat {name}, et lisada teda loetellu.", "confirmations.follow_to_list.title": "Jälgida kasutajat?", - "confirmations.hide_featured_tab.confirm": "Peida taab", + "confirmations.hide_featured_tab.confirm": "Peida vahekaart", "confirmations.hide_featured_tab.intro": "Saad seda igal ajal muuta menüüs Profiili muutmine > Profiili vahekaardi seaded.", "confirmations.hide_featured_tab.message": "See peidab vahekaardi serveri {serverName} kasutajatel ja teistel serveritel, kus kasutatakse Mastodoni uusimat versiooni. Muudel serveritel võib kuvamine erineda.", - "confirmations.hide_featured_tab.title": "Peita taab Esiletõstetud?", + "confirmations.hide_featured_tab.title": "Kas peidame vahekaardi „Esiletõstetud“?", "confirmations.logout.confirm": "Välju", "confirmations.logout.message": "Kas oled kindel, et soovid välja logida?", "confirmations.logout.title": "Logida välja?", @@ -621,7 +621,7 @@ "emoji_button.travel": "Reisimine & kohad", "empty_column.account_featured.other": "{acct} pole veel midagi esile tõstnud.", "empty_column.account_featured_self.no_collections_button": "Loo kogumik", - "empty_column.account_featured_self.no_collections_hide_tab": "Selle asemel peida see taab", + "empty_column.account_featured_self.no_collections_hide_tab": "Selle asemel peida see vahekaart", "empty_column.account_featured_self.pre_collections": "Jälgi kogumikke", "empty_column.account_featured_self.pre_collections_desc": "Kogumikud (lisanduvad Mastodon V4.6) võimaldavad sul luua enda koostatud kontode nimekirju, mida teistele soovitada.", "empty_column.account_featured_self.showcase_accounts": "Näita oma lemmikkontosid", diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index e03bfdca29..30fab0f1bf 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -64,6 +64,7 @@ "account.media": "Multivide", "account.mention": "Pieminēt @{name}", "account.menu.block": "Bloķēt kontu", + "account.menu.copy": "Kopēt saiti", "account.moved_to": "{name} norādīja, ka viņu jaunais konts tagad ir:", "account.mute": "Apklusināt @{name}", "account.mute_notifications_short": "Apklusināt paziņojumus", @@ -71,8 +72,10 @@ "account.muted": "Apklusināts", "account.muting": "Apklusināts", "account.mutual": "Jūs sekojat viens otram", + "account.name_info": "Ko tas nozīmē?", "account.no_bio": "Apraksts nav sniegts.", "account.node_modal.save": "Saglabāt", + "account.note.edit_button": "Labot", "account.open_original_page": "Atvērt pirmavota lapu", "account.posts": "Ieraksti", "account.remove_from_followers": "Dzēst sekotāju {name}", @@ -91,6 +94,7 @@ "account.unmute": "Noņemt apklusinājumu @{name}", "account.unmute_notifications_short": "Atcelet paziņojumu apklusināšanu", "account.unmute_short": "Noņemt apklusinājumu", + "account_edit.bio.edit_label": "Labot biogrāfiju", "account_edit.bio.title": "Biogrāfija", "account_edit.bio_modal.add_title": "Pievienot biogrāfiju", "account_edit.bio_modal.edit_title": "Labot biogrāfiju", @@ -98,8 +102,23 @@ "account_edit.column_title": "Labot profilu", "account_edit.custom_fields.add_label": "Pievienot lauku", "account_edit.custom_fields.edit_label": "Labot lauku", + "account_edit.field_actions.delete": "Dzēst lauku", + "account_edit.field_actions.edit": "Labot lauku", "account_edit.field_delete_modal.delete_button": "Dzēst", "account_edit.field_edit_modal.discard_confirm": "Atmest", + "account_edit.image_delete_modal.delete_button": "Dzēst", + "account_edit.image_delete_modal.title": "Dzēst attēlu?", + "account_edit.image_edit.add_button": "Pievienot attēlu", + "account_edit.image_edit.remove_button": "Noņemt attēlu", + "account_edit.save": "Saglabāt", + "account_edit.upload_modal.back": "Atpakaļ", + "account_edit.upload_modal.done": "Gatavs", + "account_edit.upload_modal.step_upload.button": "Pārlūkot failus", + "account_edit.upload_modal.title_add.avatar": "Pievienot profila fotoattēlu", + "account_edit.upload_modal.title_add.header": "Pievienot titullapas fotoattēlu", + "account_edit.upload_modal.title_replace.avatar": "Nomainīt profila fotoattēlu", + "account_edit.upload_modal.title_replace.header": "Nomainīt titullapas fotoattēlu", + "account_edit_tags.suggestions": "Ieteikumi:", "account_note.placeholder": "Noklikšķini, lai pievienotu piezīmi", "admin.dashboard.daily_retention": "Lietotāju saglabāšanas rādītājs dienā pēc reģistrēšanās", "admin.dashboard.monthly_retention": "Lietotāju saglabāšanas rādītājs mēnesī pēc reģistrēšanās", @@ -123,6 +142,11 @@ "alt_text_modal.describe_for_people_with_visual_impairments": "Aprakstīt šo cilvēkiem ar redzes traucējumiem…", "alt_text_modal.done": "Gatavs", "announcement.announcement": "Paziņojums", + "annual_report.shared_page.donate": "Ziedot", + "annual_report.summary.archetype.title_public": "Lietotāja \"{name}\" arhetips", + "annual_report.summary.archetype.title_self": "Tavs arhetips", + "annual_report.summary.close": "Aizvērt", + "annual_report.summary.copy_link": "Kopēt saiti", "annual_report.summary.most_used_app.most_used_app": "visizmantotākā lietotne", "annual_report.summary.most_used_hashtag.most_used_hashtag": "visizmantotākais tēmturis", "annual_report.summary.new_posts.new_posts": "jauni ieraksti", @@ -158,6 +182,19 @@ "closed_registrations_modal.find_another_server": "Atrast citu serveri", "closed_registrations_modal.preamble": "Mastodon ir decentralizēts, tāpēc neatkarīgi no tā, kur Tu izveido savu kontu, varēsi sekot un mijiedarboties ar ikvienu šajā serverī. Tu pat vari to pašizvietot!", "closed_registrations_modal.title": "Reģistrēšanās Mastodon", + "collections.accounts.empty_title": "Šī kolekcija ir tukša", + "collections.block_collection_owner": "Bloķēt kontu", + "collections.collection_description": "Apraksts", + "collections.collection_language": "Valoda", + "collections.collection_language_none": "Nav", + "collections.collection_name": "Nosaukums", + "collections.collection_topic": "Tēma", + "collections.continue": "Turpināt", + "collections.copy_link": "Kopēt saiti", + "collections.manage_accounts": "Pārvaldīt kontus", + "collections.remove_account": "Noņemt", + "collections.suggestions.can_not_add": "Nevar pievienot", + "collections.visibility_title": "Redzamība", "column.about": "Par", "column.blocks": "Liegtie lietotāji", "column.bookmarks": "Grāmatzīmes", @@ -185,6 +222,8 @@ "column_header.show_settings": "Rādīt iestatījumus", "column_header.unpin": "Atspraust", "column_search.cancel": "Atcelt", + "combobox.loading": "Ielādē", + "combobox.open_results": "Atvērt rezultātus", "community.column_settings.local_only": "Tikai vietējie", "community.column_settings.media_only": "Tikai multivide", "community.column_settings.remote_only": "Tikai attālinātie", @@ -218,6 +257,7 @@ "confirmations.delete.confirm": "Dzēst", "confirmations.delete.message": "Vai tiešām izdzēst šo ierakstu?", "confirmations.delete.title": "Izdzēst ierakstu?", + "confirmations.delete_collection.confirm": "Dzēst", "confirmations.delete_list.confirm": "Dzēst", "confirmations.delete_list.message": "Vai tiešām neatgriezeniski izdzēst šo sarakstu?", "confirmations.delete_list.title": "Izdzēst sarakstu?", diff --git a/config/locales/doorkeeper.et.yml b/config/locales/doorkeeper.et.yml index fb1cf2a614..786b896402 100644 --- a/config/locales/doorkeeper.et.yml +++ b/config/locales/doorkeeper.et.yml @@ -83,6 +83,10 @@ et: access_denied: Ressursi omanik või autoriseerimisserver lükkas taotluse tagasi. credential_flow_not_configured: Resource Owner Password Credentials vool ebaõnnestus, kuna Doorkeeper.configure.resource_owner_from_credentials ei ole seadistatud. invalid_client: Kliendi autentimine ebaõnnestus. Põhjus kas tundmatu klient, puudulik autentimine või toetamata autentimismeetod. + invalid_code_challenge_method: + one: "„code_challenge_method“ meetod peab olema selline: %{challenge_methods}." + other: "„code_challenge_method“ meetod peab olema üks neist: %{challenge_methods}." + zero: Kuna sobilikke „code_challenge_method“ meetodi väärtusi ei leidu, siis autentimisserver ei toeta PKCE-d. invalid_grant: Antud autoriseerimisluba on vale, aegunud, tagasi võetud, ei kattu kasutatud ümbersuunamise URLid või oli antud teisele kliendile. invalid_redirect_uri: Antud ümbersuunamise URL ei ole õige. invalid_request: diff --git a/config/locales/et.yml b/config/locales/et.yml index c2b0d918da..21e7de44ba 100644 --- a/config/locales/et.yml +++ b/config/locales/et.yml @@ -2238,7 +2238,7 @@ et: extra_instructions_html: Soovitus: Sinu kodulehel olev link võib olla nähtamatu. Oluline osa on rel="me", mis väldib kasutaja loodud sisuga lehtedel libaisikustamist. Sa saad isegi kasutada lehe HEADER osas silti link sildi a asemel, kuid HTML peab olema kättesaadav ilma JavaScripti käivitamata. here_is_how: Siin on, kuidas hint_html: "Oma isiku tuvastamine on Mastodonis kõigi jaoks. Toetub avatud veebistandarditele, nüüd ja igavesti tasuta. Kõik, mida vajad, on isiklik veebileht, mille järgi inimesed sind tunnevad. Kui lingid oma profiililt sellele veebilehele, kontrollime me, et see veebileht lingib tagasi sinu profiilile ning näitame profiilil visuaalset tähist." - instructions_html: Kopeeri ja kleebi allpool olev kood oma lehe HTML lähtekoodi. Seejärel lisa oma kodulehe aadress profiili "Muuda profiili" vahekaardi ühte lisavälja ning salvesta muudatused. + instructions_html: Kopeeri ja aseta allpool olev kood oma lehe HTML lähtekoodi. Seejärel lisa oma kodulehe aadress profiili „Muuda profiili“ vahekaardi ühte lisavälja ning salvesta muudatused. verification: Kinnitamine verified_links: Sinu kontrollitud lingid website_verification: Veebilehe kontrollimine diff --git a/config/locales/simple_form.en-GB.yml b/config/locales/simple_form.en-GB.yml index aff14eaed5..71c2b7dd76 100644 --- a/config/locales/simple_form.en-GB.yml +++ b/config/locales/simple_form.en-GB.yml @@ -61,6 +61,9 @@ en-GB: setting_default_quote_policy_private: Followers-only posts authored on Mastodon can't be quoted by others. setting_default_quote_policy_unlisted: When people quote you, their post will also be hidden from trending timelines. setting_default_sensitive: Sensitive media is hidden by default and can be revealed with a click + setting_display_media_default: Warn before showing media marked as sensitive + setting_display_media_hide_all: Warn before showing all media + setting_display_media_show_all: Show all media without warning, including media marked as sensitive setting_emoji_style: How to display emojis. "Auto" will try using native emoji, but falls back to Twemoji for legacy browsers. setting_quick_boosting_html: When enabled, clicking on the %{boost_icon} Boost icon will immediately boost instead of opening the boost/quote dropdown menu. Relocates the quoting action to the %{options_icon} (Options) menu. setting_system_scrollbars_ui: Applies only to desktop browsers based on Safari and Chrome diff --git a/config/locales/simple_form.et.yml b/config/locales/simple_form.et.yml index 6e1e9343b0..906209ded4 100644 --- a/config/locales/simple_form.et.yml +++ b/config/locales/simple_form.et.yml @@ -134,6 +134,7 @@ et: otp: 'Kaheastmelise autentimise kood telefonirakendusest või mõni taastekood:' webauthn: Kui see on USB-võti, sisesta see ning vajadusel aktiveeri. settings: + email_subscriptions: Funktsionaalsuse keelamine säilitab olemasolevad tellijad, kuid peatab e-kirjade saatmise. indexable: Su profiilileht võib ilmuda Google, Bingi ja teiste otsimootorite tulemustes. show_application: Sa saad sõltumata sellest vaadata, milline äpp su postituse postitas. tag: @@ -153,6 +154,7 @@ et: jurisdiction: Nimeta riik, kus elab see, kes arveid maksab. Kui tegemist on äriühingu või muu üksusega, märgi riik, kus see on asutatud, ning vajaduse korral linn, piirkond, territoorium või osariik. min_age: Vanus ei tohiks olla väiksem, kui sinu õigusruumis nõutav alampiir. user: + chosen_languages: Kui see valik on märgitud, kuvatakse avalikul ajajoonel ainult valitud keeltes postitusi. See seadistus ei mõjuta sinu avalehe ajajoont ega loendeid. date_of_birth: one: "%{domain} saidi teenuste kasutamiseks pead olema vähemalt %{count} aastat vana. Me ei salvesta neid andmeid." other: "%{domain} saidi teenuste kasutamiseks pead olema vähemalt %{count} aastat vana. Me ei salvesta neid andmeid." @@ -175,6 +177,7 @@ et: labels: account: attribution_domains: Veebisaidid, mis võivad sind algallikana mainida + discoverable: Võimalda mind teistel avatada fields: name: Nimetus value: Sisu @@ -222,6 +225,7 @@ et: email: E-posti aadress expires_in: Aegu pärast fields: Veebiviited + filter_action: Filtritoimingud header: Päis honeypot: "%{label} (ära sisesta)" inbox_url: Sõnumivahendusserveri sisendkausta võrguaadress @@ -353,6 +357,7 @@ et: hint: Lisainfo text: Reegel settings: + email_subscriptions: Luba e-posti aadressiga liitumised indexable: Kaasa profiilileht otsimootoritesse show_application: Näita, millisest äpist postituse saatsid tag: From c589530e224b8aa6be8a3f4eac19bb3743fce142 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 21 Apr 2026 07:10:45 -0400 Subject: [PATCH 08/10] Add constants to track media player height/width (#38755) --- app/helpers/media_player_helper.rb | 6 ++++++ app/views/media/player.html.haml | 8 ++++---- app/views/statuses/_og_image.html.haml | 4 ++-- 3 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 app/helpers/media_player_helper.rb diff --git a/app/helpers/media_player_helper.rb b/app/helpers/media_player_helper.rb new file mode 100644 index 0000000000..8b617164d7 --- /dev/null +++ b/app/helpers/media_player_helper.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module MediaPlayerHelper + PLAYER_HEIGHT = 380 + PLAYER_WIDTH = 670 +end diff --git a/app/views/media/player.html.haml b/app/views/media/player.html.haml index 39c4ccc18f..b2d2121d15 100644 --- a/app/views/media/player.html.haml +++ b/app/views/media/player.html.haml @@ -14,7 +14,7 @@ detailed: true, editable: true, frameRate: meta.dig('original', 'frame_rate'), - height: 380, + height: MediaPlayerHelper::PLAYER_HEIGHT, inline: true, media: [ActiveModelSerializers::SerializableResource.new(@media_attachment, serializer: REST::MediaAttachmentSerializer)].as_json, preview: @media_attachment.thumbnail.present? ? @media_attachment.thumbnail.url : @media_attachment.file.url(:small), @@ -25,7 +25,7 @@ - elsif @media_attachment.gifv? = react_component :media_gallery, autoplay: true, - height: 380, + height: MediaPlayerHelper::PLAYER_HEIGHT, media: [ActiveModelSerializers::SerializableResource.new(@media_attachment, serializer: REST::MediaAttachmentSerializer).as_json], standalone: true do %video{ autoplay: 'autoplay', muted: 'muted', loop: 'loop' } @@ -38,9 +38,9 @@ duration: meta.dig(:original, :duration), foregroundColor: meta.dig('colors', 'foreground'), fullscreen: true, - height: 380, + height: MediaPlayerHelper::PLAYER_HEIGHT, poster: @media_attachment.thumbnail.present? ? @media_attachment.thumbnail.url : @media_attachment.account.avatar_static_url, src: @media_attachment.file.url(:original), - width: 670 do + width: MediaPlayerHelper::PLAYER_WIDTH do %audio{ controls: 'controls' } %source{ src: @media_attachment.file.url(:original) } diff --git a/app/views/statuses/_og_image.html.haml b/app/views/statuses/_og_image.html.haml index 7b6ca915c8..fd5939bd74 100644 --- a/app/views/statuses/_og_image.html.haml +++ b/app/views/statuses/_og_image.html.haml @@ -38,8 +38,8 @@ = opengraph 'twitter:player', player_medium_url(media) = opengraph 'twitter:player:stream', full_asset_url(media.file.url(:original)) = opengraph 'twitter:player:stream:content_type', media.file_content_type - = opengraph 'twitter:player:width', '670' - = opengraph 'twitter:player:height', '380' + = opengraph 'twitter:player:width', MediaPlayerHelper::PLAYER_WIDTH + = opengraph 'twitter:player:height', MediaPlayerHelper::PLAYER_HEIGHT - if player_card = opengraph 'twitter:card', 'player' - else From 57c5d1c8dd50a02bc3a11af30b29fa8163fcdb73 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 21 Apr 2026 13:40:09 +0200 Subject: [PATCH 09/10] Remove animation detection in favour of never cropping GIFs (#38766) --- .../account_edit/modals/image_upload.tsx | 73 ++++--------------- 1 file changed, 16 insertions(+), 57 deletions(-) diff --git a/app/javascript/mastodon/features/account_edit/modals/image_upload.tsx b/app/javascript/mastodon/features/account_edit/modals/image_upload.tsx index fa8b9df4df..e63ac427c2 100644 --- a/app/javascript/mastodon/features/account_edit/modals/image_upload.tsx +++ b/app/javascript/mastodon/features/account_edit/modals/image_upload.tsx @@ -65,16 +65,23 @@ export const ImageUploadModal: FC< const handleFile = useCallback((file: File) => { try { - parseImageFile(file, (result, isAnimated) => { - if (isAnimated) { - // If the image is animated, skip cropping and go straight to alt text. - setImageBlob(file); - setStep('alt'); - } else { - setImageSrc(result); - setStep('crop'); + // If the image is animated, skip cropping and go straight to alt text. + if (file.type === 'image/gif') { + setImageBlob(file); + setStep('alt'); + return; + } + + const reader = new FileReader(); + reader.onload = () => { + const dataUri = reader.result; + if (typeof dataUri !== 'string') { + throw new Error('Expected a string'); } - }); + setImageSrc(dataUri); + setStep('crop'); + }; + reader.readAsDataURL(file); } catch (error) { console.warn('Error with image parsing:', error); setStep('select'); @@ -408,54 +415,6 @@ const StepAlt: FC<{ ); }; -/** - * Parses an image file and determines if it's an animated GIF and returns a data URI for cropping. - * Based on https://gist.github.com/zakirt/faa4a58cec5a7505b10e3686a226f285. - */ -function parseImageFile( - file: File, - cb: (buffer: string, isAnimated: boolean) => void, -): void { - const reader = new FileReader(); - reader.onload = () => { - const buffer = reader.result; - if (!(buffer instanceof ArrayBuffer)) { - throw new Error('Expected an ArrayBuffer'); - } - - // Convert the ArrayBuffer to a base64 data URI. - const bytes = new Uint8Array(buffer); - const base64 = btoa(String.fromCharCode(...bytes)); - const dataUri = `data:${file.type};base64,${base64}`; - - // If the file type is not a GIF, then it's not animated as we don't support animated WebP or PNG. - if (file.type !== 'image/gif') { - cb(dataUri, false); - } - - const view = new DataView(buffer, 10); // Start from the last 4 bytes of the Logical Screen Descriptor. - let offset = 3; - - // Check the first bit for the global color table flag. - const globalColorTable = view.getInt8(0); - if (globalColorTable & 0x08) { - // Grab last three bits to calculate the global color table size, and skip it. - offset += 3 * Math.pow(2, (globalColorTable & 0x7) + 1); - } - - // Check Graphics Control Extension and Graphics Control Label to access animated data. - let delayTime = 0; - if (view.getUint8(offset) & 0x21 && view.getUint8(offset + 1) & 0xf9) { - // Skip to the delay time, which is stored in the next two bytes. - delayTime = view.getUint16(offset + 4); - } - - // If there is a delay time, the GIF is animated. - cb(dataUri, delayTime > 0); - }; - reader.readAsArrayBuffer(file); -} - async function calculateCroppedImage( imageSrc: string, crop: Area, From a706fce6781104b3aa1315be14f1fb8ccd4fcb1b Mon Sep 17 00:00:00 2001 From: diondiondion Date: Tue, 21 Apr 2026 16:12:44 +0200 Subject: [PATCH 10/10] Implement final design for collection editor account dropdown menu (#38767) --- .../form_fields/combobox.module.scss | 19 ++-- .../form_fields/combobox_field.stories.tsx | 5 +- .../components/form_fields/combobox_field.tsx | 96 ++++++++++++++----- .../account_edit/components/tag_search.tsx | 5 +- .../features/collections/editor/accounts.tsx | 29 +++--- .../features/collections/editor/details.tsx | 5 +- .../collections/editor/styles.module.scss | 17 ++-- 7 files changed, 121 insertions(+), 55 deletions(-) diff --git a/app/javascript/mastodon/components/form_fields/combobox.module.scss b/app/javascript/mastodon/components/form_fields/combobox.module.scss index ef230a77b8..c14bac0cb6 100644 --- a/app/javascript/mastodon/components/form_fields/combobox.module.scss +++ b/app/javascript/mastodon/components/form_fields/combobox.module.scss @@ -26,7 +26,6 @@ z-index: 9999; box-sizing: border-box; max-height: min(320px, 50dvh); - padding: 4px; border-radius: 4px; color: var(--color-text-primary); background: var(--color-bg-primary); @@ -38,22 +37,18 @@ overscroll-behavior-y: contain; } -.groupLabel { - padding-block: 12px 4px; - padding-inline: 12px; +.groupTitle { + padding: 8px 16px 4px; font-size: 13px; font-weight: bold; text-transform: uppercase; - - ul:first-child > & { - padding-top: 4px; - } } .menuItem { display: flex; align-items: center; padding: 8px 12px; + margin-inline: 4px; gap: 12px; font-size: 14px; line-height: 20px; @@ -62,6 +57,14 @@ cursor: pointer; user-select: none; + &:first-child { + margin-top: 4px; + } + + &:last-child { + margin-bottom: 4px; + } + &[data-highlighted='true'] { background: var(--color-bg-overlay-highlight); } diff --git a/app/javascript/mastodon/components/form_fields/combobox_field.stories.tsx b/app/javascript/mastodon/components/form_fields/combobox_field.stories.tsx index 32fc736423..795cba727a 100644 --- a/app/javascript/mastodon/components/form_fields/combobox_field.stories.tsx +++ b/app/javascript/mastodon/components/form_fields/combobox_field.stories.tsx @@ -2,7 +2,7 @@ import { useCallback, useState } from 'react'; import type { Meta, StoryObj } from '@storybook/react-vite'; -import { ComboboxField } from './combobox_field'; +import { ComboboxField, ComboboxMenuItem } from './combobox_field'; interface Fruit { id: string; @@ -60,7 +60,7 @@ const ComboboxDemo: React.FC<{ withGroups?: boolean }> = ({ withGroups }) => { }, []); const renderItem = useCallback( - (fruit: Fruit) => {fruit.name}, + (fruit: Fruit) => {fruit.name}, [], ); @@ -93,6 +93,7 @@ const ComboboxDemo: React.FC<{ withGroups?: boolean }> = ({ withGroups }) => { const meta = { title: 'Components/Form Fields/ComboboxField', component: ComboboxField, + subcomponents: { ComboboxMenuItem }, render: () => , } satisfies Meta; diff --git a/app/javascript/mastodon/components/form_fields/combobox_field.tsx b/app/javascript/mastodon/components/form_fields/combobox_field.tsx index 64cbb3ce8a..40199d47ed 100644 --- a/app/javascript/mastodon/components/form_fields/combobox_field.tsx +++ b/app/javascript/mastodon/components/form_fields/combobox_field.tsx @@ -1,6 +1,8 @@ import { + createContext, forwardRef, useCallback, + useContext, useId, useMemo, useRef, @@ -109,6 +111,58 @@ interface ComboboxProps< interface Props extends ComboboxProps, CommonFieldWrapperProps {} +interface ComboboxItemPropsContext { + role: 'option'; + 'data-highlighted': boolean; + 'aria-selected': boolean; + 'aria-disabled': boolean; + 'data-item-id': string; + onMouseEnter: React.MouseEventHandler; + onClick: React.MouseEventHandler; +} + +const ComboboxItemPropsContext = createContext( + null, +); + +export function useComboboxItemProps() { + const context = useContext(ComboboxItemPropsContext); + + if (context === null) { + throw new Error( + 'useComboboxItemProps must be used within a Combobox component', + ); + } + + return context; +} + +export const ComboboxMenuItem: React.FC<{ + className?: string; + children: React.ReactNode; +}> = ({ className, children }) => { + const props = useComboboxItemProps(); + return ( +
  • + {children} +
  • + ); +}; + +export const ComboboxMenuGroupTitle: React.FC< + React.ComponentPropsWithoutRef<'li'> +> = ({ className, children, ...otherProps }) => { + return ( +
  • + {children} +
  • + ); +}; + /** * The combobox field allows users to select one or more items * by searching or filtering a large or dynamic list of options. @@ -371,7 +425,7 @@ const ComboboxWithRef = ( const renderItems = (items: Item[]) => items.map((item) => { const id = getItemId(item); - const isDisabled = getIsItemDisabled?.(item); + const isDisabled = getIsItemDisabled?.(item) ?? false; const isHighlighted = id === highlightedItemId; // If `getIsItemSelected` is defined, we assume 'multi-select' // behaviour and don't set `aria-selected` based on highlight, @@ -380,23 +434,23 @@ const ComboboxWithRef = ( ? getIsItemSelected(item) : isHighlighted; return ( - // eslint-disable-next-line jsx-a11y/click-events-have-key-events -
  • {renderItem(item, { isSelected, - isDisabled: isDisabled ?? false, + isDisabled, })} -
  • + ); }); @@ -498,16 +552,12 @@ const ComboboxWithRef = ( role='group' aria-labelledby={hasTitle ? groupTitleId : undefined} > - {hasTitle && ( -
  • - {customGroupTitle ?? ( - {groupKey} - )} -
  • - )} + {hasTitle && + (customGroupTitle ?? ( + + {groupKey} + + ))} {renderItems(groupItems)} ); diff --git a/app/javascript/mastodon/features/account_edit/components/tag_search.tsx b/app/javascript/mastodon/features/account_edit/components/tag_search.tsx index 2dd17c2a72..04befb4690 100644 --- a/app/javascript/mastodon/features/account_edit/components/tag_search.tsx +++ b/app/javascript/mastodon/features/account_edit/components/tag_search.tsx @@ -4,6 +4,7 @@ import { useCallback, useId, useState } from 'react'; import { defineMessages, useIntl } from 'react-intl'; import { Combobox } from '@/mastodon/components/form_fields'; +import { ComboboxMenuItem } from '@/mastodon/components/form_fields/combobox_field'; import { useSearchTags } from '@/mastodon/hooks/useSearchTags'; import type { TagSearchResult } from '@/mastodon/hooks/useSearchTags'; import { addFeaturedTags } from '@/mastodon/reducers/slices/profile_edit'; @@ -77,4 +78,6 @@ export const AccountEditTagSearch: FC = () => { ); }; -const renderItem = (item: TagSearchResult) => item.label ?? `#${item.name}`; +const renderItem = (item: TagSearchResult) => ( + {item.label ?? `#${item.name}`} +); diff --git a/app/javascript/mastodon/features/collections/editor/accounts.tsx b/app/javascript/mastodon/features/collections/editor/accounts.tsx index a51f58c236..dddd0242e0 100644 --- a/app/javascript/mastodon/features/collections/editor/accounts.tsx +++ b/app/javascript/mastodon/features/collections/editor/accounts.tsx @@ -6,6 +6,7 @@ import { useHistory } from 'react-router-dom'; import type { Map as ImmutableMap } from 'immutable'; +import { useComboboxItemProps } from '@/mastodon/components/form_fields/combobox_field'; import type { ApiMutedAccountJSON } from 'mastodon/api_types/accounts'; import type { ApiCollectionJSON } from 'mastodon/api_types/collections'; import { AccountListItem } from 'mastodon/components/account_list_item'; @@ -67,18 +68,18 @@ const AddedAccountItem: React.FC<{ const SuggestedAccountItem: React.FC<{ id: string }> = ({ id }) => { const account = useAccount(id); const handle = useAccountHandle(account, domain); + const comboboxItemProps = useComboboxItemProps(); if (!account) return null; return ( - } - > - - - - +
  • + }> + + + + +
  • ); }; @@ -158,11 +159,13 @@ const renderGroupTitle = (groupKey: GroupKey, titleId: string) => { } return ( - - - {title} - - +
  • + + + {title} + + +
  • ); }; diff --git a/app/javascript/mastodon/features/collections/editor/details.tsx b/app/javascript/mastodon/features/collections/editor/details.tsx index ae944ba41f..42ef8db970 100644 --- a/app/javascript/mastodon/features/collections/editor/details.tsx +++ b/app/javascript/mastodon/features/collections/editor/details.tsx @@ -6,6 +6,7 @@ import { useHistory } from 'react-router-dom'; import { isFulfilled } from '@reduxjs/toolkit'; +import { ComboboxMenuItem } from '@/mastodon/components/form_fields/combobox_field'; import { languages } from '@/mastodon/initial_state'; import { hasSpecialCharacters, @@ -373,7 +374,9 @@ const TopicField: React.FC = () => { ); }; -const renderTagItem = (item: TagSearchResult) => item.label ?? `#${item.name}`; +const renderTagItem = (item: TagSearchResult) => ( + {item.label ?? `#${item.name}`} +); const LanguageField: React.FC = () => { const dispatch = useAppDispatch(); diff --git a/app/javascript/mastodon/features/collections/editor/styles.module.scss b/app/javascript/mastodon/features/collections/editor/styles.module.scss index 1befc06cc1..d4b1d2d7f3 100644 --- a/app/javascript/mastodon/features/collections/editor/styles.module.scss +++ b/app/javascript/mastodon/features/collections/editor/styles.module.scss @@ -60,17 +60,20 @@ } .suggestion { - padding: 4px 0; + cursor: pointer; + user-select: none; + border-bottom: 1px solid var(--color-border-primary); - [aria-disabled='true'] & { + &[data-highlighted='true'] { + background: var(--color-bg-overlay-highlight); + } + + &[aria-disabled='true'] { opacity: 0.6; + cursor: not-allowed; } } .suggestionGroup { - padding: 4px 0; - - // Undo default group styles: - font-weight: 400; - text-transform: none; + padding-bottom: 4px; }