Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot] bf5c52c058
Update dependency lint-staged to v15 2023-10-23 10:47:50 +00:00
335 changed files with 4485 additions and 3609 deletions

View File

@ -70,7 +70,7 @@ services:
hard: -1
libretranslate:
image: libretranslate/libretranslate:v1.4.1
image: libretranslate/libretranslate:v1.3.12
restart: unless-stopped
volumes:
- lt-data:/home/libretranslate/.local

View File

@ -1,19 +0,0 @@
name: 'Setup Javascript'
description: 'Setup a Javascript environment ready to run the Mastodon code'
inputs:
onlyProduction:
description: Only install production dependencies
default: 'false'
runs:
using: 'composite'
steps:
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version-file: '.nvmrc'
- name: Install all yarn packages
shell: bash
run: yarn --frozen-lockfile ${{ inputs.onlyProduction != 'false' && '--production' || '' }}

View File

@ -1,23 +0,0 @@
name: 'Setup RUby'
description: 'Setup a Ruby environment ready to run the Mastodon code'
inputs:
ruby-version:
description: The Ruby version to install
default: '.ruby-version'
additional-system-dependencies:
description: 'Additional packages to install'
runs:
using: 'composite'
steps:
- name: Install system dependencies
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev ${{ inputs.additional-system-dependencies }}
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ inputs.ruby-version }}
bundler-cache: true

View File

@ -3,6 +3,7 @@
extends: [
'config:recommended',
':labels(dependencies)',
':maintainLockFilesMonthly', // update non-direct dependencies monthly
':prConcurrentLimitNone', // Remove limit for open PRs at any time.
':prHourlyLimit2', // Rate limit PR creation to a maximum of two per hour.
],

View File

@ -27,8 +27,14 @@ jobs:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Run bundler-audit
run: bundle exec bundler-audit

View File

@ -19,11 +19,25 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version-file: '.nvmrc'
- name: Install all yarn packages
run: yarn --frozen-lockfile
- name: Check for missing strings in English JSON
run: |

View File

@ -44,8 +44,14 @@ jobs:
run: sudo chown -R runner:docker .
# This is needed to run the normalize step
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Run i18n normalize task
run: bundle exec i18n-tasks normalize

View File

@ -35,8 +35,14 @@ jobs:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version-file: '.nvmrc'
- name: Install all yarn packages
run: yarn --frozen-lockfile
- uses: xt0rted/stylelint-problem-matcher@v1

View File

@ -30,8 +30,16 @@ jobs:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
- name: Install native Ruby dependencies
run: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Run haml-lint
run: |

View File

@ -39,8 +39,14 @@ jobs:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version-file: '.nvmrc'
- name: Install all yarn packages
run: yarn --frozen-lockfile
- name: ESLint
run: yarn lint:js --max-warnings 0

View File

@ -31,8 +31,14 @@ jobs:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version-file: '.nvmrc'
- name: Install all yarn packages
run: yarn --frozen-lockfile
- name: Prettier
run: yarn lint:json

View File

@ -31,8 +31,14 @@ jobs:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version-file: '.nvmrc'
- name: Install all yarn packages
run: yarn --frozen-lockfile
- name: Prettier
run: yarn lint:md

View File

@ -31,8 +31,14 @@ jobs:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Set-up RuboCop Problem Matcher
uses: r7kamura/rubocop-problem-matchers-action@v1

View File

@ -33,8 +33,14 @@ jobs:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version-file: '.nvmrc'
- name: Install all yarn packages
run: yarn --frozen-lockfile
- name: Prettier
run: yarn lint:yml

View File

@ -35,8 +35,14 @@ jobs:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version-file: '.nvmrc'
- name: Install all yarn packages
run: yarn --frozen-lockfile
- name: Jest testing
run: yarn jest --reporters github-actions summary

View File

@ -72,8 +72,16 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
- name: Install native Ruby dependencies
run: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up bundler cache
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Create database
run: './bin/rails db:create'

View File

@ -71,8 +71,16 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
- name: Install native Ruby dependencies
run: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up bundler cache
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Create database
run: './bin/rails db:create'

View File

@ -34,14 +34,24 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- name: Set up Node.js
uses: actions/setup-node@v3
with:
onlyProduction: 'true'
cache: yarn
node-version-file: '.nvmrc'
- name: Install native Ruby dependencies
run: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up bundler cache
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- run: yarn --frozen-lockfile --production
- name: Precompile assets
# Previously had set this, but it's not supported
# export NODE_OPTIONS=--openssl-legacy-provider
@ -125,11 +135,20 @@ jobs:
path: './public'
name: ${{ github.sha }}
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
- name: Update package index
run: sudo apt-get update
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
- name: Install additional system dependencies
run: sudo apt-get install -y ffmpeg imagemagick libpam-dev
- name: Set up bundler cache
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version}}
additional-system-dependencies: ffmpeg imagemagick libpam-dev
bundler-cache: true
- name: Load database schema
run: './bin/rails db:create db:schema:load db:seed'
@ -191,14 +210,28 @@ jobs:
path: './public'
name: ${{ github.sha }}
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
- name: Update package index
run: sudo apt-get update
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version-file: '.nvmrc'
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
- name: Install additional system dependencies
run: sudo apt-get install -y ffmpeg imagemagick
- name: Set up bundler cache
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version}}
additional-system-dependencies: ffmpeg imagemagick
bundler-cache: true
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- run: yarn --frozen-lockfile
- name: Load database schema
run: './bin/rails db:create db:schema:load db:seed'
@ -295,14 +328,28 @@ jobs:
path: './public'
name: ${{ github.sha }}
- name: Set up Ruby environment
uses: ./.github/actions/setup-ruby
- name: Update package index
run: sudo apt-get update
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version-file: '.nvmrc'
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
- name: Install additional system dependencies
run: sudo apt-get install -y ffmpeg imagemagick
- name: Set up bundler cache
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version}}
additional-system-dependencies: ffmpeg imagemagick
bundler-cache: true
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- run: yarn --frozen-lockfile
- name: Load database schema
run: './bin/rails db:create db:schema:load db:seed'

View File

@ -1,20 +1,33 @@
# This configuration was generated by
# `haml-lint --auto-gen-config`
# on 2023-10-25 08:29:48 -0400 using Haml-Lint version 0.51.0.
# on 2023-10-11 11:31:24 -0400 using Haml-Lint version 0.51.0.
# The point is for the user to remove these configuration records
# one by one as the lints are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of Haml-Lint, may require this file to be generated again.
linters:
# Offense count: 945
# Offense count: 946
LineLength:
enabled: false
# Offense count: 10
# Offense count: 22
UnnecessaryStringOutput:
enabled: false
# Offense count: 44
RuboCop:
enabled: false
# Offense count: 3
ViewLength:
exclude:
- 'app/views/admin/accounts/_buttons.html.haml'
- 'app/views/admin/accounts/_local_account.html.haml'
- 'app/views/admin/roles/_form.html.haml'
- 'app/views/layouts/application.html.haml'
- 'app/views/admin/accounts/show.html.haml'
- 'app/views/admin/reports/show.html.haml'
- 'app/views/disputes/strikes/show.html.haml'
# Offense count: 2
IdNames:
exclude:
- 'app/views/oauth/authorizations/error.html.haml'
- 'app/views/shared/_error_messages.html.haml'

2
.nvmrc
View File

@ -1 +1 @@
20.9
20.8

View File

@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config --auto-gen-only-exclude --no-exclude-limit --no-offense-counts --no-auto-gen-timestamp`
# using RuboCop version 1.57.1.
# using RuboCop version 1.56.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@ -78,6 +78,7 @@ RSpec/AnyInstance:
- 'spec/controllers/admin/accounts_controller_spec.rb'
- 'spec/controllers/admin/resets_controller_spec.rb'
- 'spec/controllers/admin/settings/branding_controller_spec.rb'
- 'spec/controllers/api/v1/media_controller_spec.rb'
- 'spec/controllers/auth/sessions_controller_spec.rb'
- 'spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb'
- 'spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb'
@ -177,6 +178,7 @@ RSpec/LetSetup:
RSpec/MessageChain:
Exclude:
- 'spec/controllers/api/v1/media_controller_spec.rb'
- 'spec/models/concerns/remotable_spec.rb'
- 'spec/models/session_activation_spec.rb'
- 'spec/models/setting_spec.rb'
@ -215,6 +217,19 @@ Rails/ApplicationController:
Exclude:
- 'app/controllers/health_controller.rb'
# Configuration parameters: Include.
# Include: db/**/*.rb
Rails/CreateTableWithTimestamps:
Exclude:
- 'db/migrate/20170508230434_create_conversation_mutes.rb'
- 'db/migrate/20170823162448_create_status_pins.rb'
- 'db/migrate/20171116161857_create_list_accounts.rb'
- 'db/migrate/20180929222014_create_account_conversations.rb'
- 'db/migrate/20181007025445_create_pghero_space_stats.rb'
- 'db/migrate/20190103124649_create_scheduled_statuses.rb'
- 'db/migrate/20220824233535_create_status_trends.rb'
- 'db/migrate/20221006061337_create_preview_card_trends.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Severity.
Rails/DuplicateAssociation:
@ -256,6 +271,7 @@ Rails/LexicallyScopedActionFilter:
Exclude:
- 'app/controllers/auth/passwords_controller.rb'
- 'app/controllers/auth/registrations_controller.rb'
- 'app/controllers/auth/sessions_controller.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
Rails/NegateInclude:
@ -271,6 +287,7 @@ Rails/NegateInclude:
- 'app/models/custom_filter.rb'
- 'app/services/activitypub/process_status_update_service.rb'
- 'app/services/fetch_link_card_service.rb'
- 'app/services/search_service.rb'
- 'app/workers/web/push_notification_worker.rb'
- 'lib/paperclip/color_extractor.rb'
@ -290,6 +307,24 @@ Rails/RakeEnvironment:
- 'lib/tasks/repo.rake'
- 'lib/tasks/statistics.rake'
# Configuration parameters: Include.
# Include: db/**/*.rb
Rails/ReversibleMigration:
Exclude:
- 'db/migrate/20160223164502_make_uris_nullable_in_statuses.rb'
- 'db/migrate/20161122163057_remove_unneeded_indexes.rb'
- 'db/migrate/20170205175257_remove_devices.rb'
- 'db/migrate/20170322143850_change_primary_key_to_bigint_on_statuses.rb'
- 'db/migrate/20170520145338_change_language_filter_to_opt_out.rb'
- 'db/migrate/20170609145826_remove_default_language_from_statuses.rb'
- 'db/migrate/20170711225116_fix_null_booleans.rb'
- 'db/migrate/20171129172043_add_index_on_stream_entries.rb'
- 'db/migrate/20171212195226_remove_duplicate_indexes_in_lists.rb'
- 'db/migrate/20171226094803_more_faster_index_on_notifications.rb'
- 'db/migrate/20180106000232_add_index_on_statuses_for_api_v1_accounts_account_id_statuses.rb'
- 'db/migrate/20180617162849_remove_unused_indexes.rb'
- 'db/migrate/20220827195229_change_canonical_email_blocks_nullable.rb'
# Configuration parameters: ForbiddenMethods, AllowedMethods.
# ForbiddenMethods: decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all
Rails/SkipsModelValidations:
@ -342,6 +377,30 @@ Rails/SkipsModelValidations:
- 'spec/services/follow_service_spec.rb'
- 'spec/services/update_account_service_spec.rb'
# Configuration parameters: Include.
# Include: db/**/*.rb
Rails/ThreeStateBooleanColumn:
Exclude:
- 'db/migrate/20160325130944_add_admin_to_users.rb'
- 'db/migrate/20161123093447_add_sensitive_to_statuses.rb'
- 'db/migrate/20170123203248_add_reject_media_to_domain_blocks.rb'
- 'db/migrate/20170127165745_add_devise_two_factor_to_users.rb'
- 'db/migrate/20170209184350_add_reply_to_statuses.rb'
- 'db/migrate/20170330163835_create_imports.rb'
- 'db/migrate/20170905165803_add_local_to_statuses.rb'
- 'db/migrate/20181203021853_add_discoverable_to_accounts.rb'
- 'db/migrate/20190509164208_add_by_moderator_to_tombstone.rb'
- 'db/migrate/20190805123746_add_capabilities_to_tags.rb'
- 'db/migrate/20191212163405_add_hide_collections_to_accounts.rb'
- 'db/migrate/20200309150742_add_forwarded_to_reports.rb'
- 'db/migrate/20210609202149_create_login_activities.rb'
- 'db/migrate/20210621221010_add_skip_sign_in_token_to_users.rb'
- 'db/migrate/20211031031021_create_preview_card_providers.rb'
- 'db/migrate/20211115032527_add_trendable_to_preview_cards.rb'
- 'db/migrate/20220202200743_add_trendable_to_accounts.rb'
- 'db/migrate/20220202200926_add_trendable_to_statuses.rb'
- 'db/migrate/20220303000827_add_ordered_media_attachment_ids_to_status_edits.rb'
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/UniqueValidationWithoutIndex:
@ -405,7 +464,7 @@ Style/CaseEquality:
Exclude:
- 'config/initializers/trusted_proxies.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowedMethods, AllowedPatterns.
# AllowedMethods: ==, equal?, eql?
Style/ClassEqualityComparison:
@ -613,6 +672,7 @@ Style/RedundantReturn:
Style/SafeNavigation:
Exclude:
- 'app/models/concerns/account_finder_concern.rb'
- 'app/models/status.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle.

View File

@ -938,4 +938,2331 @@ Some of the features in this release have been funded through the [NGI0 Discover
- Fix rate limiting for paths with formats ([Gargron](https://github.com/mastodon/mastodon/pull/20675))
- Fix out-of-bound reads in blurhash transcoder ([delroth](https://github.com/mastodon/mastodon/pull/20388))
_For previous changes, review the [stable-3.5 branch](https://github.com/mastodon/mastodon/blob/stable-3.5/CHANGELOG.md)_
## [3.5.3] - 2022-05-26
### Added
- **Add language dropdown to compose form in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/18420), [ykzts](https://github.com/mastodon/mastodon/pull/18460))
- **Add warning for limited accounts in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/18344))
- Add `limited` attribute to accounts in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/18344))
### Changed
- **Change RSS feeds** ([Gargron](https://github.com/mastodon/mastodon/pull/18356), [tribela](https://github.com/mastodon/mastodon/pull/18406))
- Titles are now date and time of post
- Bodies now render all content faithfully, including polls and emojis
- All media attachments are included with Media RSS
- Change "dangerous" to "sensitive" in privacy policy and web UI ([Gargron](https://github.com/mastodon/mastodon/pull/18515))
- Change unconfirmed accounts to not be visible in REST API ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17530))
- Change `tootctl search deploy` to improve performance ([Gargron](https://github.com/mastodon/mastodon/pull/18463), [Gargron](https://github.com/mastodon/mastodon/pull/18514))
- Change search indexing to use batches to minimize resource usage ([Gargron](https://github.com/mastodon/mastodon/pull/18451))
### Fixed
- Fix follower and other counters being able to go negative ([Gargron](https://github.com/mastodon/mastodon/pull/18517))
- Fix unnecessary query on when creating a status ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17901))
- Fix warning an account outside of a report closing all reports for that account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18387))
- Fix error when resolving a link that redirects to a local post ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18314))
- Fix preferred posting language returning unusable value in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/18428))
- Fix race condition error when external status is reblogged ([ykzts](https://github.com/mastodon/mastodon/pull/18424))
- Fix missing string for appeal validation error ([Gargron](https://github.com/mastodon/mastodon/pull/18410))
- Fix block/mute lists showing a follow button in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18364))
- Fix Redis configuration not being changed by `mastodon:setup` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18383))
- Fix streaming notifications not using quick filter logic in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18316))
- Fix ambiguous wording on appeal actions in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18328))
- Fix floating action button obscuring last element in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18332))
- Fix account warnings not being recorded in audit log ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18338))
- Fix leftover icons for direct visibility statuses ([Steffo99](https://github.com/mastodon/mastodon/pull/18305))
- Fix link verification requiring case sensitivity on links ([sgolemon](https://github.com/mastodon/mastodon/pull/18320))
- Fix embeds not setting their height correctly ([rinsuki](https://github.com/mastodon/mastodon/pull/18301))
### Security
- Fix concurrent unfollowing decrementing follower count more than once ([Gargron](https://github.com/mastodon/mastodon/pull/18527))
- Fix being able to appeal a strike unlimited times ([Gargron](https://github.com/mastodon/mastodon/pull/18529))
- Fix being able to report otherwise inaccessible statuses ([Gargron](https://github.com/mastodon/mastodon/pull/18528))
- Fix empty votes arbitrarily increasing voters count in polls ([Gargron](https://github.com/mastodon/mastodon/pull/18526))
- Fix moderator identity leak when approving appeal of sensitive marked statuses ([Gargron](https://github.com/mastodon/mastodon/pull/18525))
- Fix suspended users being able to access APIs that don't require a user ([Gargron](https://github.com/mastodon/mastodon/pull/18524))
- Fix confirmation redirect to app without `Location` header ([Gargron](https://github.com/mastodon/mastodon/pull/18523))
## [3.5.2] - 2022-05-04
### Added
- Add warning on direct messages screen in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/18289))
- We already had a warning when composing a direct message, it has now been reworded to be more clear
- Same warning is now displayed when viewing sent and received direct messages
- Add ability to set approval-based registration through tootctl ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18248))
- Add pre-filling of domain from search filter in domain allow/block admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18172))
## Changed
- Change name of “Direct” visibility to “Mentioned people only” in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/18146), [Gargron](https://github.com/mastodon/mastodon/pull/18289), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/18291))
- Change trending posts to only show one post from each account ([Gargron](https://github.com/mastodon/mastodon/pull/18181))
- Change half-life of trending posts from 6 hours to 2 hours ([Gargron](https://github.com/mastodon/mastodon/pull/18182))
- Change full-text search feature to also include polls you have voted in ([tribela](https://github.com/mastodon/mastodon/pull/18070))
- Change Redis from using one connection per process, to using a connection pool ([Gargron](https://github.com/mastodon/mastodon/pull/18135), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/18160), [Gargron](https://github.com/mastodon/mastodon/pull/18171))
- Different threads no longer have to wait on a mutex over a single connection
- However, this does increase the number of Redis connections by a fair amount
- We are planning to optimize Redis use so that the pool can be made smaller in the future
## Removed
- Remove IP matching from e-mail domain blocks ([Gargron](https://github.com/mastodon/mastodon/pull/18190))
- The IPs of the blocked e-mail domain or its MX records are no longer checked
- Previously it was too easy to block e-mail providers by mistake
## Fixed
- Fix compatibility with Friendica's pinned posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18254), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/18260))
- Fix error when looking up handle with surrounding spaces in REST API ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18225))
- Fix double render error when authorizing interaction ([Gargron](https://github.com/mastodon/mastodon/pull/18203))
- Fix error when a post references an invalid media attachment ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18211))
- Fix error when trying to revoke OAuth token without supplying a token ([Gargron](https://github.com/mastodon/mastodon/pull/18205))
- Fix error caused by missing subject in Webfinger response ([Gargron](https://github.com/mastodon/mastodon/pull/18204))
- Fix error on attempting to delete an account moderation note ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18196))
- Fix light-mode emoji borders in web UI ([Gaelan](https://github.com/mastodon/mastodon/pull/18131))
- Fix being able to scroll away from the loading bar in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/18170))
- Fix error when a bookmark or favorite has been reported and deleted ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18174))
- Fix being offered empty “Server rules violation” report option in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18165))
- Fix temporary network errors preventing from authorizing interactions with remote accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18161))
- Fix incorrect link in "new trending tags" email ([cdzombak](https://github.com/mastodon/mastodon/pull/18156))
- Fix missing indexes on some foreign keys ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18157))
- Fix n+1 query on feed merge and populate operations ([Gargron](https://github.com/mastodon/mastodon/pull/18111))
- Fix feed unmerge worker being exceptionally slow in some conditions ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18110))
- Fix PeerTube videos appearing with an erroneous “Edited at” marker ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18100))
- Fix instance actor being created incorrectly when running through migrations ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18109))
- Fix web push notifications containing HTML entities ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18071))
- Fix inconsistent parsing of `TRUSTED_PROXY_IP` ([ykzts](https://github.com/mastodon/mastodon/pull/18051))
- Fix error when fetching pinned posts ([tribela](https://github.com/mastodon/mastodon/pull/18030))
- Fix wrong optimization in feed populate operation ([dogelover911](https://github.com/mastodon/mastodon/pull/18009))
- Fix error in alias settings page ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18004))
## [3.5.1] - 2022-04-08
### Added
- Add pagination for trending statuses in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17976))
### Changed
- Change e-mail notifications to only be sent when recipient is offline ([Gargron](https://github.com/mastodon/mastodon/pull/17984))
- Send e-mails for mentions and follows by default again
- But only when recipient does not have push notifications through an app
- Change `website` attribute to be nullable on `Application` entity in REST API ([rinsuki](https://github.com/mastodon/mastodon/pull/17962))
### Removed
- Remove sign-in token authentication, instead send e-mail about new sign-in ([Gargron](https://github.com/mastodon/mastodon/pull/17970))
- You no longer need to enter a security code sent through e-mail
- Instead you get an e-mail about a new sign-in from an unfamiliar IP address
### Fixed
- Fix error responses for `from` search prefix ([single-right-quote](https://github.com/mastodon/mastodon/pull/17963))
- Fix dangling language-specific trends ([Gargron](https://github.com/mastodon/mastodon/pull/17997))
- Fix extremely rare race condition when deleting a status or account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17994))
- Fix trends returning less results per page when filtered in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17996))
- Fix pagination header on empty trends responses in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17986))
- Fix cookies secure flag being set when served over Tor ([Gargron](https://github.com/mastodon/mastodon/pull/17992))
- Fix migration error handling ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17991))
- Fix error when re-running some migrations if they get interrupted at the wrong moment ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17989))
- Fix potentially missing statuses when reconnecting to streaming API in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17981), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17987), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17980))
- Fix error when sending warning emails with custom text ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17983))
- Fix unset `SMTP_RETURN_PATH` environment variable causing e-mail not to send ([Gargron](https://github.com/mastodon/mastodon/pull/17982))
- Fix possible duplicate statuses in timelines in some edge cases in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17971))
- Fix spurious edits and require incoming edits to be explicitly marked as such ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17918))
- Fix error when encountering invalid pinned statuses ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17964))
- Fix inconsistency in error handling when removing a status ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17974))
- Fix admin API unconditionally requiring CSRF token ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17975))
- Fix trending tags endpoint missing `offset` param in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17973))
- Fix unusual number formatting in some locales ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17929))
- Fix `S3_FORCE_SINGLE_REQUEST` environment variable not working ([HolgerHuo](https://github.com/mastodon/mastodon/pull/17922))
- Fix failure to build assets with OpenSSL 3 ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17930))
- Fix PWA manifest using outdated routes ([HolgerHuo](https://github.com/mastodon/mastodon/pull/17921))
- Fix error when indexing statuses into Elasticsearch ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17912))
## [3.5.0] - 2022-03-30
### Added
- **Add support for incoming edited posts** ([Gargron](https://github.com/mastodon/mastodon/pull/16697), [Gargron](https://github.com/mastodon/mastodon/pull/17727), [Gargron](https://github.com/mastodon/mastodon/pull/17728), [Gargron](https://github.com/mastodon/mastodon/pull/17320), [Gargron](https://github.com/mastodon/mastodon/pull/17404), [Gargron](https://github.com/mastodon/mastodon/pull/17390), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17335), [Gargron](https://github.com/mastodon/mastodon/pull/17696), [Gargron](https://github.com/mastodon/mastodon/pull/17745), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17740), [Gargron](https://github.com/mastodon/mastodon/pull/17697), [Gargron](https://github.com/mastodon/mastodon/pull/17648), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17531), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17499), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17498), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17380), [Gargron](https://github.com/mastodon/mastodon/pull/17373), [Gargron](https://github.com/mastodon/mastodon/pull/17334), [Gargron](https://github.com/mastodon/mastodon/pull/17333), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17699), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17748))
- Previous versions remain available for perusal and comparison
- People who reblogged a post are notified when it's edited
- New REST APIs:
- `PUT /api/v1/statuses/:id`
- `GET /api/v1/statuses/:id/history`
- `GET /api/v1/statuses/:id/source`
- New streaming API event:
- `status.update`
- **Add appeals for moderator decisions** ([Gargron](https://github.com/mastodon/mastodon/pull/17364), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17725), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17566), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17652), [Gargron](https://github.com/mastodon/mastodon/pull/17616), [Gargron](https://github.com/mastodon/mastodon/pull/17615), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17554), [Gargron](https://github.com/mastodon/mastodon/pull/17523))
- All default moderator decisions now notify the affected user by e-mail
- They now link to an appeal page instead of suggesting replying to the e-mail
- They can now be found in account settings and not just e-mail
- Users can submit one appeal within 20 days of the decision
- Moderators can approve or reject the appeal
- **Add notifications for posts deleted by moderators** ([Gargron](https://github.com/mastodon/mastodon/pull/17204), [Gargron](https://github.com/mastodon/mastodon/pull/17668), [Gargron](https://github.com/mastodon/mastodon/pull/17746), [Gargron](https://github.com/mastodon/mastodon/pull/17679), [Gargron](https://github.com/mastodon/mastodon/pull/17487))
- New, redesigned report view in admin UI
- Common report actions now only take one click to complete
- Deleting posts or marking as sensitive from report now notifies user
- Reports can be categorized by reason and specific rules violated
- The reasons are automatically cited in the notifications, except for spam
- Marking posts as sensitive now federates using post editing
- **Add explore page with trending posts and links** ([Gargron](https://github.com/mastodon/mastodon/pull/17123), [Gargron](https://github.com/mastodon/mastodon/pull/17431), [Gargron](https://github.com/mastodon/mastodon/pull/16917), [Gargron](https://github.com/mastodon/mastodon/pull/17677), [Gargron](https://github.com/mastodon/mastodon/pull/16938), [Gargron](https://github.com/mastodon/mastodon/pull/17044), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16978), [Gargron](https://github.com/mastodon/mastodon/pull/16979), [tribela](https://github.com/mastodon/mastodon/pull/17066), [Gargron](https://github.com/mastodon/mastodon/pull/17072), [Gargron](https://github.com/mastodon/mastodon/pull/17403), [noiob](https://github.com/mastodon/mastodon/pull/17624), [mayaeh](https://github.com/mastodon/mastodon/pull/17755), [mayaeh](https://github.com/mastodon/mastodon/pull/17757), [Gargron](https://github.com/mastodon/mastodon/pull/17760), [mayaeh](https://github.com/mastodon/mastodon/pull/17762))
- Hashtag trends algorithm is extended to work for posts and links
- Links are only considered if they have an adequate preview card
- Preview card generation has been improved to support structured data
- Links can only trend if the publisher (domain) has been approved
- Posts can only trend if the author has been approved
- Individual approval and rejection for posts and links is also available
- Moderators are notified about pending trends at most once every 2 hours
- Posts and link trends are language-specific
- Search page is redesigned into explore page in web UI
- Discovery tab is coming soon in official iOS and Android apps
- New REST APIs:
- `GET /api/v1/trends/links`
- `GET /api/v1/trends/statuses`
- `GET /api/v1/trends/tags` (alias of `GET /api/v1/trends`)
- `GET /api/v1/admin/trends/links`
- `GET /api/v1/admin/trends/statuses`
- `GET /api/v1/admin/trends/tags`
- **Add graphs and retention metrics to admin dashboard** ([Gargron](https://github.com/mastodon/mastodon/pull/16829), [Gargron](https://github.com/mastodon/mastodon/pull/17617), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17570), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16910), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16909), [mashirozx](https://github.com/mastodon/mastodon/pull/16884), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16854))
- Dashboard shows more numbers with development over time
- Other data such as most used interface languages and sign-up sources
- User retention graph shows how many new users stick around
- New REST APIs:
- `POST /api/v1/admin/measures`
- `POST /api/v1/admin/dimensions`
- `POST /api/v1/admin/retention`
- Add `GET /api/v1/accounts/familiar_followers` to REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17700))
- Add `POST /api/v1/accounts/:id/remove_from_followers` to REST API ([noellabo](https://github.com/mastodon/mastodon/pull/16864))
- Add `category` and `rule_ids` params to `POST /api/v1/reports` IN REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17492), [Gargron](https://github.com/mastodon/mastodon/pull/17682), [Gargron](https://github.com/mastodon/mastodon/pull/17713))
- `category` can be one of: `spam`, `violation`, `other` (default)
- `rule_ids` must reference `rules` returned in `GET /api/v1/instance`
- Add global `lang` param to REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17464), [Gargron](https://github.com/mastodon/mastodon/pull/17592))
- Add `types` param to `GET /api/v1/notifications` in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17767))
- **Add notifications for moderators about new sign-ups** ([Gargron](https://github.com/mastodon/mastodon/pull/16953), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17629))
- When a new user confirms e-mail, moderators receive a notification
- New notification type:
- `admin.sign_up`
- Add authentication history ([Gargron](https://github.com/mastodon/mastodon/pull/16408), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16428), [baby-gnu](https://github.com/mastodon/mastodon/pull/16654))
- Add ability to automatically delete old posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16529), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17691), [tribela](https://github.com/mastodon/mastodon/pull/16653))
- Add ability to pin private posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16954), [tribela](https://github.com/mastodon/mastodon/pull/17326), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17304), [MitarashiDango](https://github.com/mastodon/mastodon/pull/17647))
- Add ability to filter search results by author using `from:` syntax ([tribela](https://github.com/mastodon/mastodon/pull/16526))
- Add ability to delete canonical email blocks in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16644))
- Add ability to purge undeliverable domains in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16686), [tribela](https://github.com/mastodon/mastodon/pull/17210), [tribela](https://github.com/mastodon/mastodon/pull/17741), [tribela](https://github.com/mastodon/mastodon/pull/17209))
- Add ability to disable e-mail token authentication for specific users in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/16427))
- **Add ability to suspend accounts in batches in admin UI** ([Gargron](https://github.com/mastodon/mastodon/pull/17009), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17301), [Gargron](https://github.com/mastodon/mastodon/pull/17444))
- New, redesigned accounts list in admin UI
- Batch suspensions are meant to help clean up spam and bot accounts
- They do not generate notifications
- Add ability to filter reports by origin of target account in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/16487))
- Add support for login through OpenID Connect ([chandrn7](https://github.com/mastodon/mastodon/pull/16221))
- Add lazy loading for emoji picker in web UI ([mashirozx](https://github.com/mastodon/mastodon/pull/16907), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17011))
- Add single option votes tooltip in polls in web UI ([Brawaru](https://github.com/mastodon/mastodon/pull/16849))
- Add confirmation modal when closing media edit modal with unsaved changes in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16518))
- Add hint about missing media attachment description in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17845))
- Add support for fetching Create and Announce activities by URI in ActivityPub ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16383))
- Add `S3_FORCE_SINGLE_REQUEST` environment variable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16866))
- Add `OMNIAUTH_ONLY` environment variable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17288), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17345))
- Add `ES_USER` and `ES_PASS` environment variables for Elasticsearch authentication ([tribela](https://github.com/mastodon/mastodon/pull/16890))
- Add `CAS_SECURITY_ASSUME_EMAIL_IS_VERIFIED` environment variable ([baby-gnu](https://github.com/mastodon/mastodon/pull/16655))
- Add ability to pass specific domains to `tootctl accounts cull` ([tribela](https://github.com/mastodon/mastodon/pull/16511))
- Add `--by-uri` option to `tootctl domains purge` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16434))
- Add `--batch-size` option to `tootctl search deploy` ([aquarla](https://github.com/mastodon/mastodon/pull/17049))
- Add `--remove-orphans` option to `tootctl statuses remove` ([noellabo](https://github.com/mastodon/mastodon/pull/17067))
### Changed
- Change design of federation pages in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/17704), [noellabo](https://github.com/mastodon/mastodon/pull/17735), [Gargron](https://github.com/mastodon/mastodon/pull/17765))
- Change design of account cards in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17689))
- Change `follow` scope to be covered by `read` and `write` scopes in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17678))
- Change design of authorized applications page ([Gargron](https://github.com/mastodon/mastodon/pull/17656), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17686))
- Change e-mail domain blocks to block IPs dynamically ([Gargron](https://github.com/mastodon/mastodon/pull/17635), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17650), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17649))
- Change report modal to include category selection in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17565), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17734), [Gargron](https://github.com/mastodon/mastodon/pull/17654), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17632))
- Change reblogs to not count towards hashtag trends anymore ([Gargron](https://github.com/mastodon/mastodon/pull/17501))
- Change languages to be listed under standard instead of native name in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/17485))
- Change routing paths to use usernames in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/16171), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16772), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16773), [mashirozx](https://github.com/mastodon/mastodon/pull/16793), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17060))
- Change list title input design in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17092))
- Change "Opt-in to profile directory" preference to be general discoverability preference ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16637))
- Change API rate limits to use /64 masking on IPv6 addresses ([tribela](https://github.com/mastodon/mastodon/pull/17588), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17600), [zunda](https://github.com/mastodon/mastodon/pull/17590))
- Change allowed formats for locally uploaded custom emojis to include GIF ([rgroothuijsen](https://github.com/mastodon/mastodon/pull/17706), [Gargron](https://github.com/mastodon/mastodon/pull/17759))
- Change error message when chosen password is too long ([rgroothuijsen](https://github.com/mastodon/mastodon/pull/17082))
- Change minimum required Elasticsearch version from 6 to 7 ([noellabo](https://github.com/mastodon/mastodon/pull/16915))
### Removed
- Remove profile directory link from main navigation panel in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17688))
- **Remove language detection through cld3** ([Gargron](https://github.com/mastodon/mastodon/pull/17478), [ykzts](https://github.com/mastodon/mastodon/pull/17539), [Gargron](https://github.com/mastodon/mastodon/pull/17496), [Gargron](https://github.com/mastodon/mastodon/pull/17722))
- cld3 is very inaccurate on short-form content even with unique alphabets
- Post language can be overridden individually using `language` param
- Otherwise, it defaults to the user's interface language
- Remove support for `OAUTH_REDIRECT_AT_SIGN_IN` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17287))
- Use `OMNIAUTH_ONLY` instead
- Remove Keybase integration ([Gargron](https://github.com/mastodon/mastodon/pull/17045))
- Remove old columns and indexes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17245), [Gargron](https://github.com/mastodon/mastodon/pull/16409), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17191))
- Remove shortcodes from newly-created media attachments ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16730), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16763))
### Deprecated
- `GET /api/v1/trends``GET /api/v1/trends/tags`
- OAuth `follow` scope → `read` and/or `write`
- `text` attribute on `DELETE /api/v1/statuses/:id``GET /api/v1/statuses/:id/source`
### Fixed
- Fix IDN domains not being rendered correctly in a few left-over places ([Gargron](https://github.com/mastodon/mastodon/pull/17848))
- Fix Sanskrit translation not being used in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17820))
- Fix Kurdish languages having the wrong language codes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17812))
- Fix pghero making database schema suggestions ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17807))
- Fix encoding glitch in the OpenGraph description of a profile page ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17821))
- Fix web manifest not permitting PWA usage from alternate domains ([HolgerHuo](https://github.com/mastodon/mastodon/pull/16714))
- Fix not being able to edit media attachments for scheduled posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17690))
- Fix subscribed relay activities being recorded as boosts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17571))
- Fix streaming API server error messages when JSON parsing fails not specifying the source ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17559))
- Fix browsers autofilling new password field with old password ([mashirozx](https://github.com/mastodon/mastodon/pull/17702))
- Fix text being invisible before fonts load in web UI ([tribela](https://github.com/mastodon/mastodon/pull/16330))
- Fix public profile pages of unconfirmed users being accessible ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17385), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17457))
- Fix nil error when trying to fetch key for signature verification ([Gargron](https://github.com/mastodon/mastodon/pull/17747))
- Fix null values being included in some indexes ([Gargron](https://github.com/mastodon/mastodon/pull/17711))
- Fix `POST /api/v1/emails/confirmations` not being available after sign-up ([Gargron](https://github.com/mastodon/mastodon/pull/17743))
- Fix rare race condition when reblogged post is deleted ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17693), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17730))
- Fix being able to add more than 4 hashtags to hashtag column in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17729))
- Fix data integrity of featured tags ([Gargron](https://github.com/mastodon/mastodon/pull/17712))
- Fix performance of account timelines ([Gargron](https://github.com/mastodon/mastodon/pull/17709))
- Fix returning empty `<p>` tag for blank account `note` in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17687))
- Fix leak of existence of otherwise inaccessible posts in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/17684))
- Fix not showing loading indicator when searching in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/17655))
- Fix media modal footer's “external link” not being a link ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17561))
- Fix reply button on media modal not giving focus to compose form ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17626))
- Fix some media attachments being converted with too high framerates ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17619))
- Fix sign in token and warning emails failing to send when contact e-mail address is malformed ([helloworldstack](https://github.com/mastodon/mastodon/pull/17589))
- Fix opening the emoji picker scrolling the single-column view to the top ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17579))
- Fix edge case where settings/admin page sidebar would be incorrectly hidden ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17580))
- Fix performance of server-side filtering ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17575))
- Fix privacy policy link not being visible on small screens ([Gargron](https://github.com/mastodon/mastodon/pull/17533))
- Fix duplicate accounts when searching by IP range in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/17524), [tribela](https://github.com/mastodon/mastodon/pull/17150))
- Fix error when performing a batch action on posts in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17532))
- Fix deletes not being signed in authorized fetch mode ([Gargron](https://github.com/mastodon/mastodon/pull/17484))
- Fix Undo Announce sometimes inlining the originally Announced status ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17516))
- Fix localization of cold-start follow recommendations ([Gargron](https://github.com/mastodon/mastodon/pull/17479), [Gargron](https://github.com/mastodon/mastodon/pull/17486))
- Fix replies collection incorrectly looping ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17462))
- Fix errors when multiple Delete are received for a given actor ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17460))
- Fixed prototype pollution bug and only allow trusted origin ([r0hanSH](https://github.com/mastodon/mastodon/pull/17420))
- Fix text being incorrectly pre-selected in composer textarea on /share ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17339))
- Fix SMTP_ENABLE_STARTTLS_AUTO/SMTP_TLS/SMTP_SSL environment variables don't work ([kgtkr](https://github.com/mastodon/mastodon/pull/17216))
- Fix media upload specific rate limits only being applied to v1 endpoint in REST API ([tribela](https://github.com/mastodon/mastodon/pull/17272))
- Fix media descriptions not being used for client-side filtering ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17206))
- Fix cold-start follow recommendation favouring older accounts due to wrong sorting ([noellabo](https://github.com/mastodon/mastodon/pull/17126))
- Fix not redirect to the right page after authenticating with WebAuthn ([heguro](https://github.com/mastodon/mastodon/pull/17098))
- Fix searching for additional hashtags in hashtag column ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17054))
- Fix color of hashtag column settings inputs ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17058))
- Fix performance of `tootctl statuses remove` ([noellabo](https://github.com/mastodon/mastodon/pull/17052))
- Fix `tootctl accounts cull` not excluding domains on timeouts and certificate issues ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16433))
- Fix 404 error when filtering admin action logs by non-existent target account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16643))
- Fix error when accessing streaming API without any OAuth scopes ([Brawaru](https://github.com/mastodon/mastodon/pull/16823))
- Fix follow request count not updating when new follow requests arrive over streaming API in web UI ([matildepark](https://github.com/mastodon/mastodon/pull/16652))
- Fix error when unsuspending a local account ([HolgerHuo](https://github.com/mastodon/mastodon/pull/16605))
- Fix crash when a notification contains a not yet processed media attachment in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16573))
- Fix wrong color of download button in audio player in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16572))
- Fix notes for others accounts not being deleted when an account is deleted ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16579))
- Fix error when logging occurrence of unsupported video file ([noellabo](https://github.com/mastodon/mastodon/pull/16581))
- Fix wrong elements in trends widget being hidden on smaller screens in web UI ([tribela](https://github.com/mastodon/mastodon/pull/16570))
- Fix link to about page being displayed in limited federation mode ([weex](https://github.com/mastodon/mastodon/pull/16432))
- Fix styling of boost button in media modal not reflecting ability to boost ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16387))
- Fix OCR failure when erroneous lang data is in cache ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16386))
- Fix downloading media from blocked domains in `tootctl media refresh` ([tribela](https://github.com/mastodon/mastodon/pull/16914))
- Fix login form being displayed on landing page when already logged in ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17348))
- Fix polling for media processing status too frequently in web UI ([tribela](https://github.com/mastodon/mastodon/pull/17271))
- Fix hashtag autocomplete overriding user-typed case ([weex](https://github.com/mastodon/mastodon/pull/16460))
- Fix WebAuthn authentication setup to not prompt for PIN ([truongnmt](https://github.com/mastodon/mastodon/pull/16545))
### Security
- Fix being able to post URLs longer than 4096 characters ([Gargron](https://github.com/mastodon/mastodon/pull/17908))
- Fix being able to bypass e-mail restrictions ([Gargron](https://github.com/mastodon/mastodon/pull/17909))
## [3.4.6] - 2022-02-03
### Fixed
- Fix `mastodon:webpush:generate_vapid_key` task requiring a functional environment ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17338))
- Fix spurious errors when receiving an Add activity for a private post ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17425))
### Security
- Fix error-prone SQL queries ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15828))
- Fix not compacting incoming signed JSON-LD activities ([puckipedia](https://github.com/mastodon/mastodon/pull/17426), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/17428)) (CVE-2022-24307)
- Fix insufficient sanitization of report comments ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17430))
- Fix stop condition of a Common Table Expression ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17427))
- Disable legacy XSS filtering ([Wonderfall](https://github.com/mastodon/mastodon/pull/17289))
## [3.4.5] - 2022-01-31
### Added
- Add more advanced migration tests ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17393))
- Add github workflow to build Docker images ([unasuke](https://github.com/mastodon/mastodon/pull/16973), [Gargron](https://github.com/mastodon/mastodon/pull/16980), [Gargron](https://github.com/mastodon/mastodon/pull/17000))
### Fixed
- Fix some old migrations failing when skipping releases ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17394))
- Fix migrations script failing in certain edge cases ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17398))
- Fix Docker build ([tribela](https://github.com/mastodon/mastodon/pull/17188))
- Fix Ruby 3.0 dependencies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16723))
- Fix followers synchronization mechanism ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16510))
## [3.4.4] - 2021-11-26
### Fixed
- Fix error when suspending user with an already blocked canonical email ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17036))
- Fix overflow of long profile fields in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17010))
- Fix confusing error when WebFinger request returns empty document ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16986))
- Fix upload of remote media with OpenStack Swift sometimes failing ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16998))
- Fix logout link not working in Safari ([noellabo](https://github.com/mastodon/mastodon/pull/16574))
- Fix “open” link of media modal not closing modal in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16524))
- Fix replying from modal in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16516))
- Fix `mastodon:setup` command crashing in some circumstances ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16976))
### Security
- Fix filtering DMs from non-followed users ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17042))
- Fix handling of recursive toots in WebUI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/17041))
## [3.4.3] - 2021-11-06
### Fixed
- Fix login being broken due to inaccurately applied backport fix in 3.4.2 ([Gargron](https://github.com/mastodon/mastodon/commit/5c47a18c8df3231aa25c6d1f140a71a7fac9cbf9))
## [3.4.2] - 2021-11-06
### Added
- Add `configuration` attribute to `GET /api/v1/instance` ([Gargron](https://github.com/mastodon/mastodon/pull/16485))
### Fixed
- Fix handling of back button with modal windows in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16499))
- Fix pop-in player when author has long username in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16468))
- Fix crash when a status with a playing video gets deleted in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16384))
- Fix crash with Microsoft Translate in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16525))
- Fix PWA not being usable from alternate domains ([HolgerHuo](https://github.com/mastodon/mastodon/pull/16714))
- Fix locale-specific number rounding errors ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16469))
- Fix scheduling a status decreasing status count ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16791))
- Fix user's canonical email address being blocked when user deletes own account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16503))
- Fix not being able to suspend users that already have their canonical e-mail blocked ([Gargron](https://github.com/mastodon/mastodon/pull/16455))
- Fix anonymous access to outbox not being cached by the reverse proxy ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16458))
- Fix followers synchronization mechanism not working when URI has empty path ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16744))
- Fix serialization of counts in REST API when user hides their network ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16418))
- Fix inefficiencies in auto-linking code ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16506))
- Fix `tootctl self-destruct` not sending delete activities for recently-suspended accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16688))
- Fix suspicious sign-in e-mail text being out of date ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16690))
- Fix some frameworks being unnecessarily loaded ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16725))
- Fix canonical e-mail blocks missing foreign key constraints ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16448))
- Fix inconsistent order on account's statuses page in admin UI ([tribela](https://github.com/mastodon/mastodon/pull/16937))
- Fix media from blocked domains being redownloaded by `tootctl media refresh` ([tribela](https://github.com/mastodon/mastodon/pull/16914))
- Fix `mastodon:setup` generated env-file syntax ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16896))
- Fix link previews being incorrectly generated from earlier links ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16885))
- Fix wrong `to`/`cc` values for remote groups in ActivityPub ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16700))
- Fix mentions with non-ascii TLDs not being processed ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16689))
- Fix authentication failures halfway through a sign-in attempt ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16607), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16792))
- Fix suspended accounts statuses being merged back into timelines ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16628))
- Fix crash when encountering invalid account fields ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16598))
- Fix invalid blurhash handling for remote activities ([noellabo](https://github.com/mastodon/mastodon/pull/16583))
- Fix newlines being added to account notes when an account moves ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16415), [noellabo](https://github.com/mastodon/mastodon/pull/16576))
- Fix crash when creating an announcement with links ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16941))
- Fix logging out from one browser logging out all other sessions ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16943))
### Security
- Fix user notes not having a length limit ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16942))
- Fix revoking a specific session not working ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16943))
## [3.4.1] - 2021-06-03
### Added
- Add new emoji assets from Twemoji 13.1.0 ([Gargron](https://github.com/mastodon/mastodon/pull/16345))
### Fixed
- Fix some ActivityPub identifiers in server actor outbox ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16343))
- Fix custom CSS path setting cookies and being uncacheable due to it ([tribela](https://github.com/mastodon/mastodon/pull/16314))
- Fix unread notification count when polling in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16272))
- Fix health check not being accessible through localhost ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16270))
- Fix some redis locks auto-releasing too fast ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16276), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16291))
- Fix e-mail confirmations API not working correctly ([Gargron](https://github.com/mastodon/mastodon/pull/16348))
- Fix migration script not being able to run if it fails midway ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16312))
- Fix account deletion sometimes failing because of optimistic locks ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16317))
- Fix deprecated slash as division in SASS files ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16347))
- Fix `tootctl search deploy` compatibility error on Ruby 3 ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16346))
- Fix mailer jobs for deleted notifications erroring out ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16294))
## [3.4.0] - 2021-05-16
### Added
- **Add follow recommendations for onboarding** ([Gargron](https://github.com/mastodon/mastodon/pull/15945), [Gargron](https://github.com/mastodon/mastodon/pull/16161), [Gargron](https://github.com/mastodon/mastodon/pull/16060), [Gargron](https://github.com/mastodon/mastodon/pull/16077), [Gargron](https://github.com/mastodon/mastodon/pull/16078), [Gargron](https://github.com/mastodon/mastodon/pull/16160), [Gargron](https://github.com/mastodon/mastodon/pull/16079), [noellabo](https://github.com/mastodon/mastodon/pull/16044), [noellabo](https://github.com/mastodon/mastodon/pull/16045), [Gargron](https://github.com/mastodon/mastodon/pull/16152), [Gargron](https://github.com/mastodon/mastodon/pull/16153), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16082), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16173), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16159), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16189))
- Tutorial on first web UI launch has been replaced with follow suggestions
- Follow suggestions take user locale into account and are a mix of accounts most followed by currently active local users, and accounts that wrote the most shared/favourited posts in the last 30 days
- Only accounts that have opted-in to being discoverable from their profile settings, and that do not require follow requests, will be suggested
- Moderators can review suggestions for every supported locale and suppress specific suggestions from appearing and admins can ensure certain accounts always show up in suggestions from the settings area
- New users no longer automatically follow admins
- **Add server rules** ([Gargron](https://github.com/mastodon/mastodon/pull/15769), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15778))
- Admins can create and edit itemized server rules
- They are available through the REST API and on the about page
- **Add canonical e-mail blocks for suspended accounts** ([Gargron](https://github.com/mastodon/mastodon/pull/16049))
- Normally, people can make multiple accounts using the same e-mail address using the `+` trick or by inserting or removing `.` characters from the first part of their address
- Once an account is suspended, it will no longer be possible for the e-mail address used by that account to be used for new sign-ups in any of its forms
- Add management of delivery availability in admin UI ([noellabo](https://github.com/mastodon/mastodon/pull/15771))
- **Add system checks to dashboard in admin UI** ([Gargron](https://github.com/mastodon/mastodon/pull/15989), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15954), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16002))
- The dashboard will now warn you if you some Sidekiq queues are not being processed, if you have not defined any server rules, or if you forgot to run database migrations from the latest Mastodon upgrade
- Add inline description of moderation actions in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15792))
- Add "recommended" label to activity/peers API toggles in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/16081))
- Add joined date to profiles in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/16169), [rinsuki](https://github.com/mastodon/mastodon/pull/16186))
- Add transition to media modal background in web UI ([mkljczk](https://github.com/mastodon/mastodon/pull/15843))
- Add option to opt-out of unread notification markers in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15842))
- Add borders to 📱, 🚲, and 📲 emojis in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15794), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16035))
- Add dropdown for boost privacy in boost confirmation modal in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15704))
- Add support for Ruby 3.0 ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16046), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16174))
- Add `Message-ID` header to outgoing emails ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16076))
- Some e-mail spam filters penalize e-mails that have a `Message-ID` header that uses a different domain name than the sending e-mail address. Now, the same domain will be used
- Add `af`, `gd` and `si` locales ([Gargron](https://github.com/mastodon/mastodon/pull/16090))
- Add guard against DNS rebinding attacks ([noellabo](https://github.com/mastodon/mastodon/pull/16087), [noellabo](https://github.com/mastodon/mastodon/pull/16095))
- Add HTTP header to explicitly opt-out of FLoC by default ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16036))
- Add missing push notification title for polls and statuses ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15929), [mkljczk](https://github.com/mastodon/mastodon/pull/15564), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15931))
- Add `POST /api/v1/emails/confirmations` to REST API ([Gargron](https://github.com/mastodon/mastodon/pull/15816), [Gargron](https://github.com/mastodon/mastodon/pull/15949))
- This method allows an app through which a user signed-up to request a new confirmation e-mail to be sent, or to change the e-mail of the account before it is confirmed
- Add `GET /api/v1/accounts/lookup` to REST API ([Gargron](https://github.com/mastodon/mastodon/pull/15740), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15750))
- This method allows to quickly convert a username of a known account to an ID that can be used with the REST API, or to check if a username is available
for sign-up
- Add `policy` param to `POST /api/v1/push/subscriptions` in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/16040))
- This param allows an app to control from whom notifications should be delivered as push notifications to the app
- Add `details` to error response for `POST /api/v1/accounts` in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/15803))
- This attribute allows an app to display more helpful information to the user about why the sign-up did not succeed
- Add `SIDEKIQ_REDIS_URL` and related environment variables to optionally use a separate Redis server for Sidekiq ([noellabo](https://github.com/mastodon/mastodon/pull/16188))
### Changed
- Change trending hashtags to be affected be reblogs ([Gargron](https://github.com/mastodon/mastodon/pull/16164))
- Previously, only original posts contributed to a hashtag's trending score
- Now, reblogs of posts will also contribute to that hashtag's trending score
- Change e-mail confirmation link to always redirect to web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16151))
- Change log level of worker lifecycle to WARN in streaming API ([Gargron](https://github.com/mastodon/mastodon/pull/16110))
- Since running with INFO log level in production is not always desirable, it is easy to miss when a worker is shutdown and a new one is started
- Change the nouns "toot" and "status" to "post" in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/16080), [Gargron](https://github.com/mastodon/mastodon/pull/16089))
- To be clear, the button still says "Toot!"
- Change order of dropdown menu on posts to be more intuitive in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/15647))
- Change description of keyboard shortcuts in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/16129))
- Change option labels on edit profile page ([Gargron](https://github.com/mastodon/mastodon/pull/16041))
- "Lock account" is now "Require follow requests"
- "List this account on the directory" is now "Suggest account to others"
- "Hide your network" is now "Hide your social graph"
- Change newly generated account IDs to not be enumerable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15844))
- Change Web Push API deliveries to use request pooling ([Gargron](https://github.com/mastodon/mastodon/pull/16014))
- Change multiple mentions with same username to render with domain ([Gargron](https://github.com/mastodon/mastodon/pull/15718), [noellabo](https://github.com/mastodon/mastodon/pull/16038))
- When a post contains mentions of two or more users who have the same username, but on different domains, render their names with domain to help disambiguate them
- Always render the domain of usernames used in profile metadata
- Change health check endpoint to reveal less information ([Gargron](https://github.com/mastodon/mastodon/pull/15988))
- Change account counters to use upsert (requires Postgres >= 9.5) ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15913))
- Change `mastodon:setup` to not call `assets:precompile` in Docker ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13942))
- **Change max. image dimensions to 1920x1080px (1080p)** ([Gargron](https://github.com/mastodon/mastodon/pull/15690))
- Previously, this was 1280x1280px
- This is the amount of pixels that original images get downsized to
- Change custom emoji to be animated when hovering container in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15637))
- Change streaming API from deprecated ClusterWS/cws to ws ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15932))
- Change systemd configuration to add sandboxing features ([Izorkin](https://github.com/mastodon/mastodon/pull/15937), [Izorkin](https://github.com/mastodon/mastodon/pull/16103), [Izorkin](https://github.com/mastodon/mastodon/pull/16127))
- Change nginx configuration to make running Onion service easier ([cohosh](https://github.com/mastodon/mastodon/pull/15498))
- Change Helm configuration ([dunn](https://github.com/mastodon/mastodon/pull/15722), [dunn](https://github.com/mastodon/mastodon/pull/15728), [dunn](https://github.com/mastodon/mastodon/pull/15748), [dunn](https://github.com/mastodon/mastodon/pull/15749), [dunn](https://github.com/mastodon/mastodon/pull/15767))
- Change Docker configuration ([SuperSandro2000](https://github.com/mastodon/mastodon/pull/10823), [mashirozx](https://github.com/mastodon/mastodon/pull/15978))
### Removed
- Remove PubSubHubbub-related columns from accounts table ([Gargron](https://github.com/mastodon/mastodon/pull/16170), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15857))
- Remove dependency on @babel/plugin-proposal-class-properties ([ykzts](https://github.com/mastodon/mastodon/pull/16155))
- Remove dependency on pluck_each gem ([Gargron](https://github.com/mastodon/mastodon/pull/16012))
- Remove spam check and dependency on nilsimsa gem ([Gargron](https://github.com/mastodon/mastodon/pull/16011))
- Remove MySQL-specific code from Mastodon::MigrationHelpers ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15924))
- Remove IE11 from supported browsers target ([gol-cha](https://github.com/mastodon/mastodon/pull/15779))
### Fixed
- Fix "You might be interested in" flashing while searching in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/16162))
- Fix display of posts without text content in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15665))
- Fix Google Translate breaking web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15610), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15611))
- Fix web UI crashing when SVG support is disabled ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15809))
- Fix web UI crash when a status opened in the media modal is deleted ([kaias1jp](https://github.com/mastodon/mastodon/pull/15701))
- Fix OCR language data failing to load in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15519))
- Fix footer links not being clickable in Safari in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/15496))
- Fix autofocus/autoselection not working on mobile in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15555), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15985))
- Fix media redownload worker retrying on unexpected response codes ([Gargron](https://github.com/mastodon/mastodon/pull/16111))
- Fix thread resolve worker retrying when status no longer exists ([Gargron](https://github.com/mastodon/mastodon/pull/16109))
- Fix n+1 queries when rendering statuses in REST API ([abcang](https://github.com/mastodon/mastodon/pull/15641))
- Fix n+1 queries when rendering notifications in REST API ([abcang](https://github.com/mastodon/mastodon/pull/15640))
- Fix delete of local reply to local parent not being forwarded ([Gargron](https://github.com/mastodon/mastodon/pull/16096))
- Fix remote reporters not receiving suspend/unsuspend activities ([Gargron](https://github.com/mastodon/mastodon/pull/16050))
- Fix understanding (not fully qualified) `as:Public` and `Public` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15948))
- Fix actor update not being distributed on profile picture deletion ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15461))
- Fix processing of incoming Delete activities ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16084))
- Fix processing of incoming Block activities ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15546))
- Fix processing of incoming Update activities of unknown accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15514))
- Fix URIs of repeat follow requests not being recorded ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15662))
- Fix error on requests with no `Digest` header ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15782))
- Fix activity object not requiring signature in secure mode ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15592))
- Fix database serialization failure returning HTTP 500 ([Gargron](https://github.com/mastodon/mastodon/pull/16101))
- Fix media processing getting stuck on too much stdin/stderr ([Gargron](https://github.com/mastodon/mastodon/pull/16136))
- Fix some inefficient array manipulations ([007lva](https://github.com/mastodon/mastodon/pull/15513), [007lva](https://github.com/mastodon/mastodon/pull/15527))
- Fix some inefficient regex matching ([007lva](https://github.com/mastodon/mastodon/pull/15528))
- Fix some inefficient SQL queries ([abcang](https://github.com/mastodon/mastodon/pull/16104), [abcang](https://github.com/mastodon/mastodon/pull/16106), [abcang](https://github.com/mastodon/mastodon/pull/16105))
- Fix trying to fetch key from empty URI when verifying HTTP signature ([Gargron](https://github.com/mastodon/mastodon/pull/16100))
- Fix `tootctl maintenance fix-duplicates` failures ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15923), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15515))
- Fix error when removing status caused by race condition ([Gargron](https://github.com/mastodon/mastodon/pull/16099))
- Fix blocking someone not clearing up list feeds ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16205))
- Fix misspelled URLs character counting ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15382))
- Fix Sidekiq hanging forever due to a Resolv bug in Ruby 2.7.3 ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16157))
- Fix edge case where follow limit interferes with accepting a follow ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/16098))
- Fix inconsistent lead text style in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/16052), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/16086))
- Fix reports of already suspended accounts being recorded ([Gargron](https://github.com/mastodon/mastodon/pull/16047))
- Fix sign-up restrictions based on IP addresses not being enforced ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15607))
- Fix YouTube embeds failing due to YouTube serving wrong OEmbed URLs ([Gargron](https://github.com/mastodon/mastodon/pull/15716))
- Fix error when rendering public pages with media without meta ([Gargron](https://github.com/mastodon/mastodon/pull/16112))
- Fix misaligned logo on follow button on public pages ([noellabo](https://github.com/mastodon/mastodon/pull/15458))
- Fix video modal not working on public pages ([noellabo](https://github.com/mastodon/mastodon/pull/15469))
- Fix race conditions on account migration creation ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15597))
- Fix not being able to change world filter expiration back to “Never” ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15858))
- Fix `.env.vagrant` not setting `RAILS_ENV` variable ([chandrn7](https://github.com/mastodon/mastodon/pull/15709))
- Fix error when muting users with `duration` in REST API ([Tak](https://github.com/mastodon/mastodon/pull/15516))
- Fix border padding on front page in light theme ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15926))
- Fix wrong URL to custom CSS when `CDN_HOST` is used ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15927))
- Fix `tootctl accounts unfollow` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15639))
- Fix `tootctl emoji import` wasting time on MacOS shadow files ([cortices](https://github.com/mastodon/mastodon/pull/15430))
- Fix `tootctl emoji import` not treating shortcodes as case-insensitive ([angristan](https://github.com/mastodon/mastodon/pull/15738))
- Fix some issues with SAML account creation ([Gargron](https://github.com/mastodon/mastodon/pull/15222), [kaiyou](https://github.com/mastodon/mastodon/pull/15511))
- Fix MX validation applying for explicitly allowed e-mail domains ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15930))
- Fix share page not using configured custom mascot ([tribela](https://github.com/mastodon/mastodon/pull/15687))
- Fix instance actor not being automatically created if it wasn't seeded properly ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15693))
- Fix HTTPS enforcement preventing Mastodon from being run as an Onion service ([cohosh](https://github.com/mastodon/mastodon/pull/15560), [jtracey](https://github.com/mastodon/mastodon/pull/15741), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15712), [cohosh](https://github.com/mastodon/mastodon/pull/15725))
- Fix app name, website and redirect URIs not having a maximum length ([Gargron](https://github.com/mastodon/mastodon/pull/16042))
## [3.3.0] - 2020-12-27
### Added
- **Add hotkeys for audio/video control in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/15158), [Gargron](https://github.com/mastodon/mastodon/pull/15198))
- `Space` and `k` to toggle playback
- `m` to toggle mute
- `f` to toggle fullscreen
- `j` and `l` to go back and forward by 10 seconds
- `.` and `,` to go back and forward by a frame (video only)
- Add expand/compress button on media modal in web UI ([mashirozx](https://github.com/mastodon/mastodon/pull/15068), [mashirozx](https://github.com/mastodon/mastodon/pull/15088), [mashirozx](https://github.com/mastodon/mastodon/pull/15094))
- Add border around 🕺 emoji in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14769))
- Add border around 🐞 emoji in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14712))
- Add home link to the getting started column when home isn't mounted ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14707))
- Add option to disable swiping motions across the web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13885))
- **Add pop-out player for audio/video in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/14870), [Gargron](https://github.com/mastodon/mastodon/pull/15157), [Gargron](https://github.com/mastodon/mastodon/pull/14915), [noellabo](https://github.com/mastodon/mastodon/pull/15309))
- Continue watching/listening when you scroll away
- Action bar to interact with/open toot from the pop-out player
- Add unread notification markers in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14818), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14960), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14954), [noellabo](https://github.com/mastodon/mastodon/pull/14897), [noellabo](https://github.com/mastodon/mastodon/pull/14907))
- Add paragraph about browser add-ons when encountering errors in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14801))
- Add import and export for bookmarks ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14956))
- Add cache buster feature for media files ([Gargron](https://github.com/mastodon/mastodon/pull/15155))
- If you have a proxy cache in front of object storage, deleted files will persist until the cache expires
- If enabled, cache buster will make a special request to the proxy to signal a cache reset
- Add duration option to the mute function ([aquarla](https://github.com/mastodon/mastodon/pull/13831))
- Add replies policy option to the list function ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9205), [trwnh](https://github.com/mastodon/mastodon/pull/15304))
- Add `og:published_time` OpenGraph tags on toots ([nornagon](https://github.com/mastodon/mastodon/pull/14865))
- **Add option to be notified when a followed user posts** ([Gargron](https://github.com/mastodon/mastodon/pull/13546), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14896), [Gargron](https://github.com/mastodon/mastodon/pull/14822))
- If you don't want to miss a toot, click the bell button!
- Add client-side validation in password change forms ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14564))
- Add client-side validation in the registration form ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14560), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14599))
- Add support for Gemini URLs ([joshleeb](https://github.com/mastodon/mastodon/pull/15013))
- Add app shortcuts to web app manifest ([mkljczk](https://github.com/mastodon/mastodon/pull/15234))
- Add WebAuthn as an alternative 2FA method ([santiagorodriguez96](https://github.com/mastodon/mastodon/pull/14466), [jiikko](https://github.com/mastodon/mastodon/pull/14806))
- Add honeypot fields and minimum fill-out time for sign-up form ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15276))
- Add icon for mutual relationships in relationship manager ([noellabo](https://github.com/mastodon/mastodon/pull/15149))
- Add follow selected followers button in relationship manager ([noellabo](https://github.com/mastodon/mastodon/pull/15148))
- **Add subresource integrity for JS and CSS assets** ([Gargron](https://github.com/mastodon/mastodon/pull/15096))
- If you use a CDN for static assets (JavaScript, CSS, and so on), you have to trust that the CDN does not modify the assets maliciously
- Subresource integrity compares server-generated asset digests with what's actually served from the CDN and prevents such attacks
- Add `ku`, `sa`, `sc`, `zgh` to available locales ([ykzts](https://github.com/mastodon/mastodon/pull/15138))
- Add ability to force an account to mark media as sensitive ([noellabo](https://github.com/mastodon/mastodon/pull/14361))
- **Add ability to block access or limit sign-ups from chosen IPs** ([Gargron](https://github.com/mastodon/mastodon/pull/14963), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15263))
- Add rules for IPs or CIDR ranges that automatically expire after a configurable amount of time
- Choose the severity of the rule, either blocking all access or merely limiting sign-ups
- **Add support for reversible suspensions through ActivityPub** ([Gargron](https://github.com/mastodon/mastodon/pull/14989))
- Servers can signal that one of their accounts has been suspended
- During suspension, the account can only delete its own content
- A reversal of the suspension can be signalled the same way
- A local suspension always overrides a remote one
- Add indication to admin UI of whether a report has been forwarded ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13237))
- Add display of reasons for joining of an account in admin UI ([mashirozx](https://github.com/mastodon/mastodon/pull/15265))
- Add option to obfuscate domain name in public list of domain blocks ([Gargron](https://github.com/mastodon/mastodon/pull/15355))
- Add option to make reasons for joining required on sign-up ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15326), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15358), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15385), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15405))
- Add ActivityPub follower synchronization mechanism ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14510), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15026))
- Add outbox attribute to instance actor ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14721))
- Add featured hashtags as an ActivityPub collection ([Gargron](https://github.com/mastodon/mastodon/pull/11595), [noellabo](https://github.com/mastodon/mastodon/pull/15277))
- Add support for dereferencing objects through bearcaps ([Gargron](https://github.com/mastodon/mastodon/pull/14683), [noellabo](https://github.com/mastodon/mastodon/pull/14981))
- Add `S3_READ_TIMEOUT` environment variable ([tateisu](https://github.com/mastodon/mastodon/pull/14952))
- Add `ALLOWED_PRIVATE_ADDRESSES` environment variable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14722))
- Add `--fix-permissions` option to `tootctl media remove-orphans` ([Gargron](https://github.com/mastodon/mastodon/pull/14383), [uist1idrju3i](https://github.com/mastodon/mastodon/pull/14715))
- Add `tootctl accounts merge` ([Gargron](https://github.com/mastodon/mastodon/pull/15201), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15264), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15256))
- Has someone changed their domain or subdomain thereby creating two accounts where there should be one?
- This command will fix it on your end
- Add `tootctl maintenance fix-duplicates` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14860), [Gargron](https://github.com/mastodon/mastodon/pull/15223), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15373))
- Index corruption in the database?
- This command is for you
- **Add support for managing multiple stream subscriptions in a single connection** ([Gargron](https://github.com/mastodon/mastodon/pull/14524), [Gargron](https://github.com/mastodon/mastodon/pull/14566), [mfmfuyu](https://github.com/mastodon/mastodon/pull/14859), [zunda](https://github.com/mastodon/mastodon/pull/14608))
- Previously, getting live updates for multiple timelines required opening a HTTP or WebSocket connection for each
- More connections means more resource consumption on both ends, not to mention the (ever so slight) delay when establishing a new connection
- Now, with just a single WebSocket connection you can subscribe and unsubscribe to and from multiple streams
- Add support for limiting results by both `min_id` and `max_id` at the same time in REST API ([tateisu](https://github.com/mastodon/mastodon/pull/14776))
- Add `GET /api/v1/accounts/:id/featured_tags` to REST API ([noellabo](https://github.com/mastodon/mastodon/pull/11817), [noellabo](https://github.com/mastodon/mastodon/pull/15270))
- Add stoplight for object storage failures, return HTTP 503 in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/13043))
- Add optional `tootctl remove media` cronjob in Helm chart ([dunn](https://github.com/mastodon/mastodon/pull/14396))
- Add clean error message when `RAILS_ENV` is unset ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15381))
### Changed
- **Change media modals look in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/15217), [Gargron](https://github.com/mastodon/mastodon/pull/15221), [Gargron](https://github.com/mastodon/mastodon/pull/15284), [Gargron](https://github.com/mastodon/mastodon/pull/15283), [Kjwon15](https://github.com/mastodon/mastodon/pull/15308), [noellabo](https://github.com/mastodon/mastodon/pull/15305), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15417))
- Background of the overlay matches the color of the image
- Action bar to interact with or open the toot from the modal
- Change order of announcements in admin UI to be newest-first ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15091))
- **Change account suspensions to be reversible by default** ([Gargron](https://github.com/mastodon/mastodon/pull/14726), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15152), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15106), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15100), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15099), [noellabo](https://github.com/mastodon/mastodon/pull/14855), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15380), [Gargron](https://github.com/mastodon/mastodon/pull/15420), [Gargron](https://github.com/mastodon/mastodon/pull/15414))
- Suspensions no longer equal deletions
- A suspended account can be unsuspended with minimal consequences for 30 days
- Immediate deletion of data is still available as an explicit option
- Suspended accounts can request an archive of their data through the UI
- Change REST API to return empty data for suspended accounts (14765)
- Change web UI to show empty profile for suspended accounts ([Gargron](https://github.com/mastodon/mastodon/pull/14766), [Gargron](https://github.com/mastodon/mastodon/pull/15345))
- Change featured hashtag suggestions to be recently used instead of most used ([abcang](https://github.com/mastodon/mastodon/pull/14760))
- Change direct toots to appear in the home feed again ([Gargron](https://github.com/mastodon/mastodon/pull/14711), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15182), [noellabo](https://github.com/mastodon/mastodon/pull/14727))
- Return to treating all toots the same instead of trying to retrofit direct visibility into an instant messaging model
- Change email address validation to return more specific errors ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14565))
- Change HTTP signature requirements to include `Digest` header on `POST` requests ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15069))
- Change click area of video/audio player buttons to be bigger in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/15049))
- Change order of filters by alphabetic by "keyword or phrase" ([ariasuni](https://github.com/mastodon/mastodon/pull/15050))
- Change suspension of remote accounts to also undo outgoing follows ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15188))
- Change string "Home" to "Home and lists" in the filter creation screen ([ariasuni](https://github.com/mastodon/mastodon/pull/15139))
- Change string "Boost to original audience" to "Boost with original visibility" in web UI ([3n-k1](https://github.com/mastodon/mastodon/pull/14598))
- Change string "Show more" to "Show newer" and "Show older" on public pages ([ariasuni](https://github.com/mastodon/mastodon/pull/15052))
- Change order of announcements to be reverse chronological in web UI ([dariusk](https://github.com/mastodon/mastodon/pull/15065), [dariusk](https://github.com/mastodon/mastodon/pull/15070))
- Change RTL detection to rely on unicode-bidi paragraph by paragraph in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/14573))
- Change visibility icon next to timestamp to be clickable in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/15053), [mayaeh](https://github.com/mastodon/mastodon/pull/15055))
- Change public thread view to hide "Show thread" link ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15266))
- Change number format on about page from full to shortened ([Gargron](https://github.com/mastodon/mastodon/pull/15327))
- Change how scheduled tasks run in multi-process environments ([noellabo](https://github.com/mastodon/mastodon/pull/15314))
- New dedicated queue `scheduler`
- Runs by default when Sidekiq is executed with no options
- Has to be added manually in a multi-process environment
### Removed
- Remove fade-in animation from modals in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/15199))
- Remove auto-redirect to direct messages in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/15142))
- Remove obsolete IndexedDB operations from web UI ([Gargron](https://github.com/mastodon/mastodon/pull/14730))
- Remove dependency on unused and unmaintained http_parser.rb gem ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14574))
### Fixed
- Fix layout on about page when contact account has a long username ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15357))
- Fix follow limit preventing re-following of a moved account ([Gargron](https://github.com/mastodon/mastodon/pull/14207), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15384))
- **Fix deletes not reaching every server that interacted with toot** ([Gargron](https://github.com/mastodon/mastodon/pull/15200))
- Previously, delete of a toot would be primarily sent to the followers of its author, people mentioned in the toot, and people who reblogged the toot
- Now, additionally, it is ensured that it is sent to people who replied to it, favourited it, and to the person it replies to even if that person is not mentioned
- Fix resolving an account through its non-canonical form (i.e. alternate domain) ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15187))
- Fix sending redundant ActivityPub events when processing remote account deletion ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15104))
- Fix Move handler not being triggered when failing to fetch target account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15107))
- Fix downloading remote media files when server returns empty filename ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14867))
- Fix account processing failing because of large collections ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15027))
- Fix not being able to unfavorite toots one has lost access to ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15192))
- Fix not being able to unbookmark toots one has lost access to ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14604))
- Fix possible casing inconsistencies in hashtag search ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14906))
- Fix updating account counters when association is not yet created ([Gargron](https://github.com/mastodon/mastodon/pull/15108))
- Fix cookies not having a SameSite attribute ([Gargron](https://github.com/mastodon/mastodon/pull/15098))
- Fix poll ending notifications being created for each vote ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15071))
- Fix multiple boosts of a same toot erroneously appearing in TL ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14759))
- Fix asset builds not picking up `CDN_HOST` change ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14381))
- Fix desktop notifications permission prompt in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/14985), [Gargron](https://github.com/mastodon/mastodon/pull/15141), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13543), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15176))
- Some time ago, browsers added a requirement that desktop notification prompts could only be displayed in response to a user-generated event (such as a click)
- This means that for some time, users who haven't already given the permission before were not getting a prompt and as such were not receiving desktop notifications
- Fix "Mark media as sensitive" string not supporting pluralizations in other languages in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/15051))
- Fix glitched image uploads when canvas read access is blocked in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15180))
- Fix some account gallery items having empty labels in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15073))
- Fix alt-key hotkeys activating while typing in a text field in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14942))
- Fix wrong seek bar width on media player in web UI ([mfmfuyu](https://github.com/mastodon/mastodon/pull/15060))
- Fix logging out on mobile in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14901))
- Fix wrong click area for GIFVs in media modal in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/14615))
- Fix unreadable placeholder text color in high contrast theme in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/14803))
- Fix scrolling issues when closing some dropdown menus in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14606))
- Fix notification filter bar incorrectly filtering gaps in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14808))
- Fix disabled boost icon being replaced by private boost icon on hover in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14456))
- Fix hashtag detection in compose form being different to server-side in web UI ([kedamaDQ](https://github.com/mastodon/mastodon/pull/14484), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14513))
- Fix home last read marker mishandling gaps in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14809))
- Fix unnecessary re-rendering of various components when typing in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/15286))
- Fix notifications being unnecessarily re-rendered in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15312))
- Fix column swiping animation logic in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15301))
- Fix inefficiency when fetching hashtag timeline ([noellabo](https://github.com/mastodon/mastodon/pull/14861), [akihikodaki](https://github.com/mastodon/mastodon/pull/14662))
- Fix inefficiency when fetching bookmarks ([akihikodaki](https://github.com/mastodon/mastodon/pull/14674))
- Fix inefficiency when fetching favourites ([akihikodaki](https://github.com/mastodon/mastodon/pull/14673))
- Fix inefficiency when fetching media-only account timeline ([akihikodaki](https://github.com/mastodon/mastodon/pull/14675))
- Fix inefficiency when deleting accounts ([Gargron](https://github.com/mastodon/mastodon/pull/15387), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15409), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15407), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15408), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15402), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/15416), [Gargron](https://github.com/mastodon/mastodon/pull/15421))
- Fix redundant query when processing batch actions on custom emojis ([niwatori24](https://github.com/mastodon/mastodon/pull/14534))
- Fix slow distinct queries where grouped queries are faster ([Gargron](https://github.com/mastodon/mastodon/pull/15287))
- Fix performance on instances list in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/15282))
- Fix server actor appearing in list of accounts in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14567))
- Fix "bootstrap timeline accounts" toggle in site settings in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15325))
- Fix PostgreSQL secret name for cronjob in Helm chart ([metal3d](https://github.com/mastodon/mastodon/pull/15072))
- Fix Procfile not being compatible with herokuish ([acuteaura](https://github.com/mastodon/mastodon/pull/12685))
- Fix installation of tini being split into multiple steps in Dockerfile ([ryncsn](https://github.com/mastodon/mastodon/pull/14686))
### Security
- Fix streaming API allowing connections to persist after access token invalidation ([Gargron](https://github.com/mastodon/mastodon/pull/15111))
- Fix 2FA/sign-in token sessions being valid after password change ([Gargron](https://github.com/mastodon/mastodon/pull/14802))
- Fix resolving accounts sometimes creating duplicate records for a given ActivityPub identifier ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15364))
## [3.2.2] - 2020-12-19
### Added
- Add `tootctl maintenance fix-duplicates` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14860), [Gargron](https://github.com/mastodon/mastodon/pull/15223))
- Index corruption in the database?
- This command is for you
### Removed
- Remove dependency on unused and unmaintained http_parser.rb gem ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14574))
### Fixed
- Fix Move handler not being triggered when failing to fetch target account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15107))
- Fix downloading remote media files when server returns empty filename ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14867))
- Fix possible casing inconsistencies in hashtag search ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14906))
- Fix updating account counters when association is not yet created ([Gargron](https://github.com/mastodon/mastodon/pull/15108))
- Fix account processing failing because of large collections ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15027))
- Fix resolving an account through its non-canonical form (i.e. alternate domain) ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15187))
- Fix slow distinct queries where grouped queries are faster ([Gargron](https://github.com/mastodon/mastodon/pull/15287))
### Security
- Fix 2FA/sign-in token sessions being valid after password change ([Gargron](https://github.com/mastodon/mastodon/pull/14802))
- Fix resolving accounts sometimes creating duplicate records for a given ActivityPub identifier ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/15364))
## [3.2.1] - 2020-10-19
### Added
- Add support for latest HTTP Signatures spec draft ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14556))
- Add support for inlined objects in ActivityPub `to`/`cc` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14514))
### Changed
- Change actors to not be served at all without authentication in limited federation mode ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14800))
- Previously, a bare version of an actor was served when not authenticated, i.e. username and public key
- Because all actor fetch requests are signed using a separate system actor, that is no longer required
### Fixed
- Fix `tootctl media` commands not recognizing very large IDs ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14536))
- Fix crash when failing to load emoji picker in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14525))
- Fix contrast requirements in thumbnail color extraction ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14464))
- Fix audio/video player not using `CDN_HOST` on public pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14486))
- Fix private boost icon not being used on public pages ([OmmyZhang](https://github.com/mastodon/mastodon/pull/14471))
- Fix audio player on Safari in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14485), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14465))
- Fix dereferencing remote statuses not using the correct account for signature when receiving a targeted inbox delivery ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14656))
- Fix nil error in `tootctl media remove` ([noellabo](https://github.com/mastodon/mastodon/pull/14657))
- Fix videos with near-60 fps being rejected ([Gargron](https://github.com/mastodon/mastodon/pull/14684))
- Fix reported statuses not being included in warning e-mail ([Gargron](https://github.com/mastodon/mastodon/pull/14778))
- Fix `Reject` activities of `Follow` objects not correctly destroying a follow relationship ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14479))
- Fix inefficiencies in fan-out-on-write service ([Gargron](https://github.com/mastodon/mastodon/pull/14682), [noellabo](https://github.com/mastodon/mastodon/pull/14709))
- Fix timeout errors when trying to webfinger some IPv6 configurations ([Gargron](https://github.com/mastodon/mastodon/pull/14919))
- Fix files served as `application/octet-stream` being rejected without attempting mime type detection ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14452))
## [3.2.0] - 2020-07-27
### Added
- Add `SMTP_SSL` environment variable ([OmmyZhang](https://github.com/mastodon/mastodon/pull/14309))
- Add hotkey for toggling content warning input in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13987))
- **Add e-mail-based sign in challenge for users with disabled 2FA** ([Gargron](https://github.com/mastodon/mastodon/pull/14013))
- If user tries signing in after:
- Being inactive for a while
- With a previously unknown IP
- Without 2FA being enabled
- Require to enter a token sent via e-mail before sigining in
- Add `limit` param to RSS feeds ([noellabo](https://github.com/mastodon/mastodon/pull/13743))
- Add `visibility` param to share page ([noellabo](https://github.com/mastodon/mastodon/pull/13023))
- Add blurhash to link previews ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13984), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14143), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13985), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/14267), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/14278), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14126), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14261), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14260))
- In web UI, toots cannot be marked as sensitive unless there is media attached
- However, it's possible to do via API or ActivityPub
- Thumbnails of link previews of such posts now use blurhash in web UI
- The Card entity in REST API has a new `blurhash` attribute
- Add support for `summary` field for media description in ActivityPub ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13763))
- Add hints about incomplete remote content to web UI ([Gargron](https://github.com/mastodon/mastodon/pull/14031), [noellabo](https://github.com/mastodon/mastodon/pull/14195))
- **Add personal notes for accounts** ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14148), [Gargron](https://github.com/mastodon/mastodon/pull/14208), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/14251))
- To clarify, these are notes only you can see, to help you remember details
- Notes can be viewed and edited from profiles in web UI
- New REST API: `POST /api/v1/accounts/:id/note` with `comment` param
- The Relationship entity in REST API has a new `note` attribute
- Add Helm chart ([dunn](https://github.com/mastodon/mastodon/pull/14090), [dunn](https://github.com/mastodon/mastodon/pull/14256), [dunn](https://github.com/mastodon/mastodon/pull/14245))
- **Add customizable thumbnails for audio and video attachments** ([Gargron](https://github.com/mastodon/mastodon/pull/14145), [Gargron](https://github.com/mastodon/mastodon/pull/14244), [Gargron](https://github.com/mastodon/mastodon/pull/14273), [Gargron](https://github.com/mastodon/mastodon/pull/14203), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14255), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14306), [noellabo](https://github.com/mastodon/mastodon/pull/14358), [noellabo](https://github.com/mastodon/mastodon/pull/14357))
- Metadata (album, artist, etc) is no longer stripped from audio files
- Album art is automatically extracted from audio files
- Thumbnail can be manually uploaded for both audio and video attachments
- Media upload APIs now support `thumbnail` param
- On `POST /api/v1/media` and `POST /api/v2/media`
- And on `PUT /api/v1/media/:id`
- ActivityPub representation of media attachments represents custom thumbnails with an `icon` attribute
- The Media Attachment entity in REST API now has a `preview_remote_url` to its `preview_url`, equivalent to `remote_url` to its `url`
- **Add color extraction for thumbnails** ([Gargron](https://github.com/mastodon/mastodon/pull/14209), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14264))
- The `meta` attribute on the Media Attachment entity in REST API can now have a `colors` attribute which in turn contains three hex colors: `background`, `foreground`, and `accent`
- The background color is chosen from the most dominant color around the edges of the thumbnail
- The foreground and accent colors are chosen from the colors that are the most different from the background color using the CIEDE2000 algorithm
- The most saturated color of the two is designated as the accent color
- The one with the highest W3C contrast is designated as the foreground color
- If there are not enough colors in the thumbnail, new ones are generated using a monochrome pattern
- Add a visibility indicator to toots in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/14123), [highemerly](https://github.com/mastodon/mastodon/pull/14292))
- Add `tootctl email_domain_blocks` ([tateisu](https://github.com/mastodon/mastodon/pull/13589), [Gargron](https://github.com/mastodon/mastodon/pull/14147))
- Add "Add new domain block" to header of federation page in admin UI ([ariasuni](https://github.com/mastodon/mastodon/pull/13934))
- Add ability to keep emoji picker open with ctrl+click in web UI ([bclindner](https://github.com/mastodon/mastodon/pull/13896), [noellabo](https://github.com/mastodon/mastodon/pull/14096))
- Add custom icon for private boosts in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14380))
- Add support for Create and Update activities that don't inline objects in ActivityPub ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14359))
- Add support for Undo activities that don't inline activities in ActivityPub ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14346))
### Changed
- Change `.env.production.sample` to be leaner and cleaner ([Gargron](https://github.com/mastodon/mastodon/pull/14206))
- It was overloaded as de-facto documentation and getting quite crowded
- Defer to the actual documentation while still giving a minimal example
- Change `tootctl search deploy` to work faster and display progress ([Gargron](https://github.com/mastodon/mastodon/pull/14300))
- Change User-Agent of link preview fetching service to include "Bot" ([Gargron](https://github.com/mastodon/mastodon/pull/14248))
- Some websites may not render OpenGraph tags into HTML if that's not the case
- Change behaviour to carry blocks over when someone migrates their followers ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14144))
- Change volume control and download buttons in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/14122))
- **Change design of audio players in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/14095), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14281), [Gargron](https://github.com/mastodon/mastodon/pull/14282), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14118), [Gargron](https://github.com/mastodon/mastodon/pull/14199), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14338))
- Change reply filter to never filter own toots in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14128))
- Change boost button to no longer serve as visibility indicator in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/14132), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14373))
- Change contrast of flash messages ([cchoi12](https://github.com/mastodon/mastodon/pull/13892))
- Change wording from "Hide media" to "Hide image/images" in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/13834))
- Change appearance of settings pages to be more consistent ([ariasuni](https://github.com/mastodon/mastodon/pull/13938))
- Change "Add media" tooltip to not include long list of formats in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/13954))
- Change how badly contrasting emoji are rendered in web UI ([leo60228](https://github.com/mastodon/mastodon/pull/13773), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13772), [mfmfuyu](https://github.com/mastodon/mastodon/pull/14020), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14015))
- Change structure of unavailable content section on about page ([ariasuni](https://github.com/mastodon/mastodon/pull/13930))
- Change behaviour to accept ActivityPub activities relayed through group actor ([noellabo](https://github.com/mastodon/mastodon/pull/14279))
- Change amount of processing retries for ActivityPub activities ([noellabo](https://github.com/mastodon/mastodon/pull/14355))
### Removed
- Remove the terms "blacklist" and "whitelist" from UX ([Gargron](https://github.com/mastodon/mastodon/pull/14149), [mayaeh](https://github.com/mastodon/mastodon/pull/14192))
- Environment variables changed (old versions continue to work):
- `WHITELIST_MODE``LIMITED_FEDERATION_MODE`
- `EMAIL_DOMAIN_BLACKLIST``EMAIL_DOMAIN_DENYLIST`
- `EMAIL_DOMAIN_WHITELIST``EMAIL_DOMAIN_ALLOWLIST`
- CLI option changed:
- `tootctl domains purge --whitelist-mode``tootctl domains purge --limited-federation-mode`
- Remove some unnecessary database indexes ([lfuelling](https://github.com/mastodon/mastodon/pull/13695), [noellabo](https://github.com/mastodon/mastodon/pull/14259))
- Remove unnecessary Node.js version upper bound ([ykzts](https://github.com/mastodon/mastodon/pull/14139))
### Fixed
- Fix `following` param not working when exact match is found in account search ([noellabo](https://github.com/mastodon/mastodon/pull/14394))
- Fix sometimes occurring duplicate mention notifications ([noellabo](https://github.com/mastodon/mastodon/pull/14378))
- Fix RSS feeds not being cacheable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14368))
- Fix lack of locking around processing of Announce activities in ActivityPub ([noellabo](https://github.com/mastodon/mastodon/pull/14365))
- Fix boosted toots from blocked account not being retroactively removed from TL ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14339))
- Fix large shortened numbers (like 1.2K) using incorrect pluralization ([Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/14061))
- Fix streaming server trying to use empty password to connect to Redis when `REDIS_PASSWORD` is given but blank ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14135))
- Fix being unable to unboost posts when blocked by their author ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14308))
- Fix account domain block not properly unfollowing accounts from domain ([Gargron](https://github.com/mastodon/mastodon/pull/14304))
- Fix removing a domain allow wiping known accounts in open federation mode ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14298))
- Fix blocks and mutes pagination in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14275))
- Fix new posts pushing down origin of opened dropdown in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14271), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14348))
- Fix timeline markers not being saved sometimes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13887), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13889), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/14155))
- Fix CSV uploads being rejected ([noellabo](https://github.com/mastodon/mastodon/pull/13835))
- Fix incompatibility with Elasticsearch 7.x ([noellabo](https://github.com/mastodon/mastodon/pull/13828))
- Fix being able to search posts where you're in the target audience but not actively mentioned ([noellabo](https://github.com/mastodon/mastodon/pull/13829))
- Fix non-local posts appearing on local-only hashtag timelines in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/13827))
- Fix `tootctl media remove-orphans` choking on unknown files in storage ([Gargron](https://github.com/mastodon/mastodon/pull/13765))
- Fix `tootctl upgrade storage-schema` misbehaving ([Gargron](https://github.com/mastodon/mastodon/pull/13761), [angristan](https://github.com/mastodon/mastodon/pull/13768))
- Fix it marking records as upgraded even though no files were moved
- Fix it not working with S3 storage
- Fix it not working with custom emojis
- Fix GIF reader raising incorrect exceptions ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13760))
- Fix hashtag search performing account search as well ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13758))
- Fix Webfinger returning wrong status code on malformed or missing param ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13759))
- Fix `rake mastodon:setup` error when some environment variables are set ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13928))
- Fix admin page crashing when trying to block an invalid domain name in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13884))
- Fix unsent toot confirmation dialog not popping up in single column mode in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13888))
- Fix performance of follow import ([noellabo](https://github.com/mastodon/mastodon/pull/13836))
- Reduce timeout of Webfinger requests to that of other requests
- Use circuit breakers to stop hitting unresponsive servers
- Avoid hitting servers that are already known to be generally unavailable
- Fix filters ignoring media descriptions ([BenLubar](https://github.com/mastodon/mastodon/pull/13837))
- Fix some actions on custom emojis leading to cryptic errors in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13951))
- Fix ActivityPub serialization of replies when some of them are URIs ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13957))
- Fix `rake mastodon:setup` choking on environment variables containing `%` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13940))
- Fix account redirect confirmation message talking about moved followers ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13950))
- Fix avatars having the wrong size on public detailed status pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14140))
- Fix various issues around OpenGraph representation of media ([Gargron](https://github.com/mastodon/mastodon/pull/14133))
- Pages containing audio no longer say "Attached: 1 image" in description
- Audio attachments now represented as OpenGraph `og:audio`
- The `twitter:player` page now uses Mastodon's proper audio/video player
- Audio/video buffered bars now display correctly in audio/video player
- Volume and progress bars now respond to movement/move smoother
- Fix audio/video/images/cards not reacting to window resizes in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/14130))
- Fix very wide media attachments resulting in too thin a thumbnail in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14127))
- Fix crash when merging posts into home feed after following someone ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14129))
- Fix unique username constraint for local users not being enforced in database ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14099))
- Fix unnecessary gap under video modal in web UI ([mfmfuyu](https://github.com/mastodon/mastodon/pull/14098))
- Fix 2FA and sign in token pages not respecting user locale ([mfmfuyu](https://github.com/mastodon/mastodon/pull/14087))
- Fix unapproved users being able to view profiles when in limited-federation mode _and_ requiring approval for sign-ups ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14093))
- Fix initial audio volume not corresponding to what's displayed in audio player in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14057))
- Fix timelines sometimes jumping when closing modals in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14019))
- Fix memory usage of downloading remote files ([Gargron](https://github.com/mastodon/mastodon/pull/14184), [Gargron](https://github.com/mastodon/mastodon/pull/14181), [noellabo](https://github.com/mastodon/mastodon/pull/14356))
- Don't read entire file (up to 40 MB) into memory
- Read and write it to temp file in small chunks
- Fix inconsistent account header padding in web UI ([trwnh](https://github.com/mastodon/mastodon/pull/14179))
- Fix Thai being skipped from language detection ([Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/13989))
- Since Thai has its own alphabet, it can be detected more reliably
- Fix broken hashtag column options styling in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14247))
- Fix pointer cursor being shown on toots that are not clickable in web UI ([arielrodrigues](https://github.com/mastodon/mastodon/pull/14185))
- Fix lock icon not being shown when locking account in profile settings ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14190))
- Fix domain blocks doing work the wrong way around ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13424))
- Instead of suspending accounts one by one, mark all as suspended first (quick)
- Only then proceed to start removing their data (slow)
- Clear out media attachments in a separate worker (slow)
## [3.1.5] - 2020-07-07
### Security
- Fix media attachment enumeration ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/14254))
- Change rate limits for various paths ([Gargron](https://github.com/mastodon/mastodon/pull/14253))
- Fix other sessions not being logged out on password change ([Gargron](https://github.com/mastodon/mastodon/pull/14252))
## [3.1.4] - 2020-05-14
### Added
- Add `vi` to available locales ([taicv](https://github.com/mastodon/mastodon/pull/13542))
- Add ability to remove identity proofs from account ([Gargron](https://github.com/mastodon/mastodon/pull/13682))
- Add ability to exclude local content from federated timeline ([noellabo](https://github.com/mastodon/mastodon/pull/13504), [noellabo](https://github.com/mastodon/mastodon/pull/13745))
- Add `remote` param to `GET /api/v1/timelines/public` REST API
- Add `public/remote` / `public:remote` variants to streaming API
- "Remote only" option in federated timeline column settings in web UI
- Add ability to exclude remote content from hashtag timelines in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/13502))
- No changes to REST API
- "Local only" option in hashtag column settings in web UI
- Add Capistrano tasks that reload the services after deploying ([berkes](https://github.com/mastodon/mastodon/pull/12642))
- Add `invites_enabled` attribute to `GET /api/v1/instance` in REST API ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13501))
- Add `tootctl emoji export` command ([lfuelling](https://github.com/mastodon/mastodon/pull/13534))
- Add separate cache directory for non-local uploads ([Gargron](https://github.com/mastodon/mastodon/pull/12821), [Hanage999](https://github.com/mastodon/mastodon/pull/13593), [mayaeh](https://github.com/mastodon/mastodon/pull/13551))
- Add `tootctl upgrade storage-schema` command to move old non-local uploads to the cache directory
- Add buttons to delete header and avatar from profile settings ([sternenseemann](https://github.com/mastodon/mastodon/pull/13234))
- Add emoji graphics and shortcodes from Twemoji 12.1.5 ([DeeUnderscore](https://github.com/mastodon/mastodon/pull/13021))
### Changed
- Change error message when trying to migrate to an account that does not have current account set as an alias to be more clear ([TheEvilSkeleton](https://github.com/mastodon/mastodon/pull/13746))
- Change delivery failure tracking to work with hostnames instead of URLs ([Gargron](https://github.com/mastodon/mastodon/pull/13437), [noellabo](https://github.com/mastodon/mastodon/pull/13481), [noellabo](https://github.com/mastodon/mastodon/pull/13482), [noellabo](https://github.com/mastodon/mastodon/pull/13535))
- Change Content-Security-Policy to not need unsafe-inline style-src ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13679), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13692), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13576), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13575), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13438))
- Change how RSS items are titled and formatted ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13592), [ykzts](https://github.com/mastodon/mastodon/pull/13591))
### Fixed
- Fix dropdown of muted and followed accounts offering option to hide boosts in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13748))
- Fix "You are already signed in" alert being shown at wrong times ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13547))
- Fix retrying of failed-to-download media files not actually working ([noellabo](https://github.com/mastodon/mastodon/pull/13741))
- Fix first poll option not being focused when adding a poll in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13740))
- Fix `sr` locale being selected over `sr-Latn` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13693))
- Fix error within error when limiting backtrace to 3 lines ([Gargron](https://github.com/mastodon/mastodon/pull/13120))
- Fix `tootctl media remove-orphans` crashing on "Import" files ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13685))
- Fix regression in `tootctl media remove-orphans` ([Gargron](https://github.com/mastodon/mastodon/pull/13405))
- Fix old unique jobs digests not having been cleaned up ([Gargron](https://github.com/mastodon/mastodon/pull/13683))
- Fix own following/followers not showing muted users ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13614))
- Fix list of followed people ignoring sorting on Follows & Followers page ([taras2358](https://github.com/mastodon/mastodon/pull/13676))
- Fix wrong pgHero Content-Security-Policy when `CDN_HOST` is set ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13595))
- Fix needlessly deduplicating usernames on collisions with remote accounts when signing-up through SAML/CAS ([kaiyou](https://github.com/mastodon/mastodon/pull/13581))
- Fix page incorrectly scrolling when bringing up dropdown menus in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13574))
- Fix messed up z-index when NoScript blocks media/previews in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13449))
- Fix "See what's happening" page showing public instead of local timeline for logged-in users ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13499))
- Fix not being able to resolve public resources in development environment ([Gargron](https://github.com/mastodon/mastodon/pull/13505))
- Fix uninformative error message when uploading unsupported image files ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13540))
- Fix expanded video player issues in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13541), [eai04191](https://github.com/mastodon/mastodon/pull/13533))
- Fix and refactor keyboard navigation in dropdown menus in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13528))
- Fix uploaded image orientation being messed up in some browsers in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13493))
- Fix actions log crash when displaying updates of deleted announcements in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13489))
- Fix search not working due to proxy settings when using hidden services ([Gargron](https://github.com/mastodon/mastodon/pull/13488))
- Fix poll refresh button not being debounced in web UI ([rasjonell](https://github.com/mastodon/mastodon/pull/13485), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13490))
- Fix confusing error when failing to add an alias to an unknown account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13480))
- Fix "Email changed" notification sometimes having wrong e-mail ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13475))
- Fix various issues on the account aliases page ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13452))
- Fix API footer link in web UI ([bubblineyuri](https://github.com/mastodon/mastodon/pull/13441))
- Fix pagination of following, followers, follow requests, blocks and mutes lists in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13445))
- Fix styling of polls in JS-less fallback on public pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13436))
- Fix trying to delete already deleted file when post-processing ([Gargron](https://github.com/mastodon/mastodon/pull/13406))
### Security
- Fix Doorkeeper vulnerability that exposed app secret to users who authorized the app and reset secret of the web UI that could have been exposed ([dependabot-preview[bot]](https://github.com/mastodon/mastodon/pull/13613), [Gargron](https://github.com/mastodon/mastodon/pull/13688))
- For apps that self-register on behalf of every individual user (such as most mobile apps), this is a non-issue
- The issue only affects developers of apps who are shared between multiple users, such as server-side apps like cross-posters
## [3.1.3] - 2020-04-05
### Added
- Add ability to filter audit log in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/13381))
- Add titles to warning presets in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/13252))
- Add option to include resolved DNS records when blacklisting e-mail domains in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/13254))
- Add ability to delete files uploaded for settings in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13192))
- Add sorting by username, creation and last activity in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13076))
- Add explanation as to why unlocked accounts may have follow requests in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13385))
- Add link to bookmarks to dropdown in web UI ([mayaeh](https://github.com/mastodon/mastodon/pull/13273))
- Add support for links to statuses in announcements to be opened in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13212), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13250))
- Add tooltips to audio/video player buttons in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/13203))
- Add submit button to the top of preferences pages ([guigeekz](https://github.com/mastodon/mastodon/pull/13068))
- Add specific rate limits for posting, following and reporting ([Gargron](https://github.com/mastodon/mastodon/pull/13172), [Gargron](https://github.com/mastodon/mastodon/pull/13390))
- 300 posts every 3 hours
- 400 follows or follow requests every 24 hours
- 400 reports every 24 hours
- Add federation support for the "hide network" preference ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11673))
- Add `--skip-media-remove` option to `tootctl statuses remove` ([tateisu](https://github.com/mastodon/mastodon/pull/13080))
### Changed
- **Change design of polls in web UI** ([Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/13257), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13313))
- Change status click areas in web UI to be bigger ([ariasuni](https://github.com/mastodon/mastodon/pull/13327))
- **Change `tootctl media remove-orphans` to work for all classes** ([Gargron](https://github.com/mastodon/mastodon/pull/13316))
- **Change local media attachments to perform heavy processing asynchronously** ([Gargron](https://github.com/mastodon/mastodon/pull/13210))
- Change video uploads to always be converted to H264/MP4 ([Gargron](https://github.com/mastodon/mastodon/pull/13220), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13239), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13242))
- Change video uploads to enforce certain limits ([Gargron](https://github.com/mastodon/mastodon/pull/13218))
- Dimensions smaller than 1920x1200px
- Frame rate at most 60fps
- Change the tooltip "Toggle visibility" to "Hide media" in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/13199))
- Change description of privacy levels to be more intuitive in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/13197))
- Change GIF label to be displayed even when autoplay is enabled in web UI ([koyuawsmbrtn](https://github.com/mastodon/mastodon/pull/13209))
- Change the string "Hide everything from …" to "Block domain …" in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13178), [mayaeh](https://github.com/mastodon/mastodon/pull/13221))
- Change wording of media display preferences to be more intuitive ([ariasuni](https://github.com/mastodon/mastodon/pull/13198))
### Deprecated
- `POST /api/v1/media``POST /api/v2/media` ([Gargron](https://github.com/mastodon/mastodon/pull/13210))
### Fixed
- Fix `tootctl media remove-orphans` ignoring `PAPERCLIP_ROOT_PATH` ([Gargron](https://github.com/mastodon/mastodon/pull/13375))
- Fix returning results when searching for URL with non-zero offset ([Gargron](https://github.com/mastodon/mastodon/pull/13377))
- Fix pinning a column in web UI sometimes redirecting out of web UI ([Gargron](https://github.com/mastodon/mastodon/pull/13376))
- Fix background jobs not using locks like they are supposed to ([Gargron](https://github.com/mastodon/mastodon/pull/13361))
- Fix content warning being unnecessarily cleared when hiding content warning input in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13348))
- Fix "Show more" not switching to "Show less" on public pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13174))
- Fix import overwrite option not being selectable ([noellabo](https://github.com/mastodon/mastodon/pull/13347))
- Fix wrong color for ellipsis in boost confirmation dialog in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/13355))
- Fix unnecessary unfollowing when importing follows with overwrite option ([noellabo](https://github.com/mastodon/mastodon/pull/13350))
- Fix 404 and 410 API errors being silently discarded in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13279))
- Fix OCR not working on Safari because of unsupported worker-src CSP ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13323))
- Fix media not being marked sensitive when a content warning is set with no text ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13277))
- Fix crash after deleting announcements in web UI ([codesections](https://github.com/mastodon/mastodon/pull/13283), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/13312))
- Fix bookmarks not being searchable ([Kjwon15](https://github.com/mastodon/mastodon/pull/13271), [noellabo](https://github.com/mastodon/mastodon/pull/13293))
- Fix reported accounts not being whitelisted from further spam checks when resolving a spam check report ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13289))
- Fix web UI crash in single-column mode on prehistoric browsers ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13267))
- Fix some timeouts when searching for URLs ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13253))
- Fix detailed view of direct messages displaying a 0 boost count in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13244))
- Fix regression in “Edit media” modal in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13243))
- Fix public posts from silenced accounts not being changed to unlisted visibility ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13096))
- Fix error when searching for URLs that contain the mention syntax ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13151))
- Fix text area above/right of emoji picker being accidentally clickable in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/13148))
- Fix too large announcements not being scrollable in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13211))
- Fix `tootctl media remove-orphans` crashing when encountering invalid media ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13170))
- Fix installation failing when Redis password contains special characters ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13156))
- Fix announcements with fully-qualified mentions to local users crashing web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13164))
### Security
- Fix re-sending of e-mail confirmation not being rate limited ([Gargron](https://github.com/mastodon/mastodon/pull/13360))
## [v3.1.2] - 2020-02-27
### Added
- Add `--reset-password` option to `tootctl accounts modify` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13126))
- Add source-mapped stacktrace to error message in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13082))
### Fixed
- Fix dismissing an announcement twice raising an obscure error ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13124))
- Fix misleading error when attempting to re-send a pending follow request ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13133))
- Fix backups failing when files are missing from media attachments ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13146))
- Fix duplicate accounts being created when fetching an account for its key only ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13147))
- Fix `/web` redirecting to `/web/web` in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13128))
- Fix previously OStatus-based accounts not being detected as ActivityPub ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13129))
- Fix account JSON/RSS not being cacheable due to wrong mime type comparison ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13116))
- Fix old browsers crashing because of missing `finally` polyfill in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13115))
- Fix account's bio not being shown if there are no proofs/fields in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13075))
- Fix sign-ups without checked user agreement being accepted through the web form ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13088))
- Fix non-x64 architectures not being able to build Docker image because of hardcoded Node.js architecture ([SaraSmiseth](https://github.com/mastodon/mastodon/pull/13081))
- Fix invite request input not being shown on sign-up error if left empty ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13089))
- Fix some migration hints mentioning GitLab instead of Mastodon ([saper](https://github.com/mastodon/mastodon/pull/13084))
### Security
- Fix leak of arbitrary statuses through unfavourite action in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/13161))
## [3.1.1] - 2020-02-10
### Fixed
- Fix yanked dependency preventing installation ([mayaeh](https://github.com/mastodon/mastodon/pull/13059))
## [3.1.0] - 2020-02-09
### Added
- Add bookmarks ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/7107), [Gargron](https://github.com/mastodon/mastodon/pull/12494), [Gomasy](https://github.com/mastodon/mastodon/pull/12381))
- Add announcements ([Gargron](https://github.com/mastodon/mastodon/pull/12662), [Gargron](https://github.com/mastodon/mastodon/pull/12967), [Gargron](https://github.com/mastodon/mastodon/pull/12970), [Gargron](https://github.com/mastodon/mastodon/pull/12963), [Gargron](https://github.com/mastodon/mastodon/pull/12950), [Gargron](https://github.com/mastodon/mastodon/pull/12990), [Gargron](https://github.com/mastodon/mastodon/pull/12949), [Gargron](https://github.com/mastodon/mastodon/pull/12989), [Gargron](https://github.com/mastodon/mastodon/pull/12964), [Gargron](https://github.com/mastodon/mastodon/pull/12965), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/12958), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/12957), [Gargron](https://github.com/mastodon/mastodon/pull/12955), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/12946), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/12954))
- Add number animations in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/12948), [Gargron](https://github.com/mastodon/mastodon/pull/12971))
- Add `kab`, `is`, `kn`, `mr`, `ur` to available locales ([Gargron](https://github.com/mastodon/mastodon/pull/12882), [BoFFire](https://github.com/mastodon/mastodon/pull/12962), [Gargron](https://github.com/mastodon/mastodon/pull/12379))
- Add profile filter category ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12918))
- Add ability to add oneself to lists ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12271))
- Add hint how to contribute translations to preferences page ([Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12736))
- Add signatures to statuses in archive takeout ([noellabo](https://github.com/mastodon/mastodon/pull/12649))
- Add support for `magnet:` and `xmpp` links ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12905), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/12709))
- Add `follow_request` notification type ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12198))
- Add ability to filter reports by account domain in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12154))
- Add link to search for users connected from the same IP address to admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12157))
- Add link to reports targeting a specific domain in admin view ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12513))
- Add support for EventSource streaming in web UI ([BenLubar](https://github.com/mastodon/mastodon/pull/12887))
- Add hotkey for opening media attachments in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12498), [Kjwon15](https://github.com/mastodon/mastodon/pull/12546))
- Add relationship-based options to status dropdowns in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/12377), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/12535), [Gargron](https://github.com/mastodon/mastodon/pull/12430))
- Add support for submitting media description with `ctrl`+`enter` in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12272))
- Add download button to audio and video players in web UI ([NimaBoscarino](https://github.com/mastodon/mastodon/pull/12179))
- Add setting for whether to crop images in timelines in web UI ([duxovni](https://github.com/mastodon/mastodon/pull/12126))
- Add support for `Event` activities ([tcitworld](https://github.com/mastodon/mastodon/pull/12637))
- Add basic support for `Group` actors ([noellabo](https://github.com/mastodon/mastodon/pull/12071))
- Add `S3_OVERRIDE_PATH_STYLE` environment variable ([Gargron](https://github.com/mastodon/mastodon/pull/12594))
- Add `S3_OPEN_TIMEOUT` environment variable ([tateisu](https://github.com/mastodon/mastodon/pull/12459))
- Add `LDAP_MAIL` environment variable ([madmath03](https://github.com/mastodon/mastodon/pull/12053))
- Add `LDAP_UID_CONVERSION_ENABLED` environment variable ([madmath03](https://github.com/mastodon/mastodon/pull/12461))
- Add `--remote-only` option to `tootctl emoji purge` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12810))
- Add `tootctl media remove-orphans` ([Gargron](https://github.com/mastodon/mastodon/pull/12568), [Gargron](https://github.com/mastodon/mastodon/pull/12571))
- Add `tootctl media lookup` command ([irlcatgirl](https://github.com/mastodon/mastodon/pull/12283))
- Add cache for OEmbed endpoints to avoid extra HTTP requests ([Gargron](https://github.com/mastodon/mastodon/pull/12403))
- Add support for KaiOS arrow navigation to public pages ([nolanlawson](https://github.com/mastodon/mastodon/pull/12251))
- Add `discoverable` to accounts in REST API ([trwnh](https://github.com/mastodon/mastodon/pull/12508))
- Add admin setting to disable default follows ([ArisuOngaku](https://github.com/mastodon/mastodon/pull/12566))
- Add support for LDAP and PAM in the OAuth password grant strategy ([ntl-purism](https://github.com/mastodon/mastodon/pull/12390), [Gargron](https://github.com/mastodon/mastodon/pull/12743))
- Allow support for `Accept`/`Reject` activities with a non-embedded object ([puckipedia](https://github.com/mastodon/mastodon/pull/12199))
- Add "Show thread" button to public profiles ([Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/13000))
### Changed
- Change `last_status_at` to be a date, not datetime in REST API ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12966))
- Change followers page to relationships page in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/12927), [Gargron](https://github.com/mastodon/mastodon/pull/12934))
- Change reported media attachments to always be hidden in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/12879), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/12907))
- Change string from "Disable" to "Disable login" in admin UI ([nileshkumar](https://github.com/mastodon/mastodon/pull/12201))
- Change report page structure in admin UI ([Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12615))
- Change swipe sensitivity to be lower on small screens in web UI ([umonaca](https://github.com/mastodon/mastodon/pull/12168))
- Change audio/video playback to stop playback when out of view in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/12486))
- Change media description label based on upload type in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12270))
- Change large numbers to render without decimal units in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/12706))
- Change "Add a choice" button to be disabled rather than hidden when poll limit reached in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12319), [hinaloe](https://github.com/mastodon/mastodon/pull/12544))
- Change `tootctl statuses remove` to keep statuses favourited or bookmarked by local users ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11267), [Gomasy](https://github.com/mastodon/mastodon/pull/12818))
- Change domain block behavior to update user records (fast) before deleting data (slower) ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12247))
- Change behaviour to strip audio metadata on uploads ([hugogameiro](https://github.com/mastodon/mastodon/pull/12171))
- Change accepted length of remote media descriptions from 420 to 1,500 characters ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12262))
- Change preferences pages structure ([Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12497), [mayaeh](https://github.com/mastodon/mastodon/pull/12517), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12801), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12797), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12799), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12793))
- Change format of titles in RSS ([devkral](https://github.com/mastodon/mastodon/pull/8596))
- Change favourite icon animation from spring-based motion to CSS animation in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12175))
- Change minimum required Node.js version to 10, and default to 12 ([Shleeble](https://github.com/mastodon/mastodon/pull/12791), [mkody](https://github.com/mastodon/mastodon/pull/12906), [Shleeble](https://github.com/mastodon/mastodon/pull/12703))
- Change spam check to exempt server staff ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12874))
- Change to fallback to to `Create` audience when `object` has no defined audience ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12249))
- Change Twemoji library to 12.1.3 in web UI ([koyuawsmbrtn](https://github.com/mastodon/mastodon/pull/12342))
- Change blocked users to be hidden from following/followers lists ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12733))
- Change signature verification to ignore signatures with invalid host ([Gargron](https://github.com/mastodon/mastodon/pull/13033))
### Removed
- Remove unused dependencies ([ykzts](https://github.com/mastodon/mastodon/pull/12861), [mayaeh](https://github.com/mastodon/mastodon/pull/12826), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/12822), [ykzts](https://github.com/mastodon/mastodon/pull/12533))
### Fixed
- Fix some translatable strings being used wrongly ([Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12569), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12589), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12502), [mayaeh](https://github.com/mastodon/mastodon/pull/12231))
- Fix headline of public timeline page when set to local-only ([ykzts](https://github.com/mastodon/mastodon/pull/12224))
- Fix space between tabs not being spread evenly in web UI ([Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12944), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12961), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12446))
- Fix interactive delays in database migrations with no TTY ([Gargron](https://github.com/mastodon/mastodon/pull/12969))
- Fix status overflowing in report dialog in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12959))
- Fix unlocalized dropdown button title in web UI ([Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/12947))
- Fix media attachments without file being uploadable ([Gargron](https://github.com/mastodon/mastodon/pull/12562))
- Fix unfollow confirmations in profile directory in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12922))
- Fix duplicate `description` meta tag on accounts public pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12923))
- Fix slow query of federated timeline ([notozeki](https://github.com/mastodon/mastodon/pull/12886))
- Fix not all of account's active IPs showing up in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/12909), [Gargron](https://github.com/mastodon/mastodon/pull/12943))
- Fix search by IP not using alternative browser sessions in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/12904))
- Fix “X new items” not showing up for slow mode on empty timelines in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12875))
- Fix OEmbed endpoint being inaccessible in secure mode ([Gargron](https://github.com/mastodon/mastodon/pull/12864))
- Fix proofs API being inaccessible in secure mode ([Gargron](https://github.com/mastodon/mastodon/pull/12495))
- Fix Ruby 2.7 incompatibilities ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12831), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/12824), [Shleeble](https://github.com/mastodon/mastodon/pull/12759), [zunda](https://github.com/mastodon/mastodon/pull/12769))
- Fix invalid poll votes being accepted in REST API ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12601))
- Fix old migrations failing because of strong migrations update ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12787), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/12692))
- Fix reuse of detailed status components in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12792))
- Fix base64-encoded file uploads not being possible in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/12748), [Gargron](https://github.com/mastodon/mastodon/pull/12857))
- Fix error due to missing authentication call in filters controller ([Gargron](https://github.com/mastodon/mastodon/pull/12746))
- Fix uncaught unknown format error in host meta controller ([Gargron](https://github.com/mastodon/mastodon/pull/12747))
- Fix URL search not returning private toots user has access to ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12742), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/12336))
- Fix cache digesting log noise on status embeds ([Gargron](https://github.com/mastodon/mastodon/pull/12750))
- Fix slowness due to layout thrashing when reloading a large set of statuses in web UI ([panarom](https://github.com/mastodon/mastodon/pull/12661), [panarom](https://github.com/mastodon/mastodon/pull/12744), [Gargron](https://github.com/mastodon/mastodon/pull/12712))
- Fix error when fetching followers/following from REST API when user has network hidden ([Gargron](https://github.com/mastodon/mastodon/pull/12716))
- Fix IDN mentions not being processed, IDN domains not being rendered ([Gargron](https://github.com/mastodon/mastodon/pull/12715), [Gargron](https://github.com/mastodon/mastodon/pull/13035), [Gargron](https://github.com/mastodon/mastodon/pull/13030))
- Fix error when searching for empty phrase ([Gargron](https://github.com/mastodon/mastodon/pull/12711))
- Fix backups stopping due to read timeouts ([chr-1x](https://github.com/mastodon/mastodon/pull/12281))
- Fix batch actions on non-pending tags in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12537))
- Fix sample `SAML_ACS_URL`, `SAML_ISSUER` ([orlea](https://github.com/mastodon/mastodon/pull/12669))
- Fix manual scrolling issue on Firefox/Windows in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12648))
- Fix archive takeout failing if total dump size exceeds 2GB ([scd31](https://github.com/mastodon/mastodon/pull/12602), [Gargron](https://github.com/mastodon/mastodon/pull/12653))
- Fix custom emoji category creation silently erroring out on duplicate category ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12647))
- Fix link crawler not specifying preferred content type ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12646))
- Fix featured hashtag setting page erroring out instead of rejecting invalid tags ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12436))
- Fix tooltip messages of single/multiple-choice polls switcher being reversed in web UI ([acid-chicken](https://github.com/mastodon/mastodon/pull/12616))
- Fix typo in help text of `tootctl statuses remove` ([trwnh](https://github.com/mastodon/mastodon/pull/12603))
- Fix generic HTTP 500 error on duplicate records ([Gargron](https://github.com/mastodon/mastodon/pull/12563))
- Fix old migration failing with new status default scope ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12493))
- Fix errors when using search API with no query ([Gargron](https://github.com/mastodon/mastodon/pull/12541), [trwnh](https://github.com/mastodon/mastodon/pull/12549))
- Fix poll options not being selectable via keyboard in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12538))
- Fix conversations not having an unread indicator in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/12506))
- Fix lost focus when modals open/close in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12437))
- Fix pending upload count not being decremented on error in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12499))
- Fix empty poll options not being removed on remote poll update ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12484))
- Fix OCR with delete & redraft in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12465))
- Fix blur behind closed registration message ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12442))
- Fix OEmbed discovery not handling different URL variants in query ([Gargron](https://github.com/mastodon/mastodon/pull/12439))
- Fix link crawler crashing on `<a>` tags without `href` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12159))
- Fix whitelisted subdomains being ignored in whitelist mode ([noiob](https://github.com/mastodon/mastodon/pull/12435))
- Fix broken audit log in whitelist mode in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12303))
- Fix unread indicator not honoring "Only media" option in local and federated timelines in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12330))
- Fix error when rebuilding home feeds ([dariusk](https://github.com/mastodon/mastodon/pull/12324))
- Fix relationship caches being broken as result of a follow request ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12299))
- Fix more items than the limit being uploadable in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12300))
- Fix various issues with account migration ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12301))
- Fix filtered out items being counted as pending items in slow mode in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12266))
- Fix notification filters not applying to poll options ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12269))
- Fix notification message for user's own poll saying it's a poll they voted on in web UI ([ykzts](https://github.com/mastodon/mastodon/pull/12219))
- Fix polls with an expiration not showing up as expired in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/12222))
- Fix volume slider having an offset between cursor and slider in Chromium in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12158))
- Fix Vagrant image not accepting connections ([shrft](https://github.com/mastodon/mastodon/pull/12180))
- Fix batch actions being hidden on small screens in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12183))
- Fix incoming federation not working in whitelist mode ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12185))
- Fix error when passing empty `source` param to `PUT /api/v1/accounts/update_credentials` ([jglauche](https://github.com/mastodon/mastodon/pull/12259))
- Fix HTTP-based streaming API being cacheable by proxies ([BenLubar](https://github.com/mastodon/mastodon/pull/12945))
- Fix users being able to register while `tootctl self-destruct` is in progress ([Kjwon15](https://github.com/mastodon/mastodon/pull/12877))
- Fix microformats detection in link crawler not ignoring `h-card` links ([nightpool](https://github.com/mastodon/mastodon/pull/12189))
- Fix outline on full-screen video in web UI ([hinaloe](https://github.com/mastodon/mastodon/pull/12176))
- Fix TLD domain blocks not being editable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12805))
- Fix Nanobox deploy hooks ([danhunsaker](https://github.com/mastodon/mastodon/pull/12663))
- Fix needlessly complicated SQL query when performing account search amongst followings ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12302))
- Fix favourites count not updating when unfavouriting in web UI ([NimaBoscarino](https://github.com/mastodon/mastodon/pull/12140))
- Fix occasional crash on scroll in Chromium in web UI ([hinaloe](https://github.com/mastodon/mastodon/pull/12274))
- Fix intersection observer not working in single-column mode web UI ([panarom](https://github.com/mastodon/mastodon/pull/12735))
- Fix voting issue with remote polls that contain trailing spaces ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12515))
- Fix dynamic elements not working in pgHero due to CSP rules ([ykzts](https://github.com/mastodon/mastodon/pull/12489))
- Fix overly verbose backtraces when delivering ActivityPub payloads ([zunda](https://github.com/mastodon/mastodon/pull/12798))
- Fix rendering `<a>` without `href` when scheme unsupported ([Gargron](https://github.com/mastodon/mastodon/pull/13040))
- Fix unfiltered params error when generating ActivityPub tag pagination ([Gargron](https://github.com/mastodon/mastodon/pull/13049))
- Fix malformed HTML causing uncaught error ([Gargron](https://github.com/mastodon/mastodon/pull/13042))
- Fix native share button not being displayed for unlisted toots ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/13045))
- Fix remote convertible media attachments (e.g. GIFs) not being saved ([Gargron](https://github.com/mastodon/mastodon/pull/13032))
- Fix account query not using faster index ([abcang](https://github.com/mastodon/mastodon/pull/13016))
- Fix error when sending moderation notification ([renatolond](https://github.com/mastodon/mastodon/pull/13014))
### Security
- Fix OEmbed leaking information about existence of non-public statuses ([Gargron](https://github.com/mastodon/mastodon/pull/12930))
- Fix password change/reset not immediately invalidating other sessions ([Gargron](https://github.com/mastodon/mastodon/pull/12928))
- Fix settings pages being cacheable by the browser ([Gargron](https://github.com/mastodon/mastodon/pull/12714))
## [3.0.1] - 2019-10-10
### Added
- Add `tootctl media usage` command ([Gargron](https://github.com/mastodon/mastodon/pull/12115))
- Add admin setting to auto-approve trending hashtags ([Gargron](https://github.com/mastodon/mastodon/pull/12122), [Gargron](https://github.com/mastodon/mastodon/pull/12130))
### Changed
- Change `tootctl media refresh` to skip already downloaded attachments ([Gargron](https://github.com/mastodon/mastodon/pull/12118))
### Removed
- Remove auto-silence behaviour from spam check ([Gargron](https://github.com/mastodon/mastodon/pull/12117))
- Remove HTML `lang` attribute from individual statuses in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/12124))
- Remove fallback to long description on sidebar and meta description ([Gargron](https://github.com/mastodon/mastodon/pull/12119))
### Fixed
- Fix preloaded JSON-LD context for identity not being used ([Gargron](https://github.com/mastodon/mastodon/pull/12138))
- Fix media editing modal changing dimensions once the image loads ([Gargron](https://github.com/mastodon/mastodon/pull/12131))
- Fix not showing whether a custom emoji has a local counterpart in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/12135))
- Fix attachment not being re-downloaded even if file is not stored ([Gargron](https://github.com/mastodon/mastodon/pull/12125))
- Fix old migration trying to use new column due to default status scope ([Gargron](https://github.com/mastodon/mastodon/pull/12095))
- Fix column back button missing for not found accounts ([trwnh](https://github.com/mastodon/mastodon/pull/12094))
- Fix issues with tootctl's parallelization and progress reporting ([Gargron](https://github.com/mastodon/mastodon/pull/12093), [Gargron](https://github.com/mastodon/mastodon/pull/12097))
- Fix existing user records with now-renamed `pt` locale ([Gargron](https://github.com/mastodon/mastodon/pull/12092))
- Fix hashtag timeline REST API accepting too many hashtags ([Gargron](https://github.com/mastodon/mastodon/pull/12091))
- Fix `GET /api/v1/instance` REST APIs being unavailable in secure mode ([Gargron](https://github.com/mastodon/mastodon/pull/12089))
- Fix performance of home feed regeneration and merging ([Gargron](https://github.com/mastodon/mastodon/pull/12084))
- Fix ffmpeg performance issues due to stdout buffer overflow ([hugogameiro](https://github.com/mastodon/mastodon/pull/12088))
- Fix S3 adapter retrying failing uploads with exponential backoff ([Gargron](https://github.com/mastodon/mastodon/pull/12085))
- Fix `tootctl accounts cull` advertising unused option flag ([Kjwon15](https://github.com/mastodon/mastodon/pull/12074))
## [3.0.0] - 2019-10-03
### Added
- Add "not available" label to unloaded media attachments in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/11715), [Gargron](https://github.com/mastodon/mastodon/pull/11745))
- **Add profile directory to web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/11688), [mayaeh](https://github.com/mastodon/mastodon/pull/11872))
- Add profile directory opt-in federation
- Add profile directory REST API
- Add special alert for throttled requests in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11677))
- Add confirmation modal when logging out from the web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11671))
- **Add audio player in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/11644), [Gargron](https://github.com/mastodon/mastodon/pull/11652), [Gargron](https://github.com/mastodon/mastodon/pull/11654), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11629), [Gargron](https://github.com/mastodon/mastodon/pull/12056))
- **Add autosuggestions for hashtags in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/11422), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11632), [Gargron](https://github.com/mastodon/mastodon/pull/11764), [Gargron](https://github.com/mastodon/mastodon/pull/11588), [Gargron](https://github.com/mastodon/mastodon/pull/11442))
- **Add media editing modal with OCR tool in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/11563), [Gargron](https://github.com/mastodon/mastodon/pull/11566), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11575), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11576), [Gargron](https://github.com/mastodon/mastodon/pull/11577), [Gargron](https://github.com/mastodon/mastodon/pull/11573), [Gargron](https://github.com/mastodon/mastodon/pull/11571))
- Add indicator of unread notifications to window title when web UI is out of focus ([Gargron](https://github.com/mastodon/mastodon/pull/11560), [Gargron](https://github.com/mastodon/mastodon/pull/11572))
- Add indicator for which options you voted for in a poll in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11195))
- **Add search results pagination to web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/11409), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11447))
- **Add option to disable real-time updates in web UI ("slow mode")** ([Gargron](https://github.com/mastodon/mastodon/pull/9984), [ykzts](https://github.com/mastodon/mastodon/pull/11880), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11883), [Gargron](https://github.com/mastodon/mastodon/pull/11898), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11859))
- Add option to disable blurhash previews in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11188))
- Add native smooth scrolling when supported in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11207))
- Add scrolling to the search bar on focus in web UI ([Kjwon15](https://github.com/mastodon/mastodon/pull/12032))
- Add refresh button to list of rebloggers/favouriters in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/12031))
- Add error description and button to copy stack trace to web UI ([Gargron](https://github.com/mastodon/mastodon/pull/12033))
- Add search and sort functions to hashtag admin UI ([mayaeh](https://github.com/mastodon/mastodon/pull/11829), [Gargron](https://github.com/mastodon/mastodon/pull/11897), [mayaeh](https://github.com/mastodon/mastodon/pull/11875))
- Add setting for default search engine indexing in admin UI ([brortao](https://github.com/mastodon/mastodon/pull/11804))
- Add account bio to account view in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11473))
- **Add option to include reported statuses in warning e-mail from admin UI** ([Gargron](https://github.com/mastodon/mastodon/pull/11639), [Gargron](https://github.com/mastodon/mastodon/pull/11812), [Gargron](https://github.com/mastodon/mastodon/pull/11741), [Gargron](https://github.com/mastodon/mastodon/pull/11698), [mayaeh](https://github.com/mastodon/mastodon/pull/11765))
- Add number of pending accounts and pending hashtags to dashboard in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/11514))
- **Add account migration UI** ([Gargron](https://github.com/mastodon/mastodon/pull/11846), [noellabo](https://github.com/mastodon/mastodon/pull/11905), [noellabo](https://github.com/mastodon/mastodon/pull/11907), [noellabo](https://github.com/mastodon/mastodon/pull/11906), [noellabo](https://github.com/mastodon/mastodon/pull/11902))
- **Add table of contents to about page** ([Gargron](https://github.com/mastodon/mastodon/pull/11885), [ykzts](https://github.com/mastodon/mastodon/pull/11941), [ykzts](https://github.com/mastodon/mastodon/pull/11895), [Kjwon15](https://github.com/mastodon/mastodon/pull/11916))
- **Add password challenge to 2FA settings, e-mail notifications** ([Gargron](https://github.com/mastodon/mastodon/pull/11878))
- **Add optional public list of domain blocks with comments** ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11298), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11515), [Gargron](https://github.com/mastodon/mastodon/pull/11908))
- Add an RSS feed for featured hashtags ([noellabo](https://github.com/mastodon/mastodon/pull/10502))
- Add explanations to featured hashtags UI and profile ([Gargron](https://github.com/mastodon/mastodon/pull/11586))
- **Add hashtag trends with admin and user settings** ([Gargron](https://github.com/mastodon/mastodon/pull/11490), [Gargron](https://github.com/mastodon/mastodon/pull/11502), [Gargron](https://github.com/mastodon/mastodon/pull/11641), [Gargron](https://github.com/mastodon/mastodon/pull/11594), [Gargron](https://github.com/mastodon/mastodon/pull/11517), [mayaeh](https://github.com/mastodon/mastodon/pull/11845), [Gargron](https://github.com/mastodon/mastodon/pull/11774), [Gargron](https://github.com/mastodon/mastodon/pull/11712), [Gargron](https://github.com/mastodon/mastodon/pull/11791), [Gargron](https://github.com/mastodon/mastodon/pull/11743), [Gargron](https://github.com/mastodon/mastodon/pull/11740), [Gargron](https://github.com/mastodon/mastodon/pull/11714), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11631), [Sasha-Sorokin](https://github.com/mastodon/mastodon/pull/11569), [Gargron](https://github.com/mastodon/mastodon/pull/11524), [Gargron](https://github.com/mastodon/mastodon/pull/11513))
- Add hashtag usage breakdown to admin UI
- Add batch actions for hashtags to admin UI
- Add trends to web UI
- Add trends to public pages
- Add user preference to hide trends
- Add admin setting to disable trends
- **Add categories for custom emojis** ([Gargron](https://github.com/mastodon/mastodon/pull/11196), [Gargron](https://github.com/mastodon/mastodon/pull/11793), [Gargron](https://github.com/mastodon/mastodon/pull/11920), [highemerly](https://github.com/mastodon/mastodon/pull/11876))
- Add custom emoji categories to emoji picker in web UI
- Add `category` to custom emojis in REST API
- Add batch actions for custom emojis in admin UI
- Add max image dimensions to error message ([raboof](https://github.com/mastodon/mastodon/pull/11552))
- Add aac, m4a, 3gp, amr, wma to allowed audio formats ([Gargron](https://github.com/mastodon/mastodon/pull/11342), [umonaca](https://github.com/mastodon/mastodon/pull/11687))
- **Add search syntax for operators and phrases** ([Gargron](https://github.com/mastodon/mastodon/pull/11411))
- **Add REST API for managing featured hashtags** ([noellabo](https://github.com/mastodon/mastodon/pull/11778))
- **Add REST API for managing timeline read markers** ([Gargron](https://github.com/mastodon/mastodon/pull/11762))
- Add `exclude_unreviewed` param to `GET /api/v2/search` REST API ([Gargron](https://github.com/mastodon/mastodon/pull/11977))
- Add `reason` param to `POST /api/v1/accounts` REST API ([Gargron](https://github.com/mastodon/mastodon/pull/12064))
- **Add ActivityPub secure mode** ([Gargron](https://github.com/mastodon/mastodon/pull/11269), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11332), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11295))
- Add HTTP signatures to all outgoing ActivityPub GET requests ([Gargron](https://github.com/mastodon/mastodon/pull/11284), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11300))
- Add support for ActivityPub Audio activities ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11189))
- Add ActivityPub actor representing the entire server ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11321), [rtucker](https://github.com/mastodon/mastodon/pull/11400), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11561), [Gargron](https://github.com/mastodon/mastodon/pull/11798))
- **Add whitelist mode** ([Gargron](https://github.com/mastodon/mastodon/pull/11291), [mayaeh](https://github.com/mastodon/mastodon/pull/11634))
- Add config of multipart threshold for S3 ([ykzts](https://github.com/mastodon/mastodon/pull/11924), [ykzts](https://github.com/mastodon/mastodon/pull/11944))
- Add health check endpoint for web ([ykzts](https://github.com/mastodon/mastodon/pull/11770), [ykzts](https://github.com/mastodon/mastodon/pull/11947))
- Add HTTP signature keyId to request log ([Gargron](https://github.com/mastodon/mastodon/pull/11591))
- Add `SMTP_REPLY_TO` environment variable ([hugogameiro](https://github.com/mastodon/mastodon/pull/11718))
- Add `tootctl preview_cards remove` command ([mayaeh](https://github.com/mastodon/mastodon/pull/11320))
- Add `tootctl media refresh` command ([Gargron](https://github.com/mastodon/mastodon/pull/11775))
- Add `tootctl cache recount` command ([Gargron](https://github.com/mastodon/mastodon/pull/11597))
- Add option to exclude suspended domains from `tootctl domains crawl` ([dariusk](https://github.com/mastodon/mastodon/pull/11454))
- Add parallelization to `tootctl search deploy` ([noellabo](https://github.com/mastodon/mastodon/pull/12051))
- Add soft delete for statuses for instant deletes through API ([Gargron](https://github.com/mastodon/mastodon/pull/11623), [Gargron](https://github.com/mastodon/mastodon/pull/11648))
- Add rails-level JSON caching ([Gargron](https://github.com/mastodon/mastodon/pull/11333), [Gargron](https://github.com/mastodon/mastodon/pull/11271))
- **Add request pool to improve delivery performance** ([Gargron](https://github.com/mastodon/mastodon/pull/10353), [ykzts](https://github.com/mastodon/mastodon/pull/11756))
- Add concurrent connection attempts to resolved IP addresses ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11757))
- Add index for remember_token to improve login performance ([abcang](https://github.com/mastodon/mastodon/pull/11881))
- **Add more accurate hashtag search** ([Gargron](https://github.com/mastodon/mastodon/pull/11579), [Gargron](https://github.com/mastodon/mastodon/pull/11427), [Gargron](https://github.com/mastodon/mastodon/pull/11448))
- **Add more accurate account search** ([Gargron](https://github.com/mastodon/mastodon/pull/11537), [Gargron](https://github.com/mastodon/mastodon/pull/11580))
- **Add a spam check** ([Gargron](https://github.com/mastodon/mastodon/pull/11217), [Gargron](https://github.com/mastodon/mastodon/pull/11806), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11296))
- Add new languages ([Gargron](https://github.com/mastodon/mastodon/pull/12062))
- Breton
- Spanish (Argentina)
- Estonian
- Macedonian
- New Norwegian
- Add NodeInfo endpoint ([Gargron](https://github.com/mastodon/mastodon/pull/12002), [Gargron](https://github.com/mastodon/mastodon/pull/12058))
### Changed
- **Change conversations UI** ([Gargron](https://github.com/mastodon/mastodon/pull/11896))
- Change dashboard to short number notation ([noellabo](https://github.com/mastodon/mastodon/pull/11847), [noellabo](https://github.com/mastodon/mastodon/pull/11911))
- Change REST API `GET /api/v1/timelines/public` to require authentication when public preview is off ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11802))
- Change REST API `POST /api/v1/follow_requests/:id/(approve|reject)` to return relationship ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11800))
- Change rate limit for media proxy ([ykzts](https://github.com/mastodon/mastodon/pull/11814))
- Change unlisted custom emoji to not appear in autosuggestions ([Gargron](https://github.com/mastodon/mastodon/pull/11818))
- Change max length of media descriptions from 420 to 1500 characters ([Gargron](https://github.com/mastodon/mastodon/pull/11819), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11836))
- **Change deletes to preserve soft-deleted statuses in unresolved reports** ([Gargron](https://github.com/mastodon/mastodon/pull/11805))
- **Change tootctl to use inline parallelization instead of Sidekiq** ([Gargron](https://github.com/mastodon/mastodon/pull/11776))
- **Change account deletion page to have better explanations** ([Gargron](https://github.com/mastodon/mastodon/pull/11753), [Gargron](https://github.com/mastodon/mastodon/pull/11763))
- Change hashtag component in web UI to show numbers for 2 last days ([Gargron](https://github.com/mastodon/mastodon/pull/11742), [Gargron](https://github.com/mastodon/mastodon/pull/11755), [Gargron](https://github.com/mastodon/mastodon/pull/11754))
- Change OpenGraph description on sign-up page to reflect invite ([Gargron](https://github.com/mastodon/mastodon/pull/11744))
- Change layout of public profile directory to be the same as in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/11705))
- Change detailed status child ordering to sort self-replies on top ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11686))
- Change window resize handler to switch to/from mobile layout as soon as needed ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11656))
- Change icon button styles to make hover/focus states more obvious ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11474))
- Change contrast of status links that are not mentions or hashtags ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11406))
- **Change hashtags to preserve first-used casing** ([Gargron](https://github.com/mastodon/mastodon/pull/11416), [Gargron](https://github.com/mastodon/mastodon/pull/11508), [Gargron](https://github.com/mastodon/mastodon/pull/11504), [Gargron](https://github.com/mastodon/mastodon/pull/11507), [Gargron](https://github.com/mastodon/mastodon/pull/11441))
- **Change unconfirmed user login behaviour** ([Gargron](https://github.com/mastodon/mastodon/pull/11375), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11394), [Gargron](https://github.com/mastodon/mastodon/pull/11860))
- **Change single-column mode to scroll the whole page** ([Gargron](https://github.com/mastodon/mastodon/pull/11359), [Gargron](https://github.com/mastodon/mastodon/pull/11894), [Gargron](https://github.com/mastodon/mastodon/pull/11891), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11655), [Gargron](https://github.com/mastodon/mastodon/pull/11463), [Gargron](https://github.com/mastodon/mastodon/pull/11458), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11395), [Gargron](https://github.com/mastodon/mastodon/pull/11418))
- Change `tootctl accounts follow` to only work with local accounts ([angristan](https://github.com/mastodon/mastodon/pull/11592))
- Change Dockerfile ([Shleeble](https://github.com/mastodon/mastodon/pull/11710), [ykzts](https://github.com/mastodon/mastodon/pull/11768), [Shleeble](https://github.com/mastodon/mastodon/pull/11707))
- Change supported Node versions to include v12 ([abcang](https://github.com/mastodon/mastodon/pull/11706))
- Change Portuguese language from `pt` to `pt-PT` ([Gargron](https://github.com/mastodon/mastodon/pull/11820))
- Change domain block silence to always require approval on follow ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11975))
- Change link preview fetcher to not perform a HEAD request first ([Gargron](https://github.com/mastodon/mastodon/pull/12028))
- Change `tootctl domains purge` to accept multiple domains at once ([Gargron](https://github.com/mastodon/mastodon/pull/12046))
### Removed
- **Remove OStatus support** ([Gargron](https://github.com/mastodon/mastodon/pull/11205), [Gargron](https://github.com/mastodon/mastodon/pull/11303), [Gargron](https://github.com/mastodon/mastodon/pull/11460), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11280), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11278))
- Remove Atom feeds and old URLs in the form of `GET /:username/updates/:id` ([Gargron](https://github.com/mastodon/mastodon/pull/11247))
- Remove WebP support ([angristan](https://github.com/mastodon/mastodon/pull/11589))
- Remove deprecated config options from Heroku and Scalingo ([ykzts](https://github.com/mastodon/mastodon/pull/11925))
- Remove deprecated REST API `GET /api/v1/search` API ([Gargron](https://github.com/mastodon/mastodon/pull/11823))
- Remove deprecated REST API `GET /api/v1/statuses/:id/card` ([Gargron](https://github.com/mastodon/mastodon/pull/11213))
- Remove deprecated REST API `POST /api/v1/notifications/dismiss?id=:id` ([Gargron](https://github.com/mastodon/mastodon/pull/11214))
- Remove deprecated REST API `GET /api/v1/timelines/direct` ([Gargron](https://github.com/mastodon/mastodon/pull/11212))
### Fixed
- Fix manifest warning ([ykzts](https://github.com/mastodon/mastodon/pull/11767))
- Fix admin UI for custom emoji not respecting GIF autoplay preference ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11801))
- Fix page body not being scrollable in admin/settings layout ([Gargron](https://github.com/mastodon/mastodon/pull/11893))
- Fix placeholder colors for inputs not being explicitly defined ([Gargron](https://github.com/mastodon/mastodon/pull/11890))
- Fix incorrect enclosure length in RSS ([tsia](https://github.com/mastodon/mastodon/pull/11889))
- Fix TOTP codes not being filtered from logs during enabling/disabling ([Gargron](https://github.com/mastodon/mastodon/pull/11877))
- Fix webfinger response not returning 410 when account is suspended ([Gargron](https://github.com/mastodon/mastodon/pull/11869))
- Fix ActivityPub Move handler queuing jobs that will fail if account is suspended ([Gargron](https://github.com/mastodon/mastodon/pull/11864))
- Fix SSO login not using existing account when e-mail is verified ([Gargron](https://github.com/mastodon/mastodon/pull/11862))
- Fix web UI allowing uploads past status limit via drag & drop ([Gargron](https://github.com/mastodon/mastodon/pull/11863))
- Fix expiring polls not being displayed as such in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11835))
- Fix 2FA challenge and password challenge for non-database users ([Gargron](https://github.com/mastodon/mastodon/pull/11831), [Gargron](https://github.com/mastodon/mastodon/pull/11943))
- Fix profile fields overflowing page width in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/11828))
- Fix web push subscriptions being deleted on rate limit or timeout ([Gargron](https://github.com/mastodon/mastodon/pull/11826))
- Fix display of long poll options in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11717), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11833))
- Fix search API not resolving URL when `type` is given ([Gargron](https://github.com/mastodon/mastodon/pull/11822))
- Fix hashtags being split by ZWNJ character ([Gargron](https://github.com/mastodon/mastodon/pull/11821))
- Fix scroll position resetting when opening media modals in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/11815))
- Fix duplicate HTML IDs on about page ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11803))
- Fix admin UI showing superfluous reject media/reports on suspended domain blocks ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11749))
- Fix ActivityPub context not being dynamically computed ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11746))
- Fix Mastodon logo style on hover on public pages' footer ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11735))
- Fix height of dashboard counters ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11736))
- Fix custom emoji animation on hover in web UI directory bios ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11716))
- Fix non-numbers being passed to Redis and causing an error ([Gargron](https://github.com/mastodon/mastodon/pull/11697))
- Fix error in REST API for an account's statuses ([Gargron](https://github.com/mastodon/mastodon/pull/11700))
- Fix uncaught error when resource param is missing in Webfinger request ([Gargron](https://github.com/mastodon/mastodon/pull/11701))
- Fix uncaught domain normalization error in remote follow ([Gargron](https://github.com/mastodon/mastodon/pull/11703))
- Fix uncaught 422 and 500 errors ([Gargron](https://github.com/mastodon/mastodon/pull/11590), [Gargron](https://github.com/mastodon/mastodon/pull/11811))
- Fix uncaught parameter missing exceptions and missing error templates ([Gargron](https://github.com/mastodon/mastodon/pull/11702))
- Fix encoding error when checking e-mail MX records ([Gargron](https://github.com/mastodon/mastodon/pull/11696))
- Fix items in StatusContent render list not all having a key ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11645))
- Fix remote and staff-removed statuses leaving media behind for a day ([Gargron](https://github.com/mastodon/mastodon/pull/11638))
- Fix CSP needlessly allowing blob URLs in script-src ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11620))
- Fix ignoring whole status because of one invalid hashtag ([Gargron](https://github.com/mastodon/mastodon/pull/11621))
- Fix hidden statuses losing focus ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11208))
- Fix loading bar being obscured by other elements in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/11598))
- Fix multiple issues with replies collection for pages further than self-replies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11582))
- Fix blurhash and autoplay not working on public pages ([Gargron](https://github.com/mastodon/mastodon/pull/11585))
- Fix 422 being returned instead of 404 when POSTing to unmatched routes ([Gargron](https://github.com/mastodon/mastodon/pull/11574), [Gargron](https://github.com/mastodon/mastodon/pull/11704))
- Fix client-side resizing of image uploads ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11570))
- Fix short number formatting for numbers above million in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/11559))
- Fix ActivityPub and REST API queries setting cookies and preventing caching ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11539), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11557), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11336), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11331))
- Fix some emojis in profile metadata labels are not emojified. ([kedamaDQ](https://github.com/mastodon/mastodon/pull/11534))
- Fix account search always returning exact match on paginated results ([Gargron](https://github.com/mastodon/mastodon/pull/11525))
- Fix acct URIs with IDN domains not being resolved ([Gargron](https://github.com/mastodon/mastodon/pull/11520))
- Fix admin dashboard missing latest features ([Gargron](https://github.com/mastodon/mastodon/pull/11505))
- Fix jumping of toot date when clicking spoiler button ([ariasuni](https://github.com/mastodon/mastodon/pull/11449))
- Fix boost to original audience not working on mobile in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11371))
- Fix handling of webfinger redirects in ResolveAccountService ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11279))
- Fix URLs appearing twice in errors of ActivityPub::DeliveryWorker ([Gargron](https://github.com/mastodon/mastodon/pull/11231))
- Fix support for HTTP proxies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11245))
- Fix HTTP requests to IPv6 hosts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11240))
- Fix error in Elasticsearch index import ([mayaeh](https://github.com/mastodon/mastodon/pull/11192))
- Fix duplicate account error when seeding development database ([ysksn](https://github.com/mastodon/mastodon/pull/11366))
- Fix performance of session clean-up scheduler ([abcang](https://github.com/mastodon/mastodon/pull/11871))
- Fix older migrations not running ([zunda](https://github.com/mastodon/mastodon/pull/11377))
- Fix URLs counting towards RTL detection ([ahangarha](https://github.com/mastodon/mastodon/pull/11759))
- Fix unnecessary status re-rendering in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11211))
- Fix http_parser.rb gem not being compiled when no network available ([petabyteboy](https://github.com/mastodon/mastodon/pull/11444))
- Fix muted text color not applying to all text ([trwnh](https://github.com/mastodon/mastodon/pull/11996))
- Fix follower/following lists resetting on back-navigation in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/11986))
- Fix n+1 query when approving multiple follow requests ([abcang](https://github.com/mastodon/mastodon/pull/12004))
- Fix records not being indexed into Elasticsearch sometimes ([Gargron](https://github.com/mastodon/mastodon/pull/12024))
- Fix needlessly indexing unsearchable statuses into Elasticsearch ([Gargron](https://github.com/mastodon/mastodon/pull/12041))
- Fix new user bootstrapping crashing when to-be-followed accounts are invalid ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/12037))
- Fix featured hashtag URL being interpreted as media or replies tab ([Gargron](https://github.com/mastodon/mastodon/pull/12048))
- Fix account counters being overwritten by parallel writes ([Gargron](https://github.com/mastodon/mastodon/pull/12045))
### Security
- Fix performance of GIF re-encoding and always strip EXIF data from videos ([Gargron](https://github.com/mastodon/mastodon/pull/12057))
## [2.9.3] - 2019-08-10
### Added
- Add GIF and WebP support for custom emojis ([Gargron](https://github.com/mastodon/mastodon/pull/11519))
- Add logout link to dropdown menu in web UI ([koyuawsmbrtn](https://github.com/mastodon/mastodon/pull/11353))
- Add indication that text search is unavailable in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11112), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11202))
- Add `suffix` to `Mastodon::Version` to help forks ([clarfon](https://github.com/mastodon/mastodon/pull/11407))
- Add on-hover animation to animated custom emoji in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11348), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11404), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11522))
- Add custom emoji support in profile metadata labels ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11350))
### Changed
- Change default interface of web and streaming from 0.0.0.0 to 127.0.0.1 ([Gargron](https://github.com/mastodon/mastodon/pull/11302), [zunda](https://github.com/mastodon/mastodon/pull/11378), [Gargron](https://github.com/mastodon/mastodon/pull/11351), [zunda](https://github.com/mastodon/mastodon/pull/11326))
- Change the retry limit of web push notifications ([highemerly](https://github.com/mastodon/mastodon/pull/11292))
- Change ActivityPub deliveries to not retry HTTP 501 errors ([Gargron](https://github.com/mastodon/mastodon/pull/11233))
- Change language detection to include hashtags as words ([Gargron](https://github.com/mastodon/mastodon/pull/11341))
- Change terms and privacy policy pages to always be accessible ([Gargron](https://github.com/mastodon/mastodon/pull/11334))
- Change robots tag to include `noarchive` when user opts out of indexing ([Kjwon15](https://github.com/mastodon/mastodon/pull/11421))
### Fixed
- Fix account domain block not clearing out notifications ([Gargron](https://github.com/mastodon/mastodon/pull/11393))
- Fix incorrect locale sometimes being detected for browser ([Gargron](https://github.com/mastodon/mastodon/pull/8657))
- Fix crash when saving invalid domain name ([Gargron](https://github.com/mastodon/mastodon/pull/11528))
- Fix pinned statuses REST API returning pagination headers ([Gargron](https://github.com/mastodon/mastodon/pull/11526))
- Fix "cancel follow request" button having unreadable text in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/11521))
- Fix image uploads being blank when canvas read access is blocked ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11499))
- Fix avatars not being animated on hover when not logged in ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11349))
- Fix overzealous sanitization of HTML lists ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11354))
- Fix block crashing when a follow request exists ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11288))
- Fix backup service crashing when an attachment is missing ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11241))
- Fix account moderation action always sending e-mail notification ([Gargron](https://github.com/mastodon/mastodon/pull/11242))
- Fix swiping columns on mobile sometimes failing in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11200))
- Fix wrong actor URI being serialized into poll updates ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11194))
- Fix statsd UDP sockets not being cleaned up in Sidekiq ([Gargron](https://github.com/mastodon/mastodon/pull/11230))
- Fix expiration date of filters being set to "never" when editing them ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11204))
- Fix support for MP4 files that are actually M4V files ([Gargron](https://github.com/mastodon/mastodon/pull/11210))
- Fix `alerts` not being typecast correctly in push subscription in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/11343))
- Fix some notices staying on unrelated pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11364))
- Fix unboosting sometimes preventing a boost from reappearing on feed ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11405), [Gargron](https://github.com/mastodon/mastodon/pull/11450))
- Fix only one middle dot being recognized in hashtags ([Gargron](https://github.com/mastodon/mastodon/pull/11345), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11363))
- Fix unnecessary SQL query performed on unauthenticated requests ([Gargron](https://github.com/mastodon/mastodon/pull/11179))
- Fix incorrect timestamp displayed on featured tags ([Kjwon15](https://github.com/mastodon/mastodon/pull/11477))
- Fix privacy dropdown active state when dropdown is placed on top of it ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11495))
- Fix filters not being applied to poll options ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11174))
- Fix keyboard navigation on various dropdowns ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11511), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11492), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11491))
- Fix keyboard navigation in modals ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11493))
- Fix image conversation being non-deterministic due to timestamps ([Gargron](https://github.com/mastodon/mastodon/pull/11408))
- Fix web UI performance ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11211), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11234))
- Fix scrolling to compose form when not necessary in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11246), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/11182))
- Fix save button being enabled when list title is empty in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11475))
- Fix poll expiration not being pre-filled on delete & redraft in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11203))
- Fix content warning sometimes being set when not requested in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11206))
### Security
- Fix invites not being disabled upon account suspension ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11412))
- Fix blocked domains still being able to fill database with account records ([Gargron](https://github.com/mastodon/mastodon/pull/11219))
## [2.9.2] - 2019-06-22
### Added
- Add `short_description` and `approval_required` to `GET /api/v1/instance` ([Gargron](https://github.com/mastodon/mastodon/pull/11146))
### Changed
- Change camera icon to paperclip icon in upload form ([koyuawsmbrtn](https://github.com/mastodon/mastodon/pull/11149))
### Fixed
- Fix audio-only OGG and WebM files not being processed as such ([Gargron](https://github.com/mastodon/mastodon/pull/11151))
- Fix audio not being downloaded from remote servers ([Gargron](https://github.com/mastodon/mastodon/pull/11145))
## [2.9.1] - 2019-06-22
### Added
- Add moderation API ([Gargron](https://github.com/mastodon/mastodon/pull/9387))
- Add audio uploads ([Gargron](https://github.com/mastodon/mastodon/pull/11123), [Gargron](https://github.com/mastodon/mastodon/pull/11141))
### Changed
- Change domain blocks to automatically support subdomains ([Gargron](https://github.com/mastodon/mastodon/pull/11138))
- Change Nanobox configuration to bring it up to date ([danhunsaker](https://github.com/mastodon/mastodon/pull/11083))
### Removed
- Remove expensive counters from federation page in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/11139))
### Fixed
- Fix converted media being saved with original extension and mime type ([Gargron](https://github.com/mastodon/mastodon/pull/11130))
- Fix layout of identity proofs settings ([acid-chicken](https://github.com/mastodon/mastodon/pull/11126))
- Fix active scope only returning suspended users ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11111))
- Fix sanitizer making block level elements unreadable ([Gargron](https://github.com/mastodon/mastodon/pull/10836))
- Fix label for site theme not being translated in admin UI ([palindromordnilap](https://github.com/mastodon/mastodon/pull/11121))
- Fix statuses not being filtered irreversibly in web UI under some circumstances ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11113))
- Fix scrolling behaviour in compose form ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11093))
## [2.9.0] - 2019-06-13
### Added
- **Add single-column mode in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/10807), [Gargron](https://github.com/mastodon/mastodon/pull/10848), [Gargron](https://github.com/mastodon/mastodon/pull/11003), [Gargron](https://github.com/mastodon/mastodon/pull/10961), [Hanage999](https://github.com/mastodon/mastodon/pull/10915), [noellabo](https://github.com/mastodon/mastodon/pull/10917), [abcang](https://github.com/mastodon/mastodon/pull/10859), [Gargron](https://github.com/mastodon/mastodon/pull/10820), [Gargron](https://github.com/mastodon/mastodon/pull/10835), [Gargron](https://github.com/mastodon/mastodon/pull/10809), [Gargron](https://github.com/mastodon/mastodon/pull/10963), [noellabo](https://github.com/mastodon/mastodon/pull/10883), [Hanage999](https://github.com/mastodon/mastodon/pull/10839))
- Add waiting time to the list of pending accounts in admin UI ([Gargron](https://github.com/mastodon/mastodon/pull/10985))
- Add a keyboard shortcut to hide/show media in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10647), [Gargron](https://github.com/mastodon/mastodon/pull/10838), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10872))
- Add `account_id` param to `GET /api/v1/notifications` ([pwoolcoc](https://github.com/mastodon/mastodon/pull/10796))
- Add confirmation modal for unboosting toots in web UI ([aurelien-reeves](https://github.com/mastodon/mastodon/pull/10287))
- Add emoji suggestions to content warning and poll option fields in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10555))
- Add `source` attribute to response of `DELETE /api/v1/statuses/:id` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10669))
- Add some caching for HTML versions of public status pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10701))
- Add button to conveniently copy OAuth code ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/11065))
### Changed
- **Change default layout to single column in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/10847))
- **Change light theme** ([Gargron](https://github.com/mastodon/mastodon/pull/10992), [Gargron](https://github.com/mastodon/mastodon/pull/10996), [yuzulabo](https://github.com/mastodon/mastodon/pull/10754), [Gargron](https://github.com/mastodon/mastodon/pull/10845))
- **Change preferences page into appearance, notifications, and other** ([Gargron](https://github.com/mastodon/mastodon/pull/10977), [Gargron](https://github.com/mastodon/mastodon/pull/10988))
- Change priority of delete activity forwards for replies and reblogs ([Gargron](https://github.com/mastodon/mastodon/pull/11002))
- Change Mastodon logo to use primary text color of the given theme ([Gargron](https://github.com/mastodon/mastodon/pull/10994))
- Change reblogs counter to be updated when boosted privately ([Gargron](https://github.com/mastodon/mastodon/pull/10964))
- Change bio limit from 160 to 500 characters ([trwnh](https://github.com/mastodon/mastodon/pull/10790))
- Change API rate limiting to reduce allowed unauthenticated requests ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10860), [hinaloe](https://github.com/mastodon/mastodon/pull/10868), [mayaeh](https://github.com/mastodon/mastodon/pull/10867))
- Change help text of `tootctl emoji import` command to specify a gzipped TAR archive is required ([dariusk](https://github.com/mastodon/mastodon/pull/11000))
- Change web UI to hide poll options behind content warnings ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10983))
- Change silencing to ensure local effects and remote effects are the same for silenced local users ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10575))
- Change `tootctl domains purge` to remove custom emoji as well ([Kjwon15](https://github.com/mastodon/mastodon/pull/10721))
- Change Docker image to keep `apt` working ([SuperSandro2000](https://github.com/mastodon/mastodon/pull/10830))
### Removed
- Remove `dist-upgrade` from Docker image ([SuperSandro2000](https://github.com/mastodon/mastodon/pull/10822))
### Fixed
- Fix RTL layout not being RTL within the columns area in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/10990))
- Fix display of alternative text when a media attachment is not available in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10981))
- Fix not being able to directly switch between list timelines in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/10973))
- Fix media sensitivity not being maintained in delete & redraft in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10980))
- Fix emoji picker being always displayed in web UI ([noellabo](https://github.com/mastodon/mastodon/pull/10979), [yuzulabo](https://github.com/mastodon/mastodon/pull/10801), [wcpaez](https://github.com/mastodon/mastodon/pull/10978))
- Fix potential private status leak through caching ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10969))
- Fix refreshing featured toots when the new collection is empty in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10971))
- Fix undoing domain block also undoing individual moderation on users from before the domain block ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10660))
- Fix time not being local in the audit log ([yuzulabo](https://github.com/mastodon/mastodon/pull/10751))
- Fix statuses removed by moderation re-appearing on subsequent fetches ([Kjwon15](https://github.com/mastodon/mastodon/pull/10732))
- Fix misattribution of inlined announces if `attributedTo` isn't present in ActivityPub ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10967))
- Fix `GET /api/v1/polls/:id` not requiring authentication for non-public polls ([Gargron](https://github.com/mastodon/mastodon/pull/10960))
- Fix handling of blank poll options in ActivityPub ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10946))
- Fix avatar preview aspect ratio on edit profile page ([Kjwon15](https://github.com/mastodon/mastodon/pull/10931))
- Fix web push notifications not being sent for polls ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10864))
- Fix cut off letters in last paragraph of statuses in web UI ([ariasuni](https://github.com/mastodon/mastodon/pull/10821))
- Fix list not being automatically unpinned when it returns 404 in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/11045))
- Fix login sometimes redirecting to paths that are not pages ([Gargron](https://github.com/mastodon/mastodon/pull/11019))
## [2.8.4] - 2019-05-24
### Fixed
- Fix delivery not retrying on some inbox errors that should be retriable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10812))
- Fix unnecessary 5 minute cooldowns on signature verifications in some cases ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10813))
- Fix possible race condition when processing statuses ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10815))
### Security
- Require specific OAuth scopes for specific endpoints of the streaming API, instead of merely requiring a token for all endpoints, and allow using WebSockets protocol negotiation to specify the access token instead of using a query string ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10818))
## [2.8.3] - 2019-05-19
### Added
- Add `og:image:alt` OpenGraph tag ([BenLubar](https://github.com/mastodon/mastodon/pull/10779))
- Add clickable area below avatar in statuses in web UI ([Dar13](https://github.com/mastodon/mastodon/pull/10766))
- Add crossed-out eye icon on account gallery in web UI ([Kjwon15](https://github.com/mastodon/mastodon/pull/10715))
- Add media description tooltip to thumbnails in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10713))
### Changed
- Change "mark as sensitive" button into a checkbox for clarity ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10748))
### Fixed
- Fix bug allowing users to publicly boost their private statuses ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10775), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10783))
- Fix performance in formatter by a little ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10765))
- Fix some colors in the light theme ([yuzulabo](https://github.com/mastodon/mastodon/pull/10754))
- Fix some colors of the high contrast theme ([yuzulabo](https://github.com/mastodon/mastodon/pull/10711))
- Fix ambivalent active state of poll refresh button in web UI ([MaciekBaron](https://github.com/mastodon/mastodon/pull/10720))
- Fix duplicate posting being possible from web UI ([hinaloe](https://github.com/mastodon/mastodon/pull/10785))
- Fix "invited by" not showing up in admin UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10791))
## [2.8.2] - 2019-05-05
### Added
- Add `SOURCE_TAG` environment variable ([ushitora-anqou](https://github.com/mastodon/mastodon/pull/10698))
### Fixed
- Fix cropped hero image on frontpage ([BaptisteGelez](https://github.com/mastodon/mastodon/pull/10702))
- Fix blurhash gem not compiling on some operating systems ([Gargron](https://github.com/mastodon/mastodon/pull/10700))
- Fix unexpected CSS animations in some browsers ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10699))
- Fix closing video modal scrolling timelines to top ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10695))
## [2.8.1] - 2019-05-04
### Added
- Add link to existing domain block when trying to block an already-blocked domain ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10663))
- Add button to view context to media modal when opened from account gallery in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/10676))
- Add ability to create multiple-choice polls in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10603))
- Add `GITHUB_REPOSITORY` and `SOURCE_BASE_URL` environment variables ([rosylilly](https://github.com/mastodon/mastodon/pull/10600))
- Add `/interact/` paths to `robots.txt` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10666))
- Add `blurhash` to the Attachment entity in the REST API ([Gargron](https://github.com/mastodon/mastodon/pull/10630))
### Changed
- Change hidden media to be shown as a blurhash-based colorful gradient instead of a black box in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/10630))
- Change rejected media to be shown as a blurhash-based gradient instead of a list of filenames in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/10630))
- Change e-mail whitelist/blacklist to not be checked when invited ([Gargron](https://github.com/mastodon/mastodon/pull/10683))
- Change cache header of REST API results to no-cache ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10655))
- Change the "mark media as sensitive" button to be more obvious in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/10673), [Gargron](https://github.com/mastodon/mastodon/pull/10682))
- Change account gallery in web UI to display 3 columns, open media modal ([Gargron](https://github.com/mastodon/mastodon/pull/10667), [Gargron](https://github.com/mastodon/mastodon/pull/10674))
### Fixed
- Fix LDAP/PAM/SAML/CAS users not being pre-approved ([Gargron](https://github.com/mastodon/mastodon/pull/10621))
- Fix accounts created through tootctl not being always pre-approved ([Gargron](https://github.com/mastodon/mastodon/pull/10684))
- Fix Sidekiq retrying ActivityPub processing jobs that fail validation ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10614))
- Fix toots not being scrolled into view sometimes through keyboard selection ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10593))
- Fix expired invite links being usable to bypass approval mode ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10657))
- Fix not being able to save e-mail preference for new pending accounts ([Gargron](https://github.com/mastodon/mastodon/pull/10622))
- Fix upload progressbar when image resizing is involved ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10632))
- Fix block action not automatically cancelling pending follow request ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10633))
- Fix stoplight logging to stderr separate from Rails logger ([Gargron](https://github.com/mastodon/mastodon/pull/10624))
- Fix sign up button not saying sign up when invite is used ([Gargron](https://github.com/mastodon/mastodon/pull/10623))
- Fix health checks in Docker Compose configuration ([fabianonline](https://github.com/mastodon/mastodon/pull/10553))
- Fix modal items not being scrollable on touch devices ([kedamaDQ](https://github.com/mastodon/mastodon/pull/10605))
- Fix Keybase configuration using wrong domain when a web domain is used ([BenLubar](https://github.com/mastodon/mastodon/pull/10565))
- Fix avatar GIFs not being animated on-hover on public profiles ([hyenagirl64](https://github.com/mastodon/mastodon/pull/10549))
- Fix OpenGraph parser not understanding some valid property meta tags ([da2x](https://github.com/mastodon/mastodon/pull/10604))
- Fix wrong fonts being displayed when Roboto is installed on user's machine ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10594))
- Fix confirmation modals being too narrow for a secondary action button ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10586))
## [2.8.0] - 2019-04-10
### Added
- Add polls ([Gargron](https://github.com/mastodon/mastodon/pull/10111), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10155), [Gargron](https://github.com/mastodon/mastodon/pull/10184), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10196), [Gargron](https://github.com/mastodon/mastodon/pull/10248), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10255), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10322), [Gargron](https://github.com/mastodon/mastodon/pull/10138), [Gargron](https://github.com/mastodon/mastodon/pull/10139), [Gargron](https://github.com/mastodon/mastodon/pull/10144), [Gargron](https://github.com/mastodon/mastodon/pull/10145),[Gargron](https://github.com/mastodon/mastodon/pull/10146), [Gargron](https://github.com/mastodon/mastodon/pull/10148), [Gargron](https://github.com/mastodon/mastodon/pull/10151), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10150), [Gargron](https://github.com/mastodon/mastodon/pull/10168), [Gargron](https://github.com/mastodon/mastodon/pull/10165), [Gargron](https://github.com/mastodon/mastodon/pull/10172), [Gargron](https://github.com/mastodon/mastodon/pull/10170), [Gargron](https://github.com/mastodon/mastodon/pull/10171), [Gargron](https://github.com/mastodon/mastodon/pull/10186), [Gargron](https://github.com/mastodon/mastodon/pull/10189), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10200), [rinsuki](https://github.com/mastodon/mastodon/pull/10203), [Gargron](https://github.com/mastodon/mastodon/pull/10213), [Gargron](https://github.com/mastodon/mastodon/pull/10246), [Gargron](https://github.com/mastodon/mastodon/pull/10265), [Gargron](https://github.com/mastodon/mastodon/pull/10261), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10333), [Gargron](https://github.com/mastodon/mastodon/pull/10352), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10140), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10142), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10141), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10162), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10161), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10158), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10156), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10160), [Gargron](https://github.com/mastodon/mastodon/pull/10185), [Gargron](https://github.com/mastodon/mastodon/pull/10188), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10195), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10208), [Gargron](https://github.com/mastodon/mastodon/pull/10187), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10214), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10209))
- Add follows & followers managing UI ([Gargron](https://github.com/mastodon/mastodon/pull/10268), [Gargron](https://github.com/mastodon/mastodon/pull/10308), [Gargron](https://github.com/mastodon/mastodon/pull/10404), [Gargron](https://github.com/mastodon/mastodon/pull/10293))
- Add identity proof integration with Keybase ([Gargron](https://github.com/mastodon/mastodon/pull/10297), [xgess](https://github.com/mastodon/mastodon/pull/10375), [Gargron](https://github.com/mastodon/mastodon/pull/10338), [Gargron](https://github.com/mastodon/mastodon/pull/10350), [Gargron](https://github.com/mastodon/mastodon/pull/10414))
- Add option to overwrite imported data instead of merging ([Gargron](https://github.com/mastodon/mastodon/pull/9962))
- Add featured hashtags to profiles ([Gargron](https://github.com/mastodon/mastodon/pull/9755), [Gargron](https://github.com/mastodon/mastodon/pull/10167), [Gargron](https://github.com/mastodon/mastodon/pull/10249), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10034))
- Add admission-based registrations mode ([Gargron](https://github.com/mastodon/mastodon/pull/10250), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10269), [Gargron](https://github.com/mastodon/mastodon/pull/10264), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10321), [Gargron](https://github.com/mastodon/mastodon/pull/10349), [Gargron](https://github.com/mastodon/mastodon/pull/10469))
- Add support for WebP uploads ([acid-chicken](https://github.com/mastodon/mastodon/pull/9879))
- Add "copy link" item to status action bars in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/9983))
- Add list title editing in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9748))
- Add a "Block & Report" button to the block confirmation dialog in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10360))
- Add disappointed elephant when the page crashes in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/10275))
- Add ability to upload multiple files at once in web UI ([tmm576](https://github.com/mastodon/mastodon/pull/9856))
- Add indication when you are not allowed to follow an account in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/10420), [Gargron](https://github.com/mastodon/mastodon/pull/10491))
- Add validations to admin settings to catch common mistakes ([Gargron](https://github.com/mastodon/mastodon/pull/10348), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10354))
- Add `type`, `limit`, `offset`, `min_id`, `max_id`, `account_id` to search API ([Gargron](https://github.com/mastodon/mastodon/pull/10091))
- Add a preferences API so apps can share basic behaviours ([Gargron](https://github.com/mastodon/mastodon/pull/10109))
- Add `visibility` param to reblog REST API ([Gargron](https://github.com/mastodon/mastodon/pull/9851), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10302))
- Add `allowfullscreen` attribute to OEmbed iframe ([rinsuki](https://github.com/mastodon/mastodon/pull/10370))
- Add `blocked_by` relationship to the REST API ([Gargron](https://github.com/mastodon/mastodon/pull/10373))
- Add `tootctl statuses remove` to sweep unreferenced statuses ([Gargron](https://github.com/mastodon/mastodon/pull/10063))
- Add `tootctl search deploy` to avoid ugly rake task syntax ([Gargron](https://github.com/mastodon/mastodon/pull/10403))
- Add `tootctl self-destruct` to shut down server gracefully ([Gargron](https://github.com/mastodon/mastodon/pull/10367))
- Add option to hide application used to toot ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9897), [rinsuki](https://github.com/mastodon/mastodon/pull/9994), [hinaloe](https://github.com/mastodon/mastodon/pull/10086))
- Add `DB_SSLMODE` configuration variable ([sascha-sl](https://github.com/mastodon/mastodon/pull/10210))
- Add click-to-copy UI to invites page ([Gargron](https://github.com/mastodon/mastodon/pull/10259))
- Add self-replies fetching ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10106), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10128), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10175), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10201))
- Add rate limit for media proxy requests ([Gargron](https://github.com/mastodon/mastodon/pull/10490))
- Add `tootctl emoji purge` ([Gargron](https://github.com/mastodon/mastodon/pull/10481))
- Add `tootctl accounts approve` ([Gargron](https://github.com/mastodon/mastodon/pull/10480))
- Add `tootctl accounts reset-relationships` ([noellabo](https://github.com/mastodon/mastodon/pull/10483))
### Changed
- Change design of landing page ([Gargron](https://github.com/mastodon/mastodon/pull/10232), [Gargron](https://github.com/mastodon/mastodon/pull/10260), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10284), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10291), [koyuawsmbrtn](https://github.com/mastodon/mastodon/pull/10356), [Gargron](https://github.com/mastodon/mastodon/pull/10245))
- Change design of profile column in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/10337), [Aditoo17](https://github.com/mastodon/mastodon/pull/10387), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10390), [mayaeh](https://github.com/mastodon/mastodon/pull/10379), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10411))
- Change language detector threshold from 140 characters to 4 words ([Gargron](https://github.com/mastodon/mastodon/pull/10376))
- Change language detector to always kick in for non-latin alphabets ([Gargron](https://github.com/mastodon/mastodon/pull/10276))
- Change icons of features on admin dashboard ([Gargron](https://github.com/mastodon/mastodon/pull/10366))
- Change DNS timeouts from 1s to 5s ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10238))
- Change Docker image to use Ubuntu with jemalloc ([Sir-Boops](https://github.com/mastodon/mastodon/pull/10100), [BenLubar](https://github.com/mastodon/mastodon/pull/10212))
- Change public pages to be cacheable by proxies ([BenLubar](https://github.com/mastodon/mastodon/pull/9059))
- Change the 410 gone response for suspended accounts to be cacheable by proxies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10339))
- Change web UI to not empty timeline of blocked users on block ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10359))
- Change JSON serializer to remove unused `@context` values ([Gargron](https://github.com/mastodon/mastodon/pull/10378))
- Change GIFV file size limit to be the same as for other videos ([rinsuki](https://github.com/mastodon/mastodon/pull/9924))
- Change Webpack to not use @babel/preset-env to compile node_modules ([ykzts](https://github.com/mastodon/mastodon/pull/10289))
- Change web UI to use new Web Share Target API ([gol-cha](https://github.com/mastodon/mastodon/pull/9963))
- Change ActivityPub reports to have persistent URIs ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10303))
- Change `tootctl accounts cull --dry-run` to list accounts that would be deleted ([BenLubar](https://github.com/mastodon/mastodon/pull/10460))
- Change format of CSV exports of follows and mutes to include extra settings ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10495), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10335))
- Change ActivityPub collections to be cacheable by proxies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10467))
- Change REST API and public profiles to not return follows/followers for users that have blocked you ([Gargron](https://github.com/mastodon/mastodon/pull/10491))
- Change the groupings of menu items in settings navigation ([Gargron](https://github.com/mastodon/mastodon/pull/10533))
### Removed
- Remove zopfli compression to speed up Webpack from 6min to 1min ([nolanlawson](https://github.com/mastodon/mastodon/pull/10288))
- Remove stats.json generation to speed up Webpack ([nolanlawson](https://github.com/mastodon/mastodon/pull/10290))
### Fixed
- Fix public timelines being broken by new toots when they are not mounted in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/10131))
- Fix quick filter settings not being saved when selecting a different filter in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10296))
- Fix remote interaction dialogs being indexed by search engines ([Gargron](https://github.com/mastodon/mastodon/pull/10240))
- Fix maxed-out invites not showing up as expired in UI ([Gargron](https://github.com/mastodon/mastodon/pull/10274))
- Fix scrollbar styles on compose textarea ([Gargron](https://github.com/mastodon/mastodon/pull/10292))
- Fix timeline merge workers being queued for remote users ([Gargron](https://github.com/mastodon/mastodon/pull/10355))
- Fix alternative relay support regression ([Gargron](https://github.com/mastodon/mastodon/pull/10398))
- Fix trying to fetch keys of unknown accounts on a self-delete from them ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10326))
- Fix CAS `:service_validate_url` option ([enewhuis](https://github.com/mastodon/mastodon/pull/10328))
- Fix race conditions when creating backups ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10234))
- Fix whitespace not being stripped out of username before validation ([aurelien-reeves](https://github.com/mastodon/mastodon/pull/10239))
- Fix n+1 query when deleting status ([Gargron](https://github.com/mastodon/mastodon/pull/10247))
- Fix exiting follows not being rejected when suspending a remote account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10230))
- Fix the underlying button element in a disabled icon button not being disabled ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10194))
- Fix race condition when streaming out deleted statuses ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10280))
- Fix performance of admin federation UI by caching account counts ([Gargron](https://github.com/mastodon/mastodon/pull/10374))
- Fix JS error on pages that don't define a CSRF token ([hinaloe](https://github.com/mastodon/mastodon/pull/10383))
- Fix `tootctl accounts cull` sometimes removing accounts that are temporarily unreachable ([BenLubar](https://github.com/mastodon/mastodon/pull/10460))
## [2.7.4] - 2019-03-05
### Fixed
- Fix web UI not cleaning up notifications after block ([Gargron](https://github.com/mastodon/mastodon/pull/10108))
- Fix redundant HTTP requests when resolving private statuses ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10115))
- Fix performance of account media query ([abcang](https://github.com/mastodon/mastodon/pull/10121))
- Fix mention processing for unknown accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10125))
- Fix getting started column not scrolling on short screens ([trwnh](https://github.com/mastodon/mastodon/pull/10075))
- Fix direct messages pagination in the web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10126))
- Fix serialization of Announce activities ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10129))
- Fix home timeline perpetually reloading when empty in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/10130))
- Fix lists export ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10136))
- Fix edit profile page crash for suspended-then-unsuspended users ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10178))
## [2.7.3] - 2019-02-23
### Added
- Add domain filter to the admin federation page ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10071))
- Add quick link from admin account view to block/unblock instance ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10073))
### Fixed
- Fix video player width not being updated to fit container width ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10069))
- Fix domain filter being shown in admin page when local filter is active ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10074))
- Fix crash when conversations have no valid participants ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10078))
- Fix error when performing admin actions on no statuses ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10094))
### Changed
- Change custom emojis to randomize stored file name ([hinaloe](https://github.com/mastodon/mastodon/pull/10090))
## [2.7.2] - 2019-02-17
### Added
- Add support for IPv6 in e-mail validation ([zoc](https://github.com/mastodon/mastodon/pull/10009))
- Add record of IP address used for signing up ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10026))
- Add tight rate-limit for API deletions (30 per 30 minutes) ([Gargron](https://github.com/mastodon/mastodon/pull/10042))
- Add support for embedded `Announce` objects attributed to the same actor ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9998), [Gargron](https://github.com/mastodon/mastodon/pull/10065))
- Add spam filter for `Create` and `Announce` activities ([Gargron](https://github.com/mastodon/mastodon/pull/10005), [Gargron](https://github.com/mastodon/mastodon/pull/10041), [Gargron](https://github.com/mastodon/mastodon/pull/10062))
- Add `registrations` attribute to `GET /api/v1/instance` ([Gargron](https://github.com/mastodon/mastodon/pull/10060))
- Add `vapid_key` to `POST /api/v1/apps` and `GET /api/v1/apps/verify_credentials` ([Gargron](https://github.com/mastodon/mastodon/pull/10058))
### Fixed
- Fix link color and add link underlines in high-contrast theme ([Gargron](https://github.com/mastodon/mastodon/pull/9949), [Gargron](https://github.com/mastodon/mastodon/pull/10028))
- Fix unicode characters in URLs not being linkified ([JMendyk](https://github.com/mastodon/mastodon/pull/8447), [hinaloe](https://github.com/mastodon/mastodon/pull/9991))
- Fix URLs linkifier grabbing ending quotation as part of the link ([Gargron](https://github.com/mastodon/mastodon/pull/9997))
- Fix authorized applications page design ([rinsuki](https://github.com/mastodon/mastodon/pull/9969))
- Fix custom emojis not showing up in share page emoji picker ([rinsuki](https://github.com/mastodon/mastodon/pull/9970))
- Fix too liberal application of whitespace in toots ([trwnh](https://github.com/mastodon/mastodon/pull/9968))
- Fix misleading e-mail hint being displayed in admin view ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9973))
- Fix tombstones not being cleared out ([abcang](https://github.com/mastodon/mastodon/pull/9978))
- Fix some timeline jumps ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9982), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/10001), [rinsuki](https://github.com/mastodon/mastodon/pull/10046))
- Fix content warning input taking keyboard focus even when hidden ([hinaloe](https://github.com/mastodon/mastodon/pull/10017))
- Fix hashtags select styling in default and high-contrast themes ([Gargron](https://github.com/mastodon/mastodon/pull/10029))
- Fix style regressions on landing page ([Gargron](https://github.com/mastodon/mastodon/pull/10030))
- Fix hashtag column not subscribing to stream on mount ([Gargron](https://github.com/mastodon/mastodon/pull/10040))
- Fix relay enabling/disabling not resetting inbox availability status ([Gargron](https://github.com/mastodon/mastodon/pull/10048))
- Fix mutes, blocks, domain blocks and follow requests not paginating ([Gargron](https://github.com/mastodon/mastodon/pull/10057))
- Fix crash on public hashtag pages when streaming fails ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10061))
### Changed
- Change icon for unlisted visibility level ([clarcharr](https://github.com/mastodon/mastodon/pull/9952))
- Change queue of actor deletes from push to pull for non-follower recipients ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/10016))
- Change robots.txt to exclude media proxy URLs ([nightpool](https://github.com/mastodon/mastodon/pull/10038))
- Change upload description input to allow line breaks ([BenLubar](https://github.com/mastodon/mastodon/pull/10036))
- Change `dist/mastodon-streaming.service` to recommend running node without intermediary npm command ([nolanlawson](https://github.com/mastodon/mastodon/pull/10032))
- Change conversations to always show names of other participants ([Gargron](https://github.com/mastodon/mastodon/pull/10047))
- Change buttons on timeline preview to open the interaction dialog ([Gargron](https://github.com/mastodon/mastodon/pull/10054))
- Change error graphic to hover-to-play ([Gargron](https://github.com/mastodon/mastodon/pull/10055))
## [2.7.1] - 2019-01-28
### Fixed
- Fix SSO authentication not working due to missing agreement boolean ([Gargron](https://github.com/mastodon/mastodon/pull/9915))
- Fix slow fallback of CopyAccountStats migration setting stats to 0 ([Gargron](https://github.com/mastodon/mastodon/pull/9930))
- Fix wrong command in migration error message ([angristan](https://github.com/mastodon/mastodon/pull/9877))
- Fix initial value of volume slider in video player and handle volume changes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9929))
- Fix missing hotkeys for notifications ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9927))
- Fix being able to attach unattached media created by other users ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9921))
- Fix unrescued SSL error during link verification ([renatolond](https://github.com/mastodon/mastodon/pull/9914))
- Fix Firefox scrollbar color regression ([trwnh](https://github.com/mastodon/mastodon/pull/9908))
- Fix scheduled status with media immediately creating a status ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9894))
- Fix missing strong style for landing page description ([Kjwon15](https://github.com/mastodon/mastodon/pull/9892))
## [2.7.0] - 2019-01-20
### Added
- Add link for adding a user to a list from their profile ([namelessGonbai](https://github.com/mastodon/mastodon/pull/9062))
- Add joining several hashtags in a single column ([gdpelican](https://github.com/mastodon/mastodon/pull/8904))
- Add volume sliders for videos ([sumdog](https://github.com/mastodon/mastodon/pull/9366))
- Add a tooltip explaining what a locked account is ([pawelngei](https://github.com/mastodon/mastodon/pull/9403))
- Add preloaded cache for common JSON-LD contexts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9412))
- Add profile directory ([Gargron](https://github.com/mastodon/mastodon/pull/9427))
- Add setting to not group reblogs in home feed ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9248))
- Add admin ability to remove a user's header image ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9495))
- Add account hashtags to ActivityPub actor JSON ([Gargron](https://github.com/mastodon/mastodon/pull/9450))
- Add error message for avatar image that's too large ([sumdog](https://github.com/mastodon/mastodon/pull/9518))
- Add notification quick-filter bar ([pawelngei](https://github.com/mastodon/mastodon/pull/9399))
- Add new first-time tutorial ([Gargron](https://github.com/mastodon/mastodon/pull/9531))
- Add moderation warnings ([Gargron](https://github.com/mastodon/mastodon/pull/9519))
- Add emoji codepoint mappings for v11.0 ([Gargron](https://github.com/mastodon/mastodon/pull/9618))
- Add REST API for creating an account ([Gargron](https://github.com/mastodon/mastodon/pull/9572))
- Add support for Malayalam in language filter ([tachyons](https://github.com/mastodon/mastodon/pull/9624))
- Add exclude_reblogs option to account statuses API ([Gargron](https://github.com/mastodon/mastodon/pull/9640))
- Add local followers page to admin account UI ([chr-1x](https://github.com/mastodon/mastodon/pull/9610))
- Add healthcheck commands to docker-compose.yml ([BenLubar](https://github.com/mastodon/mastodon/pull/9143))
- Add handler for Move activity to migrate followers ([Gargron](https://github.com/mastodon/mastodon/pull/9629))
- Add CSV export for lists and domain blocks ([Gargron](https://github.com/mastodon/mastodon/pull/9677))
- Add `tootctl accounts follow ACCT` ([Gargron](https://github.com/mastodon/mastodon/pull/9414))
- Add scheduled statuses ([Gargron](https://github.com/mastodon/mastodon/pull/9706))
- Add immutable caching for S3 objects ([nolanlawson](https://github.com/mastodon/mastodon/pull/9722))
- Add cache to custom emojis API ([Gargron](https://github.com/mastodon/mastodon/pull/9732))
- Add preview cards to non-detailed statuses on public pages ([Gargron](https://github.com/mastodon/mastodon/pull/9714))
- Add `mod` and `moderator` to list of default reserved usernames ([Gargron](https://github.com/mastodon/mastodon/pull/9713))
- Add quick links to the admin interface in the web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8545))
- Add `tootctl domains crawl` ([Gargron](https://github.com/mastodon/mastodon/pull/9809))
- Add attachment list fallback to public pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9780))
- Add `tootctl --version` ([Gargron](https://github.com/mastodon/mastodon/pull/9835))
- Add information about how to opt-in to the directory on the directory ([Gargron](https://github.com/mastodon/mastodon/pull/9834))
- Add timeouts for S3 ([Gargron](https://github.com/mastodon/mastodon/pull/9842))
- Add support for non-public reblogs from ActivityPub ([Gargron](https://github.com/mastodon/mastodon/pull/9841))
- Add sending of `Reject` activity when sending a `Block` activity ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9811))
### Changed
- Temporarily pause timeline if mouse moved recently ([lmorchard](https://github.com/mastodon/mastodon/pull/9200))
- Change the password form order ([mayaeh](https://github.com/mastodon/mastodon/pull/9267))
- Redesign admin UI for accounts ([Gargron](https://github.com/mastodon/mastodon/pull/9340), [Gargron](https://github.com/mastodon/mastodon/pull/9643))
- Redesign admin UI for instances/domain blocks ([Gargron](https://github.com/mastodon/mastodon/pull/9645))
- Swap avatar and header input fields in profile page ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9271))
- When posting in mobile mode, go back to previous history location ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9502))
- Split out is_changing_upload from is_submitting ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9536))
- Back to the getting-started when pins the timeline. ([kedamaDQ](https://github.com/mastodon/mastodon/pull/9561))
- Allow unauthenticated REST API access to GET /api/v1/accounts/:id/statuses ([Gargron](https://github.com/mastodon/mastodon/pull/9573))
- Limit maximum visibility of local silenced users to unlisted ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9583))
- Change API error message for unconfirmed accounts ([noellabo](https://github.com/mastodon/mastodon/pull/9625))
- Change the icon to "reply-all" when it's a reply to other accounts ([mayaeh](https://github.com/mastodon/mastodon/pull/9378))
- Do not ignore federated reports targeting already-reported accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9534))
- Upgrade default Ruby version to 2.6.0 ([Gargron](https://github.com/mastodon/mastodon/pull/9688))
- Change e-mail digest frequency ([Gargron](https://github.com/mastodon/mastodon/pull/9689))
- Change Docker images for Tor support in docker-compose.yml ([Sir-Boops](https://github.com/mastodon/mastodon/pull/9438))
- Display fallback link card thumbnail when none is given ([Gargron](https://github.com/mastodon/mastodon/pull/9715))
- Change account bio length validation to ignore mention domains and URLs ([Gargron](https://github.com/mastodon/mastodon/pull/9717))
- Use configured contact user for "anonymous" federation activities ([yukimochi](https://github.com/mastodon/mastodon/pull/9661))
- Change remote interaction dialog to use specific actions instead of generic "interact" ([Gargron](https://github.com/mastodon/mastodon/pull/9743))
- Always re-fetch public key when signature verification fails to support blind key rotation ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9667))
- Make replies to boosts impossible, connect reply to original status instead ([valerauko](https://github.com/mastodon/mastodon/pull/9129))
- Change e-mail MX validation to check both A and MX records against blacklist ([Gargron](https://github.com/mastodon/mastodon/pull/9489))
- Hide floating action button on search and getting started pages ([tmm576](https://github.com/mastodon/mastodon/pull/9826))
- Redesign public hashtag page to use a masonry layout ([Gargron](https://github.com/mastodon/mastodon/pull/9822))
- Use `summary` as summary instead of content warning for converted ActivityPub objects ([Gargron](https://github.com/mastodon/mastodon/pull/9823))
- Display a double reply arrow on public pages for toots that are replies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9808))
- Change admin UI right panel size to be wider ([Kjwon15](https://github.com/mastodon/mastodon/pull/9768))
### Removed
- Remove links to bridge.joinmastodon.org (non-functional) ([Gargron](https://github.com/mastodon/mastodon/pull/9608))
- Remove LD-Signatures from activities that do not need them ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9659))
### Fixed
- Remove unused computation of reblog references from updateTimeline ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9244))
- Fix loaded embeds resetting if a status arrives from API again ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9270))
- Fix race condition causing shallow status with only a "favourited" attribute ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9272))
- Remove intermediary arrays when creating hash maps from results ([Gargron](https://github.com/mastodon/mastodon/pull/9291))
- Extract counters from accounts table to account_stats table to improve performance ([Gargron](https://github.com/mastodon/mastodon/pull/9295))
- Change identities id column to a bigint ([Gargron](https://github.com/mastodon/mastodon/pull/9371))
- Fix conversations API pagination ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9407))
- Improve account suspension speed and completeness ([Gargron](https://github.com/mastodon/mastodon/pull/9290))
- Fix thread depth computation in statuses_controller ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9426))
- Fix database deadlocks by moving account stats update outside transaction ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9437))
- Escape HTML in profile name preview in profile settings ([pawelngei](https://github.com/mastodon/mastodon/pull/9446))
- Use same CORS policy for /@:username and /users/:username ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9485))
- Make custom emoji domains case insensitive ([Esteth](https://github.com/mastodon/mastodon/pull/9474))
- Various fixes to scrollable lists and media gallery ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9501))
- Fix bootsnap cache directory being declared relatively ([Gargron](https://github.com/mastodon/mastodon/pull/9511))
- Fix timeline pagination in the web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9516))
- Fix padding on dropdown elements in preferences ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9517))
- Make avatar and headers respect GIF autoplay settings ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9515))
- Do no retry Web Push workers if the server returns a 4xx response ([Gargron](https://github.com/mastodon/mastodon/pull/9434))
- Minor scrollable list fixes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9551))
- Ignore low-confidence CharlockHolmes guesses when parsing link cards ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9510))
- Fix `tootctl accounts rotate` not updating public keys ([Gargron](https://github.com/mastodon/mastodon/pull/9556))
- Fix CSP / X-Frame-Options for media players ([jomo](https://github.com/mastodon/mastodon/pull/9558))
- Fix unnecessary loadMore calls when the end of a timeline has been reached ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9581))
- Skip mailer job retries when a record no longer exists ([Gargron](https://github.com/mastodon/mastodon/pull/9590))
- Fix composer not getting focus after reply confirmation dialog ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9602))
- Fix signature verification stoplight triggering on non-timeout errors ([Gargron](https://github.com/mastodon/mastodon/pull/9617))
- Fix ThreadResolveWorker getting queued with invalid URLs ([Gargron](https://github.com/mastodon/mastodon/pull/9628))
- Fix crash when clearing uninitialized timeline ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9662))
- Avoid duplicate work by merging ReplyDistributionWorker into DistributionWorker ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9660))
- Skip full text search if it fails, instead of erroring out completely ([Kjwon15](https://github.com/mastodon/mastodon/pull/9654))
- Fix profile metadata links not verifying correctly sometimes ([shrft](https://github.com/mastodon/mastodon/pull/9673))
- Ensure blocked user unfollows blocker if Block/Undo-Block activities are processed out of order ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9687))
- Fix unreadable text color in report modal for some statuses ([Gargron](https://github.com/mastodon/mastodon/pull/9716))
- Stop GIFV timeline preview explicitly when it's opened in modal ([kedamaDQ](https://github.com/mastodon/mastodon/pull/9749))
- Fix scrollbar width compensation ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9824))
- Fix race conditions when processing deleted toots ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9815))
- Fix SSO issues on WebKit browsers by disabling Same-Site cookie again ([moritzheiber](https://github.com/mastodon/mastodon/pull/9819))
- Fix empty OEmbed error ([renatolond](https://github.com/mastodon/mastodon/pull/9807))
- Fix drag & drop modal not disappearing sometimes ([hinaloe](https://github.com/mastodon/mastodon/pull/9797))
- Fix statuses with content warnings being displayed in web push notifications sometimes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9778))
- Fix scroll-to-detailed status not working on public pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9773))
- Fix media modal loading indicator ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9771))
- Fix hashtag search results not having a permalink fallback in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9810))
- Fix slightly cropped font on settings page dropdowns when using system font ([ariasuni](https://github.com/mastodon/mastodon/pull/9839))
- Fix not being able to drag & drop text into forms ([tmm576](https://github.com/mastodon/mastodon/pull/9840))
### Security
- Sanitize and sandbox toot embeds in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9552))
- Add tombstones for remote statuses to prevent replay attacks ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9830))
## [2.6.5] - 2018-12-01
### Changed
- Change lists to display replies to others on the list and list owner ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9324))
### Fixed
- Fix failures caused by commonly-used JSON-LD contexts being unavailable ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9412))
## [2.6.4] - 2018-11-30
### Fixed
- Fix yarn dependencies not installing due to yanked event-stream package ([Gargron](https://github.com/mastodon/mastodon/pull/9401))
## [2.6.3] - 2018-11-30
### Added
- Add hyphen to characters allowed in remote usernames ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9345))
### Changed
- Change server user count to exclude suspended accounts ([Gargron](https://github.com/mastodon/mastodon/pull/9380))
### Fixed
- Fix ffmpeg processing sometimes stalling due to overfilled stdout buffer ([hugogameiro](https://github.com/mastodon/mastodon/pull/9368))
- Fix missing DNS records raising the wrong kind of exception ([Gargron](https://github.com/mastodon/mastodon/pull/9379))
- Fix already queued deliveries still trying to reach inboxes marked as unavailable ([Gargron](https://github.com/mastodon/mastodon/pull/9358))
### Security
- Fix TLS handshake timeout not being enforced ([Gargron](https://github.com/mastodon/mastodon/pull/9381))
## [2.6.2] - 2018-11-23
### Added
- Add Page to whitelisted ActivityPub types ([mbajur](https://github.com/mastodon/mastodon/pull/9188))
- Add 20px to column width in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/9227))
- Add amount of freed disk space in `tootctl media remove` ([Gargron](https://github.com/mastodon/mastodon/pull/9229), [Gargron](https://github.com/mastodon/mastodon/pull/9239), [mayaeh](https://github.com/mastodon/mastodon/pull/9288))
- Add "Show thread" link to self-replies ([Gargron](https://github.com/mastodon/mastodon/pull/9228))
### Changed
- Change order of Atom and RSS links so Atom is first ([Alkarex](https://github.com/mastodon/mastodon/pull/9302))
- Change Nginx configuration for Nanobox apps ([danhunsaker](https://github.com/mastodon/mastodon/pull/9310))
- Change the follow action to appear instant in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/9220))
- Change how the ActiveRecord connection is instantiated in on_worker_boot ([Gargron](https://github.com/mastodon/mastodon/pull/9238))
- Change `tootctl accounts cull` to always touch accounts so they can be skipped ([renatolond](https://github.com/mastodon/mastodon/pull/9293))
- Change mime type comparison to ignore JSON-LD profile ([valerauko](https://github.com/mastodon/mastodon/pull/9179))
### Fixed
- Fix web UI crash when conversation has no last status ([sammy8806](https://github.com/mastodon/mastodon/pull/9207))
- Fix follow limit validator reporting lower number past threshold ([Gargron](https://github.com/mastodon/mastodon/pull/9230))
- Fix form validation flash message color and input borders ([Gargron](https://github.com/mastodon/mastodon/pull/9235))
- Fix invalid twitter:player cards being displayed ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9254))
- Fix emoji update date being processed incorrectly ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9255))
- Fix playing embed resetting if status is reloaded in web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9270), [Gargron](https://github.com/mastodon/mastodon/pull/9275))
- Fix web UI crash when favouriting a deleted status ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9272))
- Fix intermediary arrays being created for hash maps ([Gargron](https://github.com/mastodon/mastodon/pull/9291))
- Fix filter ID not being a string in REST API ([Gargron](https://github.com/mastodon/mastodon/pull/9303))
### Security
- Fix multiple remote account deletions being able to deadlock the database ([Gargron](https://github.com/mastodon/mastodon/pull/9292))
- Fix HTTP connection timeout of 10s not being enforced ([Gargron](https://github.com/mastodon/mastodon/pull/9329))
## [2.6.1] - 2018-10-30
### Fixed
- Fix resolving resources by URL not working due to a regression in [valerauko](https://github.com/mastodon/mastodon/pull/9132) ([Gargron](https://github.com/mastodon/mastodon/pull/9171))
- Fix reducer error in web UI when a conversation has no last status ([Gargron](https://github.com/mastodon/mastodon/pull/9173))
## [2.6.0] - 2018-10-30
### Added
- Add link ownership verification ([Gargron](https://github.com/mastodon/mastodon/pull/8703))
- Add conversations API ([Gargron](https://github.com/mastodon/mastodon/pull/8832))
- Add limit for the number of people that can be followed from one account ([Gargron](https://github.com/mastodon/mastodon/pull/8807))
- Add admin setting to customize mascot ([ashleyhull-versent](https://github.com/mastodon/mastodon/pull/8766))
- Add support for more granular ActivityPub audiences from other software, i.e. circles ([Gargron](https://github.com/mastodon/mastodon/pull/8950), [Gargron](https://github.com/mastodon/mastodon/pull/9093), [Gargron](https://github.com/mastodon/mastodon/pull/9150))
- Add option to block all reports from a domain ([Gargron](https://github.com/mastodon/mastodon/pull/8830))
- Add user preference to always expand toots marked with content warnings ([webroo](https://github.com/mastodon/mastodon/pull/8762))
- Add user preference to always hide all media ([fvh-P](https://github.com/mastodon/mastodon/pull/8569))
- Add `force_login` param to OAuth authorize page ([Gargron](https://github.com/mastodon/mastodon/pull/8655))
- Add `tootctl accounts backup` ([Gargron](https://github.com/mastodon/mastodon/pull/8642), [Gargron](https://github.com/mastodon/mastodon/pull/8811))
- Add `tootctl accounts create` ([Gargron](https://github.com/mastodon/mastodon/pull/8642), [Gargron](https://github.com/mastodon/mastodon/pull/8811))
- Add `tootctl accounts cull` ([Gargron](https://github.com/mastodon/mastodon/pull/8642), [Gargron](https://github.com/mastodon/mastodon/pull/8811))
- Add `tootctl accounts delete` ([Gargron](https://github.com/mastodon/mastodon/pull/8642), [Gargron](https://github.com/mastodon/mastodon/pull/8811))
- Add `tootctl accounts modify` ([Gargron](https://github.com/mastodon/mastodon/pull/8642), [Gargron](https://github.com/mastodon/mastodon/pull/8811))
- Add `tootctl accounts refresh` ([Gargron](https://github.com/mastodon/mastodon/pull/8642), [Gargron](https://github.com/mastodon/mastodon/pull/8811))
- Add `tootctl feeds build` ([Gargron](https://github.com/mastodon/mastodon/pull/8642), [Gargron](https://github.com/mastodon/mastodon/pull/8811))
- Add `tootctl feeds clear` ([Gargron](https://github.com/mastodon/mastodon/pull/8642), [Gargron](https://github.com/mastodon/mastodon/pull/8811))
- Add `tootctl settings registrations open` ([Gargron](https://github.com/mastodon/mastodon/pull/8642), [Gargron](https://github.com/mastodon/mastodon/pull/8811))
- Add `tootctl settings registrations close` ([Gargron](https://github.com/mastodon/mastodon/pull/8642), [Gargron](https://github.com/mastodon/mastodon/pull/8811))
- Add `min_id` param to REST API to support backwards pagination ([Gargron](https://github.com/mastodon/mastodon/pull/8736))
- Add a confirmation dialog when hitting reply and the compose box isn't empty ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8893))
- Add PostgreSQL disk space growth tracking in PGHero ([Gargron](https://github.com/mastodon/mastodon/pull/8906))
- Add button for disabling local account to report quick actions bar ([Gargron](https://github.com/mastodon/mastodon/pull/9024))
- Add Czech language ([Aditoo17](https://github.com/mastodon/mastodon/pull/8594))
- Add `same-site` (`lax`) attribute to cookies ([sorin-davidoi](https://github.com/mastodon/mastodon/pull/8626))
- Add support for styled scrollbars in Firefox Nightly ([sorin-davidoi](https://github.com/mastodon/mastodon/pull/8653))
- Add highlight to the active tab in web UI profiles ([rhoio](https://github.com/mastodon/mastodon/pull/8673))
- Add auto-focus for comment textarea in report modal ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8689))
- Add auto-focus for emoji picker's search field ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8688))
- Add nginx and systemd templates to `dist/` directory ([Gargron](https://github.com/mastodon/mastodon/pull/8770))
- Add support for `/.well-known/change-password` ([Gargron](https://github.com/mastodon/mastodon/pull/8828))
- Add option to override FFMPEG binary path ([sascha-sl](https://github.com/mastodon/mastodon/pull/8855))
- Add `dns-prefetch` tag when using different host for assets or uploads ([Gargron](https://github.com/mastodon/mastodon/pull/8942))
- Add `description` meta tag ([Gargron](https://github.com/mastodon/mastodon/pull/8941))
- Add `Content-Security-Policy` header ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8957))
- Add cache for the instance info API ([ykzts](https://github.com/mastodon/mastodon/pull/8765))
- Add suggested follows to search screen in mobile layout ([Gargron](https://github.com/mastodon/mastodon/pull/9010))
- Add CORS header to `/.well-known/*` routes ([BenLubar](https://github.com/mastodon/mastodon/pull/9083))
- Add `card` attribute to statuses returned from REST API ([Gargron](https://github.com/mastodon/mastodon/pull/9120))
- Add in-stream link preview ([Gargron](https://github.com/mastodon/mastodon/pull/9120))
- Add support for ActivityPub `Page` objects ([mbajur](https://github.com/mastodon/mastodon/pull/9121))
### Changed
- Change forms design ([Gargron](https://github.com/mastodon/mastodon/pull/8703))
- Change reports overview to group by target account ([Gargron](https://github.com/mastodon/mastodon/pull/8674))
- Change web UI to show "read more" link on overly long in-stream statuses ([lanodan](https://github.com/mastodon/mastodon/pull/8205))
- Change design of direct messages column ([Gargron](https://github.com/mastodon/mastodon/pull/8832), [Gargron](https://github.com/mastodon/mastodon/pull/9022))
- Change home timelines to exclude DMs ([Gargron](https://github.com/mastodon/mastodon/pull/8940))
- Change list timelines to exclude all replies ([cbayerlein](https://github.com/mastodon/mastodon/pull/8683))
- Change admin accounts UI default sort to most recent ([Gargron](https://github.com/mastodon/mastodon/pull/8813))
- Change documentation URL in the UI ([Gargron](https://github.com/mastodon/mastodon/pull/8898))
- Change style of success and failure messages ([Gargron](https://github.com/mastodon/mastodon/pull/8973))
- Change DM filtering to always allow DMs from staff ([qguv](https://github.com/mastodon/mastodon/pull/8993))
- Change recommended Ruby version to 2.5.3 ([zunda](https://github.com/mastodon/mastodon/pull/9003))
- Change docker-compose default to persist volumes in current directory ([Gargron](https://github.com/mastodon/mastodon/pull/9055))
- Change character counters on edit profile page to input length limit ([Gargron](https://github.com/mastodon/mastodon/pull/9100))
- Change notification filtering to always let through messages from staff ([Gargron](https://github.com/mastodon/mastodon/pull/9152))
- Change "hide boosts from user" function also hiding notifications about boosts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9147))
- Change CSS `detailed-status__wrapper` class actually wrap the detailed status ([trwnh](https://github.com/mastodon/mastodon/pull/8547))
### Deprecated
- `GET /api/v1/timelines/direct``GET /api/v1/conversations` ([Gargron](https://github.com/mastodon/mastodon/pull/8832))
- `POST /api/v1/notifications/dismiss``POST /api/v1/notifications/:id/dismiss` ([Gargron](https://github.com/mastodon/mastodon/pull/8905))
- `GET /api/v1/statuses/:id/card``card` attributed included in status ([Gargron](https://github.com/mastodon/mastodon/pull/9120))
### Removed
- Remove "on this device" label in column push settings ([rhoio](https://github.com/mastodon/mastodon/pull/8704))
- Remove rake tasks in favour of tootctl commands ([Gargron](https://github.com/mastodon/mastodon/pull/8675))
### Fixed
- Fix remote statuses using instance's default locale if no language given ([Kjwon15](https://github.com/mastodon/mastodon/pull/8861))
- Fix streaming API not exiting when port or socket is unavailable ([Gargron](https://github.com/mastodon/mastodon/pull/9023))
- Fix network calls being performed in database transaction in ActivityPub handler ([Gargron](https://github.com/mastodon/mastodon/pull/8951))
- Fix dropdown arrow position ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8637))
- Fix first element of dropdowns being focused even if not using keyboard ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8679))
- Fix tootctl requiring `bundle exec` invocation ([abcang](https://github.com/mastodon/mastodon/pull/8619))
- Fix public pages not using animation preference for avatars ([renatolond](https://github.com/mastodon/mastodon/pull/8614))
- Fix OEmbed/OpenGraph cards not understanding relative URLs ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8669))
- Fix some dark emojis not having a white outline ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8597))
- Fix media description not being displayed in various media modals ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8678))
- Fix generated URLs of desktop notifications missing base URL ([GenbuHase](https://github.com/mastodon/mastodon/pull/8758))
- Fix RTL styles ([mabkenar](https://github.com/mastodon/mastodon/pull/8764), [mabkenar](https://github.com/mastodon/mastodon/pull/8767), [mabkenar](https://github.com/mastodon/mastodon/pull/8823), [mabkenar](https://github.com/mastodon/mastodon/pull/8897), [mabkenar](https://github.com/mastodon/mastodon/pull/9005), [mabkenar](https://github.com/mastodon/mastodon/pull/9007), [mabkenar](https://github.com/mastodon/mastodon/pull/9018), [mabkenar](https://github.com/mastodon/mastodon/pull/9021), [mabkenar](https://github.com/mastodon/mastodon/pull/9145), [mabkenar](https://github.com/mastodon/mastodon/pull/9146))
- Fix crash in streaming API when tag param missing ([Gargron](https://github.com/mastodon/mastodon/pull/8955))
- Fix hotkeys not working when no element is focused ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8998))
- Fix some hotkeys not working on detailed status view ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9006))
- Fix og:url on status pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9047))
- Fix upload option buttons only being visible on hover ([Gargron](https://github.com/mastodon/mastodon/pull/9074))
- Fix tootctl not returning exit code 1 on wrong arguments ([sascha-sl](https://github.com/mastodon/mastodon/pull/9094))
- Fix preview cards for appearing for profiles mentioned in toot ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/6934), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/9158))
- Fix local accounts sometimes being duplicated as faux-remote ([Gargron](https://github.com/mastodon/mastodon/pull/9109))
- Fix emoji search when the shortcode has multiple separators ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/9124))
- Fix dropdowns sometimes being partially obscured by other elements ([kedamaDQ](https://github.com/mastodon/mastodon/pull/9126))
- Fix cache not updating when reply/boost/favourite counters or media sensitivity update ([Gargron](https://github.com/mastodon/mastodon/pull/9119))
- Fix empty display name precedence over username in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/9163))
- Fix td instead of th in sessions table header ([Gargron](https://github.com/mastodon/mastodon/pull/9162))
- Fix handling of content types with profile ([valerauko](https://github.com/mastodon/mastodon/pull/9132))
## [2.5.2] - 2018-10-12
### Security
- Fix XSS vulnerability ([Gargron](https://github.com/mastodon/mastodon/pull/8959))
## [2.5.1] - 2018-10-07
### Fixed
- Fix database migrations for PostgreSQL below 9.5 ([Gargron](https://github.com/mastodon/mastodon/pull/8903))
- Fix class autoloading issue in ActivityPub Create handler ([Gargron](https://github.com/mastodon/mastodon/pull/8820))
- Fix cache statistics not being sent via statsd when statsd enabled ([ykzts](https://github.com/mastodon/mastodon/pull/8831))
- Bump puma from 3.11.4 to 3.12.0 ([dependabot[bot]](https://github.com/mastodon/mastodon/pull/8883))
### Security
- Fix some local images not having their EXIF metadata stripped on upload ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8714))
- Fix being able to enable a disabled relay via ActivityPub Accept handler ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8864))
- Bump nokogiri from 1.8.4 to 1.8.5 ([dependabot[bot]](https://github.com/mastodon/mastodon/pull/8881))
- Fix being able to report statuses not belonging to the reported account ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/8916))

View File

@ -28,7 +28,7 @@ RUN apt-get update && \
libgdbm-dev \
libgmp-dev \
libssl-dev \
libyaml-dev \
libyaml-0-2 \
ca-certificates \
libreadline8 \
python3 \

View File

@ -4,7 +4,7 @@ source 'https://rubygems.org'
ruby '>= 3.0.0'
gem 'puma', '~> 6.3'
gem 'rails', '~> 7.1.1'
gem 'rails', '~> 7.0'
gem 'sprockets', '~> 3.7.2'
gem 'thor', '~> 1.2'
gem 'rack', '~> 2.2.7'

View File

@ -39,83 +39,75 @@ GIT
GEM
remote: https://rubygems.org/
specs:
actioncable (7.1.1)
actionpack (= 7.1.1)
activesupport (= 7.1.1)
actioncable (7.0.8)
actionpack (= 7.0.8)
activesupport (= 7.0.8)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6)
actionmailbox (7.1.1)
actionpack (= 7.1.1)
activejob (= 7.1.1)
activerecord (= 7.1.1)
activestorage (= 7.1.1)
activesupport (= 7.1.1)
actionmailbox (7.0.8)
actionpack (= 7.0.8)
activejob (= 7.0.8)
activerecord (= 7.0.8)
activestorage (= 7.0.8)
activesupport (= 7.0.8)
mail (>= 2.7.1)
net-imap
net-pop
net-smtp
actionmailer (7.1.1)
actionpack (= 7.1.1)
actionview (= 7.1.1)
activejob (= 7.1.1)
activesupport (= 7.1.1)
actionmailer (7.0.8)
actionpack (= 7.0.8)
actionview (= 7.0.8)
activejob (= 7.0.8)
activesupport (= 7.0.8)
mail (~> 2.5, >= 2.5.4)
net-imap
net-pop
net-smtp
rails-dom-testing (~> 2.2)
actionpack (7.1.1)
actionview (= 7.1.1)
activesupport (= 7.1.1)
nokogiri (>= 1.8.5)
rack (>= 2.2.4)
rack-session (>= 1.0.1)
rails-dom-testing (~> 2.0)
actionpack (7.0.8)
actionview (= 7.0.8)
activesupport (= 7.0.8)
rack (~> 2.0, >= 2.2.4)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
actiontext (7.1.1)
actionpack (= 7.1.1)
activerecord (= 7.1.1)
activestorage (= 7.1.1)
activesupport (= 7.1.1)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (7.0.8)
actionpack (= 7.0.8)
activerecord (= 7.0.8)
activestorage (= 7.0.8)
activesupport (= 7.0.8)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
actionview (7.1.1)
activesupport (= 7.1.1)
actionview (7.0.8)
activesupport (= 7.0.8)
builder (~> 3.1)
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
active_model_serializers (0.10.14)
actionpack (>= 4.1)
activemodel (>= 4.1)
case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
activejob (7.1.1)
activesupport (= 7.1.1)
activejob (7.0.8)
activesupport (= 7.0.8)
globalid (>= 0.3.6)
activemodel (7.1.1)
activesupport (= 7.1.1)
activerecord (7.1.1)
activemodel (= 7.1.1)
activesupport (= 7.1.1)
timeout (>= 0.4.0)
activestorage (7.1.1)
actionpack (= 7.1.1)
activejob (= 7.1.1)
activerecord (= 7.1.1)
activesupport (= 7.1.1)
activemodel (7.0.8)
activesupport (= 7.0.8)
activerecord (7.0.8)
activemodel (= 7.0.8)
activesupport (= 7.0.8)
activestorage (7.0.8)
actionpack (= 7.0.8)
activejob (= 7.0.8)
activerecord (= 7.0.8)
activesupport (= 7.0.8)
marcel (~> 1.0)
activesupport (7.1.1)
base64
bigdecimal
mini_mime (>= 1.1.0)
activesupport (7.0.8)
concurrent-ruby (~> 1.0, >= 1.0.2)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
@ -166,7 +158,6 @@ GEM
erubi (~> 1.4)
parser (>= 2.4)
smart_properties
bigdecimal (3.1.4)
bindata (2.4.15)
binding_of_caller (1.0.0)
debug_inspector (>= 0.0.1)
@ -246,8 +237,6 @@ GEM
dotenv-rails (2.8.1)
dotenv (= 2.8.1)
railties (>= 3.2)
drb (2.1.1)
ruby2_keywords
ed25519 (1.3.0)
elasticsearch (7.13.3)
elasticsearch-api (= 7.13.3)
@ -316,8 +305,8 @@ GEM
fuubar (2.5.1)
rspec-core (~> 3.0)
ruby-progressbar (~> 1.4)
globalid (1.2.1)
activesupport (>= 6.1)
globalid (1.1.0)
activesupport (>= 5.0)
haml (6.2.0)
temple (>= 0.8.2)
thor
@ -368,11 +357,7 @@ GEM
rainbow (>= 2.2.2, < 4.0)
terminal-table (>= 1.5.1)
idn-ruby (0.1.5)
io-console (0.6.0)
ipaddress (0.8.3)
irb (1.8.1)
rdoc
reline (>= 0.3.8)
jmespath (1.6.2)
json (2.6.3)
json-canonicalization (0.3.2)
@ -449,6 +434,7 @@ GEM
azure-storage-blob (~> 2.0.1)
hashie (~> 5.0)
memory_profiler (1.0.1)
method_source (1.0.0)
mime-types (3.5.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2023.0808)
@ -458,12 +444,11 @@ GEM
msgpack (1.7.1)
multi_json (1.15.0)
multipart-post (2.3.0)
mutex_m (0.1.2)
net-http (0.3.2)
uri
net-http-persistent (4.0.2)
connection_pool (~> 2.2)
net-imap (0.4.1)
net-imap (0.3.7)
date
net-protocol
net-ldap (0.18.0)
@ -471,7 +456,7 @@ GEM
net-protocol
net-protocol (0.2.1)
timeout
net-smtp (0.4.0)
net-smtp (0.3.3)
net-protocol
nio4r (2.5.9)
nokogiri (1.15.4)
@ -527,12 +512,10 @@ GEM
net-smtp
premailer (~> 1.7, >= 1.7.9)
private_address_check (0.5.0)
psych (5.1.1)
stringio
public_suffix (5.0.3)
puma (6.4.0)
nio4r (~> 2.0)
pundit (2.3.1)
pundit (2.3.0)
activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.7.1)
@ -551,27 +534,22 @@ GEM
rack
rack-proxy (0.7.6)
rack
rack-session (1.0.1)
rack (< 3)
rack-test (2.1.0)
rack (>= 1.3)
rackup (1.0.0)
rack (< 3)
webrick
rails (7.1.1)
actioncable (= 7.1.1)
actionmailbox (= 7.1.1)
actionmailer (= 7.1.1)
actionpack (= 7.1.1)
actiontext (= 7.1.1)
actionview (= 7.1.1)
activejob (= 7.1.1)
activemodel (= 7.1.1)
activerecord (= 7.1.1)
activestorage (= 7.1.1)
activesupport (= 7.1.1)
rails (7.0.8)
actioncable (= 7.0.8)
actionmailbox (= 7.0.8)
actionmailer (= 7.0.8)
actionpack (= 7.0.8)
actiontext (= 7.0.8)
actionview (= 7.0.8)
activejob (= 7.0.8)
activemodel (= 7.0.8)
activerecord (= 7.0.8)
activestorage (= 7.0.8)
activesupport (= 7.0.8)
bundler (>= 1.15.0)
railties (= 7.1.1)
railties (= 7.0.8)
rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.rc1)
actionview (>= 5.0.1.rc1)
@ -586,22 +564,19 @@ GEM
rails-i18n (7.0.8)
i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 8)
railties (7.1.1)
actionpack (= 7.1.1)
activesupport (= 7.1.1)
irb
rackup (>= 1.0.0)
railties (7.0.8)
actionpack (= 7.0.8)
activesupport (= 7.0.8)
method_source
rake (>= 12.2)
thor (~> 1.0, >= 1.2.2)
zeitwerk (~> 2.6)
thor (~> 1.0)
zeitwerk (~> 2.5)
rainbow (3.1.1)
rake (13.0.6)
rdf (3.2.11)
link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.6.1)
rdf (~> 3.2)
rdoc (6.5.0)
psych (>= 4.0.0)
redcarpet (3.6.0)
redis (4.8.1)
redis-namespace (1.11.0)
@ -609,15 +584,13 @@ GEM
redlock (1.3.2)
redis (>= 3.0.0, < 6.0)
regexp_parser (2.8.2)
reline (0.3.9)
io-console (~> 0.5)
request_store (1.5.1)
rack (>= 1.4)
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.2.6)
rotp (6.3.0)
rotp (6.2.2)
rouge (4.1.2)
rpam2 (4.0.2)
rqrcode (2.2.0)
@ -739,7 +712,6 @@ GEM
statsd-ruby (1.5.0)
stoplight (3.0.2)
redlock (~> 1.0)
stringio (3.0.8)
strong_migrations (0.8.0)
activerecord (>= 5.2)
swd (1.3.0)
@ -811,7 +783,6 @@ GEM
rack-proxy (>= 0.6.1)
railties (>= 5.2)
semantic_range (>= 2.3.0)
webrick (1.8.1)
websocket (1.2.10)
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
@ -907,7 +878,7 @@ DEPENDENCIES
rack-attack (~> 6.6)
rack-cors (~> 2.0)
rack-test (~> 2.1)
rails (~> 7.1.1)
rails (~> 7.0)
rails-controller-testing (~> 1.0)
rails-i18n (~> 7.0)
rails-settings-cached (~> 0.6)!
@ -958,4 +929,4 @@ RUBY VERSION
ruby 3.2.2p53
BUNDLED WITH
2.4.20
2.4.13

View File

@ -67,7 +67,7 @@ Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Stre
### Requirements
- **PostgreSQL** 12+
- **PostgreSQL** 9.5+
- **Redis** 4+
- **Ruby** 2.7+
- **Node.js** 16+

View File

@ -21,7 +21,7 @@ module Admin
account_action.save!
if account_action.with_report?
redirect_to admin_reports_path, notice: I18n.t('admin.reports.processed_msg', id: resource_params[:report_id])
redirect_to admin_reports_path, notice: I18n.t('admin.reports.processed_msg', id: params[:report_id])
else
redirect_to admin_account_path(@account.id)
end

View File

@ -20,7 +20,7 @@ class Admin::Disputes::AppealsController < Admin::BaseController
authorize @appeal, :approve?
log_action :reject, @appeal
@appeal.reject!(current_account)
UserMailer.appeal_rejected(@appeal.account.user, @appeal).deliver_later
UserMailer.appeal_rejected(@appeal.account.user, @appeal)
redirect_to disputes_strike_path(@appeal.strike)
end

View File

@ -49,7 +49,7 @@ module Admin
private
def set_instance
@instance = Instance.find_or_initialize_by(domain: TagManager.instance.normalize_domain(params[:id]&.strip))
@instance = Instance.find(TagManager.instance.normalize_domain(params[:id]&.strip))
end
def set_instances

View File

@ -12,7 +12,6 @@ class ApplicationController < ActionController::Base
include DomainControlHelper
include DatabaseHelper
include AuthorizedFetchHelper
include SelfDestructHelper
helper_method :current_account
helper_method :current_session
@ -40,8 +39,6 @@ class ApplicationController < ActionController::Base
service_unavailable
end
before_action :check_self_destruct!
before_action :store_referrer, except: :raise_not_found, if: :devise_controller?
before_action :require_functional!, if: :user_signed_in?
@ -173,15 +170,6 @@ class ApplicationController < ActionController::Base
end
end
def check_self_destruct!
return unless self_destruct?
respond_to do |format|
format.any { render 'errors/self_destruct', layout: 'auth', status: 410, formats: [:html] }
format.json { render json: { error: Rack::Utils::HTTP_STATUS_CODES[410] }, status: code }
end
end
def set_cache_control_defaults
response.cache_control.replace(private: true, no_store: true)
end

View File

@ -7,7 +7,6 @@ class Auth::ChallengesController < ApplicationController
before_action :authenticate_user!
skip_before_action :check_self_destruct!
skip_before_action :require_functional!
def create

View File

@ -12,7 +12,6 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
before_action :extend_csp_for_captcha!, only: [:show, :confirm_captcha]
before_action :require_captcha_if_needed!, only: [:show]
skip_before_action :check_self_destruct!
skip_before_action :require_functional!
def show
@ -39,12 +38,6 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
show
end
def redirect_to_app?
truthy_param?(:redirect_to_app)
end
helper_method :redirect_to_app?
private
def require_captcha_if_needed!
@ -88,7 +81,7 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
end
def after_confirmation_path_for(_resource_name, user)
if user.created_by_application && redirect_to_app?
if user.created_by_application && truthy_param?(:redirect_to_app)
user.created_by_application.confirmation_redirect_uri
elsif user_signed_in?
web_url('start')

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true
class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :check_self_destruct!
skip_before_action :verify_authenticity_token
def self.provides_callback_for(provider)

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true
class Auth::PasswordsController < Devise::PasswordsController
skip_before_action :check_self_destruct!
before_action :check_validity_of_reset_password_token, only: :edit
before_action :set_body_classes

View File

@ -17,7 +17,6 @@ class Auth::RegistrationsController < Devise::RegistrationsController
before_action :require_rules_acceptance!, only: :new
before_action :set_registration_form_time, only: :new
skip_before_action :check_self_destruct!, only: [:edit, :update]
skip_before_action :require_functional!, only: [:edit, :update]
def new

View File

@ -3,7 +3,6 @@
class Auth::SessionsController < Devise::SessionsController
layout 'auth'
skip_before_action :check_self_destruct!
skip_before_action :require_no_authentication, only: [:create]
skip_before_action :require_functional!
skip_before_action :update_user_sign_in

View File

@ -3,7 +3,6 @@
class BackupsController < ApplicationController
include RoutingHelper
skip_before_action :check_self_destruct!
skip_before_action :require_functional!
before_action :authenticate_user!

View File

@ -92,10 +92,18 @@ module CacheConcern
arguments
end
def attributes_for_database(record)
attributes = record.attributes_for_database
attributes.transform_values! { |attr| attr.is_a?(::ActiveModel::Type::Binary::Data) ? attr.to_s : attr }
attributes
if Rails.gem_version >= Gem::Version.new('7.0')
def attributes_for_database(record)
attributes = record.attributes_for_database
attributes.transform_values! { |attr| attr.is_a?(::ActiveModel::Type::Binary::Data) ? attr.to_s : attr }
attributes
end
else
def attributes_for_database(record)
attributes = record.instance_variable_get(:@attributes).send(:attributes).transform_values(&:value_for_database)
attributes.transform_values! { |attr| attr.is_a?(::ActiveModel::Type::Binary::Data) ? attr.to_s : attr }
attributes
end
end
def deserialize_record(class_name, attributes_from_database, new_record = false) # rubocop:disable Style/OptionalBooleanParameter

View File

@ -7,7 +7,6 @@ module ExportControllerConcern
before_action :authenticate_user!
before_action :load_export
skip_before_action :check_self_destruct!
skip_before_action :require_functional!
end

View File

@ -5,7 +5,6 @@ class Settings::ExportsController < Settings::BaseController
include Redisable
include Lockable
skip_before_action :check_self_destruct!
skip_before_action :require_functional!
def show

View File

@ -1,9 +1,6 @@
# frozen_string_literal: true
class Settings::LoginActivitiesController < Settings::BaseController
skip_before_action :check_self_destruct!
skip_before_action :require_functional!
def index
@login_activities = LoginActivity.where(user: current_user).order(id: :desc).page(params[:page])
end

View File

@ -3,7 +3,6 @@
module Settings
module TwoFactorAuthentication
class WebauthnCredentialsController < BaseController
skip_before_action :check_self_destruct!
skip_before_action :require_functional!
before_action :require_otp_enabled

View File

@ -4,7 +4,6 @@ module Settings
class TwoFactorAuthenticationMethodsController < BaseController
include ChallengableConcern
skip_before_action :check_self_destruct!
skip_before_action :require_functional!
before_action :require_challenge!, only: :disable

View File

@ -1,14 +0,0 @@
# frozen_string_literal: true
module SelfDestructHelper
def self.self_destruct?
value = ENV.fetch('SELF_DESTRUCT', nil)
value.present? && Rails.application.message_verifier('self-destruct').verify(value) == ENV['LOCAL_DOMAIN']
rescue ActiveSupport::MessageVerifier::InvalidSignature
false
end
def self_destruct?
SelfDestructHelper.self_destruct?
end
end

View File

@ -1,3 +0,0 @@
// eslint-disable-next-line import/no-anonymous-default-export
export default 'SvgrURL';
export const ReactComponent = 'div';

View File

@ -1,7 +1,6 @@
import { render, fireEvent, screen } from '@testing-library/react';
import renderer from 'react-test-renderer';
import { render, fireEvent, screen } from 'mastodon/test_helpers';
import { Button } from '../button';
describe('<Button />', () => {

View File

@ -18,6 +18,7 @@ import { Avatar } from './avatar';
import { Button } from './button';
import { FollowersCounter } from './counters';
import { DisplayName } from './display_name';
import { IconButton } from './icon_button';
import { RelativeTimestamp } from './relative_timestamp';
const messages = defineMessages({
@ -44,7 +45,10 @@ class Account extends ImmutablePureComponent {
intl: PropTypes.object.isRequired,
hidden: PropTypes.bool,
minimal: PropTypes.bool,
actionIcon: PropTypes.string,
actionTitle: PropTypes.string,
defaultAction: PropTypes.string,
onActionClick: PropTypes.func,
withBio: PropTypes.bool,
};
@ -72,8 +76,12 @@ class Account extends ImmutablePureComponent {
this.props.onMuteNotifications(this.props.account, false);
};
handleAction = () => {
this.props.onActionClick(this.props.account);
};
render () {
const { account, intl, hidden, withBio, defaultAction, size, minimal } = this.props;
const { account, intl, hidden, withBio, onActionClick, actionIcon, actionTitle, defaultAction, size, minimal } = this.props;
if (!account) {
return <EmptyAccount size={size} minimal={minimal} />;
@ -90,7 +98,9 @@ class Account extends ImmutablePureComponent {
let buttons;
if (account.get('id') !== me && account.get('relationship', null) !== null) {
if (actionIcon && onActionClick) {
buttons = <IconButton icon={actionIcon} title={actionTitle} onClick={this.handleAction} />;
} else if (!actionIcon && account.get('id') !== me && account.get('relationship', null) !== null) {
const following = account.getIn(['relationship', 'following']);
const requested = account.getIn(['relationship', 'requested']);
const blocking = account.getIn(['relationship', 'blocking']);

View File

@ -7,8 +7,6 @@ import classNames from 'classnames';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as LinkIcon } from '@material-symbols/svg-600/outlined/link.svg';
import { Icon } from 'mastodon/components/icon';
const filename = url => url.split('/').pop().split('#')[0].split('?')[0];
@ -27,7 +25,7 @@ export default class AttachmentList extends ImmutablePureComponent {
<div className={classNames('attachment-list', { compact })}>
{!compact && (
<div className='attachment-list__icon'>
<Icon id='link' icon={LinkIcon} />
<Icon id='link' />
</div>
)}
@ -38,7 +36,7 @@ export default class AttachmentList extends ImmutablePureComponent {
return (
<li key={attachment.get('id')}>
<a href={displayUrl} target='_blank' rel='noopener noreferrer'>
{compact && <Icon id='link' icon={LinkIcon} />}
{compact && <Icon id='link' />}
{compact && ' ' }
{displayUrl ? filename(displayUrl) : <FormattedMessage id='attachments_list.unprocessed' defaultMessage='(unprocessed)' />}
</a>

View File

@ -3,7 +3,7 @@ import { PureComponent } from 'react';
import { assetHost } from 'mastodon/utils/config';
import { unicodeMapping } from '../features/emoji/emoji_unicode_mapping_light';
import unicodeMapping from '../features/emoji/emoji_unicode_mapping_light';
export default class AutosuggestEmoji extends PureComponent {

View File

@ -2,9 +2,9 @@ import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { ReactComponent as GroupsIcon } from '@material-symbols/svg-600/outlined/group.svg';
import { ReactComponent as PersonIcon } from '@material-symbols/svg-600/outlined/person.svg';
import { ReactComponent as SmartToyIcon } from '@material-symbols/svg-600/outlined/smart_toy.svg';
import { ReactComponent as GroupsIcon } from '@material-design-icons/svg/outlined/group.svg';
import { ReactComponent as PersonIcon } from '@material-design-icons/svg/outlined/person.svg';
import { ReactComponent as SmartToyIcon } from '@material-design-icons/svg/outlined/smart_toy.svg';
export const Badge = ({ icon, label, domain }) => (

View File

@ -0,0 +1,13 @@
export const Check: React.FC = () => (
<svg
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 20 20'
fill='currentColor'
>
<path
fillRule='evenodd'
d='M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z'
clipRule='evenodd'
/>
</svg>
);

View File

@ -0,0 +1,63 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import { createPortal } from 'react-dom';
import { FormattedMessage } from 'react-intl';
import { withRouter } from 'react-router-dom';
import { Icon } from 'mastodon/components/icon';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
class ColumnBackButton extends PureComponent {
static propTypes = {
multiColumn: PropTypes.bool,
onClick: PropTypes.func,
...WithRouterPropTypes,
};
handleClick = () => {
const { onClick, history } = this.props;
if (onClick) {
onClick();
} else if (history.location?.state?.fromMastodon) {
history.goBack();
} else {
history.push('/');
}
};
render () {
const { multiColumn } = this.props;
const component = (
<button onClick={this.handleClick} className='column-back-button'>
<Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
</button>
);
if (multiColumn) {
return component;
} else {
// The portal container and the component may be rendered to the DOM in
// the same React render pass, so the container might not be available at
// the time `render()` is called.
const container = document.getElementById('tabs-bar__portal');
if (container === null) {
// The container wasn't available, force a re-render so that the
// component can eventually be inserted in the container and not scroll
// with the rest of the area.
this.forceUpdate();
return component;
} else {
return createPortal(component, container);
}
}
}
}
export default withRouter(ColumnBackButton);

View File

@ -1,45 +0,0 @@
import { useCallback } from 'react';
import { FormattedMessage } from 'react-intl';
import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg';
import { Icon } from 'mastodon/components/icon';
import { ButtonInTabsBar } from 'mastodon/features/ui/util/columns_context';
import { useAppHistory } from './router';
type OnClickCallback = () => void;
function useHandleClick(onClick?: OnClickCallback) {
const history = useAppHistory();
return useCallback(() => {
if (onClick) {
onClick();
} else if (history.location.state?.fromMastodon) {
history.goBack();
} else {
history.push('/');
}
}, [history, onClick]);
}
export const ColumnBackButton: React.FC<{ onClick: OnClickCallback }> = ({
onClick,
}) => {
const handleClick = useHandleClick(onClick);
const component = (
<button onClick={handleClick} className='column-back-button'>
<Icon
id='chevron-left'
icon={ArrowBackIcon}
className='column-back-button__icon'
/>
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
</button>
);
return <ButtonInTabsBar>{component}</ButtonInTabsBar>;
};

View File

@ -0,0 +1,20 @@
import { FormattedMessage } from 'react-intl';
import { Icon } from 'mastodon/components/icon';
import ColumnBackButton from './column_back_button';
export default class ColumnBackButtonSlim extends ColumnBackButton {
render () {
return (
<div className='column-back-button--slim'>
<div role='button' tabIndex={0} onClick={this.handleClick} className='column-back-button column-back-button--slim-button'>
<Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
</div>
</div>
);
}
}

View File

@ -1,24 +1,15 @@
import PropTypes from 'prop-types';
import { PureComponent, useCallback } from 'react';
import { PureComponent } from 'react';
import { createPortal } from 'react-dom';
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
import classNames from 'classnames';
import { withRouter } from 'react-router-dom';
import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg';
import { ReactComponent as ChevronLeftIcon } from '@material-symbols/svg-600/outlined/chevron_left.svg';
import { ReactComponent as ChevronRightIcon } from '@material-symbols/svg-600/outlined/chevron_right.svg';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { ReactComponent as TuneIcon } from '@material-symbols/svg-600/outlined/tune.svg';
import { Icon } from 'mastodon/components/icon';
import { ButtonInTabsBar, useColumnsContext } from 'mastodon/features/ui/util/columns_context';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
import { useAppHistory } from './router';
const messages = defineMessages({
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' },
@ -26,34 +17,6 @@ const messages = defineMessages({
moveRight: { id: 'column_header.moveRight_settings', defaultMessage: 'Move column to the right' },
});
const BackButton = ({ pinned, show }) => {
const history = useAppHistory();
const { multiColumn } = useColumnsContext();
const handleBackClick = useCallback(() => {
if (history.location?.state?.fromMastodon) {
history.goBack();
} else {
history.push('/');
}
}, [history]);
const showButton = history && !pinned && ((multiColumn && history.location?.state?.fromMastodon) || show);
if(!showButton) return null;
return (<button onClick={handleBackClick} className='column-header__back-button'>
<Icon id='chevron-left' icon={ArrowBackIcon} className='column-back-button__icon' />
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
</button>);
};
BackButton.propTypes = {
pinned: PropTypes.bool,
show: PropTypes.bool,
};
class ColumnHeader extends PureComponent {
static contextTypes = {
@ -64,7 +27,6 @@ class ColumnHeader extends PureComponent {
intl: PropTypes.object.isRequired,
title: PropTypes.node,
icon: PropTypes.string,
iconComponent: PropTypes.func,
active: PropTypes.bool,
multiColumn: PropTypes.bool,
extraButton: PropTypes.node,
@ -102,6 +64,16 @@ class ColumnHeader extends PureComponent {
this.props.onMove(1);
};
handleBackClick = () => {
const { history } = this.props;
if (history.location?.state?.fromMastodon) {
history.goBack();
} else {
history.push('/');
}
};
handleTransitionEnd = () => {
this.setState({ animating: false });
};
@ -115,7 +87,7 @@ class ColumnHeader extends PureComponent {
};
render () {
const { title, icon, iconComponent, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues } = this.props;
const { title, icon, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues, history } = this.props;
const { collapsed, animating } = this.state;
const wrapperClassName = classNames('column-header__wrapper', {
@ -146,19 +118,26 @@ class ColumnHeader extends PureComponent {
}
if (multiColumn && pinned) {
pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='times' icon={CloseIcon} /> <FormattedMessage id='column_header.unpin' defaultMessage='Unpin' /></button>;
pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='times' /> <FormattedMessage id='column_header.unpin' defaultMessage='Unpin' /></button>;
moveButtons = (
<div key='move-buttons' className='column-header__setting-arrows'>
<button title={formatMessage(messages.moveLeft)} aria-label={formatMessage(messages.moveLeft)} className='icon-button column-header__setting-btn' onClick={this.handleMoveLeft}><Icon id='chevron-left' icon={ChevronLeftIcon} /></button>
<button title={formatMessage(messages.moveRight)} aria-label={formatMessage(messages.moveRight)} className='icon-button column-header__setting-btn' onClick={this.handleMoveRight}><Icon id='chevron-right' icon={ChevronRightIcon} /></button>
<button title={formatMessage(messages.moveLeft)} aria-label={formatMessage(messages.moveLeft)} className='icon-button column-header__setting-btn' onClick={this.handleMoveLeft}><Icon id='chevron-left' /></button>
<button title={formatMessage(messages.moveRight)} aria-label={formatMessage(messages.moveRight)} className='icon-button column-header__setting-btn' onClick={this.handleMoveRight}><Icon id='chevron-right' /></button>
</div>
);
} else if (multiColumn && this.props.onPin) {
pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='plus' icon={AddIcon} /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>;
pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='plus' /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>;
}
backButton = <BackButton pinned={pinned} show={showBackButton} />;
if (!pinned && ((multiColumn && history.location?.state?.fromMastodon) || showBackButton)) {
backButton = (
<button onClick={this.handleBackClick} className='column-header__back-button'>
<Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
</button>
);
}
const collapsedContent = [
extraContent,
@ -178,21 +157,21 @@ class ColumnHeader extends PureComponent {
onClick={this.handleToggleClick}
>
<i className='icon-with-badge'>
<Icon id='sliders' icon={TuneIcon} />
<Icon id='sliders' />
{collapseIssues && <i className='icon-with-badge__issue-badge' />}
</i>
</button>
);
}
const hasTitle = (icon || iconComponent) && title;
const hasTitle = icon && title;
const component = (
<div className={wrapperClassName}>
<h1 className={buttonClassName}>
{hasTitle && (
<button onClick={this.handleTitleClick}>
<Icon id={icon} icon={iconComponent} className='column-header__icon' />
<Icon id={icon} fixedWidth className='column-header__icon' />
{title}
</button>
)}
@ -216,12 +195,22 @@ class ColumnHeader extends PureComponent {
</div>
);
if (placeholder) {
if (multiColumn || placeholder) {
return component;
} else {
return (<ButtonInTabsBar>
{component}
</ButtonInTabsBar>);
// The portal container and the component may be rendered to the DOM in
// the same React render pass, so the container might not be available at
// the time `render()` is called.
const container = document.getElementById('tabs-bar__portal');
if (container === null) {
// The container wasn't available, force a re-render so that the
// component can eventually be inserted in the container and not scroll
// with the rest of the area.
this.forceUpdate();
return component;
} else {
return createPortal(component, container);
}
}
}

View File

@ -3,8 +3,6 @@ import { useCallback, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { bannerSettings } from 'mastodon/settings';
import { IconButton } from './icon_button';
@ -38,7 +36,6 @@ export const DismissableBanner: React.FC<PropsWithChildren<Props>> = ({
<div className='dismissable-banner__action'>
<IconButton
icon='times'
iconComponent={CloseIcon}
title={intl.formatMessage(messages.dismiss)}
onClick={handleDismiss}
/>

View File

@ -2,8 +2,6 @@ import { useCallback } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { ReactComponent as LockOpenIcon } from '@material-symbols/svg-600/outlined/lock_open.svg';
import { IconButton } from './icon_button';
const messages = defineMessages({
@ -36,7 +34,6 @@ export const Domain: React.FC<Props> = ({ domain, onUnblockDomain }) => {
<IconButton
active
icon='unlock'
iconComponent={LockOpenIcon}
title={intl.formatMessage(messages.unblockDomain, { domain })}
onClick={handleDomainUnblock}
/>

View File

@ -6,7 +6,6 @@ import { withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { supportsPassiveEvents } from 'detect-passive-events';
import Overlay from 'react-overlays/Overlay';
@ -164,7 +163,6 @@ class Dropdown extends PureComponent {
static propTypes = {
children: PropTypes.node,
icon: PropTypes.string,
iconComponent: PropTypes.func,
items: PropTypes.oneOfType([PropTypes.array, ImmutablePropTypes.list]).isRequired,
loading: PropTypes.bool,
size: PropTypes.number,
@ -257,7 +255,7 @@ class Dropdown extends PureComponent {
};
findTarget = () => {
return this.target?.buttonRef?.current;
return this.target;
};
componentWillUnmount = () => {
@ -273,7 +271,6 @@ class Dropdown extends PureComponent {
render () {
const {
icon,
iconComponent,
items,
size,
title,
@ -294,11 +291,9 @@ class Dropdown extends PureComponent {
onMouseDown: this.handleMouseDown,
onKeyDown: this.handleButtonKeyDown,
onKeyPress: this.handleKeyPress,
ref: this.setTargetRef,
}) : (
<IconButton
icon={!open ? icon : 'close'}
iconComponent={!open ? iconComponent : CloseIcon}
title={title}
active={open}
disabled={disabled}
@ -307,14 +302,14 @@ class Dropdown extends PureComponent {
onMouseDown={this.handleMouseDown}
onKeyDown={this.handleButtonKeyDown}
onKeyPress={this.handleKeyPress}
ref={this.setTargetRef}
/>
);
return (
<>
{button}
<span ref={this.setTargetRef}>
{button}
</span>
<Overlay show={open} offset={[5, 5]} placement={'bottom'} flip target={this.findTarget} popperConfig={{ strategy: 'fixed' }}>
{({ props, arrowProps, placement }) => (
<div {...props}>

View File

@ -5,8 +5,6 @@ import { FormattedMessage, injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { ReactComponent as ArrowDropDownIcon } from '@material-symbols/svg-600/outlined/arrow_drop_down.svg';
import { openModal } from 'mastodon/actions/modal';
import { Icon } from 'mastodon/components/icon';
import InlineAccount from 'mastodon/components/inline_account';
@ -68,7 +66,7 @@ class EditedTimestamp extends PureComponent {
return (
<DropdownMenu statusId={statusId} renderItem={this.renderItem} scrollable renderHeader={this.renderHeader} onItemClick={this.handleItemClick}>
<button className='dropdown-menu__text-button'>
<FormattedMessage id='status.edited' defaultMessage='Edited {date}' values={{ date: intl.formatDate(timestamp, { hour12: false, month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) }} /> <Icon id='caret-down' icon={ArrowDropDownIcon} />
<FormattedMessage id='status.edited' defaultMessage='Edited {date}' values={{ date: intl.formatDate(timestamp, { hour12: false, month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) }} /> <Icon id='caret-down' />
</button>
</DropdownMenu>
);

View File

@ -1,52 +1,20 @@
import classNames from 'classnames';
import { ReactComponent as CheckBoxOutlineBlankIcon } from '@material-symbols/svg-600/outlined/check_box_outline_blank.svg';
interface SVGPropsWithTitle extends React.SVGProps<SVGSVGElement> {
title?: string;
}
export type IconProp = React.FC<SVGPropsWithTitle>;
interface Props extends React.SVGProps<SVGSVGElement> {
children?: never;
interface Props extends React.HTMLAttributes<HTMLImageElement> {
id: string;
icon: IconProp;
title?: string;
className?: string;
fixedWidth?: boolean;
children?: never;
}
export const Icon: React.FC<Props> = ({
id,
icon: IconComponent,
className,
title: titleProp,
fixedWidth,
...other
}) => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!IconComponent) {
if (process.env.NODE_ENV !== 'production') {
throw new Error(
`<Icon id="${id}" className="${className}"> is missing an "icon" prop.`,
);
}
IconComponent = CheckBoxOutlineBlankIcon;
}
const ariaHidden = titleProp ? undefined : true;
const role = !ariaHidden ? 'img' : undefined;
// Set the title to an empty string to remove the built-in SVG one if any
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const title = titleProp || '';
return (
<IconComponent
className={classNames('icon', `icon-${id}`, className)}
title={title}
aria-hidden={ariaHidden}
role={role}
{...other}
/>
);
};
}) => (
<i
className={classNames('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })}
{...other}
/>
);

View File

@ -1,20 +1,19 @@
import { PureComponent, createRef } from 'react';
import { PureComponent } from 'react';
import classNames from 'classnames';
import { AnimatedNumber } from './animated_number';
import type { IconProp } from './icon';
import { Icon } from './icon';
interface Props {
className?: string;
title: string;
icon: string;
iconComponent: IconProp;
onClick?: React.MouseEventHandler<HTMLButtonElement>;
onMouseDown?: React.MouseEventHandler<HTMLButtonElement>;
onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;
onKeyPress?: React.KeyboardEventHandler<HTMLButtonElement>;
size: number;
active: boolean;
expanded?: boolean;
style?: React.CSSProperties;
@ -33,9 +32,8 @@ interface States {
deactivate: boolean;
}
export class IconButton extends PureComponent<Props, States> {
buttonRef = createRef<HTMLButtonElement>();
static defaultProps = {
size: 18,
active: false,
disabled: false,
animate: false,
@ -87,6 +85,10 @@ export class IconButton extends PureComponent<Props, States> {
render() {
const style = {
fontSize: `${this.props.size}px`,
width: `${this.props.size * 1.28571429}px`,
height: `${this.props.size * 1.28571429}px`,
lineHeight: `${this.props.size}px`,
...this.props.style,
...(this.props.active ? this.props.activeStyle : {}),
};
@ -97,7 +99,6 @@ export class IconButton extends PureComponent<Props, States> {
disabled,
expanded,
icon,
iconComponent,
inverted,
overlay,
tabIndex,
@ -119,9 +120,13 @@ export class IconButton extends PureComponent<Props, States> {
'icon-button--with-counter': typeof counter !== 'undefined',
});
if (typeof counter !== 'undefined') {
style.width = 'auto';
}
let contents = (
<>
<Icon id={icon} icon={iconComponent} aria-hidden='true' />{' '}
<Icon id={icon} fixedWidth aria-hidden='true' />{' '}
{typeof counter !== 'undefined' && (
<span className='icon-button__counter'>
<AnimatedNumber value={counter} />
@ -153,7 +158,6 @@ export class IconButton extends PureComponent<Props, States> {
style={style}
tabIndex={tabIndex}
disabled={disabled}
ref={this.buttonRef}
>
{contents}
</button>

View File

@ -1,24 +1,21 @@
import type { IconProp } from './icon';
import { Icon } from './icon';
const formatNumber = (num: number): number | string => (num > 40 ? '40+' : num);
interface Props {
id: string;
icon: IconProp;
count: number;
issueBadge: boolean;
className: string;
}
export const IconWithBadge: React.FC<Props> = ({
id,
icon,
count,
issueBadge,
className,
}) => (
<i className='icon-with-badge'>
<Icon id={id} icon={icon} className={className} />
<Icon id={id} fixedWidth className={className} />
{count > 0 && (
<i className='icon-with-badge__badge'>{formatNumber(count)}</i>
)}

View File

@ -2,8 +2,6 @@ import { useCallback } from 'react';
import { useIntl, defineMessages } from 'react-intl';
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
import { Icon } from 'mastodon/components/icon';
const messages = defineMessages({
@ -30,7 +28,7 @@ export const LoadGap: React.FC<Props> = ({ disabled, maxId, onClick }) => {
onClick={handleClick}
aria-label={intl.formatMessage(messages.load_more)}
>
<Icon id='ellipsis-h' icon={MoreHorizIcon} />
<Icon id='ellipsis-h' />
</button>
);
};

View File

@ -8,7 +8,6 @@ import classNames from 'classnames';
import { is } from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
import { debounce } from 'lodash';
import { Blurhash } from 'mastodon/components/blurhash';
@ -324,7 +323,7 @@ class MediaGallery extends PureComponent {
</button>
);
} else if (visible) {
spoilerButton = <IconButton title={intl.formatMessage(messages.toggle_visible, { number: size })} icon='eye-slash' iconComponent={VisibilityOffIcon} overlay onClick={this.handleOpen} ariaHidden />;
spoilerButton = <IconButton title={intl.formatMessage(messages.toggle_visible, { number: size })} icon='eye-slash' overlay onClick={this.handleOpen} ariaHidden />;
} else {
spoilerButton = (
<button type='button' onClick={this.handleOpen} className='spoiler-button__overlay'>

View File

@ -5,8 +5,6 @@ import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { ReactComponent as CancelPresentationIcon } from '@material-symbols/svg-600/outlined/cancel_presentation.svg';
import { removePictureInPicture } from 'mastodon/actions/picture_in_picture';
import { Icon } from 'mastodon/components/icon';
@ -27,7 +25,7 @@ class PictureInPicturePlaceholder extends PureComponent {
return (
<div className='picture-in-picture-placeholder' style={{ aspectRatio }} role='button' tabIndex={0} onClick={this.handleClick}>
<Icon id='window-restore' icon={CancelPresentationIcon} />
<Icon id='window-restore' />
<FormattedMessage id='picture_in_picture.restore' defaultMessage='Put it back' />
</div>
);

View File

@ -7,7 +7,6 @@ import classNames from 'classnames';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
import escapeTextContentForBrowser from 'escape-html';
import spring from 'react-motion/lib/spring';
@ -193,7 +192,7 @@ class Poll extends ImmutablePureComponent {
/>
{!!voted && <span className='poll__voted'>
<Icon id='check' icon={CheckIcon} className='poll__voted__mark' title={intl.formatMessage(messages.voted)} />
<Icon id='check' className='poll__voted__mark' title={intl.formatMessage(messages.voted)} />
</span>}
</label>

View File

@ -1,13 +1,9 @@
import type { PropsWithChildren } from 'react';
import React from 'react';
import { Router as OriginalRouter, useHistory } from 'react-router';
import { Router as OriginalRouter } from 'react-router';
import type {
LocationDescriptor,
LocationDescriptorObject,
Path,
} from 'history';
import type { LocationDescriptor, Path } from 'history';
import { createBrowserHistory } from 'history';
import { layoutFromWindow } from 'mastodon/is_mobile';
@ -16,68 +12,47 @@ interface MastodonLocationState {
fromMastodon?: boolean;
mastodonModalKey?: string;
}
type HistoryPath = Path | LocationDescriptor<MastodonLocationState>;
type LocationState = MastodonLocationState | null | undefined;
type HistoryPath = Path | LocationDescriptor<LocationState>;
const browserHistory = createBrowserHistory<LocationState>();
const browserHistory = createBrowserHistory<
MastodonLocationState | undefined
>();
const originalPush = browserHistory.push.bind(browserHistory);
const originalReplace = browserHistory.replace.bind(browserHistory);
export function useAppHistory() {
return useHistory<LocationState>();
}
function normalizePath(
path: HistoryPath,
state?: LocationState,
): LocationDescriptorObject<LocationState> {
const location = typeof path === 'string' ? { pathname: path } : { ...path };
if (location.state === undefined && state !== undefined) {
location.state = state;
} else if (
location.state !== undefined &&
state !== undefined &&
process.env.NODE_ENV === 'development'
) {
// eslint-disable-next-line no-console
console.log(
'You should avoid providing a 2nd state argument to push when the 1st argument is a location-like object that already has state; it is ignored',
);
}
if (
layoutFromWindow() === 'multi-column' &&
!location.pathname?.startsWith('/deck')
) {
location.pathname = `/deck${location.pathname}`;
}
return location;
function extractRealPath(path: HistoryPath) {
if (typeof path === 'string') return path;
else return path.pathname;
}
browserHistory.push = (path: HistoryPath, state?: MastodonLocationState) => {
const location = normalizePath(path, state);
state = state ?? {};
state.fromMastodon = true;
location.state = location.state ?? {};
location.state.fromMastodon = true;
const realPath = extractRealPath(path);
if (!realPath) return;
originalPush(location);
if (layoutFromWindow() === 'multi-column' && !realPath.startsWith('/deck')) {
originalPush(`/deck${realPath}`, state);
} else {
originalPush(path, state);
}
};
browserHistory.replace = (path: HistoryPath, state?: MastodonLocationState) => {
const location = normalizePath(path, state);
if (!location.pathname) return;
if (browserHistory.location.state?.fromMastodon) {
location.state = location.state ?? {};
location.state.fromMastodon = true;
state = state ?? {};
state.fromMastodon = true;
}
originalReplace(location);
const realPath = extractRealPath(path);
if (!realPath) return;
if (layoutFromWindow() === 'multi-column' && !realPath.startsWith('/deck')) {
originalReplace(`/deck${realPath}`, state);
} else {
originalReplace(path, state);
}
};
export const Router: React.FC<PropsWithChildren> = ({ children }) => {

View File

@ -7,10 +7,6 @@ import classNames from 'classnames';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
import { ReactComponent as PushPinIcon } from '@material-symbols/svg-600/outlined/push_pin.svg';
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
import { HotKeys } from 'react-hotkeys';
import { Icon } from 'mastodon/components/icon';
@ -31,7 +27,6 @@ import { getHashtagBarForStatus } from './hashtag_bar';
import { RelativeTimestamp } from './relative_timestamp';
import StatusActionBar from './status_action_bar';
import StatusContent from './status_content';
import { VisibilityIcon } from './visibility_icon';
const domParser = new DOMParser();
@ -410,7 +405,7 @@ class Status extends ImmutablePureComponent {
if (featured) {
prepend = (
<div className='status__prepend'>
<div className='status__prepend-icon-wrapper'><Icon id='thumb-tack' icon={PushPinIcon} className='status__prepend-icon' /></div>
<div className='status__prepend-icon-wrapper'><Icon id='thumb-tack' className='status__prepend-icon' fixedWidth /></div>
<FormattedMessage id='status.pinned' defaultMessage='Pinned post' />
</div>
);
@ -419,7 +414,7 @@ class Status extends ImmutablePureComponent {
prepend = (
<div className='status__prepend'>
<div className='status__prepend-icon-wrapper'><Icon id='retweet' icon={RepeatIcon} className='status__prepend-icon' /></div>
<div className='status__prepend-icon-wrapper'><Icon id='retweet' className='status__prepend-icon' fixedWidth /></div>
<FormattedMessage id='status.reblogged_by' defaultMessage='{name} boosted' values={{ name: <a onClick={this.handlePrependAccountClick} data-id={status.getIn(['account', 'id'])} href={`/@${status.getIn(['account', 'acct'])}`} className='status__display-name muted'><bdi><strong dangerouslySetInnerHTML={display_name_html} /></bdi></a> }} />
</div>
);
@ -431,7 +426,7 @@ class Status extends ImmutablePureComponent {
} else if (status.get('visibility') === 'direct') {
prepend = (
<div className='status__prepend'>
<div className='status__prepend-icon-wrapper'><Icon id='at' icon={AlternateEmailIcon} className='status__prepend-icon' /></div>
<div className='status__prepend-icon-wrapper'><Icon id='at' className='status__prepend-icon' fixedWidth /></div>
<FormattedMessage id='status.direct_indicator' defaultMessage='Private mention' />
</div>
);
@ -440,7 +435,7 @@ class Status extends ImmutablePureComponent {
prepend = (
<div className='status__prepend'>
<div className='status__prepend-icon-wrapper'><Icon id='reply' icon={ReplyIcon} className='status__prepend-icon' /></div>
<div className='status__prepend-icon-wrapper'><Icon id='reply' className='status__prepend-icon' fixedWidth /></div>
<FormattedMessage id='status.replied_to' defaultMessage='Replied to {name}' values={{ name: <a onClick={this.handlePrependAccountClick} data-id={status.getIn(['account', 'id'])} href={`/@${status.getIn(['account', 'acct'])}`} className='status__display-name muted'><bdi><strong dangerouslySetInnerHTML={display_name_html} /></bdi></a> }} />
</div>
);
@ -539,6 +534,15 @@ class Status extends ImmutablePureComponent {
statusAvatar = <AvatarOverlay account={status.get('account')} friend={account} />;
}
const visibilityIconInfo = {
'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) },
'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) },
'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
};
const visibilityIcon = visibilityIconInfo[status.get('visibility')];
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
const expanded = !status.get('hidden') || status.get('spoiler_text').length === 0;
@ -553,7 +557,7 @@ class Status extends ImmutablePureComponent {
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
<div onClick={this.handleClick} className='status__info'>
<a href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
<span className='status__visibility-icon'><VisibilityIcon visibility={status.get('visibility')} /></span>
<span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span>
<RelativeTimestamp timestamp={status.get('created_at')} />{status.get('edited_at') && <abbr title={intl.formatMessage(messages.edited, { date: intl.formatDate(status.get('edited_at'), { hour12: false, year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) })}> *</abbr>}
</a>

View File

@ -9,16 +9,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as BookmarkIcon } from '@material-symbols/svg-600/outlined/bookmark-fill.svg';
import { ReactComponent as BookmarkBorderIcon } from '@material-symbols/svg-600/outlined/bookmark.svg';
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
import { ReactComponent as ReplyAllIcon } from '@material-symbols/svg-600/outlined/reply_all.svg';
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
import { ReactComponent as StarBorderIcon } from '@material-symbols/svg-600/outlined/star.svg';
import { ReactComponent as VisibilityIcon } from '@material-symbols/svg-600/outlined/visibility.svg';
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
@ -346,15 +336,12 @@ class StatusActionBar extends ImmutablePureComponent {
}
let replyIcon;
let replyIconComponent;
let replyTitle;
if (status.get('in_reply_to_id', null) === null) {
replyIcon = 'reply';
replyIconComponent = ReplyIcon;
replyTitle = intl.formatMessage(messages.reply);
} else {
replyIcon = 'reply-all';
replyIconComponent = ReplyAllIcon;
replyTitle = intl.formatMessage(messages.replyAll);
}
@ -372,29 +359,29 @@ class StatusActionBar extends ImmutablePureComponent {
}
const filterButton = this.props.onFilter && (
<IconButton className='status__action-bar__button' title={intl.formatMessage(messages.hide)} icon='eye' iconComponent={VisibilityIcon} onClick={this.handleHideClick} />
<IconButton className='status__action-bar__button' title={intl.formatMessage(messages.hide)} icon='eye' onClick={this.handleHideClick} />
);
const isReply = status.get('in_reply_to_account_id') === status.getIn(['account', 'id']);
return (
<div className='status__action-bar'>
<IconButton className='status__action-bar__button' title={replyTitle} icon={isReply ? 'reply' : replyIcon} iconComponent={isReply ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
<IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
<IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
<IconButton className='status__action-bar__button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} />
<IconButton className='status__action-bar__button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
<IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
<IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
<IconButton className='status__action-bar__button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />
{filterButton}
<DropdownMenuContainer
scrollKey={scrollKey}
status={status}
items={menu}
icon='ellipsis-h'
iconComponent={MoreHorizIcon}
direction='right'
title={intl.formatMessage(messages.more)}
/>
<div className='status__action-bar__dropdown'>
<DropdownMenuContainer
scrollKey={scrollKey}
status={status}
items={menu}
icon='ellipsis-h'
size={18}
direction='right'
title={intl.formatMessage(messages.more)}
/>
</div>
</div>
);
}

View File

@ -9,8 +9,6 @@ import { Link, withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { ReactComponent as ChevronRightIcon } from '@material-symbols/svg-600/outlined/chevron_right.svg';
import { Icon } from 'mastodon/components/icon';
import PollContainer from 'mastodon/containers/poll_container';
import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state';
@ -259,7 +257,7 @@ class StatusContent extends PureComponent {
const readMoreButton = renderReadMore && (
<button className='status__content__read-more-button' onClick={this.props.onClick} key='read-more'>
<FormattedMessage id='status.read_more' defaultMessage='Read more' /><Icon id='angle-right' icon={ChevronRightIcon} />
<FormattedMessage id='status.read_more' defaultMessage='Read more' /><Icon id='angle-right' fixedWidth />
</button>
);

View File

@ -1,5 +1,3 @@
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
import { Icon } from './icon';
const domParser = new DOMParser();
@ -23,7 +21,7 @@ interface Props {
}
export const VerifiedBadge: React.FC<Props> = ({ link }) => (
<span className='verified-badge'>
<Icon id='check' icon={CheckIcon} className='verified-badge__mark' />
<Icon id='check' className='verified-badge__mark' />
<span dangerouslySetInnerHTML={stripRelMe(link)} />
</span>
);

View File

@ -1,62 +0,0 @@
import { defineMessages, useIntl } from 'react-intl';
import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
import { ReactComponent as LockIcon } from '@material-symbols/svg-600/outlined/lock.svg';
import { ReactComponent as LockOpenIcon } from '@material-symbols/svg-600/outlined/lock_open.svg';
import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
import { Icon } from './icon';
type Visibility = 'public' | 'unlisted' | 'private' | 'direct';
const messages = defineMessages({
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
private_short: {
id: 'privacy.private.short',
defaultMessage: 'Followers only',
},
direct_short: {
id: 'privacy.direct.short',
defaultMessage: 'Mentioned people only',
},
});
export const VisibilityIcon: React.FC<{ visibility: Visibility }> = ({
visibility,
}) => {
const intl = useIntl();
const visibilityIconInfo = {
public: {
icon: 'globe',
iconComponent: PublicIcon,
text: intl.formatMessage(messages.public_short),
},
unlisted: {
icon: 'unlock',
iconComponent: LockOpenIcon,
text: intl.formatMessage(messages.unlisted_short),
},
private: {
icon: 'lock',
iconComponent: LockIcon,
text: intl.formatMessage(messages.private_short),
},
direct: {
icon: 'at',
iconComponent: AlternateEmailIcon,
text: intl.formatMessage(messages.direct_short),
},
};
const visibilityIcon = visibilityIconInfo[visibility];
return (
<Icon
id={visibilityIcon.icon}
icon={visibilityIcon.iconComponent}
title={visibilityIcon.text}
/>
);
};

View File

@ -10,9 +10,6 @@ import { List as ImmutableList } from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { ReactComponent as ChevronRightIcon } from '@material-symbols/svg-600/outlined/chevron_right.svg';
import { ReactComponent as ExpandMoreIcon } from '@material-symbols/svg-600/outlined/expand_more.svg';
import { fetchServer, fetchExtendedDescription, fetchDomainBlocks } from 'mastodon/actions/server';
import Column from 'mastodon/components/column';
import { Icon } from 'mastodon/components/icon';
@ -76,7 +73,7 @@ class Section extends PureComponent {
return (
<div className={classNames('about__section', { active: !collapsed })}>
<div className='about__section__title' role='button' tabIndex={0} onClick={this.handleClick}>
<Icon id={collapsed ? 'chevron-right' : 'chevron-down'} icon={collapsed ? ChevronRightIcon : ExpandMoreIcon} /> {title}
<Icon id={collapsed ? 'chevron-right' : 'chevron-down'} fixedWidth /> {title}
</div>
{!collapsed && (

View File

@ -3,9 +3,6 @@ import { FormattedMessage } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { Icon } from 'mastodon/components/icon';
export default class FollowRequestNote extends ImmutablePureComponent {
@ -25,12 +22,12 @@ export default class FollowRequestNote extends ImmutablePureComponent {
<div className='follow-request-banner__action'>
<button type='button' className='button button-tertiary button--confirmation' onClick={onAuthorize}>
<Icon id='check' icon={CheckIcon} />
<Icon id='check' fixedWidth />
<FormattedMessage id='follow_request.authorize' defaultMessage='Authorize' />
</button>
<button type='button' className='button button-tertiary button--destructive' onClick={onReject}>
<Icon id='times' icon={CloseIcon} />
<Icon id='times' fixedWidth />
<FormattedMessage id='follow_request.reject' defaultMessage='Reject' />
</button>
</div>

View File

@ -9,12 +9,6 @@ import { NavLink, withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
import { ReactComponent as LockIcon } from '@material-symbols/svg-600/outlined/lock.svg';
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications.svg';
import { ReactComponent as NotificationsActiveIcon } from '@material-symbols/svg-600/outlined/notifications_active-fill.svg';
import { Avatar } from 'mastodon/components/avatar';
import { Badge, AutomatedBadge, GroupBadge } from 'mastodon/components/badge';
import { Button } from 'mastodon/components/button';
@ -264,7 +258,7 @@ class Header extends ImmutablePureComponent {
}
if (account.getIn(['relationship', 'requested']) || account.getIn(['relationship', 'following'])) {
bellBtn = <IconButton icon={account.getIn(['relationship', 'notifying']) ? 'bell' : 'bell-o'} iconComponent={account.getIn(['relationship', 'notifying']) ? NotificationsActiveIcon : NotificationsIcon} active={account.getIn(['relationship', 'notifying'])} title={intl.formatMessage(account.getIn(['relationship', 'notifying']) ? messages.disableNotifications : messages.enableNotifications, { name: account.get('username') })} onClick={this.props.onNotifyToggle} />;
bellBtn = <IconButton icon={account.getIn(['relationship', 'notifying']) ? 'bell' : 'bell-o'} size={24} active={account.getIn(['relationship', 'notifying'])} title={intl.formatMessage(account.getIn(['relationship', 'notifying']) ? messages.disableNotifications : messages.enableNotifications, { name: account.get('username') })} onClick={this.props.onNotifyToggle} />;
}
if (me !== account.get('id')) {
@ -286,7 +280,7 @@ class Header extends ImmutablePureComponent {
}
if (account.get('locked')) {
lockedIcon = <Icon id='lock' icon={LockIcon} title={intl.formatMessage(messages.account_locked)} />;
lockedIcon = <Icon id='lock' title={intl.formatMessage(messages.account_locked)} />;
}
if (signedIn && account.get('id') !== me) {
@ -416,7 +410,7 @@ class Header extends ImmutablePureComponent {
</>
)}
<DropdownMenuContainer disabled={menu.length === 0} items={menu} icon='ellipsis-v' iconComponent={MoreHorizIcon} size={24} direction='right' />
<DropdownMenuContainer disabled={menu.length === 0} items={menu} icon='ellipsis-v' size={24} direction='right' />
</div>
)}
</div>
@ -454,7 +448,7 @@ class Header extends ImmutablePureComponent {
<dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} className='translate' />
<dd className='translate' title={pair.get('value_plain')}>
{pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' icon={CheckIcon} className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} />
{pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} />
</dd>
</dl>
))}

View File

@ -5,10 +5,6 @@ import classNames from 'classnames';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as AudiotrackIcon } from '@material-symbols/svg-600/outlined/music_note.svg';
import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow.svg';
import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
import { Blurhash } from 'mastodon/components/blurhash';
import { Icon } from 'mastodon/components/icon';
import { autoPlayGif, displayMedia, useBlurhash } from 'mastodon/initial_state';
@ -73,7 +69,7 @@ export default class MediaItem extends ImmutablePureComponent {
if (!visible) {
icon = (
<span className='account-gallery__item__icons'>
<Icon id='eye-slash' icon={VisibilityOffIcon} />
<Icon id='eye-slash' />
</span>
);
} else {
@ -88,9 +84,9 @@ export default class MediaItem extends ImmutablePureComponent {
);
if (attachment.get('type') === 'audio') {
label = <Icon id='music' icon={AudiotrackIcon} />;
label = <Icon id='music' />;
} else {
label = <Icon id='play' icon={PlayArrowIcon} />;
label = <Icon id='play' />;
}
} else if (attachment.get('type') === 'image') {
const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;

View File

@ -8,7 +8,7 @@ import { connect } from 'react-redux';
import { lookupAccount, fetchAccount } from 'mastodon/actions/accounts';
import { openModal } from 'mastodon/actions/modal';
import { ColumnBackButton } from 'mastodon/components/column_back_button';
import ColumnBackButton from 'mastodon/components/column_back_button';
import { LoadMore } from 'mastodon/components/load_more';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import ScrollContainer from 'mastodon/containers/scroll_container';
@ -203,7 +203,7 @@ class AccountGallery extends ImmutablePureComponent {
return (
<Column>
<ColumnBackButton />
<ColumnBackButton multiColumn={multiColumn} />
<ScrollContainer scrollKey='account_gallery'>
<div className='scrollable scrollable--flex' onScroll={this.handleScroll}>

View File

@ -16,7 +16,7 @@ import { getAccountHidden } from 'mastodon/selectors';
import { lookupAccount, fetchAccount } from '../../actions/accounts';
import { fetchFeaturedTags } from '../../actions/featured_tags';
import { expandAccountFeaturedTimeline, expandAccountTimeline, connectTimeline, disconnectTimeline } from '../../actions/timelines';
import { ColumnBackButton } from '../../components/column_back_button';
import ColumnBackButton from '../../components/column_back_button';
import { LoadingIndicator } from '../../components/loading_indicator';
import StatusList from '../../components/status_list';
import Column from '../ui/components/column';
@ -184,7 +184,7 @@ class AccountTimeline extends ImmutablePureComponent {
return (
<Column>
<ColumnBackButton />
<ColumnBackButton multiColumn={multiColumn} />
<StatusList
prepend={<HeaderContainer accountId={this.props.accountId} hideTabs={forceEmptyState} tagged={this.props.params.tagged} />}

View File

@ -7,12 +7,6 @@ import classNames from 'classnames';
import { is } from 'immutable';
import { ReactComponent as DownloadIcon } from '@material-symbols/svg-600/outlined/download.svg';
import { ReactComponent as PauseIcon } from '@material-symbols/svg-600/outlined/pause.svg';
import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow-fill.svg';
import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
import { ReactComponent as VolumeOffIcon } from '@material-symbols/svg-600/outlined/volume_off-fill.svg';
import { ReactComponent as VolumeUpIcon } from '@material-symbols/svg-600/outlined/volume_up-fill.svg';
import { throttle, debounce } from 'lodash';
import { Icon } from 'mastodon/components/icon';
@ -560,8 +554,8 @@ class Audio extends PureComponent {
<div className='video-player__controls active'>
<div className='video-player__buttons-bar'>
<div className='video-player__buttons left'>
<button type='button' title={intl.formatMessage(paused ? messages.play : messages.pause)} aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} className='player-button' onClick={this.togglePlay}><Icon id={paused ? 'play' : 'pause'} icon={paused ? PlayArrowIcon : PauseIcon} /></button>
<button type='button' title={intl.formatMessage(muted ? messages.unmute : messages.mute)} aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} className='player-button' onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} icon={muted ? VolumeOffIcon : VolumeUpIcon} /></button>
<button type='button' title={intl.formatMessage(paused ? messages.play : messages.pause)} aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} className='player-button' onClick={this.togglePlay}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>
<button type='button' title={intl.formatMessage(muted ? messages.unmute : messages.mute)} aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} className='player-button' onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
<div className={classNames('video-player__volume', { active: this.state.hovered })} ref={this.setVolumeRef} onMouseDown={this.handleVolumeMouseDown}>
<div className='video-player__volume__current' style={{ width: `${muted ? 0 : volume * 100}%`, backgroundColor: this._getAccentColor() }} />
@ -581,9 +575,9 @@ class Audio extends PureComponent {
</div>
<div className='video-player__buttons right'>
{!editable && <button type='button' title={intl.formatMessage(messages.hide)} aria-label={intl.formatMessage(messages.hide)} className='player-button' onClick={this.toggleReveal}><Icon id='eye-slash' icon={VisibilityOffIcon} /></button>}
{!editable && <button type='button' title={intl.formatMessage(messages.hide)} aria-label={intl.formatMessage(messages.hide)} className='player-button' onClick={this.toggleReveal}><Icon id='eye-slash' fixedWidth /></button>}
<a title={intl.formatMessage(messages.download)} aria-label={intl.formatMessage(messages.download)} className='video-player__download__icon player-button' href={this.props.src} download>
<Icon id={'download'} icon={DownloadIcon} />
<Icon id={'download'} fixedWidth />
</a>
</div>
</div>

View File

@ -6,10 +6,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as BlockIcon } from '@material-symbols/svg-600/outlined/block-fill.svg';
import { debounce } from 'lodash';
import { fetchBlocks, expandBlocks } from '../../actions/blocks';
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import { LoadingIndicator } from '../../components/loading_indicator';
import ScrollableList from '../../components/scrollable_list';
import AccountContainer from '../../containers/account_container';
@ -59,7 +59,8 @@ class Blocks extends ImmutablePureComponent {
const emptyMessage = <FormattedMessage id='empty_column.blocks' defaultMessage="You haven't blocked any users yet." />;
return (
<Column bindToDocument={!multiColumn} icon='ban' iconComponent={BlockIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
<Column bindToDocument={!multiColumn} icon='ban' heading={intl.formatMessage(messages.heading)}>
<ColumnBackButtonSlim />
<ScrollableList
scrollKey='blocks'
onLoadMore={this.handleLoadMore}

View File

@ -8,7 +8,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as BookmarksIcon } from '@material-symbols/svg-600/outlined/bookmarks-fill.svg';
import { debounce } from 'lodash';
import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'mastodon/actions/bookmarks';
@ -80,8 +79,7 @@ class Bookmarks extends ImmutablePureComponent {
return (
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.heading)}>
<ColumnHeader
icon='bookmarks'
iconComponent={BookmarksIcon}
icon='bookmark'
title={intl.formatMessage(messages.heading)}
onPin={this.handlePin}
onMove={this.handleMove}

View File

@ -7,8 +7,6 @@ import { Helmet } from 'react-helmet';
import { connect } from 'react-redux';
import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg';
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
import { domain } from 'mastodon/initial_state';
@ -130,7 +128,6 @@ class CommunityTimeline extends PureComponent {
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
<ColumnHeader
icon='users'
iconComponent={PeopleIcon}
active={hasUnread}
title={intl.formatMessage(messages.title)}
onPin={this.handlePin}

View File

@ -5,8 +5,6 @@ import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { ReactComponent as MenuIcon } from '@material-symbols/svg-600/outlined/menu.svg';
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
const messages = defineMessages({
@ -62,7 +60,7 @@ class ActionBar extends PureComponent {
return (
<div className='compose__action-bar'>
<div className='compose__action-bar-dropdown'>
<DropdownMenuContainer items={menu} icon='bars' iconComponent={MenuIcon} size={24} direction='right' />
<DropdownMenuContainer items={menu} icon='bars' size={18} direction='right' />
</div>
</div>
);

View File

@ -7,7 +7,6 @@ import classNames from 'classnames';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as LockIcon } from '@material-symbols/svg-600/outlined/lock.svg';
import { length } from 'stringz';
import { Icon } from 'mastodon/components/icon';
@ -230,7 +229,7 @@ class ComposeForm extends ImmutablePureComponent {
if (this.props.isEditing) {
publishText = intl.formatMessage(messages.saveChanges);
} else if (this.props.privacy === 'private' || this.props.privacy === 'direct') {
publishText = <><Icon id='lock' icon={LockIcon} /> {intl.formatMessage(messages.publish)}</>;
publishText = <span className='compose-form__publish-private'><Icon id='lock' /> {intl.formatMessage(messages.publish)}</span>;
} else {
publishText = this.props.privacy !== 'unlisted' ? intl.formatMessage(messages.publishLoud, { publish: intl.formatMessage(messages.publish) }) : intl.formatMessage(messages.publish);
}

View File

@ -3,11 +3,8 @@ import { PureComponent } from 'react';
import { defineMessages, injectIntl } from 'react-intl';
import { ReactComponent as InsertChartIcon } from '@material-symbols/svg-600/outlined/insert_chart.svg';
import { IconButton } from '../../../components/icon_button';
const messages = defineMessages({
add_poll: { id: 'poll_button.add_poll', defaultMessage: 'Add a poll' },
remove_poll: { id: 'poll_button.remove_poll', defaultMessage: 'Remove poll' },
@ -43,7 +40,6 @@ class PollButton extends PureComponent {
<div className='compose-form__poll-button'>
<IconButton
icon='tasks'
iconComponent={InsertChartIcon}
title={intl.formatMessage(active ? messages.remove_poll : messages.add_poll)}
disabled={disabled}
onClick={this.handleClick}

View File

@ -8,9 +8,6 @@ import classNames from 'classnames';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import AutosuggestInput from 'mastodon/components/autosuggest_input';
import { Icon } from 'mastodon/components/icon';
import { IconButton } from 'mastodon/components/icon_button';
@ -111,7 +108,7 @@ class OptionIntl extends PureComponent {
</label>
<div className='poll__cancel'>
<IconButton disabled={index <= 1} title={intl.formatMessage(messages.remove_option)} icon='times' iconComponent={CloseIcon} onClick={this.handleOptionRemove} />
<IconButton disabled={index <= 1} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />
</div>
</li>
);
@ -167,7 +164,7 @@ class PollForm extends ImmutablePureComponent {
</ul>
<div className='poll__footer'>
<button type='button' disabled={options.size >= 4} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' icon={AddIcon} /> <FormattedMessage {...messages.add_option} /></button>
<button type='button' disabled={options.size >= 4} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button>
{/* eslint-disable-next-line jsx-a11y/no-onchange */}
<select value={expiresIn} onChange={this.handleSelectDuration}>

View File

@ -5,15 +5,9 @@ import { injectIntl, defineMessages } from 'react-intl';
import classNames from 'classnames';
import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
import { ReactComponent as LockIcon } from '@material-symbols/svg-600/outlined/lock.svg';
import { ReactComponent as LockOpenIcon } from '@material-symbols/svg-600/outlined/lock_open.svg';
import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
import { supportsPassiveEvents } from 'detect-passive-events';
import Overlay from 'react-overlays/Overlay';
import { Icon } from 'mastodon/components/icon';
import { IconButton } from '../../../components/icon_button';
@ -129,7 +123,7 @@ class PrivacyDropdownMenu extends PureComponent {
{items.map(item => (
<div role='option' tabIndex={0} key={item.value} data-index={item.value} onKeyDown={this.handleKeyDown} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? this.setFocusRef : null}>
<div className='privacy-dropdown__option__icon'>
<Icon id={item.icon} icon={item.iconComponent} />
<Icon id={item.icon} fixedWidth />
</div>
<div className='privacy-dropdown__option__content'>
@ -228,14 +222,14 @@ class PrivacyDropdown extends PureComponent {
const { intl: { formatMessage } } = this.props;
this.options = [
{ icon: 'globe', iconComponent: PublicIcon, value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) },
{ icon: 'unlock', iconComponent: LockOpenIcon, value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long) },
{ icon: 'lock', iconComponent: LockIcon, value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) },
{ icon: 'globe', value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) },
{ icon: 'unlock', value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long) },
{ icon: 'lock', value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) },
];
if (!this.props.noDirect) {
this.options.push(
{ icon: 'at', iconComponent: AlternateEmailIcon, value: 'direct', text: formatMessage(messages.direct_short), meta: formatMessage(messages.direct_long) },
{ icon: 'at', value: 'direct', text: formatMessage(messages.direct_short), meta: formatMessage(messages.direct_long) },
);
}
}
@ -259,24 +253,25 @@ class PrivacyDropdown extends PureComponent {
const valueOption = this.options.find(item => item.value === value);
return (
<div ref={this.setTargetRef} onKeyDown={this.handleKeyDown}>
<IconButton
className='privacy-dropdown__value-icon'
icon={valueOption.icon}
iconComponent={valueOption.iconComponent}
title={intl.formatMessage(messages.change_privacy)}
size={18}
expanded={open}
active={open}
inverted
onClick={this.handleToggle}
onMouseDown={this.handleMouseDown}
onKeyDown={this.handleButtonKeyDown}
style={{ height: null, lineHeight: '27px' }}
disabled={disabled}
/>
<div className={classNames('privacy-dropdown', placement, { active: open })} onKeyDown={this.handleKeyDown}>
<div className={classNames('privacy-dropdown__value', { active: this.options.indexOf(valueOption) === (placement === 'bottom' ? 0 : (this.options.length - 1)) })} ref={this.setTargetRef}>
<IconButton
className='privacy-dropdown__value-icon'
icon={valueOption.icon}
title={intl.formatMessage(messages.change_privacy)}
size={18}
expanded={open}
active={open}
inverted
onClick={this.handleToggle}
onMouseDown={this.handleMouseDown}
onKeyDown={this.handleButtonKeyDown}
style={{ height: null, lineHeight: '27px' }}
disabled={disabled}
/>
</div>
<Overlay show={open} placement={placement} flip target={this.findTarget} container={container} popperConfig={{ strategy: 'fixed', onFirstUpdate: this.handleOverlayEnter }}>
<Overlay show={open} placement={'bottom'} flip target={this.findTarget} container={container} popperConfig={{ strategy: 'fixed', onFirstUpdate: this.handleOverlayEnter }}>
{({ props, placement }) => (
<div {...props}>
<div className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}>

View File

@ -5,8 +5,6 @@ import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import AttachmentList from 'mastodon/components/attachment_list';
import { WithOptionalRouterPropTypes, withOptionalRouter } from 'mastodon/utils/react_router';
@ -50,7 +48,7 @@ class ReplyIndicator extends ImmutablePureComponent {
return (
<div className='reply-indicator'>
<div className='reply-indicator__header'>
<div className='reply-indicator__cancel'><IconButton title={intl.formatMessage(messages.cancel)} icon='times' iconComponent={CloseIcon} onClick={this.handleClick} inverted /></div>
<div className='reply-indicator__cancel'><IconButton title={intl.formatMessage(messages.cancel)} icon='times' onClick={this.handleClick} inverted /></div>
<a href={`/@${status.getIn(['account', 'acct'])}`} onClick={this.handleAccountClick} className='reply-indicator__display-name'>
<div className='reply-indicator__display-avatar'><Avatar account={status.get('account')} size={24} /></div>

View File

@ -8,10 +8,6 @@ import { withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { ReactComponent as CancelIcon } from '@material-symbols/svg-600/outlined/cancel-fill.svg';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { ReactComponent as SearchIcon } from '@material-symbols/svg-600/outlined/search.svg';
import { Icon } from 'mastodon/components/icon';
import { domain, searchEnabled } from 'mastodon/initial_state';
import { HASHTAG_REGEX } from 'mastodon/utils/hashtags';
@ -336,8 +332,8 @@ class Search extends PureComponent {
/>
<div role='button' tabIndex={0} className='search__icon' onClick={this.handleClear}>
<Icon id='search' icon={SearchIcon} className={hasValue ? '' : 'active'} />
<Icon id='times-circle' icon={CancelIcon} className={hasValue ? 'active' : ''} aria-label={intl.formatMessage(messages.placeholder)} />
<Icon id='search' className={hasValue ? '' : 'active'} />
<Icon id='times-circle' className={hasValue ? 'active' : ''} aria-label={intl.formatMessage(messages.placeholder)} />
</div>
<div className='search__popout'>
@ -349,7 +345,7 @@ class Search extends PureComponent {
{recent.size > 0 ? this._getOptions().map(({ label, action, forget }, i) => (
<button key={label} onMouseDown={action} className={classNames('search__popout__menu__item search__popout__menu__item--flex', { selected: selectedOption === i })}>
<span>{label}</span>
<button className='icon-button' onMouseDown={forget}><Icon id='times' icon={CloseIcon} /></button>
<button className='icon-button' onMouseDown={forget}><Icon id='times' /></button>
</button>
)) : (
<div className='search__popout__menu__message'>

View File

@ -5,11 +5,6 @@ import { FormattedMessage } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as FindInPageIcon } from '@material-symbols/svg-600/outlined/find_in_page.svg';
import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg';
import { ReactComponent as SearchIcon } from '@material-symbols/svg-600/outlined/search.svg';
import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
import { Icon } from 'mastodon/components/icon';
import { LoadMore } from 'mastodon/components/load_more';
import { SearchSection } from 'mastodon/features/explore/components/search_section';
@ -49,7 +44,7 @@ class SearchResults extends ImmutablePureComponent {
if (results.get('accounts') && results.get('accounts').size > 0) {
accounts = (
<SearchSection title={<><Icon id='users' icon={PeopleIcon} /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></>}>
<SearchSection title={<><Icon id='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></>}>
{withoutLastResult(results.get('accounts')).map(accountId => <AccountContainer key={accountId} id={accountId} />)}
{(results.get('accounts').size > INITIAL_PAGE_LIMIT && results.get('accounts').size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreAccounts} />}
</SearchSection>
@ -58,7 +53,7 @@ class SearchResults extends ImmutablePureComponent {
if (results.get('hashtags') && results.get('hashtags').size > 0) {
hashtags = (
<SearchSection title={<><Icon id='hashtag' icon={TagIcon} /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></>}>
<SearchSection title={<><Icon id='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></>}>
{withoutLastResult(results.get('hashtags')).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
{(results.get('hashtags').size > INITIAL_PAGE_LIMIT && results.get('hashtags').size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreHashtags} />}
</SearchSection>
@ -67,7 +62,7 @@ class SearchResults extends ImmutablePureComponent {
if (results.get('statuses') && results.get('statuses').size > 0) {
statuses = (
<SearchSection title={<><Icon id='quote-right' icon={FindInPageIcon} /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></>}>
<SearchSection title={<><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></>}>
{withoutLastResult(results.get('statuses')).map(statusId => <StatusContainer key={statusId} id={statusId} />)}
{(results.get('statuses').size > INITIAL_PAGE_LIMIT && results.get('statuses').size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreStatuses} />}
</SearchSection>
@ -78,7 +73,7 @@ class SearchResults extends ImmutablePureComponent {
return (
<div className='search-results'>
<div className='search-results__header'>
<Icon id='search' icon={SearchIcon} />
<Icon id='search' fixedWidth />
<FormattedMessage id='explore.search_results' defaultMessage='Search results' />
</div>

View File

@ -5,9 +5,6 @@ import { FormattedMessage } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { ReactComponent as EditIcon } from '@material-symbols/svg-600/outlined/edit.svg';
import { ReactComponent as InfoIcon } from '@material-symbols/svg-600/outlined/info.svg';
import spring from 'react-motion/lib/spring';
import { Icon } from 'mastodon/components/icon';
@ -50,13 +47,13 @@ export default class Upload extends ImmutablePureComponent {
{({ scale }) => (
<div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
<div className='compose-form__upload__actions'>
<button type='button' className='icon-button' onClick={this.handleUndoClick}><Icon id='times' icon={CloseIcon} /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button>
<button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' icon={EditIcon} /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>
<button type='button' className='icon-button' onClick={this.handleUndoClick}><Icon id='times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button>
<button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>
</div>
{(media.get('description') || '').length === 0 && (
<div className='compose-form__upload__warning'>
<button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='info-circle' icon={InfoIcon} /> <FormattedMessage id='upload_form.description_missing' defaultMessage='No description added' /></button>
<button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='info-circle' /> <FormattedMessage id='upload_form.description_missing' defaultMessage='No description added' /></button>
</div>
)}
</div>

View File

@ -6,8 +6,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as AddPhotoAlternateIcon } from '@material-symbols/svg-600/outlined/add_photo_alternate.svg';
import { IconButton } from '../../../components/icon_button';
const messages = defineMessages({
@ -64,7 +62,7 @@ class UploadButton extends ImmutablePureComponent {
return (
<div className='compose-form__upload-button'>
<IconButton icon='paperclip' iconComponent={AddPhotoAlternateIcon} title={message} disabled={disabled} onClick={this.handleClick} className='compose-form__upload-button-icon' size={18} inverted style={iconStyle} />
<IconButton icon='paperclip' title={message} disabled={disabled} onClick={this.handleClick} className='compose-form__upload-button-icon' size={18} inverted style={iconStyle} />
<label>
<span style={{ display: 'none' }}>{message}</span>
<input

View File

@ -3,7 +3,6 @@ import { PureComponent } from 'react';
import { FormattedMessage } from 'react-intl';
import { ReactComponent as UploadFileIcon } from '@material-symbols/svg-600/outlined/upload_file.svg';
import spring from 'react-motion/lib/spring';
import { Icon } from 'mastodon/components/icon';
@ -36,7 +35,7 @@ export default class UploadProgress extends PureComponent {
return (
<div className='upload-progress'>
<div className='upload-progress__icon'>
<Icon id='upload' icon={UploadFileIcon} />
<Icon id='upload' />
</div>
<div className='upload-progress__message'>

View File

@ -9,13 +9,6 @@ import { Link } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg';
import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
import { ReactComponent as LogoutIcon } from '@material-symbols/svg-600/outlined/logout.svg';
import { ReactComponent as MenuIcon } from '@material-symbols/svg-600/outlined/menu.svg';
import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications-fill.svg';
import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
import { ReactComponent as SettingsIcon } from '@material-symbols/svg-600/outlined/settings-fill.svg';
import spring from 'react-motion/lib/spring';
import { openModal } from 'mastodon/actions/modal';
@ -108,21 +101,21 @@ class Compose extends PureComponent {
return (
<div className='drawer' role='region' aria-label={intl.formatMessage(messages.compose)}>
<nav className='drawer__header'>
<Link to='/getting-started' className='drawer__tab' title={intl.formatMessage(messages.start)} aria-label={intl.formatMessage(messages.start)}><Icon id='bars' icon={MenuIcon} /></Link>
<Link to='/getting-started' className='drawer__tab' title={intl.formatMessage(messages.start)} aria-label={intl.formatMessage(messages.start)}><Icon id='bars' fixedWidth /></Link>
{!columns.some(column => column.get('id') === 'HOME') && (
<Link to='/home' className='drawer__tab' title={intl.formatMessage(messages.home_timeline)} aria-label={intl.formatMessage(messages.home_timeline)}><Icon id='home' icon={HomeIcon} /></Link>
<Link to='/home' className='drawer__tab' title={intl.formatMessage(messages.home_timeline)} aria-label={intl.formatMessage(messages.home_timeline)}><Icon id='home' fixedWidth /></Link>
)}
{!columns.some(column => column.get('id') === 'NOTIFICATIONS') && (
<Link to='/notifications' className='drawer__tab' title={intl.formatMessage(messages.notifications)} aria-label={intl.formatMessage(messages.notifications)}><Icon id='bell' icon={NotificationsIcon} /></Link>
<Link to='/notifications' className='drawer__tab' title={intl.formatMessage(messages.notifications)} aria-label={intl.formatMessage(messages.notifications)}><Icon id='bell' fixedWidth /></Link>
)}
{!columns.some(column => column.get('id') === 'COMMUNITY') && (
<Link to='/public/local' className='drawer__tab' title={intl.formatMessage(messages.community)} aria-label={intl.formatMessage(messages.community)}><Icon id='users' icon={PeopleIcon} /></Link>
<Link to='/public/local' className='drawer__tab' title={intl.formatMessage(messages.community)} aria-label={intl.formatMessage(messages.community)}><Icon id='users' fixedWidth /></Link>
)}
{!columns.some(column => column.get('id') === 'PUBLIC') && (
<Link to='/public' className='drawer__tab' title={intl.formatMessage(messages.public)} aria-label={intl.formatMessage(messages.public)}><Icon id='globe' icon={PublicIcon} /></Link>
<Link to='/public' className='drawer__tab' title={intl.formatMessage(messages.public)} aria-label={intl.formatMessage(messages.public)}><Icon id='globe' fixedWidth /></Link>
)}
<a href='/settings/preferences' className='drawer__tab' title={intl.formatMessage(messages.preferences)} aria-label={intl.formatMessage(messages.preferences)}><Icon id='cog' icon={SettingsIcon} /></a>
<a href='/auth/sign_out' className='drawer__tab' title={intl.formatMessage(messages.logout)} aria-label={intl.formatMessage(messages.logout)} onClick={this.handleLogoutClick}><Icon id='sign-out' icon={LogoutIcon} /></a>
<a href='/settings/preferences' className='drawer__tab' title={intl.formatMessage(messages.preferences)} aria-label={intl.formatMessage(messages.preferences)}><Icon id='cog' fixedWidth /></a>
<a href='/auth/sign_out' className='drawer__tab' title={intl.formatMessage(messages.logout)} aria-label={intl.formatMessage(messages.logout)} onClick={this.handleLogoutClick}><Icon id='sign-out' fixedWidth /></a>
</nav>
{multiColumn && <SearchContainer /> }

View File

@ -8,8 +8,6 @@ import { Link, withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
import { HotKeys } from 'react-hotkeys';
import AttachmentList from 'mastodon/components/attachment_list';
@ -180,7 +178,7 @@ class Conversation extends ImmutablePureComponent {
)}
<div className='status__action-bar'>
<IconButton className='status__action-bar-button' title={intl.formatMessage(messages.reply)} icon='reply' iconComponent={ReplyIcon} onClick={this.handleReply} />
<IconButton className='status__action-bar-button' title={intl.formatMessage(messages.reply)} icon='reply' onClick={this.handleReply} />
<div className='status__action-bar-dropdown'>
<DropdownMenuContainer
@ -188,7 +186,6 @@ class Conversation extends ImmutablePureComponent {
status={lastStatus}
items={menu}
icon='ellipsis-h'
iconComponent={MoreHorizIcon}
size={18}
direction='right'
title={intl.formatMessage(messages.more)}

View File

@ -7,8 +7,6 @@ import { Helmet } from 'react-helmet';
import { connect } from 'react-redux';
import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
import { mountConversations, unmountConversations, expandConversations } from 'mastodon/actions/conversations';
import { connectDirectStream } from 'mastodon/actions/streaming';
@ -83,7 +81,6 @@ class DirectTimeline extends PureComponent {
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
<ColumnHeader
icon='at'
iconComponent={AlternateEmailIcon}
active={hasUnread}
title={intl.formatMessage(messages.title)}
onPin={this.handlePin}

View File

@ -9,8 +9,6 @@ import { List as ImmutableList } from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg';
import { addColumn, removeColumn, moveColumn, changeColumnParams } from 'mastodon/actions/columns';
import { fetchDirectory, expandDirectory } from 'mastodon/actions/directory';
import Column from 'mastodon/components/column';
@ -158,7 +156,6 @@ class Directory extends PureComponent {
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
<ColumnHeader
icon='address-book-o'
iconComponent={PeopleIcon}
title={intl.formatMessage(messages.title)}
onPin={this.handlePin}
onMove={this.handleMove}

View File

@ -8,10 +8,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as BlockIcon } from '@material-symbols/svg-600/outlined/block-fill.svg';
import { debounce } from 'lodash';
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import { LoadingIndicator } from '../../components/loading_indicator';
import ScrollableList from '../../components/scrollable_list';
import DomainContainer from '../../containers/domain_container';
@ -60,7 +60,9 @@ class Blocks extends ImmutablePureComponent {
const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no blocked domains yet.' />;
return (
<Column bindToDocument={!multiColumn} icon='ban' iconComponent={BlockIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
<Column bindToDocument={!multiColumn} icon='minus-circle' heading={intl.formatMessage(messages.heading)}>
<ColumnBackButtonSlim />
<ScrollableList
scrollKey='domain_blocks'
onLoadMore={this.handleLoadMore}

View File

@ -4,7 +4,7 @@ import { assetHost } from 'mastodon/utils/config';
import { autoPlayGif } from '../../initial_state';
import { unicodeMapping } from './emoji_unicode_mapping_light';
import unicodeMapping from './emoji_unicode_mapping_light';
const trie = new Trie(Object.keys(unicodeMapping));

View File

@ -13,20 +13,15 @@ export type Search = string;
* This could be a potential area of refactoring or error handling.
* The non-existence of 'skins' property is evident at [this location]{@link app/javascript/mastodon/features/emoji/emoji_compressed.js:121}.
*/
type Skins = null;
export type Skins = null;
type Filename = string;
type UnicodeFilename = string;
export type FilenameData = [
filename: Filename,
unicodeFilename?: UnicodeFilename,
][];
export type FilenameData = string[] | string[][];
export type ShortCodesToEmojiDataKey =
| EmojiData['id']
| BaseEmoji['native']
| keyof NimbleEmojiIndex['emojis'];
type SearchData = [
export type SearchData = [
BaseEmoji['native'],
Emoji['short_names'],
Search,
@ -37,9 +32,9 @@ export type ShortCodesToEmojiData = Record<
ShortCodesToEmojiDataKey,
[FilenameData, SearchData]
>;
type EmojisWithoutShortCodes = FilenameData;
export type EmojisWithoutShortCodes = FilenameData[];
type EmojiCompressed = [
export type EmojiCompressed = [
ShortCodesToEmojiData,
Skins,
Category[],

View File

@ -30,13 +30,22 @@ const emojis: Emojis = {};
// decompress
Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
const [_filenameData, searchData] = shortCodesToEmojiData[shortCode];
const [native, short_names, search, unified] = searchData;
const native = searchData[0];
let short_names = searchData[1];
const search = searchData[2];
let unified = searchData[3];
if (!unified) {
// unified name can be derived from unicodeToUnifiedName
unified = unicodeToUnifiedName(native);
}
if (short_names) short_names = [shortCode].concat(short_names);
emojis[shortCode] = {
native,
search,
short_names: short_names ? [shortCode].concat(short_names) : undefined,
unified: unified ?? unicodeToUnifiedName(native),
short_names,
unified,
};
});

View File

@ -0,0 +1,37 @@
// A mapping of unicode strings to an object containing the filename
// (i.e. the svg filename) and a shortCode intended to be shown
// as a "title" attribute in an HTML element (aka tooltip).
import emojiCompressed from './emoji_compressed';
import { unicodeToFilename } from './unicode_to_filename';
const [
shortCodesToEmojiData,
_skins,
_categories,
_short_names,
emojisWithoutShortCodes,
] = emojiCompressed;
// decompress
const unicodeMapping = {};
function processEmojiMapData(emojiMapData, shortCode) {
let [ native, filename ] = emojiMapData;
if (!filename) {
// filename name can be derived from unicodeToFilename
filename = unicodeToFilename(native);
}
unicodeMapping[native] = {
shortCode: shortCode,
filename: filename,
};
}
Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
let [ filenameData ] = shortCodesToEmojiData[shortCode];
filenameData.forEach(emojiMapData => processEmojiMapData(emojiMapData, shortCode));
});
emojisWithoutShortCodes.forEach(emojiMapData => processEmojiMapData(emojiMapData));
export default unicodeMapping;

View File

@ -1,60 +0,0 @@
// A mapping of unicode strings to an object containing the filename
// (i.e. the svg filename) and a shortCode intended to be shown
// as a "title" attribute in an HTML element (aka tooltip).
import type {
FilenameData,
ShortCodesToEmojiDataKey,
} from './emoji_compressed';
import emojiCompressed from './emoji_compressed';
import { unicodeToFilename } from './unicode_to_filename';
type UnicodeMapping = {
[key in FilenameData[number][0]]: {
shortCode: ShortCodesToEmojiDataKey;
filename: FilenameData[number][number];
};
};
const [
shortCodesToEmojiData,
_skins,
_categories,
_short_names,
emojisWithoutShortCodes,
] = emojiCompressed;
// decompress
const unicodeMapping: UnicodeMapping = {};
function processEmojiMapData(
emojiMapData: FilenameData[number],
shortCode?: ShortCodesToEmojiDataKey,
) {
const [native, _filename] = emojiMapData;
let filename = emojiMapData[1];
if (!filename) {
// filename name can be derived from unicodeToFilename
filename = unicodeToFilename(native);
}
unicodeMapping[native] = {
shortCode,
filename,
};
}
Object.keys(shortCodesToEmojiData).forEach(
(shortCode: ShortCodesToEmojiDataKey) => {
if (shortCode === undefined) return;
const [filenameData, _searchData] = shortCodesToEmojiData[shortCode];
filenameData.forEach((emojiMapData) => {
processEmojiMapData(emojiMapData, shortCode);
});
},
);
emojisWithoutShortCodes.forEach((emojiMapData) => {
processEmojiMapData(emojiMapData);
});
export { unicodeMapping };

View File

@ -8,9 +8,6 @@ import { NavLink, Switch, Route } from 'react-router-dom';
import { connect } from 'react-redux';
import { ReactComponent as SearchIcon } from '@material-symbols/svg-600/outlined/search.svg';
import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
import Column from 'mastodon/components/column';
import ColumnHeader from 'mastodon/components/column_header';
import Search from 'mastodon/features/compose/containers/search_container';
@ -60,7 +57,6 @@ class Explore extends PureComponent {
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
<ColumnHeader
icon={isSearching ? 'search' : 'hashtag'}
iconComponent={isSearching ? SearchIcon : TagIcon}
title={intl.formatMessage(isSearching ? messages.searchResults : messages.title)}
onClick={this.handleHeaderClick}
multiColumn={multiColumn}

View File

@ -3,15 +3,12 @@ import { PureComponent } from 'react';
import { FormattedMessage } from 'react-intl';
import { withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { fetchTrendingLinks } from 'mastodon/actions/trends';
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
import Story from './components/story';
@ -26,17 +23,10 @@ class Links extends PureComponent {
links: ImmutablePropTypes.list,
isLoading: PropTypes.bool,
dispatch: PropTypes.func.isRequired,
...WithRouterPropTypes,
};
componentDidMount () {
const { dispatch, links, history } = this.props;
// If we're navigating back to the screen, do not trigger a reload
if (history.action === 'POP' && links.size > 0) {
return;
}
const { dispatch } = this.props;
dispatch(fetchTrendingLinks());
}
@ -87,4 +77,4 @@ class Links extends PureComponent {
}
export default connect(mapStateToProps)(withRouter(Links));
export default connect(mapStateToProps)(Links);

View File

@ -9,10 +9,6 @@ import { List as ImmutableList } from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { ReactComponent as FindInPageIcon } from '@material-symbols/svg-600/outlined/find_in_page.svg';
import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg';
import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
import { submitSearch, expandSearch } from 'mastodon/actions/search';
import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag';
import { Icon } from 'mastodon/components/icon';
@ -169,19 +165,19 @@ class Results extends PureComponent {
filteredResults = (accounts.size + hashtags.size + statuses.size) > 0 ? (
<>
{accounts.size > 0 && (
<SearchSection key='accounts' title={<><Icon id='users' icon={PeopleIcon} /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></>} onClickMore={this.handleLoadMoreAccounts}>
<SearchSection key='accounts' title={<><Icon id='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></>} onClickMore={this.handleLoadMoreAccounts}>
{accounts.take(INITIAL_DISPLAY).map(id => <Account key={id} id={id} />)}
</SearchSection>
)}
{hashtags.size > 0 && (
<SearchSection key='hashtags' title={<><Icon id='hashtag' icon={TagIcon} /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></>} onClickMore={this.handleLoadMoreHashtags}>
<SearchSection key='hashtags' title={<><Icon id='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></>} onClickMore={this.handleLoadMoreHashtags}>
{hashtags.take(INITIAL_DISPLAY).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
</SearchSection>
)}
{statuses.size > 0 && (
<SearchSection key='statuses' title={<><Icon id='quote-right' icon={FindInPageIcon} /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></>} onClickMore={this.handleLoadMoreStatuses}>
<SearchSection key='statuses' title={<><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></>} onClickMore={this.handleLoadMoreStatuses}>
{statuses.take(INITIAL_DISPLAY).map(id => <Status key={id} id={id} />)}
</SearchSection>
)}

View File

@ -3,19 +3,15 @@ import { PureComponent } from 'react';
import { FormattedMessage } from 'react-intl';
import { withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { debounce } from 'lodash';
import { fetchTrendingStatuses, expandTrendingStatuses } from 'mastodon/actions/trends';
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
import StatusList from 'mastodon/components/status_list';
import { getStatusList } from 'mastodon/selectors';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
const mapStateToProps = state => ({
statusIds: getStatusList(state, 'trending'),
@ -31,17 +27,10 @@ class Statuses extends PureComponent {
hasMore: PropTypes.bool,
multiColumn: PropTypes.bool,
dispatch: PropTypes.func.isRequired,
...WithRouterPropTypes,
};
componentDidMount () {
const { dispatch, statusIds, history } = this.props;
// If we're navigating back to the screen, do not trigger a reload
if (history.action === 'POP' && statusIds.size > 0) {
return;
}
const { dispatch } = this.props;
dispatch(fetchTrendingStatuses());
}
@ -75,4 +64,4 @@ class Statuses extends PureComponent {
}
export default connect(mapStateToProps)(withRouter(Statuses));
export default connect(mapStateToProps)(Statuses);

View File

@ -3,15 +3,12 @@ import { PureComponent } from 'react';
import { FormattedMessage } from 'react-intl';
import { withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { fetchSuggestions } from 'mastodon/actions/suggestions';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import AccountCard from 'mastodon/features/directory/components/account_card';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
const mapStateToProps = state => ({
suggestions: state.getIn(['suggestions', 'items']),
@ -24,17 +21,10 @@ class Suggestions extends PureComponent {
isLoading: PropTypes.bool,
suggestions: ImmutablePropTypes.list,
dispatch: PropTypes.func.isRequired,
...WithRouterPropTypes,
};
componentDidMount () {
const { dispatch, suggestions, history } = this.props;
// If we're navigating back to the screen, do not trigger a reload
if (history.action === 'POP' && suggestions.size > 0) {
return;
}
const { dispatch } = this.props;
dispatch(fetchSuggestions(true));
}
@ -62,4 +52,4 @@ class Suggestions extends PureComponent {
}
export default connect(mapStateToProps)(withRouter(Suggestions));
export default connect(mapStateToProps)(Suggestions);

View File

@ -3,8 +3,6 @@ import { PureComponent } from 'react';
import { FormattedMessage } from 'react-intl';
import { withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
@ -12,7 +10,6 @@ import { fetchTrendingHashtags } from 'mastodon/actions/trends';
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
const mapStateToProps = state => ({
hashtags: state.getIn(['trends', 'tags', 'items']),
@ -25,17 +22,10 @@ class Tags extends PureComponent {
hashtags: ImmutablePropTypes.list,
isLoading: PropTypes.bool,
dispatch: PropTypes.func.isRequired,
...WithRouterPropTypes,
};
componentDidMount () {
const { dispatch, history, hashtags } = this.props;
// If we're navigating back to the screen, do not trigger a reload
if (history.action === 'POP' && hashtags.size > 0) {
return;
}
const { dispatch } = this.props;
dispatch(fetchTrendingHashtags());
}
@ -73,4 +63,4 @@ class Tags extends PureComponent {
}
export default connect(mapStateToProps)(withRouter(Tags));
export default connect(mapStateToProps)(Tags);

View File

@ -8,7 +8,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
import { debounce } from 'lodash';
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
@ -81,7 +80,6 @@ class Favourites extends ImmutablePureComponent {
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.heading)}>
<ColumnHeader
icon='star'
iconComponent={StarIcon}
title={intl.formatMessage(messages.heading)}
onPin={this.handlePin}
onMove={this.handleMove}

View File

@ -8,7 +8,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as RefreshIcon } from '@material-symbols/svg-600/outlined/refresh.svg';
import { debounce } from 'lodash';
import { fetchFavourites, expandFavourites } from 'mastodon/actions/interactions';
@ -74,7 +73,7 @@ class Favourites extends ImmutablePureComponent {
showBackButton
multiColumn={multiColumn}
extraButton={(
<button type='button' className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' icon={RefreshIcon} /></button>
<button type='button' className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' /></button>
)}
/>

View File

@ -5,7 +5,6 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
import fuzzysort from 'fuzzysort';
import { Icon } from 'mastodon/components/icon';
@ -79,7 +78,7 @@ class SelectFilter extends PureComponent {
renderCreateNew (name) {
return (
<div key='add-new-filter' role='button' tabIndex={0} className='language-dropdown__dropdown__results__item' onClick={this.handleNewFilterClick} onKeyDown={this.handleKeyDown}>
<Icon id='plus' icon={AddIcon} /> <FormattedMessage id='filter_modal.select_filter.prompt_new' defaultMessage='New category: {name}' values={{ name }} />
<Icon id='plus' fixedWidth /> <FormattedMessage id='filter_modal.select_filter.prompt_new' defaultMessage='New category: {name}' values={{ name }} />
</div>
);
}

View File

@ -6,8 +6,6 @@ import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
import { Helmet } from 'react-helmet';
import { NavLink } from 'react-router-dom';
import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
import { addColumn } from 'mastodon/actions/columns';
import { changeSetting } from 'mastodon/actions/settings';
import { connectPublicStream, connectCommunityStream } from 'mastodon/actions/streaming';
@ -162,7 +160,6 @@ const Firehose = ({ feedType, multiColumn }) => {
<Column bindToDocument={!multiColumn} ref={columnRef} label={intl.formatMessage(messages.title)}>
<ColumnHeader
icon='globe'
iconComponent={PublicIcon}
active={hasUnread}
title={intl.formatMessage(messages.title)}
onPin={handlePin}

View File

@ -7,9 +7,6 @@ import { Link } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { Avatar } from '../../../components/avatar';
import { DisplayName } from '../../../components/display_name';
import { IconButton } from '../../../components/icon_button';
@ -44,8 +41,8 @@ class AccountAuthorize extends ImmutablePureComponent {
</div>
<div className='account--panel'>
<div className='account--panel__button'><IconButton title={intl.formatMessage(messages.authorize)} icon='check' iconComponent={CheckIcon} onClick={onAuthorize} /></div>
<div className='account--panel__button'><IconButton title={intl.formatMessage(messages.reject)} icon='times' iconComponent={CloseIcon} onClick={onReject} /></div>
<div className='account--panel__button'><IconButton title={intl.formatMessage(messages.authorize)} icon='check' onClick={onAuthorize} /></div>
<div className='account--panel__button'><IconButton title={intl.formatMessage(messages.reject)} icon='times' onClick={onReject} /></div>
</div>
</div>
);

View File

@ -8,10 +8,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add.svg';
import { debounce } from 'lodash';
import { fetchFollowRequests, expandFollowRequests } from '../../actions/accounts';
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import ScrollableList from '../../components/scrollable_list';
import { me } from '../../initial_state';
import Column from '../ui/components/column';
@ -67,7 +67,8 @@ class FollowRequests extends ImmutablePureComponent {
);
return (
<Column bindToDocument={!multiColumn} icon='user-plus' iconComponent={PersonAddIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
<Column bindToDocument={!multiColumn} icon='user-plus' heading={intl.formatMessage(messages.heading)}>
<ColumnBackButtonSlim />
<ScrollableList
scrollKey='follow_requests'
onLoadMore={this.handleLoadMore}

View File

@ -8,7 +8,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
import { debounce } from 'lodash';
import { expandFollowedHashtags, fetchFollowedHashtags } from 'mastodon/actions/tags';
@ -56,7 +55,6 @@ class FollowedTags extends ImmutablePureComponent {
<Column bindToDocument={!multiColumn}>
<ColumnHeader
icon='hashtag'
iconComponent={TagIcon}
title={intl.formatMessage(messages.heading)}
showBackButton
multiColumn={multiColumn}

View File

@ -19,7 +19,7 @@ import {
fetchFollowers,
expandFollowers,
} from '../../actions/accounts';
import { ColumnBackButton } from '../../components/column_back_button';
import ColumnBackButton from '../../components/column_back_button';
import { LoadingIndicator } from '../../components/loading_indicator';
import ScrollableList from '../../components/scrollable_list';
import AccountContainer from '../../containers/account_container';
@ -147,7 +147,7 @@ class Followers extends ImmutablePureComponent {
return (
<Column>
<ColumnBackButton />
<ColumnBackButton multiColumn={multiColumn} />
<ScrollableList
scrollKey='followers'

View File

@ -19,7 +19,7 @@ import {
fetchFollowing,
expandFollowing,
} from '../../actions/accounts';
import { ColumnBackButton } from '../../components/column_back_button';
import ColumnBackButton from '../../components/column_back_button';
import { LoadingIndicator } from '../../components/loading_indicator';
import ScrollableList from '../../components/scrollable_list';
import AccountContainer from '../../containers/account_container';
@ -147,7 +147,7 @@ class Following extends ImmutablePureComponent {
return (
<Column>
<ColumnBackButton />
<ColumnBackButton multiColumn={multiColumn} />
<ScrollableList
scrollKey='following'

View File

@ -9,9 +9,6 @@ import { withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
import { ReactComponent as ChevronLeftIcon } from '@material-symbols/svg-600/outlined/chevron_left.svg';
import { ReactComponent as ChevronRightIcon } from '@material-symbols/svg-600/outlined/chevron_right.svg';
import TransitionMotion from 'react-motion/lib/TransitionMotion';
import spring from 'react-motion/lib/spring';
import ReactSwipeableViews from 'react-swipeable-views';
@ -21,7 +18,7 @@ import { AnimatedNumber } from 'mastodon/components/animated_number';
import { Icon } from 'mastodon/components/icon';
import { IconButton } from 'mastodon/components/icon_button';
import EmojiPickerDropdown from 'mastodon/features/compose/containers/emoji_picker_dropdown_container';
import { unicodeMapping } from 'mastodon/features/emoji/emoji_unicode_mapping_light';
import unicodeMapping from 'mastodon/features/emoji/emoji_unicode_mapping_light';
import { autoPlayGif, reduceMotion, disableSwiping, mascot } from 'mastodon/initial_state';
import { assetHost } from 'mastodon/utils/config';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
@ -297,7 +294,7 @@ class ReactionsBar extends ImmutablePureComponent {
/>
))}
{visibleReactions.size < 8 && <EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={<Icon id='plus' icon={AddIcon} />} />}
{visibleReactions.size < 8 && <EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={<Icon id='plus' />} />}
</div>
)}
</TransitionMotion>
@ -443,9 +440,9 @@ class Announcements extends ImmutablePureComponent {
{announcements.size > 1 && (
<div className='announcements__pagination'>
<IconButton disabled={announcements.size === 1} title={intl.formatMessage(messages.previous)} icon='chevron-left' iconComponent={ChevronLeftIcon} onClick={this.handlePrevClick} size={13} />
<IconButton disabled={announcements.size === 1} title={intl.formatMessage(messages.previous)} icon='chevron-left' onClick={this.handlePrevClick} size={13} />
<span>{index + 1} / {announcements.size}</span>
<IconButton disabled={announcements.size === 1} title={intl.formatMessage(messages.next)} icon='chevron-right' iconComponent={ChevronRightIcon} onClick={this.handleNextClick} size={13} />
<IconButton disabled={announcements.size === 1} title={intl.formatMessage(messages.next)} icon='chevron-right' onClick={this.handleNextClick} size={13} />
</div>
)}
</div>

View File

@ -9,18 +9,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
import { ReactComponent as BookmarksIcon } from '@material-symbols/svg-600/outlined/bookmarks-fill.svg';
import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg';
import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg';
import { ReactComponent as MenuIcon } from '@material-symbols/svg-600/outlined/menu.svg';
import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add.svg';
import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
import { ReactComponent as SettingsIcon } from '@material-symbols/svg-600/outlined/settings-fill.svg';
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star.svg';
import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
import { fetchFollowRequests } from 'mastodon/actions/accounts';
import Column from 'mastodon/components/column';
import ColumnHeader from 'mastodon/components/column_header';
@ -113,38 +101,38 @@ class GettingStarted extends ImmutablePureComponent {
if (showTrends) {
navItems.push(
<ColumnLink key='explore' icon='hashtag' iconComponent={TagIcon} text={intl.formatMessage(messages.explore)} to='/explore' />,
<ColumnLink key='explore' icon='hashtag' text={intl.formatMessage(messages.explore)} to='/explore' />,
);
}
navItems.push(
<ColumnLink key='community_timeline' icon='users' iconComponent={PeopleIcon} text={intl.formatMessage(messages.community_timeline)} to='/public/local' />,
<ColumnLink key='public_timeline' icon='globe' iconComponent={PublicIcon} text={intl.formatMessage(messages.public_timeline)} to='/public' />,
<ColumnLink key='community_timeline' icon='users' text={intl.formatMessage(messages.community_timeline)} to='/public/local' />,
<ColumnLink key='public_timeline' icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/public' />,
);
if (signedIn) {
navItems.push(
<ColumnSubheading key='header-personal' text={intl.formatMessage(messages.personal)} />,
<ColumnLink key='home' icon='home' iconComponent={HomeIcon} text={intl.formatMessage(messages.home_timeline)} to='/home' />,
<ColumnLink key='direct' icon='at' iconComponent={AlternateEmailIcon} text={intl.formatMessage(messages.direct)} to='/conversations' />,
<ColumnLink key='bookmark' icon='bookmarks' iconComponent={BookmarksIcon} text={intl.formatMessage(messages.bookmarks)} to='/bookmarks' />,
<ColumnLink key='favourites' icon='star' iconComponent={StarIcon} text={intl.formatMessage(messages.favourites)} to='/favourites' />,
<ColumnLink key='lists' icon='list-ul' iconComponent={ListAltIcon} text={intl.formatMessage(messages.lists)} to='/lists' />,
<ColumnLink key='home' icon='home' text={intl.formatMessage(messages.home_timeline)} to='/home' />,
<ColumnLink key='direct' icon='at' text={intl.formatMessage(messages.direct)} to='/conversations' />,
<ColumnLink key='bookmark' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} to='/bookmarks' />,
<ColumnLink key='favourites' icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />,
<ColumnLink key='lists' icon='list-ul' text={intl.formatMessage(messages.lists)} to='/lists' />,
);
if (myAccount.get('locked') || unreadFollowRequests > 0) {
navItems.push(<ColumnLink key='follow_requests' icon='user-plus' iconComponent={PersonAddIcon} text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);
navItems.push(<ColumnLink key='follow_requests' icon='user-plus' text={intl.formatMessage(messages.follow_requests)} badge={badgeDisplay(unreadFollowRequests, 40)} to='/follow_requests' />);
}
navItems.push(
<ColumnSubheading key='header-settings' text={intl.formatMessage(messages.settings_subheading)} />,
<ColumnLink key='preferences' icon='cog' iconComponent={SettingsIcon} text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />,
<ColumnLink key='preferences' icon='gears' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />,
);
}
return (
<Column>
{(signedIn && !multiColumn) ? <NavigationContainer /> : <ColumnHeader title={intl.formatMessage(messages.menu)} icon='bars' iconComponent={MenuIcon} multiColumn={multiColumn} />}
{(signedIn && !multiColumn) ? <NavigationContainer /> : <ColumnHeader title={intl.formatMessage(messages.menu)} icon='bars' multiColumn={multiColumn} />}
<div className='getting-started scrollable scrollable--flex'>
<div className='getting-started__wrapper'>

View File

@ -8,7 +8,6 @@ import { Helmet } from 'react-helmet';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
import { isEqual } from 'lodash';
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
@ -191,7 +190,6 @@ class HashtagTimeline extends PureComponent {
<Column bindToDocument={!multiColumn} ref={this.setRef} label={`#${id}`}>
<ColumnHeader
icon='hashtag'
iconComponent={TagIcon}
active={hasUnread}
title={this.title()}
onPin={this.handlePin}

View File

@ -10,9 +10,6 @@ import { List as ImmutableList } from 'immutable';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { ReactComponent as CampaignIcon } from '@material-symbols/svg-600/outlined/campaign.svg';
import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
import { fetchAnnouncements, toggleShowAnnouncements } from 'mastodon/actions/announcements';
import { IconWithBadge } from 'mastodon/components/icon_with_badge';
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
@ -184,7 +181,7 @@ class HomeTimeline extends PureComponent {
aria-label={intl.formatMessage(showAnnouncements ? messages.hide_announcements : messages.show_announcements)}
onClick={this.handleToggleAnnouncementsClick}
>
<IconWithBadge id='bullhorn' icon={CampaignIcon} count={unreadAnnouncements} />
<IconWithBadge id='bullhorn' count={unreadAnnouncements} />
</button>
);
}
@ -201,7 +198,6 @@ class HomeTimeline extends PureComponent {
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
<ColumnHeader
icon='home'
iconComponent={HomeIcon}
active={hasUnread}
title={intl.formatMessage(messages.title)}
onPin={this.handlePin}

View File

@ -7,10 +7,6 @@ import classNames from 'classnames';
import { connect } from 'react-redux';
import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add.svg';
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star.svg';
import { throttle, escapeRegExp } from 'lodash';
import { openModal, closeModal } from 'mastodon/actions/modal';
@ -358,22 +354,22 @@ class InteractionModal extends React.PureComponent {
switch(type) {
case 'reply':
icon = <Icon id='reply' icon={ReplyIcon} />;
icon = <Icon id='reply' />;
title = <FormattedMessage id='interaction_modal.title.reply' defaultMessage="Reply to {name}'s post" values={{ name }} />;
actionDescription = <FormattedMessage id='interaction_modal.description.reply' defaultMessage='With an account on Mastodon, you can respond to this post.' />;
break;
case 'reblog':
icon = <Icon id='retweet' icon={RepeatIcon} />;
icon = <Icon id='retweet' />;
title = <FormattedMessage id='interaction_modal.title.reblog' defaultMessage="Boost {name}'s post" values={{ name }} />;
actionDescription = <FormattedMessage id='interaction_modal.description.reblog' defaultMessage='With an account on Mastodon, you can boost this post to share it with your own followers.' />;
break;
case 'favourite':
icon = <Icon id='star' icon={StarIcon} />;
icon = <Icon id='star' />;
title = <FormattedMessage id='interaction_modal.title.favourite' defaultMessage="Favorite {name}'s post" values={{ name }} />;
actionDescription = <FormattedMessage id='interaction_modal.description.favourite' defaultMessage='With an account on Mastodon, you can favorite this post to let the author know you appreciate it and save it for later.' />;
break;
case 'follow':
icon = <Icon id='user-plus' icon={PersonAddIcon} />;
icon = <Icon id='user-plus' />;
title = <FormattedMessage id='interaction_modal.title.follow' defaultMessage='Follow {name}' values={{ name }} />;
actionDescription = <FormattedMessage id='interaction_modal.description.follow' defaultMessage='With an account on Mastodon, you can follow {name} to receive their posts in your home feed.' values={{ name }} />;
break;

View File

@ -6,8 +6,6 @@ import { Helmet } from 'react-helmet';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as InfoIcon } from '@material-symbols/svg-600/outlined/info.svg';
import Column from 'mastodon/components/column';
import ColumnHeader from 'mastodon/components/column_header';
@ -29,8 +27,7 @@ class KeyboardShortcuts extends ImmutablePureComponent {
<Column>
<ColumnHeader
title={intl.formatMessage(messages.heading)}
icon='info-circle'
iconComponent={InfoIcon}
icon='question'
multiColumn={multiColumn}
/>

View File

@ -6,10 +6,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg';
import { Icon } from 'mastodon/components/icon';
import { removeFromListAdder, addToListAdder } from '../../../actions/lists';
@ -50,16 +46,16 @@ class List extends ImmutablePureComponent {
let button;
if (added) {
button = <IconButton icon='times' iconComponent={CloseIcon} title={intl.formatMessage(messages.remove)} onClick={onRemove} />;
button = <IconButton icon='times' title={intl.formatMessage(messages.remove)} onClick={onRemove} />;
} else {
button = <IconButton icon='plus' iconComponent={AddIcon} title={intl.formatMessage(messages.add)} onClick={onAdd} />;
button = <IconButton icon='plus' title={intl.formatMessage(messages.add)} onClick={onAdd} />;
}
return (
<div className='list'>
<div className='list__wrapper'>
<div className='list__display-name'>
<Icon id='list-ul' icon={ListAltIcon} className='column-link__icon' />
<Icon id='list-ul' className='column-link__icon' fixedWidth />
{list.get('title')}
</div>

View File

@ -6,9 +6,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { removeFromListEditor, addToListEditor } from '../../../actions/lists';
import { Avatar } from '../../../components/avatar';
import { DisplayName } from '../../../components/display_name';
@ -56,9 +53,9 @@ class Account extends ImmutablePureComponent {
let button;
if (added) {
button = <IconButton icon='times' iconComponent={CloseIcon} title={intl.formatMessage(messages.remove)} onClick={onRemove} />;
button = <IconButton icon='times' title={intl.formatMessage(messages.remove)} onClick={onRemove} />;
} else {
button = <IconButton icon='plus' iconComponent={AddIcon} title={intl.formatMessage(messages.add)} onClick={onAdd} />;
button = <IconButton icon='plus' title={intl.formatMessage(messages.add)} onClick={onAdd} />;
}
return (

View File

@ -5,8 +5,6 @@ import { defineMessages, injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
import { changeListEditorTitle, submitListEditor } from '../../../actions/lists';
import { IconButton } from '../../../components/icon_button';
@ -63,7 +61,6 @@ class ListForm extends PureComponent {
<IconButton
disabled={disabled}
icon='check'
iconComponent={CheckIcon}
title={title}
onClick={this.handleClick}
/>

View File

@ -7,9 +7,6 @@ import classNames from 'classnames';
import { connect } from 'react-redux';
import { ReactComponent as CancelIcon } from '@material-symbols/svg-600/outlined/cancel.svg';
import { ReactComponent as SearchIcon } from '@material-symbols/svg-600/outlined/search.svg';
import { Icon } from 'mastodon/components/icon';
import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from '../../../actions/lists';
@ -72,8 +69,8 @@ class Search extends PureComponent {
</label>
<div role='button' tabIndex={0} className='search__icon' onClick={this.handleClear}>
<Icon id='search' icon={SearchIcon} className={classNames({ active: !hasValue })} />
<Icon id='times-circle' icon={CancelIcon} aria-label={intl.formatMessage(messages.search)} className={classNames({ active: hasValue })} />
<Icon id='search' className={classNames({ active: !hasValue })} />
<Icon id='times-circle' aria-label={intl.formatMessage(messages.search)} className={classNames({ active: hasValue })} />
</div>
</div>
);

View File

@ -9,9 +9,6 @@ import { withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { ReactComponent as DeleteIcon } from '@material-symbols/svg-600/outlined/delete.svg';
import { ReactComponent as EditIcon } from '@material-symbols/svg-600/outlined/edit.svg';
import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg';
import Toggle from 'react-toggle';
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
@ -184,7 +181,6 @@ class ListTimeline extends PureComponent {
<Column bindToDocument={!multiColumn} ref={this.setRef} label={title}>
<ColumnHeader
icon='list-ul'
iconComponent={ListAltIcon}
active={hasUnread}
title={title}
onPin={this.handlePin}
@ -195,11 +191,11 @@ class ListTimeline extends PureComponent {
>
<div className='column-settings__row column-header__links'>
<button type='button' className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.handleEditClick}>
<Icon id='pencil' icon={EditIcon} /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />
<Icon id='pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />
</button>
<button type='button' className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.handleDeleteClick}>
<Icon id='trash' icon={DeleteIcon} /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />
<Icon id='trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />
</button>
</div>

View File

@ -9,8 +9,6 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg';
import { fetchLists } from 'mastodon/actions/lists';
import Column from 'mastodon/components/column';
import ColumnHeader from 'mastodon/components/column_header';
@ -67,7 +65,7 @@ class Lists extends ImmutablePureComponent {
return (
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.heading)}>
<ColumnHeader title={intl.formatMessage(messages.heading)} icon='list-ul' iconComponent={ListAltIcon} multiColumn={multiColumn} />
<ColumnHeader title={intl.formatMessage(messages.heading)} icon='list-ul' multiColumn={multiColumn} />
<NewListForm />
@ -78,7 +76,7 @@ class Lists extends ImmutablePureComponent {
bindToDocument={!multiColumn}
>
{lists.map(list =>
<ColumnLink key={list.get('id')} to={`/lists/${list.get('id')}`} icon='list-ul' iconComponent={ListAltIcon} text={list.get('title')} />,
<ColumnLink key={list.get('id')} to={`/lists/${list.get('id')}`} icon='list-ul' text={list.get('title')} />,
)}
</ScrollableList>

View File

@ -8,10 +8,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as VolumeOffIcon } from '@material-symbols/svg-600/outlined/volume_off.svg';
import { debounce } from 'lodash';
import { fetchMutes, expandMutes } from '../../actions/mutes';
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import { LoadingIndicator } from '../../components/loading_indicator';
import ScrollableList from '../../components/scrollable_list';
import AccountContainer from '../../containers/account_container';
@ -61,7 +61,8 @@ class Mutes extends ImmutablePureComponent {
const emptyMessage = <FormattedMessage id='empty_column.mutes' defaultMessage="You haven't muted any users yet." />;
return (
<Column bindToDocument={!multiColumn} icon='volume-off' iconComponent={VolumeOffIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
<Column bindToDocument={!multiColumn} icon='volume-off' heading={intl.formatMessage(messages.heading)}>
<ColumnBackButtonSlim />
<ScrollableList
scrollKey='mutes'
onLoadMore={this.handleLoadMore}

View File

@ -3,8 +3,6 @@ import { PureComponent } from 'react';
import { FormattedMessage } from 'react-intl';
import { ReactComponent as DeleteForeverIcon } from '@material-symbols/svg-600/outlined/delete_forever.svg';
import { Icon } from 'mastodon/components/icon';
export default class ClearColumnButton extends PureComponent {
@ -15,7 +13,7 @@ export default class ClearColumnButton extends PureComponent {
render () {
return (
<button className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.props.onClick}><Icon id='eraser' icon={DeleteForeverIcon} /> <FormattedMessage id='notifications.clear' defaultMessage='Clear notifications' /></button>
<button className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.props.onClick}><Icon id='eraser' /> <FormattedMessage id='notifications.clear' defaultMessage='Clear notifications' /></button>
);
}

View File

@ -3,13 +3,6 @@ import { PureComponent } from 'react';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
import { ReactComponent as InsertChartIcon } from '@material-symbols/svg-600/outlined/insert_chart.svg';
import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add.svg';
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
import { ReactComponent as ReplyAllIcon } from '@material-symbols/svg-600/outlined/reply_all.svg';
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star.svg';
import { Icon } from 'mastodon/components/icon';
const tooltips = defineMessages({
@ -73,42 +66,42 @@ class FilterBar extends PureComponent {
onClick={this.onClick('mention')}
title={intl.formatMessage(tooltips.mentions)}
>
<Icon id='reply-all' icon={ReplyAllIcon} />
<Icon id='reply-all' fixedWidth />
</button>
<button
className={selectedFilter === 'favourite' ? 'active' : ''}
onClick={this.onClick('favourite')}
title={intl.formatMessage(tooltips.favourites)}
>
<Icon id='star' icon={StarIcon} />
<Icon id='star' fixedWidth />
</button>
<button
className={selectedFilter === 'reblog' ? 'active' : ''}
onClick={this.onClick('reblog')}
title={intl.formatMessage(tooltips.boosts)}
>
<Icon id='retweet' icon={RepeatIcon} />
<Icon id='retweet' fixedWidth />
</button>
<button
className={selectedFilter === 'poll' ? 'active' : ''}
onClick={this.onClick('poll')}
title={intl.formatMessage(tooltips.polls)}
>
<Icon id='tasks' icon={InsertChartIcon} />
<Icon id='tasks' fixedWidth />
</button>
<button
className={selectedFilter === 'status' ? 'active' : ''}
onClick={this.onClick('status')}
title={intl.formatMessage(tooltips.statuses)}
>
<Icon id='home' icon={HomeIcon} />
<Icon id='home' fixedWidth />
</button>
<button
className={selectedFilter === 'follow' ? 'active' : ''}
onClick={this.onClick('follow')}
title={intl.formatMessage(tooltips.follows)}
>
<Icon id='user-plus' icon={PersonAddIcon} />
<Icon id='user-plus' fixedWidth />
</button>
</div>
);

View File

@ -7,9 +7,6 @@ import { Link } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { Avatar } from 'mastodon/components/avatar';
import { DisplayName } from 'mastodon/components/display_name';
import { IconButton } from 'mastodon/components/icon_button';
@ -53,8 +50,8 @@ class FollowRequest extends ImmutablePureComponent {
</Link>
<div className='account__relationship'>
<IconButton title={intl.formatMessage(messages.authorize)} icon='check' iconComponent={CheckIcon} onClick={onAuthorize} />
<IconButton title={intl.formatMessage(messages.reject)} icon='times' iconComponent={CloseIcon} onClick={onReject} />
<IconButton title={intl.formatMessage(messages.authorize)} icon='check' onClick={onAuthorize} />
<IconButton title={intl.formatMessage(messages.reject)} icon='times' onClick={onReject} />
</div>
</div>
</div>

View File

@ -8,14 +8,6 @@ import { Link, withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as EditIcon } from '@material-symbols/svg-600/outlined/edit.svg';
import { ReactComponent as FlagIcon } from '@material-symbols/svg-600/outlined/flag-fill.svg';
import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
import { ReactComponent as InsertChartIcon } from '@material-symbols/svg-600/outlined/insert_chart.svg';
import { ReactComponent as PersonIcon } from '@material-symbols/svg-600/outlined/person-fill.svg';
import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add-fill.svg';
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
import { HotKeys } from 'react-hotkeys';
import { Icon } from 'mastodon/components/icon';
@ -136,7 +128,9 @@ class Notification extends ImmutablePureComponent {
<HotKeys handlers={this.getHandlers()}>
<div className={classNames('notification notification-follow focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.follow, { name: account.get('acct') }), notification.get('created_at'))}>
<div className='notification__message'>
<Icon id='user-plus' icon={PersonAddIcon} />
<div className='notification__favourite-icon-wrapper'>
<Icon id='user-plus' fixedWidth />
</div>
<span title={notification.get('created_at')}>
<FormattedMessage id='notification.follow' defaultMessage='{name} followed you' values={{ name: link }} />
@ -156,7 +150,9 @@ class Notification extends ImmutablePureComponent {
<HotKeys handlers={this.getHandlers()}>
<div className={classNames('notification notification-follow-request focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.follow_request', defaultMessage: '{name} has requested to follow you' }, { name: account.get('acct') }), notification.get('created_at'))}>
<div className='notification__message'>
<Icon id='user' icon={PersonIcon} />
<div className='notification__favourite-icon-wrapper'>
<Icon id='user' fixedWidth />
</div>
<span title={notification.get('created_at')}>
<FormattedMessage id='notification.follow_request' defaultMessage='{name} has requested to follow you' values={{ name: link }} />
@ -194,7 +190,9 @@ class Notification extends ImmutablePureComponent {
<HotKeys handlers={this.getHandlers()}>
<div className={classNames('notification notification-favourite focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.favourite, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
<div className='notification__message'>
<Icon id='star' icon={StarIcon} className='star-icon' />
<div className='notification__favourite-icon-wrapper'>
<Icon id='star' className='star-icon' fixedWidth />
</div>
<span title={notification.get('created_at')}>
<FormattedMessage id='notification.favourite' defaultMessage='{name} favorited your status' values={{ name: link }} />
@ -224,7 +222,9 @@ class Notification extends ImmutablePureComponent {
<HotKeys handlers={this.getHandlers()}>
<div className={classNames('notification notification-reblog focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.reblog, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
<div className='notification__message'>
<Icon id='retweet' icon={RepeatIcon} />
<div className='notification__favourite-icon-wrapper'>
<Icon id='retweet' fixedWidth />
</div>
<span title={notification.get('created_at')}>
<FormattedMessage id='notification.reblog' defaultMessage='{name} boosted your status' values={{ name: link }} />
@ -258,7 +258,9 @@ class Notification extends ImmutablePureComponent {
<HotKeys handlers={this.getHandlers()}>
<div className={classNames('notification notification-status focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.status, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
<div className='notification__message'>
<Icon id='home' icon={HomeIcon} />
<div className='notification__favourite-icon-wrapper'>
<Icon id='home' fixedWidth />
</div>
<span title={notification.get('created_at')}>
<FormattedMessage id='notification.status' defaultMessage='{name} just posted' values={{ name: link }} />
@ -293,7 +295,9 @@ class Notification extends ImmutablePureComponent {
<HotKeys handlers={this.getHandlers()}>
<div className={classNames('notification notification-update focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.update, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
<div className='notification__message'>
<Icon id='pencil' icon={EditIcon} />
<div className='notification__favourite-icon-wrapper'>
<Icon id='pencil' fixedWidth />
</div>
<span title={notification.get('created_at')}>
<FormattedMessage id='notification.update' defaultMessage='{name} edited a post' values={{ name: link }} />
@ -330,7 +334,9 @@ class Notification extends ImmutablePureComponent {
<HotKeys handlers={this.getHandlers()}>
<div className={classNames('notification notification-poll focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, message, notification.get('created_at'))}>
<div className='notification__message'>
<Icon id='tasks' icon={InsertChartIcon} />
<div className='notification__favourite-icon-wrapper'>
<Icon id='tasks' fixedWidth />
</div>
<span title={notification.get('created_at')}>
{ownPoll ? (
@ -365,7 +371,9 @@ class Notification extends ImmutablePureComponent {
<HotKeys handlers={this.getHandlers()}>
<div className={classNames('notification notification-admin-sign-up focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminSignUp, { name: account.get('acct') }), notification.get('created_at'))}>
<div className='notification__message'>
<Icon id='user-plus' icon={PersonAddIcon} />
<div className='notification__favourite-icon-wrapper'>
<Icon id='user-plus' fixedWidth />
</div>
<span title={notification.get('created_at')}>
<FormattedMessage id='notification.admin.sign_up' defaultMessage='{name} signed up' values={{ name: link }} />
@ -393,7 +401,9 @@ class Notification extends ImmutablePureComponent {
<HotKeys handlers={this.getHandlers()}>
<div className={classNames('notification notification-admin-report focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminReport, { name: account.get('acct'), target: notification.getIn(['report', 'target_account', 'acct']) }), notification.get('created_at'))}>
<div className='notification__message'>
<Icon id='flag' icon={FlagIcon} />
<div className='notification__favourite-icon-wrapper'>
<Icon id='flag' fixedWidth />
</div>
<span title={notification.get('created_at')}>
<FormattedMessage id='notification.admin.report' defaultMessage='{name} reported {target}' values={{ name: link, target: targetLink }} />

View File

@ -5,9 +5,6 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { ReactComponent as TuneIcon } from '@material-symbols/svg-600/outlined/tune.svg';
import { requestBrowserPermission } from 'mastodon/actions/notifications';
import { changeSetting } from 'mastodon/actions/settings';
import { Button } from 'mastodon/components/button';
@ -39,11 +36,11 @@ class NotificationsPermissionBanner extends PureComponent {
return (
<div className='notifications-permission-banner'>
<div className='notifications-permission-banner__close'>
<IconButton icon='times' iconComponent={CloseIcon} onClick={this.handleClose} title={intl.formatMessage(messages.close)} />
<IconButton icon='times' onClick={this.handleClose} title={intl.formatMessage(messages.close)} />
</div>
<h2><FormattedMessage id='notifications_permission_banner.title' defaultMessage='Never miss a thing' /></h2>
<p><FormattedMessage id='notifications_permission_banner.how_to_control' defaultMessage="To receive notifications when Mastodon isn't open, enable desktop notifications. You can control precisely which types of interactions generate desktop notifications through the {icon} button above once they're enabled." values={{ icon: <Icon id='sliders' icon={TuneIcon} /> }} /></p>
<p><FormattedMessage id='notifications_permission_banner.how_to_control' defaultMessage="To receive notifications when Mastodon isn't open, enable desktop notifications. You can control precisely which types of interactions generate desktop notifications through the {icon} button above once they're enabled." values={{ icon: <Icon id='sliders' /> }} /></p>
<Button onClick={this.handleClick}><FormattedMessage id='notifications_permission_banner.enable' defaultMessage='Enable desktop notifications' /></Button>
</div>
);

View File

@ -10,8 +10,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { ReactComponent as DoneAllIcon } from '@material-symbols/svg-600/outlined/done_all.svg';
import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications-fill.svg';
import { debounce } from 'lodash';
import { compareId } from 'mastodon/compare_id';
@ -262,7 +260,7 @@ class Notifications extends PureComponent {
onClick={this.handleMarkAsRead}
className='column-header__button'
>
<Icon id='done-all' icon={DoneAllIcon} />
<Icon id='check' />
</button>
);
}
@ -271,7 +269,6 @@ class Notifications extends PureComponent {
<Column bindToDocument={!multiColumn} ref={this.setColumnRef} label={intl.formatMessage(messages.title)}>
<ColumnHeader
icon='bell'
iconComponent={NotificationsIcon}
active={isUnread}
title={intl.formatMessage(messages.title)}
onPin={this.handlePin}

View File

@ -0,0 +1,7 @@
const ArrowSmallRight = () => (
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='currentColor'>
<path fillRule='evenodd' d='M5 10a.75.75 0 01.75-.75h6.638L10.23 7.29a.75.75 0 111.04-1.08l3.5 3.25a.75.75 0 010 1.08l-3.5 3.25a.75.75 0 11-1.04-1.08l2.158-1.96H5.75A.75.75 0 015 10z' clipRule='evenodd' />
</svg>
);
export default ArrowSmallRight;

View File

@ -3,9 +3,7 @@ import { Fragment } from 'react';
import classNames from 'classnames';
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/done.svg';
import { Icon } from 'mastodon/components/icon';
import { Check } from 'mastodon/components/check';
const ProgressIndicator = ({ steps, completed }) => (
<div className='onboarding__progress-indicator'>
@ -14,7 +12,7 @@ const ProgressIndicator = ({ steps, completed }) => (
{i > 0 && <div className={classNames('onboarding__progress-indicator__line', { active: completed > i })} />}
<div className={classNames('onboarding__progress-indicator__step', { active: completed > i })}>
{completed > i && <Icon icon={CheckIcon} />}
{completed > i && <Check />}
</div>
</Fragment>
))}

View File

@ -1,15 +1,15 @@
import PropTypes from 'prop-types';
import { ReactComponent as ArrowRightAltIcon } from '@material-symbols/svg-600/outlined/arrow_right_alt.svg';
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/done.svg';
import { Check } from 'mastodon/components/check';
import { Icon } from 'mastodon/components/icon';
const Step = ({ label, description, icon, iconComponent, completed, onClick, href }) => {
import ArrowSmallRight from './arrow_small_right';
const Step = ({ label, description, icon, completed, onClick, href }) => {
const content = (
<>
<div className='onboarding__steps__item__icon'>
<Icon id={icon} icon={iconComponent} />
<Icon id={icon} />
</div>
<div className='onboarding__steps__item__description'>
@ -18,7 +18,7 @@ const Step = ({ label, description, icon, iconComponent, completed, onClick, hre
</div>
<div className={completed ? 'onboarding__steps__item__progress' : 'onboarding__steps__item__go'}>
{completed ? <Icon icon={CheckIcon} /> : <Icon icon={ArrowRightAltIcon} />}
{completed ? <Check /> : <ArrowSmallRight />}
</div>
</>
);
@ -42,7 +42,6 @@ Step.propTypes = {
label: PropTypes.node,
description: PropTypes.node,
icon: PropTypes.string,
iconComponent: PropTypes.func,
completed: PropTypes.bool,
href: PropTypes.string,
onClick: PropTypes.func,

View File

@ -9,7 +9,7 @@ import { connect } from 'react-redux';
import { fetchSuggestions } from 'mastodon/actions/suggestions';
import { markAsPartial } from 'mastodon/actions/timelines';
import Column from 'mastodon/components/column';
import { ColumnBackButton } from 'mastodon/components/column_back_button';
import ColumnBackButton from 'mastodon/components/column_back_button';
import { EmptyAccount } from 'mastodon/components/empty_account';
import Account from 'mastodon/containers/account_container';
@ -25,6 +25,7 @@ class Follows extends PureComponent {
dispatch: PropTypes.func.isRequired,
suggestions: ImmutablePropTypes.list,
isLoading: PropTypes.bool,
multiColumn: PropTypes.bool,
};
componentDidMount () {
@ -38,7 +39,7 @@ class Follows extends PureComponent {
}
render () {
const { onBack, isLoading, suggestions } = this.props;
const { onBack, isLoading, suggestions, multiColumn } = this.props;
let loadedContent;
@ -52,7 +53,7 @@ class Follows extends PureComponent {
return (
<Column>
<ColumnBackButton onClick={onBack} />
<ColumnBackButton multiColumn={multiColumn} onClick={onBack} />
<div className='scrollable privacy-policy'>
<div className='column-title'>

View File

@ -9,24 +9,19 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as AccountCircleIcon } from '@material-symbols/svg-600/outlined/account_circle.svg';
import { ReactComponent as ArrowRightAltIcon } from '@material-symbols/svg-600/outlined/arrow_right_alt.svg';
import { ReactComponent as ContentCopyIcon } from '@material-symbols/svg-600/outlined/content_copy.svg';
import { ReactComponent as EditNoteIcon } from '@material-symbols/svg-600/outlined/edit_note.svg';
import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add.svg';
import { debounce } from 'lodash';
import illustration from 'mastodon/../images/elephant_ui_conversation.svg';
import { fetchAccount } from 'mastodon/actions/accounts';
import { focusCompose } from 'mastodon/actions/compose';
import { closeOnboarding } from 'mastodon/actions/onboarding';
import { Icon } from 'mastodon/components/icon';
import Column from 'mastodon/features/ui/components/column';
import { me } from 'mastodon/initial_state';
import { makeGetAccount } from 'mastodon/selectors';
import { assetHost } from 'mastodon/utils/config';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
import ArrowSmallRight from './components/arrow_small_right';
import Step from './components/step';
import Follows from './follows';
import Share from './share';
@ -47,6 +42,7 @@ class Onboarding extends ImmutablePureComponent {
static propTypes = {
dispatch: PropTypes.func.isRequired,
account: ImmutablePropTypes.map,
multiColumn: PropTypes.bool,
...WithRouterPropTypes,
};
@ -99,14 +95,14 @@ class Onboarding extends ImmutablePureComponent {
}
render () {
const { account } = this.props;
const { account, multiColumn } = this.props;
const { step, shareClicked } = this.state;
switch(step) {
case 'follows':
return <Follows onBack={this.handleBackClick} />;
return <Follows onBack={this.handleBackClick} multiColumn={multiColumn} />;
case 'share':
return <Share onBack={this.handleBackClick} />;
return <Share onBack={this.handleBackClick} multiColumn={multiColumn} />;
}
return (
@ -119,10 +115,10 @@ class Onboarding extends ImmutablePureComponent {
</div>
<div className='onboarding__steps'>
<Step onClick={this.handleProfileClick} href='/settings/profile' completed={(!account.get('avatar').endsWith('missing.png')) || (account.get('display_name').length > 0 && account.get('note').length > 0)} icon='address-book-o' iconComponent={AccountCircleIcon} label={<FormattedMessage id='onboarding.steps.setup_profile.title' defaultMessage='Customize your profile' />} description={<FormattedMessage id='onboarding.steps.setup_profile.body' defaultMessage='Others are more likely to interact with you with a filled out profile.' />} />
<Step onClick={this.handleFollowClick} completed={(account.get('following_count') * 1) >= 7} icon='user-plus' iconComponent={PersonAddIcon} label={<FormattedMessage id='onboarding.steps.follow_people.title' defaultMessage='Find at least {count, plural, one {one person} other {# people}} to follow' values={{ count: 7 }} />} description={<FormattedMessage id='onboarding.steps.follow_people.body' defaultMessage="You curate your own home feed. Let's fill it with interesting people." />} />
<Step onClick={this.handleComposeClick} completed={(account.get('statuses_count') * 1) >= 1} icon='pencil-square-o' iconComponent={EditNoteIcon} label={<FormattedMessage id='onboarding.steps.publish_status.title' defaultMessage='Make your first post' />} description={<FormattedMessage id='onboarding.steps.publish_status.body' defaultMessage='Say hello to the world.' values={{ emoji: <img className='emojione' alt='🐘' src={`${assetHost}/emoji/1f418.svg`} /> }} />} />
<Step onClick={this.handleShareClick} completed={shareClicked} icon='copy' iconComponent={ContentCopyIcon} label={<FormattedMessage id='onboarding.steps.share_profile.title' defaultMessage='Share your profile' />} description={<FormattedMessage id='onboarding.steps.share_profile.body' defaultMessage='Let your friends know how to find you on Mastodon!' />} />
<Step onClick={this.handleProfileClick} href='/settings/profile' completed={(!account.get('avatar').endsWith('missing.png')) || (account.get('display_name').length > 0 && account.get('note').length > 0)} icon='address-book-o' label={<FormattedMessage id='onboarding.steps.setup_profile.title' defaultMessage='Customize your profile' />} description={<FormattedMessage id='onboarding.steps.setup_profile.body' defaultMessage='Others are more likely to interact with you with a filled out profile.' />} />
<Step onClick={this.handleFollowClick} completed={(account.get('following_count') * 1) >= 7} icon='user-plus' label={<FormattedMessage id='onboarding.steps.follow_people.title' defaultMessage='Find at least {count, plural, one {one person} other {# people}} to follow' values={{ count: 7 }} />} description={<FormattedMessage id='onboarding.steps.follow_people.body' defaultMessage="You curate your own home feed. Let's fill it with interesting people." />} />
<Step onClick={this.handleComposeClick} completed={(account.get('statuses_count') * 1) >= 1} icon='pencil-square-o' label={<FormattedMessage id='onboarding.steps.publish_status.title' defaultMessage='Make your first post' />} description={<FormattedMessage id='onboarding.steps.publish_status.body' defaultMessage='Say hello to the world.' values={{ emoji: <img className='emojione' alt='🐘' src={`${assetHost}/emoji/1f418.svg`} /> }} />} />
<Step onClick={this.handleShareClick} completed={shareClicked} icon='copy' label={<FormattedMessage id='onboarding.steps.share_profile.title' defaultMessage='Share your profile' />} description={<FormattedMessage id='onboarding.steps.share_profile.body' defaultMessage='Let your friends know how to find you on Mastodon!' />} />
</div>
<p className='onboarding__lead'><FormattedMessage id='onboarding.start.skip' defaultMessage="Don't need help getting started?" /></p>
@ -130,12 +126,12 @@ class Onboarding extends ImmutablePureComponent {
<div className='onboarding__links'>
<Link to='/explore' className='onboarding__link'>
<FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage='Take me to trending' />
<Icon icon={ArrowRightAltIcon} />
<ArrowSmallRight />
</Link>
<Link to='/home' className='onboarding__link'>
<FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='Take me to my home feed' />
<Icon icon={ArrowRightAltIcon} />
<ArrowSmallRight />
</Link>
</div>
</div>

View File

@ -9,15 +9,15 @@ import { Link } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { ReactComponent as ArrowRightAltIcon } from '@material-symbols/svg-600/outlined/arrow_right_alt.svg';
import { ReactComponent as ContentCopyIcon } from '@material-symbols/svg-600/outlined/content_copy.svg';
import SwipeableViews from 'react-swipeable-views';
import Column from 'mastodon/components/column';
import { ColumnBackButton } from 'mastodon/components/column_back_button';
import ColumnBackButton from 'mastodon/components/column_back_button';
import { Icon } from 'mastodon/components/icon';
import { me, domain } from 'mastodon/initial_state';
import ArrowSmallRight from './components/arrow_small_right';
const messages = defineMessages({
shareableMessage: { id: 'onboarding.share.message', defaultMessage: 'I\'m {username} on #Mastodon! Come follow me at {url}' },
});
@ -79,7 +79,7 @@ class CopyPasteText extends PureComponent {
<textarea readOnly value={value} ref={this.setRef} onClick={this.handleInputClick} onFocus={this.handleFocus} onBlur={this.handleBlur} />
<button className='button' onClick={this.handleButtonClick}>
<Icon id='copy' icon={ContentCopyIcon} /> {copied ? <FormattedMessage id='copypaste.copied' defaultMessage='Copied' /> : <FormattedMessage id='copypaste.copy_to_clipboard' defaultMessage='Copy to clipboard' />}
<Icon id='copy' /> {copied ? <FormattedMessage id='copypaste.copied' defaultMessage='Copied' /> : <FormattedMessage id='copypaste.copy_to_clipboard' defaultMessage='Copy to clipboard' />}
</button>
</div>
);
@ -146,17 +146,18 @@ class Share extends PureComponent {
static propTypes = {
onBack: PropTypes.func,
account: ImmutablePropTypes.map,
multiColumn: PropTypes.bool,
intl: PropTypes.object,
};
render () {
const { onBack, account, intl } = this.props;
const { onBack, account, multiColumn, intl } = this.props;
const url = (new URL(`/@${account.get('username')}`, document.baseURI)).href;
return (
<Column>
<ColumnBackButton onClick={onBack} />
<ColumnBackButton multiColumn={multiColumn} onClick={onBack} />
<div className='scrollable privacy-policy'>
<div className='column-title'>
@ -177,12 +178,12 @@ class Share extends PureComponent {
<div className='onboarding__links'>
<Link to='/home' className='onboarding__link'>
<FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='Take me to my home feed' />
<Icon icon={ArrowRightAltIcon} />
<ArrowSmallRight />
</Link>
<Link to='/explore' className='onboarding__link'>
<FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage='Take me to trending' />
<Icon icon={ArrowRightAltIcon} />
<ArrowSmallRight />
</Link>
</div>

View File

@ -9,12 +9,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as OpenInNewIcon } from '@material-symbols/svg-600/outlined/open_in_new.svg';
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
import { ReactComponent as ReplyAllIcon } from '@material-symbols/svg-600/outlined/reply_all.svg';
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star.svg';
import { initBoostModal } from 'mastodon/actions/boosts';
import { replyCompose } from 'mastodon/actions/compose';
import { reblog, favourite, unreblog, unfavourite } from 'mastodon/actions/interactions';
@ -175,15 +169,13 @@ class Footer extends ImmutablePureComponent {
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
let replyIcon, replyIconComponent, replyTitle;
let replyIcon, replyTitle;
if (status.get('in_reply_to_id', null) === null) {
replyIcon = 'reply';
replyIconComponent = RepeatIcon;
replyTitle = intl.formatMessage(messages.reply);
} else {
replyIcon = 'reply-all';
replyIconComponent = ReplyAllIcon;
replyTitle = intl.formatMessage(messages.replyAll);
}
@ -201,10 +193,10 @@ class Footer extends ImmutablePureComponent {
return (
<div className='picture-in-picture__footer'>
<IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} iconComponent={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={StarIcon} onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
{withOpenButton && <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.open)} icon='external-link' iconComponent={OpenInNewIcon} onClick={this.handleOpenClick} href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} />}
<IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
{withOpenButton && <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.open)} icon='external-link' onClick={this.handleOpenClick} href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} />}
</div>
);
}

View File

@ -8,8 +8,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { Avatar } from 'mastodon/components/avatar';
import { DisplayName } from 'mastodon/components/display_name';
import { IconButton } from 'mastodon/components/icon_button';
@ -42,7 +40,7 @@ class Header extends ImmutablePureComponent {
<DisplayName account={account} />
</Link>
<IconButton icon='times' iconComponent={CloseIcon} onClick={onClose} title={intl.formatMessage(messages.close)} />
<IconButton icon='times' onClick={onClose} title={intl.formatMessage(messages.close)} />
</div>
);
}

View File

@ -8,11 +8,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as PushPinIcon } from '@material-symbols/svg-600/outlined/push_pin.svg';
import { getStatusList } from 'mastodon/selectors';
import { fetchPinnedStatuses } from '../../actions/pin_statuses';
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import StatusList from '../../components/status_list';
import Column from '../ui/components/column';
@ -51,7 +50,8 @@ class PinnedStatuses extends ImmutablePureComponent {
const { intl, statusIds, hasMore, multiColumn } = this.props;
return (
<Column bindToDocument={!multiColumn} icon='thumb-tack' iconComponent={PushPinIcon} heading={intl.formatMessage(messages.heading)} ref={this.setRef} alwaysShowBackButton>
<Column bindToDocument={!multiColumn} icon='thumb-tack' heading={intl.formatMessage(messages.heading)} ref={this.setRef}>
<ColumnBackButtonSlim />
<StatusList
statusIds={statusIds}
scrollKey='pinned_statuses'

View File

@ -7,8 +7,6 @@ import { Helmet } from 'react-helmet';
import { connect } from 'react-redux';
import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
import { domain } from 'mastodon/initial_state';
@ -133,7 +131,6 @@ class PublicTimeline extends PureComponent {
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
<ColumnHeader
icon='globe'
iconComponent={PublicIcon}
active={hasUnread}
title={intl.formatMessage(messages.title)}
onPin={this.handlePin}

View File

@ -8,7 +8,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as RefreshIcon } from '@material-symbols/svg-600/outlined/refresh.svg';
import { debounce } from 'lodash';
import { Icon } from 'mastodon/components/icon';
@ -75,7 +74,7 @@ class Reblogs extends ImmutablePureComponent {
showBackButton
multiColumn={multiColumn}
extraButton={(
<button type='button' className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' icon={RefreshIcon} /></button>
<button type='button' className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' /></button>
)}
/>

View File

@ -3,9 +3,7 @@ import { PureComponent } from 'react';
import classNames from 'classnames';
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/done.svg';
import { Icon } from 'mastodon/components/icon';
import { Check } from 'mastodon/components/check';
export default class Option extends PureComponent {
@ -49,7 +47,7 @@ export default class Option extends PureComponent {
onKeyPress={this.handleKeyPress}
aria-checked={checked}
aria-label={label}
>{checked && <Icon icon={CheckIcon} />}</span>
>{checked && <Check />}</span>
{labelComponent ? labelComponent : (
<span className='poll__option__text'>

View File

@ -1,17 +1,26 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import { injectIntl, defineMessages } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { Avatar } from 'mastodon/components/avatar';
import { DisplayName } from 'mastodon/components/display_name';
import { Icon } from 'mastodon/components/icon';
import MediaAttachments from 'mastodon/components/media_attachments';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import StatusContent from 'mastodon/components/status_content';
import { VisibilityIcon } from 'mastodon/components/visibility_icon';
import Option from './option';
const messages = defineMessages({
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
});
class StatusCheckBox extends PureComponent {
static propTypes = {
@ -28,12 +37,21 @@ class StatusCheckBox extends PureComponent {
};
render () {
const { status, checked } = this.props;
const { status, checked, intl } = this.props;
if (status.get('reblog')) {
return null;
}
const visibilityIconInfo = {
'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) },
'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) },
'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
};
const visibilityIcon = visibilityIconInfo[status.get('visibility')];
const labelComponent = (
<div className='status-check-box__status poll__option__text'>
<div className='detailed-status__display-name'>
@ -42,7 +60,7 @@ class StatusCheckBox extends PureComponent {
</div>
<div>
<DisplayName account={status.get('account')} /> · <span className='status__visibility-icon'><VisibilityIcon visibility={status.get('visibility')} /></span> <RelativeTimestamp timestamp={status.get('created_at')} />
<DisplayName account={status.get('account')} /> · <span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span> <RelativeTimestamp timestamp={status.get('created_at')} />
</div>
</div>
@ -66,4 +84,4 @@ class StatusCheckBox extends PureComponent {
}
export default StatusCheckBox;
export default injectIntl(StatusCheckBox);

View File

@ -9,15 +9,6 @@ import { withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { ReactComponent as BookmarkIcon } from '@material-symbols/svg-600/outlined/bookmark-fill.svg';
import { ReactComponent as BookmarkBorderIcon } from '@material-symbols/svg-600/outlined/bookmark.svg';
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
import { ReactComponent as ReplyAllIcon } from '@material-symbols/svg-600/outlined/reply_all.svg';
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
import { ReactComponent as StarBorderIcon } from '@material-symbols/svg-600/outlined/star.svg';
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
@ -279,13 +270,10 @@ class ActionBar extends PureComponent {
}
let replyIcon;
let replyIconComponent;
if (status.get('in_reply_to_id', null) === null) {
replyIcon = 'reply';
replyIconComponent = ReplyIcon;
} else {
replyIcon = 'reply-all';
replyIconComponent = ReplyAllIcon;
}
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
@ -303,13 +291,13 @@ class ActionBar extends PureComponent {
return (
<div className='detailed-status__action-bar'>
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} iconComponent={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} /></div>
<div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} /></div>
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} /></div>
<div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} /></div>
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /></div>
<div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} /></div>
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div>
<div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} /></div>
<div className='detailed-status__action-bar-dropdown'>
<DropdownMenuContainer icon='ellipsis-h' iconComponent={MoreHorizIcon} status={status} items={menu} direction='left' title={intl.formatMessage(messages.more)} />
<DropdownMenuContainer size={18} icon='ellipsis-h' status={status} items={menu} direction='left' title={intl.formatMessage(messages.more)} />
</div>
</div>
);

View File

@ -10,10 +10,6 @@ import classNames from 'classnames';
import Immutable from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { ReactComponent as DescriptionIcon } from '@material-symbols/svg-600/outlined/description-fill.svg';
import { ReactComponent as OpenInNewIcon } from '@material-symbols/svg-600/outlined/open_in_new.svg';
import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow-fill.svg';
import { Blurhash } from 'mastodon/components/blurhash';
import { Icon } from 'mastodon/components/icon';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
@ -143,7 +139,7 @@ export default class Card extends PureComponent {
<strong className='status-card__title' title={card.get('title')} lang={language}>{card.get('title')}</strong>
{card.get('author_name').length > 0 ? <span className='status-card__author'><FormattedMessage id='link_preview.author' defaultMessage='By {name}' values={{ name: <strong>{card.get('author_name')}</strong> }} /></span> : <span className='status-card__description' lang={language}>{card.get('description')}</span>}
{card.get('author_name').length > 0 ? <span className='status-card__author'><FormattedMessage id='link_preview.author' defaultMessage='By {name}' values={{ name: <strong>{card.get('author_name')}</strong> }} /></span> : <span className='status-card__description'>{card.get('description')}</span>}
</div>
);
@ -201,8 +197,8 @@ export default class Card extends PureComponent {
{revealed ? (
<div className='status-card__actions' onClick={this.handleEmbedClick} role='none'>
<div>
<button type='button' onClick={this.handleEmbedClick}><Icon id='play' icon={PlayArrowIcon} /></button>
<a href={card.get('url')} target='_blank' rel='noopener noreferrer'><Icon id='external-link' icon={OpenInNewIcon} /></a>
<button type='button' onClick={this.handleEmbedClick}><Icon id='play' /></button>
<a href={card.get('url')} target='_blank' rel='noopener noreferrer'><Icon id='external-link' /></a>
</div>
</div>
) : spoilerButton}
@ -226,7 +222,7 @@ export default class Card extends PureComponent {
} else {
embed = (
<div className='status-card__image'>
<Icon id='file-text' icon={DescriptionIcon} />
<Icon id='file-text' />
</div>
);
}

View File

@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
import { FormattedDate, FormattedMessage } from 'react-intl';
import { injectIntl, defineMessages, FormattedDate, FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import { Link, withRouter } from 'react-router-dom';
@ -8,16 +8,11 @@ import { Link, withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
import { AnimatedNumber } from 'mastodon/components/animated_number';
import EditedTimestamp from 'mastodon/components/edited_timestamp';
import { getHashtagBarForStatus } from 'mastodon/components/hashtag_bar';
import { Icon } from 'mastodon/components/icon';
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
import { VisibilityIcon } from 'mastodon/components/visibility_icon';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
import { Avatar } from '../../../components/avatar';
@ -30,6 +25,13 @@ import Video from '../../video';
import Card from './card';
const messages = defineMessages({
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
});
class DetailedStatus extends ImmutablePureComponent {
static propTypes = {
@ -58,7 +60,7 @@ class DetailedStatus extends ImmutablePureComponent {
handleAccountClick = (e) => {
if (e.button === 0 && !(e.ctrlKey || e.metaKey) && this.props.history) {
e.preventDefault();
this.props.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
this.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
}
e.stopPropagation();
@ -135,7 +137,7 @@ class DetailedStatus extends ImmutablePureComponent {
render () {
const status = this._properStatus();
const outerStyle = { boxSizing: 'border-box' };
const { compact, pictureInPicture } = this.props;
const { intl, compact, pictureInPicture } = this.props;
if (!status) {
return null;
@ -144,8 +146,7 @@ class DetailedStatus extends ImmutablePureComponent {
let media = '';
let applicationLink = '';
let reblogLink = '';
const reblogIcon = 'retweet';
const reblogIconComponent = RepeatIcon;
let reblogIcon = 'retweet';
let favouriteLink = '';
let edited = '';
@ -222,7 +223,15 @@ class DetailedStatus extends ImmutablePureComponent {
applicationLink = <> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></>;
}
const visibilityLink = <> · <VisibilityIcon visibility={status.get('visibility')} /></>;
const visibilityIconInfo = {
'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) },
'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) },
'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
};
const visibilityIcon = visibilityIconInfo[status.get('visibility')];
const visibilityLink = <> · <Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></>;
if (['private', 'direct'].includes(status.get('visibility'))) {
reblogLink = '';
@ -231,7 +240,7 @@ class DetailedStatus extends ImmutablePureComponent {
<>
{' · '}
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/reblogs`} className='detailed-status__link'>
<Icon id={reblogIcon} icon={reblogIconComponent} />
<Icon id={reblogIcon} />
<span className='detailed-status__reblogs'>
<AnimatedNumber value={status.get('reblogs_count')} />
</span>
@ -243,7 +252,7 @@ class DetailedStatus extends ImmutablePureComponent {
<>
{' · '}
<a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
<Icon id={reblogIcon} icon={reblogIconComponent} />
<Icon id={reblogIcon} />
<span className='detailed-status__reblogs'>
<AnimatedNumber value={status.get('reblogs_count')} />
</span>
@ -255,7 +264,7 @@ class DetailedStatus extends ImmutablePureComponent {
if (this.props.history) {
favouriteLink = (
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/favourites`} className='detailed-status__link'>
<Icon id='star' icon={StarIcon} />
<Icon id='star' />
<span className='detailed-status__favorites'>
<AnimatedNumber value={status.get('favourites_count')} />
</span>
@ -264,7 +273,7 @@ class DetailedStatus extends ImmutablePureComponent {
} else {
favouriteLink = (
<a href={`/interact/${status.get('id')}?type=favourite`} className='detailed-status__link' onClick={this.handleModalLink}>
<Icon id='star' icon={StarIcon} />
<Icon id='star' />
<span className='detailed-status__favorites'>
<AnimatedNumber value={status.get('favourites_count')} />
</span>
@ -289,7 +298,7 @@ class DetailedStatus extends ImmutablePureComponent {
<div ref={this.setRef} className={classNames('detailed-status', { compact })}>
{status.get('visibility') === 'direct' && (
<div className='status__prepend'>
<div className='status__prepend-icon-wrapper'><Icon id='at' icon={AlternateEmailIcon} className='status__prepend-icon' /></div>
<div className='status__prepend-icon-wrapper'><Icon id='at' className='status__prepend-icon' fixedWidth /></div>
<FormattedMessage id='status.direct_indicator' defaultMessage='Private mention' />
</div>
)}
@ -322,4 +331,4 @@ class DetailedStatus extends ImmutablePureComponent {
}
export default withRouter(DetailedStatus);
export default withRouter(injectIntl(DetailedStatus));

View File

@ -12,8 +12,6 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { ReactComponent as VisibilityIcon } from '@material-symbols/svg-600/outlined/visibility.svg';
import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
import { HotKeys } from 'react-hotkeys';
import { Icon } from 'mastodon/components/icon';
@ -687,7 +685,7 @@ class Status extends ImmutablePureComponent {
showBackButton
multiColumn={multiColumn}
extraButton={(
<button type='button' className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} icon={status.get('hidden') ? VisibilityOffIcon : VisibilityIcon} /></button>
<button type='button' className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} /></button>
)}
/>

View File

@ -8,8 +8,6 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { followAccount } from 'mastodon/actions/accounts';
import { Button } from 'mastodon/components/button';
import { IconButton } from 'mastodon/components/icon_button';
@ -103,7 +101,7 @@ class SubscribedLanguagesModal extends ImmutablePureComponent {
return (
<div className='modal-root__modal report-dialog-modal'>
<div className='report-modal__target'>
<IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' iconComponent={CloseIcon} onClick={onClose} size={20} />
<IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={20} />
<FormattedMessage id='subscribed_languages.target' defaultMessage='Change subscribed languages for {target}' values={{ target: <strong>{acct}</strong> }} />
</div>

View File

@ -1,15 +1,13 @@
import { render, fireEvent, screen } from 'mastodon/test_helpers';
import { render, fireEvent, screen } from '@testing-library/react';
import Column from '../column';
const fakeIcon = () => <span />;
describe('<Column />', () => {
describe('<ColumnHeader /> click handler', () => {
it('runs the scroll animation if the column contains scrollable content', () => {
const scrollToMock = jest.fn();
const { container } = render(
<Column heading='notifications' icon='notifications' iconComponent={fakeIcon}>
<Column heading='notifications'>
<div className='scrollable' />
</Column>,
);
@ -19,7 +17,7 @@ describe('<Column />', () => {
});
it('does not try to scroll if there is no scrollable content', () => {
render(<Column heading='notifications' icon='notifications' iconComponent={fakeIcon} />);
render(<Column heading='notifications' />);
fireEvent.click(screen.getByText('notifications'));
});
});

View File

@ -20,12 +20,12 @@ export default class ActionsModal extends ImmutablePureComponent {
return <li key={`sep-${i}`} className='dropdown-menu__separator' />;
}
const { icon = null, iconComponent = null, text, meta = null, active = false, href = '#' } = action;
const { icon = null, text, meta = null, active = false, href = '#' } = action;
return (
<li key={`${text}-${i}`}>
<a href={href} target='_blank' rel='noopener noreferrer' onClick={this.props.onClick} data-index={i} className={classNames({ active })}>
{icon && <IconButton title={text} icon={icon} iconComponent={iconComponent} role='presentation' tabIndex={-1} inverted />}
{icon && <IconButton title={text} icon={icon} role='presentation' tabIndex={-1} inverted />}
<div>
<div className={classNames({ 'actions-modal__item-label': !!meta })}>{text}</div>
<div>{meta}</div>

View File

@ -9,12 +9,9 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
import { changeBoostPrivacy } from 'mastodon/actions/boosts';
import AttachmentList from 'mastodon/components/attachment_list';
import { Icon } from 'mastodon/components/icon';
import { VisibilityIcon } from 'mastodon/components/visibility_icon';
import PrivacyDropdown from 'mastodon/features/compose/components/privacy_dropdown';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
@ -27,6 +24,10 @@ import StatusContent from '../../../components/status_content';
const messages = defineMessages({
cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
});
const mapStateToProps = state => {
@ -75,13 +76,22 @@ class BoostModal extends ImmutablePureComponent {
const { status, privacy, intl } = this.props;
const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog;
const visibilityIconInfo = {
'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) },
'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) },
'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) },
};
const visibilityIcon = visibilityIconInfo[status.get('visibility')];
return (
<div className='modal-root__modal boost-modal'>
<div className='boost-modal__container'>
<div className={classNames('status', `status-${status.get('visibility')}`, 'light')}>
<div className='status__info'>
<a href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
<span className='status__visibility-icon'><VisibilityIcon visibility={status.get('visibility')} /></span>
<span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span>
<RelativeTimestamp timestamp={status.get('created_at')} />
</a>
@ -106,7 +116,7 @@ class BoostModal extends ImmutablePureComponent {
</div>
<div className='boost-modal__action-bar'>
<div><FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' icon={RepeatIcon} /></span> }} /></div>
<div><FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' /></span> }} /></div>
{status.get('visibility') !== 'private' && !status.get('reblogged') && (
<PrivacyDropdown
noDirect

View File

@ -3,8 +3,6 @@ import { PureComponent } from 'react';
import { defineMessages, injectIntl } from 'react-intl';
import { ReactComponent as RefreshIcon } from '@material-symbols/svg-600/outlined/refresh.svg';
import { IconButton } from '../../../components/icon_button';
const messages = defineMessages({
@ -33,7 +31,7 @@ class BundleModalError extends PureComponent {
return (
<div className='modal-root__modal error-modal'>
<div className='error-modal__body'>
<IconButton title={formatMessage(messages.retry)} icon='refresh' iconComponent={RefreshIcon} onClick={this.handleRetry} size={64} />
<IconButton title={formatMessage(messages.retry)} icon='refresh' onClick={this.handleRetry} size={64} />
{formatMessage(messages.error)}
</div>

View File

@ -3,17 +3,16 @@ import { PureComponent } from 'react';
import { debounce } from 'lodash';
import ColumnHeader from '../../../components/column_header';
import { isMobile } from '../../../is_mobile';
import { scrollTop } from '../../../scroll';
import ColumnHeader from './column_header';
export default class Column extends PureComponent {
static propTypes = {
heading: PropTypes.string,
alwaysShowBackButton: PropTypes.bool,
icon: PropTypes.string,
iconComponent: PropTypes.func,
children: PropTypes.node,
active: PropTypes.bool,
hideHeadingOnMobile: PropTypes.bool,
@ -51,14 +50,13 @@ export default class Column extends PureComponent {
};
render () {
const { heading, icon, iconComponent, children, active, hideHeadingOnMobile, alwaysShowBackButton } = this.props;
const { heading, icon, children, active, hideHeadingOnMobile } = this.props;
const showHeading = heading && (!hideHeadingOnMobile || (hideHeadingOnMobile && !isMobile(window.innerWidth)));
const columnHeaderId = showHeading && heading.replace(/ /g, '-');
const header = showHeading && (
<ColumnHeader icon={icon} iconComponent={iconComponent} active={active} title={heading} onClick={this.handleHeaderClick} columnHeaderId={columnHeaderId} showBackButton={alwaysShowBackButton} />
<ColumnHeader icon={icon} active={active} type={heading} onClick={this.handleHeaderClick} columnHeaderId={columnHeaderId} />
);
return (
<div

View File

@ -0,0 +1,40 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import classNames from 'classnames';
import { Icon } from 'mastodon/components/icon';
export default class ColumnHeader extends PureComponent {
static propTypes = {
icon: PropTypes.string,
type: PropTypes.string,
active: PropTypes.bool,
onClick: PropTypes.func,
columnHeaderId: PropTypes.string,
};
handleClick = () => {
this.props.onClick();
};
render () {
const { icon, type, active, columnHeaderId } = this.props;
let iconElement = '';
if (icon) {
iconElement = <Icon id={icon} fixedWidth className='column-header__icon' />;
}
return (
<h1 className={classNames('column-header', { active })} id={columnHeaderId || null}>
<button onClick={this.handleClick}>
{iconElement}
{type}
</button>
</h1>
);
}
}

View File

@ -5,10 +5,10 @@ import { NavLink } from 'react-router-dom';
import { Icon } from 'mastodon/components/icon';
const ColumnLink = ({ icon, iconComponent, text, to, href, method, badge, transparent, ...other }) => {
const ColumnLink = ({ icon, text, to, href, method, badge, transparent, ...other }) => {
const className = classNames('column-link', { 'column-link--transparent': transparent });
const badgeElement = typeof badge !== 'undefined' ? <span className='column-link__badge'>{badge}</span> : null;
const iconElement = (typeof icon === 'string' || iconComponent) ? <Icon id={icon} icon={iconComponent} className='column-link__icon' /> : icon;
const iconElement = typeof icon === 'string' ? <Icon id={icon} fixedWidth className='column-link__icon' /> : icon;
if (href) {
return (
@ -31,7 +31,6 @@ const ColumnLink = ({ icon, iconComponent, text, to, href, method, badge, transp
ColumnLink.propTypes = {
icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
iconComponent: PropTypes.func,
text: PropTypes.string.isRequired,
to: PropTypes.string,
href: PropTypes.string,

View File

@ -0,0 +1,32 @@
import PropTypes from 'prop-types';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Column from '../../../components/column';
import ColumnHeader from '../../../components/column_header';
export default class ColumnLoading extends ImmutablePureComponent {
static propTypes = {
title: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
icon: PropTypes.string,
multiColumn: PropTypes.bool,
};
static defaultProps = {
title: '',
icon: '',
};
render() {
let { title, icon, multiColumn } = this.props;
return (
<Column>
<ColumnHeader icon={icon} title={title} multiColumn={multiColumn} focusable={false} placeholder />
<div className='scrollable' />
</Column>
);
}
}

View File

@ -1,13 +0,0 @@
import Column from '../../../components/column';
import ColumnHeader from '../../../components/column_header';
interface Props {
multiColumn?: boolean;
}
export const ColumnLoading: React.FC<Props> = (otherProps) => (
<Column>
<ColumnHeader {...otherProps} />
<div className='scrollable' />
</Column>
);

View File

@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
import { Children, cloneElement, useCallback } from 'react';
import { Children, cloneElement } from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
@ -21,10 +21,9 @@ import {
ListTimeline,
Directory,
} from '../util/async-components';
import { useColumnsContext } from '../util/columns_context';
import BundleColumnError from './bundle_column_error';
import { ColumnLoading } from './column_loading';
import ColumnLoading from './column_loading';
import ComposePanel from './compose_panel';
import DrawerLoading from './drawer_loading';
import NavigationPanel from './navigation_panel';
@ -44,17 +43,6 @@ const componentMap = {
'DIRECTORY': Directory,
};
const TabsBarPortal = () => {
const {setTabsBarElement} = useColumnsContext();
const setRef = useCallback((element) => {
if(element)
setTabsBarElement(element);
}, [setTabsBarElement]);
return <div id='tabs-bar__portal' ref={setRef} />;
};
export default class ColumnsArea extends ImmutablePureComponent {
static propTypes = {
columns: ImmutablePropTypes.list.isRequired,
@ -158,7 +146,7 @@ export default class ColumnsArea extends ImmutablePureComponent {
</div>
<div className='columns-area__panels__main'>
<div className='tabs-bar__wrapper'><TabsBarPortal /></div>
<div className='tabs-bar__wrapper'><div id='tabs-bar__portal' /></div>
<div className='columns-area columns-area--mobile'>{children}</div>
</div>

View File

@ -6,7 +6,6 @@ import { FormattedMessage } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import escapeTextContentForBrowser from 'escape-html';
import { closeModal } from 'mastodon/actions/modal';
@ -66,7 +65,7 @@ class CompareHistoryModal extends PureComponent {
return (
<div className='modal-root__modal compare-history-modal'>
<div className='report-modal__target'>
<IconButton className='report-modal__close' icon='times' iconComponent={CloseIcon} onClick={onClose} size={20} />
<IconButton className='report-modal__close' icon='times' onClick={onClose} size={20} />
{label}
</div>

View File

@ -4,8 +4,6 @@ import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import api from 'mastodon/api';
import { IconButton } from 'mastodon/components/icon_button';
@ -64,7 +62,7 @@ class EmbedModal extends ImmutablePureComponent {
return (
<div className='modal-root__modal report-modal embed-modal'>
<div className='report-modal__target'>
<IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' iconComponent={CloseIcon} onClick={onClose} size={16} />
<IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={16} />
<FormattedMessage id='status.embed' defaultMessage='Embed' />
</div>

View File

@ -5,8 +5,6 @@ import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { fetchFilters, createFilter, createFilterStatus } from 'mastodon/actions/filters';
import { fetchStatus } from 'mastodon/actions/statuses';
import { IconButton } from 'mastodon/components/icon_button';
@ -122,7 +120,7 @@ class FilterModal extends ImmutablePureComponent {
return (
<div className='modal-root__modal report-dialog-modal'>
<div className='report-modal__target'>
<IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' iconComponent={CloseIcon} onClick={onClose} size={20} />
<IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={20} />
<FormattedMessage id='filter_modal.title.status' defaultMessage='Filter a post' />
</div>

View File

@ -9,7 +9,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import Textarea from 'react-textarea-autosize';
import { length } from 'stringz';
// eslint-disable-next-line import/extensions
@ -313,7 +312,7 @@ class FocalPointModal extends ImmutablePureComponent {
return (
<div className='modal-root__modal report-modal' style={{ maxWidth: 960 }}>
<div className='report-modal__target'>
<IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' iconComponent={CloseIcon} onClick={onClose} size={20} />
<IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={20} />
<FormattedMessage id='upload_modal.edit_media' defaultMessage='Edit media' />
</div>

View File

@ -6,8 +6,6 @@ import { injectIntl, defineMessages } from 'react-intl';
import { List as ImmutableList } from 'immutable';
import { connect } from 'react-redux';
import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add.svg';
import { fetchFollowRequests } from 'mastodon/actions/accounts';
import { IconWithBadge } from 'mastodon/components/icon_with_badge';
import ColumnLink from 'mastodon/features/ui/components/column_link';
@ -45,7 +43,7 @@ class FollowRequestsColumnLink extends Component {
<ColumnLink
transparent
to='/follow_requests'
icon={<IconWithBadge className='column-link__icon' id='user-plus' icon={PersonAddIcon} count={count} />}
icon={<IconWithBadge className='column-link__icon' id='user-plus' count={count} />}
text={intl.formatMessage(messages.text)}
/>
);

View File

@ -7,8 +7,6 @@ import { Link, withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { ReactComponent as SearchIcon } from '@material-symbols/svg-600/outlined/search.svg';
import { openModal } from 'mastodon/actions/modal';
import { fetchServer } from 'mastodon/actions/server';
import { Avatar } from 'mastodon/components/avatar';
@ -69,7 +67,7 @@ class Header extends PureComponent {
if (signedIn) {
content = (
<>
{location.pathname !== '/search' && <Link to='/search' className='button button-secondary' aria-label={intl.formatMessage(messages.search)}><Icon id='search' icon={SearchIcon} /></Link>}
{location.pathname !== '/search' && <Link to='/search' className='button button-secondary' aria-label={intl.formatMessage(messages.search)}><Icon id='search' /></Link>}
{location.pathname !== '/publish' && <Link to='/publish' className='button button-secondary'><FormattedMessage id='compose_form.publish_form' defaultMessage='New post' /></Link>}
<Account />
</>

View File

@ -5,8 +5,6 @@ import { defineMessages, injectIntl } from 'react-intl';
import classNames from 'classnames';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { IconButton } from 'mastodon/components/icon_button';
import ImageLoader from './image_loader';
@ -55,7 +53,7 @@ class ImageModal extends PureComponent {
</div>
<div className={navigationClassName}>
<IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' iconComponent={CloseIcon} onClick={onClose} size={40} />
<IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={40} />
</div>
</div>
);

View File

@ -5,8 +5,6 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg';
import { fetchLists } from 'mastodon/actions/lists';
import ColumnLink from './column_link';
@ -47,7 +45,7 @@ class ListPanel extends ImmutablePureComponent {
<hr />
{lists.map(list => (
<ColumnLink icon='list-ul' iconComponent={ListAltIcon} key={list.get('id')} strict text={list.get('title')} to={`/lists/${list.get('id')}`} transparent />
<ColumnLink icon='list-ul' key={list.get('id')} strict text={list.get('title')} to={`/lists/${list.get('id')}`} transparent />
))}
</div>
);

View File

@ -7,9 +7,6 @@ import classNames from 'classnames';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ReactComponent as ChevronLeftIcon } from '@material-symbols/svg-600/outlined/chevron_left.svg';
import { ReactComponent as ChevronRightIcon } from '@material-symbols/svg-600/outlined/chevron_right.svg';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import ReactSwipeableViews from 'react-swipeable-views';
import { getAverageFromBlurhash } from 'mastodon/blurhash';
@ -142,8 +139,8 @@ class MediaModal extends ImmutablePureComponent {
const index = this.getIndex();
const leftNav = media.size > 1 && <button tabIndex={0} className='media-modal__nav media-modal__nav--left' onClick={this.handlePrevClick} aria-label={intl.formatMessage(messages.previous)}><Icon id='chevron-left' icon={ChevronLeftIcon} /></button>;
const rightNav = media.size > 1 && <button tabIndex={0} className='media-modal__nav media-modal__nav--right' onClick={this.handleNextClick} aria-label={intl.formatMessage(messages.next)}><Icon id='chevron-right' icon={ChevronRightIcon} /></button>;
const leftNav = media.size > 1 && <button tabIndex={0} className='media-modal__nav media-modal__nav--left' onClick={this.handlePrevClick} aria-label={intl.formatMessage(messages.previous)}><Icon id='chevron-left' fixedWidth /></button>;
const rightNav = media.size > 1 && <button tabIndex={0} className='media-modal__nav media-modal__nav--right' onClick={this.handleNextClick} aria-label={intl.formatMessage(messages.next)}><Icon id='chevron-right' fixedWidth /></button>;
const content = media.map((image) => {
const width = image.getIn(['meta', 'original', 'width']) || null;
@ -246,7 +243,7 @@ class MediaModal extends ImmutablePureComponent {
</div>
<div className={navigationClassName}>
<IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' iconComponent={CloseIcon} onClick={onClose} size={40} />
<IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={40} />
{leftNav}
{rightNav}

View File

@ -5,17 +5,6 @@ import { defineMessages, injectIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg';
import { ReactComponent as BookmarksIcon } from '@material-symbols/svg-600/outlined/bookmarks-fill.svg';
import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg';
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
import { ReactComponent as SearchIcon } from '@material-symbols/svg-600/outlined/search.svg';
import { ReactComponent as SettingsIcon } from '@material-symbols/svg-600/outlined/settings-fill.svg';
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
import { ReactComponent as TagIcon } from '@material-symbols/svg-600/outlined/tag.svg';
import { WordmarkLogo } from 'mastodon/components/logo';
import { NavigationPortal } from 'mastodon/components/navigation_portal';
import { timelinePreview, trendsEnabled } from 'mastodon/initial_state';
@ -89,20 +78,20 @@ class NavigationPanel extends Component {
{signedIn && (
<>
<ColumnLink transparent to='/home' icon='home' iconComponent={HomeIcon} text={intl.formatMessage(messages.home)} />
<ColumnLink transparent to='/home' icon='home' text={intl.formatMessage(messages.home)} />
<ColumnLink transparent to='/notifications' icon={<NotificationsCounterIcon className='column-link__icon' />} text={intl.formatMessage(messages.notifications)} />
<FollowRequestsColumnLink />
</>
)}
{trendsEnabled ? (
<ColumnLink transparent to='/explore' icon='hashtag' iconComponent={TagIcon} text={intl.formatMessage(messages.explore)} />
<ColumnLink transparent to='/explore' icon='hashtag' text={intl.formatMessage(messages.explore)} />
) : (
<ColumnLink transparent to='/search' icon='search' iconComponent={SearchIcon} text={intl.formatMessage(messages.search)} />
<ColumnLink transparent to='/search' icon='search' text={intl.formatMessage(messages.search)} />
)}
{(signedIn || timelinePreview) && (
<ColumnLink transparent to='/public/local' isActive={this.isFirehoseActive} icon='globe' iconComponent={PublicIcon} text={intl.formatMessage(messages.firehose)} />
<ColumnLink transparent to='/public/local' isActive={this.isFirehoseActive} icon='globe' text={intl.formatMessage(messages.firehose)} />
)}
{!signedIn && (
@ -114,22 +103,22 @@ class NavigationPanel extends Component {
{signedIn && (
<>
<ColumnLink transparent to='/conversations' icon='at' iconComponent={AlternateEmailIcon} text={intl.formatMessage(messages.direct)} />
<ColumnLink transparent to='/bookmarks' icon='bookmarks' iconComponent={BookmarksIcon} text={intl.formatMessage(messages.bookmarks)} />
<ColumnLink transparent to='/favourites' icon='star' iconComponent={StarIcon} text={intl.formatMessage(messages.favourites)} />
<ColumnLink transparent to='/lists' icon='list-ul' iconComponent={ListAltIcon} text={intl.formatMessage(messages.lists)} />
<ColumnLink transparent to='/conversations' icon='at' text={intl.formatMessage(messages.direct)} />
<ColumnLink transparent to='/bookmarks' icon='bookmark' text={intl.formatMessage(messages.bookmarks)} />
<ColumnLink transparent to='/favourites' icon='star' text={intl.formatMessage(messages.favourites)} />
<ColumnLink transparent to='/lists' icon='list-ul' text={intl.formatMessage(messages.lists)} />
<ListPanel />
<hr />
<ColumnLink transparent href='/settings/preferences' icon='cog' iconComponent={SettingsIcon} text={intl.formatMessage(messages.preferences)} />
<ColumnLink transparent href='/settings/preferences' icon='cog' text={intl.formatMessage(messages.preferences)} />
</>
)}
<div className='navigation-panel__legal'>
<hr />
<ColumnLink transparent to='/about' icon='ellipsis-h' iconComponent={MoreHorizIcon} text={intl.formatMessage(messages.about)} />
<ColumnLink transparent to='/about' icon='ellipsis-h' text={intl.formatMessage(messages.about)} />
</div>
<NavigationPortal />

View File

@ -1,14 +1,10 @@
import { connect } from 'react-redux';
import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications-fill.svg';
import { IconWithBadge } from 'mastodon/components/icon_with_badge';
const mapStateToProps = state => ({
count: state.getIn(['notifications', 'unread']),
id: 'bell',
icon: NotificationsIcon,
});
export default connect(mapStateToProps)(IconWithBadge);

View File

@ -7,8 +7,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
import { submitReport } from 'mastodon/actions/reports';
import { fetchServer } from 'mastodon/actions/server';
import { expandAccountTimeline } from 'mastodon/actions/timelines';
@ -211,7 +209,7 @@ class ReportModal extends ImmutablePureComponent {
return (
<div className='modal-root__modal report-dialog-modal'>
<div className='report-modal__target'>
<IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' iconComponent={CloseIcon} onClick={onClose} size={20} />
<IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={20} />
<FormattedMessage id='report.target' defaultMessage='Report {target}' values={{ target: <strong>{account.get('acct')}</strong> }} />
</div>

View File

@ -3,9 +3,6 @@ import { PureComponent } from 'react';
import { defineMessages, injectIntl } from 'react-intl';
import { ReactComponent as FullscreenExitIcon } from '@material-symbols/svg-600/outlined/fullscreen_exit.svg';
import { ReactComponent as RectangleIcon } from '@material-symbols/svg-600/outlined/rectangle.svg';
import { IconButton } from 'mastodon/components/icon_button';
const messages = defineMessages({
@ -421,7 +418,6 @@ class ZoomableImage extends PureComponent {
className={`media-modal__zoom-button ${zoomButtonShouldHide}`}
title={zoomButtonTitle}
icon={this.state.zoomState}
iconComponent={this.state.zoomState === 'compress' ? FullscreenExitIcon : RectangleIcon}
onClick={this.handleZoomClick}
size={40}
style={{

View File

@ -64,8 +64,8 @@ import {
About,
PrivacyPolicy,
} from './util/async-components';
import { ColumnsContextProvider } from './util/columns_context';
import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers';
// Dummy import, to make sure that <Status /> ends up in the application bundle.
// Without this it ends up in ~8 very commonly used bundles.
import '../../components/status';
@ -179,70 +179,68 @@ class SwitchingColumnsArea extends PureComponent {
}
return (
<ColumnsContextProvider multiColumn={!singleColumn}>
<ColumnsAreaContainer ref={this.setRef} singleColumn={singleColumn}>
<WrappedSwitch>
{redirect}
<ColumnsAreaContainer ref={this.setRef} singleColumn={singleColumn}>
<WrappedSwitch>
{redirect}
{singleColumn ? <Redirect from='/deck' to='/home' exact /> : null}
{singleColumn && pathName.startsWith('/deck/') ? <Redirect from={pathName} to={pathName.slice(5)} /> : null}
{/* Redirect old bookmarks (without /deck) with home-like routes to the advanced interface */}
{!singleColumn && pathName === '/getting-started' ? <Redirect from='/getting-started' to='/deck/getting-started' exact /> : null}
{!singleColumn && pathName === '/home' ? <Redirect from='/home' to='/deck/getting-started' exact /> : null}
{singleColumn ? <Redirect from='/deck' to='/home' exact /> : null}
{singleColumn && pathName.startsWith('/deck/') ? <Redirect from={pathName} to={pathName.slice(5)} /> : null}
{/* Redirect old bookmarks (without /deck) with home-like routes to the advanced interface */}
{!singleColumn && pathName === '/getting-started' ? <Redirect from='/getting-started' to='/deck/getting-started' exact /> : null}
{!singleColumn && pathName === '/home' ? <Redirect from='/home' to='/deck/getting-started' exact /> : null}
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
<WrappedRoute path='/about' component={About} content={children} />
<WrappedRoute path='/privacy-policy' component={PrivacyPolicy} content={children} />
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
<WrappedRoute path='/about' component={About} content={children} />
<WrappedRoute path='/privacy-policy' component={PrivacyPolicy} content={children} />
<WrappedRoute path={['/home', '/timelines/home']} component={HomeTimeline} content={children} />
<Redirect from='/timelines/public' to='/public' exact />
<Redirect from='/timelines/public/local' to='/public/local' exact />
<WrappedRoute path='/public' exact component={Firehose} componentParams={{ feedType: 'public' }} content={children} />
<WrappedRoute path='/public/local' exact component={Firehose} componentParams={{ feedType: 'community' }} content={children} />
<WrappedRoute path='/public/remote' exact component={Firehose} componentParams={{ feedType: 'public:remote' }} content={children} />
<WrappedRoute path={['/conversations', '/timelines/direct']} component={DirectTimeline} content={children} />
<WrappedRoute path='/tags/:id' component={HashtagTimeline} content={children} />
<WrappedRoute path='/lists/:id' component={ListTimeline} content={children} />
<WrappedRoute path='/notifications' component={Notifications} content={children} />
<WrappedRoute path='/favourites' component={FavouritedStatuses} content={children} />
<WrappedRoute path={['/home', '/timelines/home']} component={HomeTimeline} content={children} />
<Redirect from='/timelines/public' to='/public' exact />
<Redirect from='/timelines/public/local' to='/public/local' exact />
<WrappedRoute path='/public' exact component={Firehose} componentParams={{ feedType: 'public' }} content={children} />
<WrappedRoute path='/public/local' exact component={Firehose} componentParams={{ feedType: 'community' }} content={children} />
<WrappedRoute path='/public/remote' exact component={Firehose} componentParams={{ feedType: 'public:remote' }} content={children} />
<WrappedRoute path={['/conversations', '/timelines/direct']} component={DirectTimeline} content={children} />
<WrappedRoute path='/tags/:id' component={HashtagTimeline} content={children} />
<WrappedRoute path='/lists/:id' component={ListTimeline} content={children} />
<WrappedRoute path='/notifications' component={Notifications} content={children} />
<WrappedRoute path='/favourites' component={FavouritedStatuses} content={children} />
<WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} />
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
<WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} />
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
<WrappedRoute path='/start' exact component={Onboarding} content={children} />
<WrappedRoute path='/directory' component={Directory} content={children} />
<WrappedRoute path={['/explore', '/search']} component={Explore} content={children} />
<WrappedRoute path={['/publish', '/statuses/new']} component={Compose} content={children} />
<WrappedRoute path='/start' exact component={Onboarding} content={children} />
<WrappedRoute path='/directory' component={Directory} content={children} />
<WrappedRoute path={['/explore', '/search']} component={Explore} content={children} />
<WrappedRoute path={['/publish', '/statuses/new']} component={Compose} content={children} />
<WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} />
<WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} />
<WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />
<WrappedRoute path={['/accounts/:id/followers', '/users/:acct/followers', '/@:acct/followers']} component={Followers} content={children} />
<WrappedRoute path={['/accounts/:id/following', '/users/:acct/following', '/@:acct/following']} component={Following} content={children} />
<WrappedRoute path={['/@:acct/media', '/accounts/:id/media']} component={AccountGallery} content={children} />
<WrappedRoute path='/@:acct/:statusId' exact component={Status} content={children} />
<WrappedRoute path='/@:acct/:statusId/reblogs' component={Reblogs} content={children} />
<WrappedRoute path='/@:acct/:statusId/favourites' component={Favourites} content={children} />
<WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} />
<WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} />
<WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />
<WrappedRoute path={['/accounts/:id/followers', '/users/:acct/followers', '/@:acct/followers']} component={Followers} content={children} />
<WrappedRoute path={['/accounts/:id/following', '/users/:acct/following', '/@:acct/following']} component={Following} content={children} />
<WrappedRoute path={['/@:acct/media', '/accounts/:id/media']} component={AccountGallery} content={children} />
<WrappedRoute path='/@:acct/:statusId' exact component={Status} content={children} />
<WrappedRoute path='/@:acct/:statusId/reblogs' component={Reblogs} content={children} />
<WrappedRoute path='/@:acct/:statusId/favourites' component={Favourites} content={children} />
{/* Legacy routes, cannot be easily factored with other routes because they share a param name */}
<WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} />
<WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} />
<WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} />
<WrappedRoute path='/statuses/:statusId/reblogs' component={Reblogs} content={children} />
<WrappedRoute path='/statuses/:statusId/favourites' component={Favourites} content={children} />
{/* Legacy routes, cannot be easily factored with other routes because they share a param name */}
<WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} />
<WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} />
<WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} />
<WrappedRoute path='/statuses/:statusId/reblogs' component={Reblogs} content={children} />
<WrappedRoute path='/statuses/:statusId/favourites' component={Favourites} content={children} />
<WrappedRoute path='/follow_requests' component={FollowRequests} content={children} />
<WrappedRoute path='/blocks' component={Blocks} content={children} />
<WrappedRoute path='/domain_blocks' component={DomainBlocks} content={children} />
<WrappedRoute path='/followed_tags' component={FollowedTags} content={children} />
<WrappedRoute path='/mutes' component={Mutes} content={children} />
<WrappedRoute path='/lists' component={Lists} content={children} />
<WrappedRoute path='/follow_requests' component={FollowRequests} content={children} />
<WrappedRoute path='/blocks' component={Blocks} content={children} />
<WrappedRoute path='/domain_blocks' component={DomainBlocks} content={children} />
<WrappedRoute path='/followed_tags' component={FollowedTags} content={children} />
<WrappedRoute path='/mutes' component={Mutes} content={children} />
<WrappedRoute path='/lists' component={Lists} content={children} />
<Route component={BundleColumnError} />
</WrappedSwitch>
</ColumnsAreaContainer>
</ColumnsContextProvider>
<Route component={BundleColumnError} />
</WrappedSwitch>
</ColumnsAreaContainer>
);
}

View File

@ -1,51 +0,0 @@
import type { ReactElement } from 'react';
import { createContext, useContext, useMemo, useState } from 'react';
import { createPortal } from 'react-dom';
export const ColumnsContext = createContext<{
tabsBarElement: HTMLElement | null;
setTabsBarElement: (element: HTMLElement) => void;
multiColumn: boolean;
}>({
tabsBarElement: null,
multiColumn: false,
setTabsBarElement: () => undefined, // no-op
});
export function useColumnsContext() {
return useContext(ColumnsContext);
}
export const ButtonInTabsBar: React.FC<{
children: ReactElement | string | undefined;
}> = ({ children }) => {
const { multiColumn, tabsBarElement } = useColumnsContext();
if (multiColumn) {
return children;
} else if (!tabsBarElement) {
return children;
} else {
return createPortal(children, tabsBarElement);
}
};
type ContextValue = React.ContextType<typeof ColumnsContext>;
export const ColumnsContextProvider: React.FC<
React.PropsWithChildren<{ multiColumn: boolean }>
> = ({ multiColumn, children }) => {
const [tabsBarElement, setTabsBarElement] =
useState<ContextValue['tabsBarElement']>(null);
const contextValue = useMemo<ContextValue>(
() => ({ multiColumn, tabsBarElement, setTabsBarElement }),
[multiColumn, tabsBarElement],
);
return (
<ColumnsContext.Provider value={contextValue}>
{children}
</ColumnsContext.Provider>
);
};

View File

@ -6,7 +6,7 @@ import { Switch, Route, useLocation } from 'react-router-dom';
import StackTrace from 'stacktrace-js';
import BundleColumnError from '../components/bundle_column_error';
import { ColumnLoading } from '../components/column_loading';
import ColumnLoading from '../components/column_loading';
import BundleContainer from '../containers/bundle_container';
// Small wrapper to pass multiColumn to the route components

View File

@ -7,14 +7,6 @@ import classNames from 'classnames';
import { is } from 'immutable';
import { ReactComponent as FullscreenIcon } from '@material-symbols/svg-600/outlined/fullscreen.svg';
import { ReactComponent as FullscreenExitIcon } from '@material-symbols/svg-600/outlined/fullscreen_exit.svg';
import { ReactComponent as PauseIcon } from '@material-symbols/svg-600/outlined/pause.svg';
import { ReactComponent as PlayArrowIcon } from '@material-symbols/svg-600/outlined/play_arrow-fill.svg';
import { ReactComponent as RectangleIcon } from '@material-symbols/svg-600/outlined/rectangle.svg';
import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
import { ReactComponent as VolumeOffIcon } from '@material-symbols/svg-600/outlined/volume_off-fill.svg';
import { ReactComponent as VolumeUpIcon } from '@material-symbols/svg-600/outlined/volume_up-fill.svg';
import { throttle } from 'lodash';
import { Blurhash } from 'mastodon/components/blurhash';
@ -600,8 +592,8 @@ class Video extends PureComponent {
<div className='video-player__buttons-bar'>
<div className='video-player__buttons left'>
<button type='button' title={intl.formatMessage(paused ? messages.play : messages.pause)} aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} className='player-button' onClick={this.togglePlay} autoFocus={autoFocus}><Icon id={paused ? 'play' : 'pause'} icon={paused ? PlayArrowIcon : PauseIcon} /></button>
<button type='button' title={intl.formatMessage(muted ? messages.unmute : messages.mute)} aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} className='player-button' onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} icon={muted ? VolumeOffIcon : VolumeUpIcon} /></button>
<button type='button' title={intl.formatMessage(paused ? messages.play : messages.pause)} aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} className='player-button' onClick={this.togglePlay} autoFocus={autoFocus}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>
<button type='button' title={intl.formatMessage(muted ? messages.unmute : messages.mute)} aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} className='player-button' onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
<div className={classNames('video-player__volume', { active: this.state.hovered })} onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>
<div className='video-player__volume__current' style={{ width: `${muted ? 0 : volume * 100}%` }} />
@ -623,10 +615,10 @@ class Video extends PureComponent {
</div>
<div className='video-player__buttons right'>
{(!onCloseVideo && !editable && !fullscreen && !this.props.alwaysVisible) && <button type='button' title={intl.formatMessage(messages.hide)} aria-label={intl.formatMessage(messages.hide)} className='player-button' onClick={this.toggleReveal}><Icon id='eye-slash' icon={VisibilityOffIcon} /></button>}
{(!fullscreen && onOpenVideo) && <button type='button' title={intl.formatMessage(messages.expand)} aria-label={intl.formatMessage(messages.expand)} className='player-button' onClick={this.handleOpenVideo}><Icon id='expand' icon={RectangleIcon} /></button>}
{onCloseVideo && <button type='button' title={intl.formatMessage(messages.close)} aria-label={intl.formatMessage(messages.close)} className='player-button' onClick={this.handleCloseVideo}><Icon id='compress' icon={FullscreenExitIcon} /></button>}
<button type='button' title={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} aria-label={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} className='player-button' onClick={this.toggleFullscreen}><Icon id={fullscreen ? 'compress' : 'arrows-alt'} icon={fullscreen ? FullscreenExitIcon : FullscreenIcon} /></button>
{(!onCloseVideo && !editable && !fullscreen && !this.props.alwaysVisible) && <button type='button' title={intl.formatMessage(messages.hide)} aria-label={intl.formatMessage(messages.hide)} className='player-button' onClick={this.toggleReveal}><Icon id='eye-slash' fixedWidth /></button>}
{(!fullscreen && onOpenVideo) && <button type='button' title={intl.formatMessage(messages.expand)} aria-label={intl.formatMessage(messages.expand)} className='player-button' onClick={this.handleOpenVideo}><Icon id='expand' fixedWidth /></button>}
{onCloseVideo && <button type='button' title={intl.formatMessage(messages.close)} aria-label={intl.formatMessage(messages.close)} className='player-button' onClick={this.handleCloseVideo}><Icon id='compress' fixedWidth /></button>}
<button type='button' title={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} aria-label={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} className='player-button' onClick={this.toggleFullscreen}><Icon id={fullscreen ? 'compress' : 'arrows-alt'} fixedWidth /></button>
</div>
</div>
</div>

View File

@ -534,7 +534,6 @@
"reply_indicator.cancel": "Zrušit",
"report.block": "Blokovat",
"report.block_explanation": "Neuvidíte příspěvky tohoto uživatele. On neuvidí vaše příspěvky, ani vás nebude moci sledovat. Pozná, že je blokován.",
"report.categories.legal": "Právní ustanovení",
"report.categories.other": "Ostatní",
"report.categories.spam": "Spam",
"report.categories.violation": "Obsah porušuje jedno nebo více pravidel serveru",
@ -591,7 +590,6 @@
"search_popout.options": "Možnosti hledání",
"search_popout.quick_actions": "Rychlé akce",
"search_popout.recent": "Nedávná vyhledávání",
"search_popout.specific_date": "konkrétní datum",
"search_popout.user": "uživatel",
"search_results.accounts": "Profily",
"search_results.all": "Vše",

View File

@ -1,5 +1,5 @@
{
"about.blocks": "Moderoidut palvelimet",
"about.blocks": "Valvotut palvelimet",
"about.contact": "Ota yhteyttä:",
"about.disclaimer": "Mastodon on vapaa avoimen lähdekoodin ohjelmisto ja Mastodon gGmbH:n tavaramerkki.",
"about.domain_blocks.no_reason_available": "Syytä ei ole ilmoitettu",

View File

@ -20,7 +20,7 @@
"account.block_short": "Bloquear",
"account.blocked": "Bloqueada",
"account.browse_more_on_origin_server": "Busca máis no perfil orixinal",
"account.cancel_follow_request": "Cancelar a solicitude de seguimento",
"account.cancel_follow_request": "Retirar solicitude de seguimento",
"account.direct": "Mencionar de xeito privado a @{name}",
"account.disable_notifications": "Deixar de notificarme cando @{name} publica",
"account.domain_blocked": "Dominio agochado",

View File

@ -202,7 +202,7 @@
"dismissable_banner.community_timeline": "אלו הם החצרוצים הציבוריים האחרונים מהמשתמשים על שרת {domain}.",
"dismissable_banner.dismiss": "בטל",
"dismissable_banner.explore_links": "אלו הקישורים האחרונים ששותפו על ידי משתמשים ששרת זה רואה ברשת המבוזרת כרגע.",
"dismissable_banner.explore_statuses": "ההודעות האלו, משרת זה ואחרים ברשת המבוזרת, צוברים חשיפה היום. הודעות חדשות יותר עם יותר הדהודים וחיבובים מדורגים גבוה יותר.",
"dismissable_banner.explore_statuses": "ההודעות האלו, משרת זה ואחרים ברשת המבוזרת, צוברים חשיפה היום. הודעות חדשות יותר עם יותר הדהודים וחיבובים מדורגים יותר לגובה.",
"dismissable_banner.explore_tags": "התגיות האלו, משרת זה ואחרים ברשת המבוזרת, צוברות חשיפה כעת.",
"dismissable_banner.public_timeline": "אלו ההודעות האחרונות שהתקבלו מהמשתמשים שנעקבים על ידי משתמשים מ־{domain}.",
"embed.instructions": "ניתן להטמיע את ההודעה הזו באתרך ע\"י העתקת הקוד שלהלן.",
@ -315,7 +315,7 @@
"home.pending_critical_update.title": "יצא עדכון אבטחה חשוב!",
"home.show_announcements": "הצג הכרזות",
"interaction_modal.description.favourite": "עם חשבון מסטודון, ניתן לחבב את ההודעה כדי לומר למחבר/ת שהערכת את תוכנו או כדי לשמור אותו לקריאה בעתיד.",
"interaction_modal.description.follow": "עם חשבון מסטודון, ניתן לעקוב אחרי {name} כדי לקבל את הפוסטים שלו/ה בפיד הבית.",
"interaction_modal.description.follow": "עם חשבון מסטודון, ניתן לעקוב אחרי {name} כדי לקבל את הםוסטים שלו/ה בפיד הבית.",
"interaction_modal.description.reblog": "עם חשבון מסטודון, ניתן להדהד את החצרוץ ולשתף עם עוקבים.",
"interaction_modal.description.reply": "עם חשבון מסטודון, ניתן לענות לחצרוץ.",
"interaction_modal.login.action": "קח אותי לדף הבית",
@ -493,7 +493,7 @@
"onboarding.steps.setup_profile.title": "התאמה אישית של הפרופיל",
"onboarding.steps.share_profile.body": "ספרו לחברים איך למצוא אתכם במסטודון!",
"onboarding.steps.share_profile.title": "לשתף פרופיל",
"onboarding.tips.2fa": "<strong>הידעת?</strong> ניתן לאבטח את החשבון ע\"י הקמת אימות דו-שלבי במסך מאפייני החשבון. השיטה תעבוד עם כל יישומון תואם TOTP על המכשיר שלך, ללא צורך במספר טלפון!",
"onboarding.tips.2fa": "<strong>הידעת?</strong> ניתן לאבטח את החשבון ע\"י הקמת אימות בשני צעדים במסך מאפייני החשבון. השיטה תעבוד עם כל יישומון תואם TOTP על המגשיר שלך, אין צורך לתת לנו את מספר הטלפון!",
"onboarding.tips.accounts_from_other_servers": "<strong>הידעת?</strong> כיוון שמסטודון פועל ברשת מבוזרת, חלק מהפרופילים שתתקלו בהם פועלים משרתים אחרים משרת הבית שלכם. ניתן להיות איתם בקשר בצורה זהה לכל חשבון אחר! שם השרת שלהם הוא החלק השני של שם המשתמש שלהם!",
"onboarding.tips.migration": "<strong>הידעת?</strong> אם תחליטו כי {domain} איננו שרת שמתאים לכם בעתיד, ניתן לעבור לשרת אחר מבלי לאבד עוקבים. תוכלו אפילו להקים שרת משלכן!",
"onboarding.tips.verification": "<strong>הידעת?</strong> ניתן לאשרר את החשבון ע\"י קישור הפרופיל אל האתר שלכם ומהאתר חזרה לפרופיל. לא נדרשים תשלומים ומסמכים!",
@ -575,7 +575,7 @@
"report.thanks.title": "לא מעוניין/ת לראות את זה?",
"report.thanks.title_actionable": "תודה על הדיווח, נבדוק את העניין.",
"report.unfollow": "הפסיקו לעקוב אחרי @{name}",
"report.unfollow_explanation": "אתם עוקבים אחרי החשבון הזה. כדי להפסיק לראות את הפרסומים שלו בפיד הבית שלכם, הפסיקו לעקוב אחריו.",
"report.unfollow_explanation": "אתם עוקבים אחרי החשבון הזה. כדי להפסיק לראות את הפרסומים שלו בפיד הבית שלכם, הפסיקו לעקוב אחריהם.",
"report_notification.attached_statuses": "{count, plural, one {הודעה מצורפת} two {הודעותיים מצורפות} many {{count} הודעות מצורפות} other {{count} הודעות מצורפות}}",
"report_notification.categories.legal": "חוקי",
"report_notification.categories.other": "שונות",

View File

@ -590,7 +590,7 @@
"search.quick_action.open_url": "마스토돈에서 URL 열기",
"search.quick_action.status_search": "{x}에 맞는 게시물",
"search.search_or_paste": "검색하거나 URL 붙여넣기",
"search_popout.full_text_search_disabled_message": "{domain}에서는 이용할 수 없습니다.",
"search_popout.full_text_search_disabled_message": "{domain}에서는 수 없습니다.",
"search_popout.language_code": "ISO 언어코드",
"search_popout.options": "검색 옵션",
"search_popout.quick_actions": "빠른 작업",

View File

@ -81,7 +81,7 @@
"admin.impact_report.instance_follows": "Obserwujący, których straciliby ich użytkownicy",
"admin.impact_report.title": "Podsumowanie wpływu",
"alert.rate_limited.message": "Spróbuj ponownie po {retry_time, time, medium}.",
"alert.rate_limited.title": "Ograniczenie liczby zapytań",
"alert.rate_limited.title": "Ograniczony czasowo",
"alert.unexpected.message": "Wystąpił nieoczekiwany błąd.",
"alert.unexpected.title": "Ups!",
"announcement.announcement": "Ogłoszenie",

View File

@ -590,7 +590,6 @@
"search.quick_action.open_url": "在 Mastodon 中打開網址",
"search.quick_action.status_search": "符合的帖文 {x}",
"search.search_or_paste": "搜尋或貼上網址",
"search_popout.full_text_search_disabled_message": "在 {domain} 上無法使用。",
"search_popout.language_code": "ISO 語言代碼",
"search_popout.options": "搜尋選項",
"search_popout.quick_actions": "快速動作",

View File

@ -662,9 +662,9 @@
"status.share": "分享",
"status.show_filter_reason": "仍要顯示",
"status.show_less": "減少顯示",
"status.show_less_all": "隱藏所有內容警告與額外標籤",
"status.show_less_all": "減少顯示這類嘟文",
"status.show_more": "顯示更多",
"status.show_more_all": "顯示所有內容警告與額外標籤",
"status.show_more_all": "顯示更多這類嘟文",
"status.show_original": "顯示原文",
"status.title.with_attachments": "{user} 嘟了 {attachmentCount, plural, other {{attachmentCount} 個附加檔案}}",
"status.translate": "翻譯",

View File

@ -1,62 +0,0 @@
import PropTypes from 'prop-types';
import type { PropsWithChildren } from 'react';
import { Component } from 'react';
import { IntlProvider } from 'react-intl';
import { MemoryRouter } from 'react-router';
// eslint-disable-next-line import/no-extraneous-dependencies
import { render as rtlRender } from '@testing-library/react';
class FakeIdentityWrapper extends Component<
PropsWithChildren<{ signedIn: boolean }>
> {
static childContextTypes = {
identity: PropTypes.shape({
signedIn: PropTypes.bool.isRequired,
accountId: PropTypes.string,
disabledAccountId: PropTypes.string,
accessToken: PropTypes.string,
}).isRequired,
};
getChildContext() {
return {
identity: {
signedIn: this.props.signedIn,
accountId: '123',
accessToken: 'test-access-token',
},
};
}
render() {
return this.props.children;
}
}
function render(
ui: React.ReactElement,
{ locale = 'en', signedIn = true, ...renderOptions } = {},
) {
const Wrapper = (props: { children: React.ReactElement }) => {
return (
<MemoryRouter>
<IntlProvider locale={locale}>
<FakeIdentityWrapper signedIn={signedIn}>
{props.children}
</FakeIdentityWrapper>
</IntlProvider>
</MemoryRouter>
);
};
return rtlRender(ui, { wrapper: Wrapper, ...renderOptions });
}
// re-export everything
// eslint-disable-next-line import/no-extraneous-dependencies
export * from '@testing-library/react';
// override render method
export { render };

View File

@ -2,7 +2,7 @@ import './public-path';
import React from 'react';
import { createRoot } from 'react-dom/client';
import Rails from '@rails/ujs';
import { delegate } from '@rails/ujs';
import ready from '../mastodon/ready';
@ -20,7 +20,7 @@ const setAnnouncementEndsAttributes = (target) => {
}
};
Rails.delegate(document, 'input[type="datetime-local"]#announcement_starts_at', 'change', ({ target }) => {
delegate(document, 'input[type="datetime-local"]#announcement_starts_at', 'change', ({ target }) => {
setAnnouncementEndsAttributes(target);
});
@ -43,7 +43,7 @@ const hideSelectAll = () => {
hiddenField.value = '0';
};
Rails.delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
[].forEach.call(document.querySelectorAll(batchCheckboxClassName), (content) => {
@ -59,7 +59,7 @@ Rails.delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
}
});
Rails.delegate(document, '.batch-table__select-all button', 'click', () => {
delegate(document, '.batch-table__select-all button', 'click', () => {
const hiddenField = document.querySelector('#select_all_matching');
const active = hiddenField.value === '1';
const selectedMsg = document.querySelector('.batch-table__select-all .selected');
@ -76,7 +76,7 @@ Rails.delegate(document, '.batch-table__select-all button', 'click', () => {
}
});
Rails.delegate(document, batchCheckboxClassName, 'change', () => {
delegate(document, batchCheckboxClassName, 'change', () => {
const checkAllElement = document.querySelector('#batch_checkbox_all');
const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
@ -94,19 +94,19 @@ Rails.delegate(document, batchCheckboxClassName, 'change', () => {
}
});
Rails.delegate(document, '.media-spoiler-show-button', 'click', () => {
delegate(document, '.media-spoiler-show-button', 'click', () => {
[].forEach.call(document.querySelectorAll('button.media-spoiler'), (element) => {
element.click();
});
});
Rails.delegate(document, '.media-spoiler-hide-button', 'click', () => {
delegate(document, '.media-spoiler-hide-button', 'click', () => {
[].forEach.call(document.querySelectorAll('.spoiler-button.spoiler-button--visible button'), (element) => {
element.click();
});
});
Rails.delegate(document, '.filter-subset--with-select select', 'change', ({ target }) => {
delegate(document, '.filter-subset--with-select select', 'change', ({ target }) => {
target.form.submit();
});
@ -123,7 +123,7 @@ const onDomainBlockSeverityChange = (target) => {
}
};
Rails.delegate(document, '#domain_block_severity', 'change', ({ target }) => onDomainBlockSeverityChange(target));
delegate(document, '#domain_block_severity', 'change', ({ target }) => onDomainBlockSeverityChange(target));
const onEnableBootstrapTimelineAccountsChange = (target) => {
const bootstrapTimelineAccountsField = document.querySelector('#form_admin_settings_bootstrap_timeline_accounts');
@ -140,7 +140,7 @@ const onEnableBootstrapTimelineAccountsChange = (target) => {
}
};
Rails.delegate(document, '#form_admin_settings_enable_bootstrap_timeline_accounts', 'change', ({ target }) => onEnableBootstrapTimelineAccountsChange(target));
delegate(document, '#form_admin_settings_enable_bootstrap_timeline_accounts', 'change', ({ target }) => onEnableBootstrapTimelineAccountsChange(target));
const onChangeRegistrationMode = (target) => {
const enabled = target.value === 'approved';
@ -177,7 +177,7 @@ const convertLocalDatetimeToUTC = (value) => {
return fullISO8601.slice(0, fullISO8601.indexOf('T') + 6);
};
Rails.delegate(document, '#form_admin_settings_registrations_mode', 'change', ({ target }) => onChangeRegistrationMode(target));
delegate(document, '#form_admin_settings_registrations_mode', 'change', ({ target }) => onChangeRegistrationMode(target));
ready(() => {
const domainBlockSeverityInput = document.getElementById('domain_block_severity');
@ -214,7 +214,7 @@ ready(() => {
}
});
Rails.delegate(document, 'form', 'submit', ({ target }) => {
delegate(document, 'form', 'submit', ({ target }) => {
[].forEach.call(target.querySelectorAll('input[type="datetime-local"]'), element => {
if (element.value && element.validity.valid) {
element.value = convertLocalDatetimeToUTC(element.value);

View File

@ -5,7 +5,7 @@ import './public-path';
import { IntlMessageFormat } from 'intl-messageformat';
import { defineMessages } from 'react-intl';
import Rails from '@rails/ujs';
import { delegate } from '@rails/ujs';
import axios from 'axios';
import { throttle } from 'lodash';
@ -145,7 +145,7 @@ function loaded() {
});
}
Rails.delegate(document, '#user_account_attributes_username', 'input', throttle(({ target }) => {
delegate(document, '#user_account_attributes_username', 'input', throttle(({ target }) => {
if (target.value && target.value.length > 0) {
axios.get('/api/v1/accounts/lookup', { params: { acct: target.value } }).then(() => {
target.setCustomValidity(formatMessage(messages.usernameTaken));
@ -157,7 +157,7 @@ function loaded() {
}
}, 500, { leading: false, trailing: true }));
Rails.delegate(document, '#user_password,#user_password_confirmation', 'input', () => {
delegate(document, '#user_password,#user_password_confirmation', 'input', () => {
const password = document.getElementById('user_password');
const confirmation = document.getElementById('user_password_confirmation');
if (!confirmation) return;
@ -171,7 +171,7 @@ function loaded() {
}
});
Rails.delegate(document, '.status__content__spoiler-link', 'click', function() {
delegate(document, '.status__content__spoiler-link', 'click', function() {
const statusEl = this.parentNode.parentNode;
if (statusEl.dataset.spoiler === 'expanded') {
@ -192,7 +192,7 @@ function loaded() {
});
}
Rails.delegate(document, '#edit_profile input[type=file]', 'change', ({ target }) => {
delegate(document, '#edit_profile input[type=file]', 'change', ({ target }) => {
const avatar = document.getElementById(target.id + '-preview');
const [file] = target.files || [];
const url = file ? URL.createObjectURL(file) : avatar.dataset.originalSrc;
@ -200,13 +200,13 @@ Rails.delegate(document, '#edit_profile input[type=file]', 'change', ({ target }
avatar.src = url;
});
Rails.delegate(document, '.input-copy input', 'click', ({ target }) => {
delegate(document, '.input-copy input', 'click', ({ target }) => {
target.focus();
target.select();
target.setSelectionRange(0, target.value.length);
});
Rails.delegate(document, '.input-copy button', 'click', ({ target }) => {
delegate(document, '.input-copy button', 'click', ({ target }) => {
const input = target.parentNode.querySelector('.input-copy__wrapper input');
const oldReadOnly = input.readonly;
@ -248,23 +248,23 @@ const toggleSidebar = () => {
sidebar.classList.toggle('visible');
};
Rails.delegate(document, '.sidebar__toggle__icon', 'click', () => {
delegate(document, '.sidebar__toggle__icon', 'click', () => {
toggleSidebar();
});
Rails.delegate(document, '.sidebar__toggle__icon', 'keydown', e => {
delegate(document, '.sidebar__toggle__icon', 'keydown', e => {
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
toggleSidebar();
}
});
Rails.delegate(document, '.custom-emoji', 'mouseover', ({ target }) => target.src = target.getAttribute('data-original'));
Rails.delegate(document, '.custom-emoji', 'mouseout', ({ target }) => target.src = target.getAttribute('data-static'));
delegate(document, '.custom-emoji', 'mouseover', ({ target }) => target.src = target.getAttribute('data-original'));
delegate(document, '.custom-emoji', 'mouseout', ({ target }) => target.src = target.getAttribute('data-static'));
// Empty the honeypot fields in JS in case something like an extension
// automatically filled them.
Rails.delegate(document, '#registration_new_user,#new_user', 'submit', () => {
delegate(document, '#registration_new_user,#new_user', 'submit', () => {
['user_website', 'user_confirm_password', 'registration_user_website', 'registration_user_confirm_password'].forEach(id => {
const field = document.getElementById(id);
if (field) {

View File

@ -12,6 +12,7 @@
@import 'mastodon/forms';
@import 'mastodon/accounts';
@import 'mastodon/statuses';
@import 'mastodon/boost';
@import 'mastodon/components';
@import 'mastodon/polls';
@import 'mastodon/modal';

View File

@ -0,0 +1,44 @@
button.icon-button {
i.fa-retweet {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='22' height='209'><path d='M4.97 3.16c-.1.03-.17.1-.22.18L.8 8.24c-.2.3.03.78.4.8H3.6v2.68c0 4.26-.55 3.62 3.66 3.62h7.66l-2.3-2.84c-.03-.02-.03-.04-.05-.06H7.27c-.44 0-.72-.3-.72-.72v-2.7h2.5c.37.03.63-.48.4-.77L5.5 3.35c-.12-.17-.34-.25-.53-.2zm12.16.43c-.55-.02-1.32.02-2.4.02H7.1l2.32 2.85.03.06h5.25c.42 0 .72.28.72.72v2.7h-2.5c-.36.02-.56.54-.3.8l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.26-.28 0-.83-.37-.8H18.4v-2.7c0-3.15.4-3.62-1.25-3.66z' fill='#{hex-color($action-button-color)}' stroke-width='0'/><path d='M7.78 19.66c-.24.02-.44.25-.44.5v2.46h-.06c-1.08 0-1.86-.03-2.4-.03-1.64 0-1.25.43-1.25 3.65v4.47c0 4.26-.56 3.62 3.65 3.62H8.5l-1.3-1.06c-.1-.08-.18-.2-.2-.3-.02-.17.06-.35.2-.45l1.33-1.1H7.28c-.44 0-.72-.3-.72-.7v-4.48c0-.44.28-.72.72-.72h.06v2.5c0 .38.54.63.82.38l4.9-3.93c.25-.18.25-.6 0-.78l-4.9-3.92c-.1-.1-.24-.14-.38-.12zm9.34 2.93c-.54-.02-1.3.02-2.4.02h-1.25l1.3 1.07c.1.07.18.2.2.33.02.16-.06.3-.2.4l-1.33 1.1h1.28c.42 0 .72.28.72.72v4.47c0 .42-.3.72-.72.72h-.1v-2.47c0-.3-.3-.53-.6-.47-.07 0-.14.05-.2.1l-4.9 3.93c-.26.18-.26.6 0 .78l4.9 3.92c.27.25.82 0 .8-.38v-2.5h.1c4.27 0 3.65.67 3.65-3.62v-4.47c0-3.15.4-3.62-1.25-3.66zM10.34 38.66c-.24.02-.44.25-.43.5v2.47H7.3c-1.08 0-1.86-.04-2.4-.04-1.64 0-1.25.43-1.25 3.65v4.47c0 3.66-.23 3.7 2.34 3.66l-1.34-1.1c-.1-.08-.18-.2-.2-.3 0-.17.07-.35.2-.45l1.96-1.6c-.03-.06-.04-.13-.04-.2v-4.48c0-.44.28-.72.72-.72H9.9v2.5c0 .36.5.6.8.38l4.93-3.93c.24-.18.24-.6 0-.78l-4.94-3.92c-.1-.08-.23-.13-.36-.12zm5.63 2.93l1.34 1.1c.1.07.18.2.2.33.02.16-.03.3-.16.4l-1.96 1.6c.02.07.06.13.06.22v4.47c0 .42-.3.72-.72.72h-2.66v-2.47c0-.3-.3-.53-.6-.47-.06.02-.12.05-.18.1l-4.94 3.93c-.24.18-.24.6 0 .78l4.94 3.92c.28.22.78-.02.78-.38v-2.5h2.66c4.27 0 3.65.67 3.65-3.62v-4.47c0-3.66.34-3.7-2.4-3.66zM13.06 57.66c-.23.03-.4.26-.4.5v2.47H7.28c-1.08 0-1.86-.04-2.4-.04-1.64 0-1.25.43-1.25 3.65v4.87l2.93-2.37v-2.5c0-.44.28-.72.72-.72h5.38v2.5c0 .36.5.6.78.38l4.94-3.93c.24-.18.24-.6 0-.78l-4.94-3.92c-.1-.1-.24-.14-.38-.12zm5.3 6.15l-2.92 2.4v2.52c0 .42-.3.72-.72.72h-5.4v-2.47c0-.3-.32-.53-.6-.47-.07.02-.13.05-.2.1L3.6 70.52c-.25.18-.25.6 0 .78l4.93 3.92c.28.22.78-.02.78-.38v-2.5h5.42c4.27 0 3.65.67 3.65-3.62v-4.47-.44zM19.25 78.8c-.1.03-.2.1-.28.17l-.9.9c-.44-.3-1.36-.25-3.35-.25H7.28c-1.08 0-1.86-.03-2.4-.03-1.64 0-1.25.43-1.25 3.65v.7l2.93.3v-1c0-.44.28-.72.72-.72h7.44c.2 0 .37.08.5.2l-1.8 1.8c-.25.26-.08.76.27.8l6.27.7c.28.03.56-.25.53-.53l-.7-6.25c0-.27-.3-.48-.55-.44zm-17.2 6.1c-.2.07-.36.3-.33.54l.7 6.25c.02.36.58.55.83.27l.8-.8c.02 0 .04-.02.04 0 .46.24 1.37.17 3.18.17h7.44c4.27 0 3.65.67 3.65-3.62v-.75l-2.93-.3v1.05c0 .42-.3.72-.72.72H7.28c-.15 0-.3-.03-.4-.1L8.8 86.4c.3-.24.1-.8-.27-.84l-6.28-.65h-.2zM4.88 98.6c-1.33 0-1.34.48-1.3 2.3l1.14-1.37c.08-.1.22-.17.34-.2.16 0 .34.08.44.2l1.66 2.03c.04 0 .07-.03.12-.03h7.44c.34 0 .57.2.65.5h-2.43c-.34.05-.53.52-.3.78l3.92 4.95c.18.24.6.24.78 0l3.94-4.94c.22-.27-.02-.76-.37-.77H18.4c.02-3.9.6-3.4-3.66-3.4H7.28c-1.08 0-1.86-.04-2.4-.04zm.15 2.46c-.1.03-.2.1-.28.2l-3.94 4.9c-.2.28.03.77.4.78H3.6c-.02 3.94-.45 3.4 3.66 3.4h7.44c3.65 0 3.74.3 3.7-2.25l-1.1 1.34c-.1.1-.2.17-.32.2-.16 0-.34-.08-.44-.2l-1.65-2.03c-.06.02-.1.04-.18.04H7.28c-.35 0-.57-.2-.66-.5h2.44c.37 0 .63-.5.4-.78l-3.96-4.9c-.1-.15-.3-.23-.47-.2zM4.88 117.6c-1.16 0-1.3.3-1.3 1.56l1.14-1.38c.08-.1.22-.14.34-.16.16 0 .34.04.44.16l2.22 2.75h7c.42 0 .72.28.72.72v.53h-2.6c-.3.1-.43.54-.2.78l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-.53c0-4.2.72-3.63-3.66-3.63H7.28c-1.08 0-1.86-.03-2.4-.03zm.1 1.74c-.1.03-.17.1-.23.16L.8 124.44c-.2.28.03.77.4.78H3.6v.5c0 4.26-.55 3.62 3.66 3.62h7.44c1.03 0 1.74.02 2.28 0-.16.02-.34-.03-.44-.15l-2.22-2.76H7.28c-.44 0-.72-.3-.72-.72v-.5h2.5c.37.02.63-.5.4-.78L5.5 119.5c-.12-.15-.34-.22-.53-.16zm12.02 10c1.2-.02 1.4-.25 1.4-1.53l-1.1 1.36c-.07.1-.17.17-.3.18zM5.94 136.6l2.37 2.93h6.42c.42 0 .72.28.72.72v1.25h-2.6c-.3.1-.43.54-.2.78l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-1.25c0-4.2.72-3.63-3.66-3.63H7.28c-.6 0-.92-.02-1.34-.03zm-1.72.06c-.4.08-.54.3-.6.75l.6-.74zm.84.93c-.12 0-.24.08-.3.18l-3.95 4.9c-.24.3 0 .83.4.82H3.6v1.22c0 4.26-.55 3.62 3.66 3.62h7.44c.63 0 .97.02 1.4.03l-2.37-2.93H7.28c-.44 0-.72-.3-.72-.72v-1.22h2.5c.4.04.67-.53.4-.8l-3.96-4.92c-.1-.13-.27-.2-.44-.2zm13.28 10.03l-.56.7c.36-.07.5-.3.56-.7zM17.13 155.6c-.55-.02-1.32.03-2.4.03h-8.2l2.38 2.9h5.82c.42 0 .72.28.72.72v1.97H12.9c-.32.06-.48.52-.28.78l3.94 4.94c.2.23.6.22.78-.03l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-1.97c0-3.15.4-3.62-1.25-3.66zm-12.1.28c-.1.02-.2.1-.28.18l-3.94 4.9c-.2.3.03.78.4.8H3.6v1.96c0 4.26-.55 3.62 3.66 3.62h8.24l-2.36-2.9H7.28c-.44 0-.72-.3-.72-.72v-1.97h2.5c.37.02.63-.5.4-.78l-3.96-4.9c-.1-.15-.3-.22-.47-.2zM5.13 174.5c-.15 0-.3.07-.38.2L.8 179.6c-.24.27 0 .82.4.8H3.6v2.32c0 4.26-.55 3.62 3.66 3.62h7.94l-2.35-2.9h-5.6c-.43 0-.7-.3-.7-.72v-2.3h2.5c.38.03.66-.54.4-.83l-3.97-4.9c-.1-.13-.23-.2-.38-.2zm12 .1c-.55-.02-1.32.03-2.4.03H6.83l2.35 2.9h5.52c.42 0 .72.28.72.72v2.34h-2.6c-.3.1-.43.53-.2.78l3.92 4.9c.18.24.6.24.78 0l3.94-4.9c.22-.3-.02-.78-.37-.8H18.4v-2.33c0-3.15.4-3.62-1.25-3.66zM4.97 193.16c-.1.03-.17.1-.22.18l-3.94 4.9c-.2.3.03.78.4.8H3.6v2.68c0 4.26-.55 3.62 3.66 3.62h7.66l-2.3-2.84c-.03-.02-.03-.04-.05-.06H7.27c-.44 0-.72-.3-.72-.72v-2.7h2.5c.37.03.63-.48.4-.77l-3.96-4.9c-.12-.17-.34-.25-.53-.2zm12.16.43c-.55-.02-1.32.03-2.4.03H7.1l2.32 2.84.03.06h5.25c.42 0 .72.28.72.72v2.7h-2.5c-.36.02-.56.54-.3.8l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.26-.28 0-.83-.37-.8H18.4v-2.7c0-3.15.4-3.62-1.25-3.66z' fill='#{hex-color($highlight-text-color)}' stroke-width='0'/></svg>");
}
&:hover i.fa-retweet {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='22' height='209'><path d='M4.97 3.16c-.1.03-.17.1-.22.18L.8 8.24c-.2.3.03.78.4.8H3.6v2.68c0 4.26-.55 3.62 3.66 3.62h7.66l-2.3-2.84c-.03-.02-.03-.04-.05-.06H7.27c-.44 0-.72-.3-.72-.72v-2.7h2.5c.37.03.63-.48.4-.77L5.5 3.35c-.12-.17-.34-.25-.53-.2zm12.16.43c-.55-.02-1.32.02-2.4.02H7.1l2.32 2.85.03.06h5.25c.42 0 .72.28.72.72v2.7h-2.5c-.36.02-.56.54-.3.8l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.26-.28 0-.83-.37-.8H18.4v-2.7c0-3.15.4-3.62-1.25-3.66z' fill='#{hex-color(lighten($action-button-color, 7%))}' stroke-width='0'/><path d='M7.78 19.66c-.24.02-.44.25-.44.5v2.46h-.06c-1.08 0-1.86-.03-2.4-.03-1.64 0-1.25.43-1.25 3.65v4.47c0 4.26-.56 3.62 3.65 3.62H8.5l-1.3-1.06c-.1-.08-.18-.2-.2-.3-.02-.17.06-.35.2-.45l1.33-1.1H7.28c-.44 0-.72-.3-.72-.7v-4.48c0-.44.28-.72.72-.72h.06v2.5c0 .38.54.63.82.38l4.9-3.93c.25-.18.25-.6 0-.78l-4.9-3.92c-.1-.1-.24-.14-.38-.12zm9.34 2.93c-.54-.02-1.3.02-2.4.02h-1.25l1.3 1.07c.1.07.18.2.2.33.02.16-.06.3-.2.4l-1.33 1.1h1.28c.42 0 .72.28.72.72v4.47c0 .42-.3.72-.72.72h-.1v-2.47c0-.3-.3-.53-.6-.47-.07 0-.14.05-.2.1l-4.9 3.93c-.26.18-.26.6 0 .78l4.9 3.92c.27.25.82 0 .8-.38v-2.5h.1c4.27 0 3.65.67 3.65-3.62v-4.47c0-3.15.4-3.62-1.25-3.66zM10.34 38.66c-.24.02-.44.25-.43.5v2.47H7.3c-1.08 0-1.86-.04-2.4-.04-1.64 0-1.25.43-1.25 3.65v4.47c0 3.66-.23 3.7 2.34 3.66l-1.34-1.1c-.1-.08-.18-.2-.2-.3 0-.17.07-.35.2-.45l1.96-1.6c-.03-.06-.04-.13-.04-.2v-4.48c0-.44.28-.72.72-.72H9.9v2.5c0 .36.5.6.8.38l4.93-3.93c.24-.18.24-.6 0-.78l-4.94-3.92c-.1-.08-.23-.13-.36-.12zm5.63 2.93l1.34 1.1c.1.07.18.2.2.33.02.16-.03.3-.16.4l-1.96 1.6c.02.07.06.13.06.22v4.47c0 .42-.3.72-.72.72h-2.66v-2.47c0-.3-.3-.53-.6-.47-.06.02-.12.05-.18.1l-4.94 3.93c-.24.18-.24.6 0 .78l4.94 3.92c.28.22.78-.02.78-.38v-2.5h2.66c4.27 0 3.65.67 3.65-3.62v-4.47c0-3.66.34-3.7-2.4-3.66zM13.06 57.66c-.23.03-.4.26-.4.5v2.47H7.28c-1.08 0-1.86-.04-2.4-.04-1.64 0-1.25.43-1.25 3.65v4.87l2.93-2.37v-2.5c0-.44.28-.72.72-.72h5.38v2.5c0 .36.5.6.78.38l4.94-3.93c.24-.18.24-.6 0-.78l-4.94-3.92c-.1-.1-.24-.14-.38-.12zm5.3 6.15l-2.92 2.4v2.52c0 .42-.3.72-.72.72h-5.4v-2.47c0-.3-.32-.53-.6-.47-.07.02-.13.05-.2.1L3.6 70.52c-.25.18-.25.6 0 .78l4.93 3.92c.28.22.78-.02.78-.38v-2.5h5.42c4.27 0 3.65.67 3.65-3.62v-4.47-.44zM19.25 78.8c-.1.03-.2.1-.28.17l-.9.9c-.44-.3-1.36-.25-3.35-.25H7.28c-1.08 0-1.86-.03-2.4-.03-1.64 0-1.25.43-1.25 3.65v.7l2.93.3v-1c0-.44.28-.72.72-.72h7.44c.2 0 .37.08.5.2l-1.8 1.8c-.25.26-.08.76.27.8l6.27.7c.28.03.56-.25.53-.53l-.7-6.25c0-.27-.3-.48-.55-.44zm-17.2 6.1c-.2.07-.36.3-.33.54l.7 6.25c.02.36.58.55.83.27l.8-.8c.02 0 .04-.02.04 0 .46.24 1.37.17 3.18.17h7.44c4.27 0 3.65.67 3.65-3.62v-.75l-2.93-.3v1.05c0 .42-.3.72-.72.72H7.28c-.15 0-.3-.03-.4-.1L8.8 86.4c.3-.24.1-.8-.27-.84l-6.28-.65h-.2zM4.88 98.6c-1.33 0-1.34.48-1.3 2.3l1.14-1.37c.08-.1.22-.17.34-.2.16 0 .34.08.44.2l1.66 2.03c.04 0 .07-.03.12-.03h7.44c.34 0 .57.2.65.5h-2.43c-.34.05-.53.52-.3.78l3.92 4.95c.18.24.6.24.78 0l3.94-4.94c.22-.27-.02-.76-.37-.77H18.4c.02-3.9.6-3.4-3.66-3.4H7.28c-1.08 0-1.86-.04-2.4-.04zm.15 2.46c-.1.03-.2.1-.28.2l-3.94 4.9c-.2.28.03.77.4.78H3.6c-.02 3.94-.45 3.4 3.66 3.4h7.44c3.65 0 3.74.3 3.7-2.25l-1.1 1.34c-.1.1-.2.17-.32.2-.16 0-.34-.08-.44-.2l-1.65-2.03c-.06.02-.1.04-.18.04H7.28c-.35 0-.57-.2-.66-.5h2.44c.37 0 .63-.5.4-.78l-3.96-4.9c-.1-.15-.3-.23-.47-.2zM4.88 117.6c-1.16 0-1.3.3-1.3 1.56l1.14-1.38c.08-.1.22-.14.34-.16.16 0 .34.04.44.16l2.22 2.75h7c.42 0 .72.28.72.72v.53h-2.6c-.3.1-.43.54-.2.78l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-.53c0-4.2.72-3.63-3.66-3.63H7.28c-1.08 0-1.86-.03-2.4-.03zm.1 1.74c-.1.03-.17.1-.23.16L.8 124.44c-.2.28.03.77.4.78H3.6v.5c0 4.26-.55 3.62 3.66 3.62h7.44c1.03 0 1.74.02 2.28 0-.16.02-.34-.03-.44-.15l-2.22-2.76H7.28c-.44 0-.72-.3-.72-.72v-.5h2.5c.37.02.63-.5.4-.78L5.5 119.5c-.12-.15-.34-.22-.53-.16zm12.02 10c1.2-.02 1.4-.25 1.4-1.53l-1.1 1.36c-.07.1-.17.17-.3.18zM5.94 136.6l2.37 2.93h6.42c.42 0 .72.28.72.72v1.25h-2.6c-.3.1-.43.54-.2.78l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-1.25c0-4.2.72-3.63-3.66-3.63H7.28c-.6 0-.92-.02-1.34-.03zm-1.72.06c-.4.08-.54.3-.6.75l.6-.74zm.84.93c-.12 0-.24.08-.3.18l-3.95 4.9c-.24.3 0 .83.4.82H3.6v1.22c0 4.26-.55 3.62 3.66 3.62h7.44c.63 0 .97.02 1.4.03l-2.37-2.93H7.28c-.44 0-.72-.3-.72-.72v-1.22h2.5c.4.04.67-.53.4-.8l-3.96-4.92c-.1-.13-.27-.2-.44-.2zm13.28 10.03l-.56.7c.36-.07.5-.3.56-.7zM17.13 155.6c-.55-.02-1.32.03-2.4.03h-8.2l2.38 2.9h5.82c.42 0 .72.28.72.72v1.97H12.9c-.32.06-.48.52-.28.78l3.94 4.94c.2.23.6.22.78-.03l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-1.97c0-3.15.4-3.62-1.25-3.66zm-12.1.28c-.1.02-.2.1-.28.18l-3.94 4.9c-.2.3.03.78.4.8H3.6v1.96c0 4.26-.55 3.62 3.66 3.62h8.24l-2.36-2.9H7.28c-.44 0-.72-.3-.72-.72v-1.97h2.5c.37.02.63-.5.4-.78l-3.96-4.9c-.1-.15-.3-.22-.47-.2zM5.13 174.5c-.15 0-.3.07-.38.2L.8 179.6c-.24.27 0 .82.4.8H3.6v2.32c0 4.26-.55 3.62 3.66 3.62h7.94l-2.35-2.9h-5.6c-.43 0-.7-.3-.7-.72v-2.3h2.5c.38.03.66-.54.4-.83l-3.97-4.9c-.1-.13-.23-.2-.38-.2zm12 .1c-.55-.02-1.32.03-2.4.03H6.83l2.35 2.9h5.52c.42 0 .72.28.72.72v2.34h-2.6c-.3.1-.43.53-.2.78l3.92 4.9c.18.24.6.24.78 0l3.94-4.9c.22-.3-.02-.78-.37-.8H18.4v-2.33c0-3.15.4-3.62-1.25-3.66zM4.97 193.16c-.1.03-.17.1-.22.18l-3.94 4.9c-.2.3.03.78.4.8H3.6v2.68c0 4.26-.55 3.62 3.66 3.62h7.66l-2.3-2.84c-.03-.02-.03-.04-.05-.06H7.27c-.44 0-.72-.3-.72-.72v-2.7h2.5c.37.03.63-.48.4-.77l-3.96-4.9c-.12-.17-.34-.25-.53-.2zm12.16.43c-.55-.02-1.32.03-2.4.03H7.1l2.32 2.84.03.06h5.25c.42 0 .72.28.72.72v2.7h-2.5c-.36.02-.56.54-.3.8l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.26-.28 0-.83-.37-.8H18.4v-2.7c0-3.15.4-3.62-1.25-3.66z' fill='#{hex-color($highlight-text-color)}' stroke-width='0'/></svg>");
}
&.reblogPrivate {
i.fa-retweet {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' height='209' width='22'><path d='M 4.9707031 3.1503906 L 4.9707031 3.1601562 C 4.8707031 3.1901563 4.8 3.2598438 4.75 3.3398438 L 0.80078125 8.2402344 C 0.60078125 8.5402344 0.8292187 9.0190625 1.1992188 9.0390625 L 3.5996094 9.0390625 L 3.5996094 11.720703 C 3.5996094 15.980703 3.0497656 15.339844 7.2597656 15.339844 L 11.869141 15.339844 L 11.869141 14.119141 L 11.869141 13.523438 L 11.869141 12.441406 C 11.869141 12.441406 11.869141 12.439453 11.869141 12.439453 L 7.2695312 12.439453 C 6.8295312 12.439453 6.5507814 12.140703 6.5507812 11.720703 L 6.5507812 9.0195312 L 9.0507812 9.0195312 C 9.4207813 9.0495313 9.6792188 8.54 9.4492188 8.25 L 5.5 3.3496094 C 5.38 3.1796094 5.1607031 3.1003906 4.9707031 3.1503906 z M 17.150391 3.5800781 L 17.130859 3.5898438 C 16.580859 3.5698436 15.810469 3.609375 14.730469 3.609375 L 7.0996094 3.609375 L 9.4199219 6.4609375 L 9.4492188 6.5195312 L 14.699219 6.5195312 C 15.106887 6.5195312 15.397113 6.7872181 15.414062 7.2050781 C 15.738375 7.0991315 16.077769 7.0273437 16.435547 7.0273438 L 16.578125 7.0273438 C 17.24903 7.0273438 17.874081 7.2325787 18.400391 7.578125 L 18.400391 7.2402344 C 18.400391 4.0902344 18.800391 3.6200781 17.150391 3.5800781 z M 16.435547 8.0273438 C 15.143818 8.0273438 14.083984 9.0851838 14.083984 10.376953 L 14.083984 11.607422 L 13.570312 11.607422 C 13.375448 11.607422 13.210603 11.704118 13.119141 11.791016 C 13.027691 11.877916 12.983569 11.958238 12.951172 12.03125 C 12.886382 12.177277 12.867187 12.304789 12.867188 12.441406 L 12.867188 13.523438 L 12.867188 14.119141 L 12.867188 15.677734 L 12.867188 16.509766 L 13.570312 16.509766 L 19.472656 16.509766 L 20.173828 16.509766 L 20.173828 15.677734 L 20.173828 13.523438 L 20.173828 12.441406 C 20.173828 12.304794 20.156597 12.177281 20.091797 12.03125 C 20.059397 11.95824 20.015299 11.877916 19.923828 11.791016 C 19.832368 11.704116 19.667509 11.607422 19.472656 11.607422 L 18.927734 11.607422 L 18.927734 10.376953 C 18.927734 9.0851838 17.867902 8.0273438 16.576172 8.0273438 L 16.435547 8.0273438 z M 16.435547 9.2207031 L 16.576172 9.2207031 C 17.22782 9.2207031 17.734375 9.7251013 17.734375 10.376953 L 17.734375 11.607422 L 15.277344 11.607422 L 15.277344 10.376953 C 15.277344 9.7251013 15.7839 9.2207031 16.435547 9.2207031 z M 12.919922 9.9394531 C 12.559922 9.9594531 12.359141 10.480234 12.619141 10.740234 L 12.751953 10.904297 C 12.862211 10.870135 12.980058 10.842244 13.085938 10.802734 L 13.085938 10.378906 C 13.085938 10.228632 13.111295 10.084741 13.130859 9.9394531 L 12.919922 9.9394531 z M 19.882812 9.9394531 C 19.902378 10.084741 19.927734 10.228632 19.927734 10.378906 L 19.927734 10.791016 C 20.168811 10.875098 20.455966 10.916935 20.613281 11.066406 C 20.691227 11.140457 20.749315 11.223053 20.806641 11.302734 L 21.259766 10.740234 C 21.519766 10.460234 21.260625 9.9094531 20.890625 9.9394531 L 19.882812 9.9394531 z M 16.435547 10.220703 C 16.301234 10.220703 16.277344 10.244432 16.277344 10.378906 L 16.277344 10.607422 L 16.734375 10.607422 L 16.734375 10.378906 C 16.734375 10.244433 16.712442 10.220703 16.578125 10.220703 L 16.435547 10.220703 z ' fill='#{hex-color($action-button-color)}' stroke-width='0'/><path d='M 7.7792969 19.650391 L 7.7792969 19.660156 C 7.5392969 19.680156 7.3398437 19.910156 7.3398438 20.160156 L 7.3398438 22.619141 L 7.2792969 22.619141 C 6.1992969 22.619141 5.4208594 22.589844 4.8808594 22.589844 C 3.2408594 22.589844 3.6308594 23.020234 3.6308594 26.240234 L 3.6308594 30.710938 C 3.6308594 34.970937 3.0692969 34.330078 7.2792969 34.330078 L 8.5 34.330078 L 7.1992188 33.269531 C 7.0992188 33.189531 7.02 33.070703 7 32.970703 C 6.98 32.800703 7.0592186 32.619531 7.1992188 32.519531 L 8.5292969 31.419922 L 7.2792969 31.419922 C 6.8392969 31.419922 6.5605469 31.120703 6.5605469 30.720703 L 6.5605469 26.240234 C 6.5605469 25.800234 6.8392969 25.519531 7.2792969 25.519531 L 7.3398438 25.519531 L 7.3398438 28.019531 C 7.3398438 28.399531 7.8801564 28.650391 8.1601562 28.400391 L 13.060547 24.470703 C 13.310547 24.290703 13.310547 23.869453 13.060547 23.689453 L 8.1601562 19.769531 C 8.0601563 19.669531 7.9192969 19.630391 7.7792969 19.650391 z M 17.119141 22.580078 L 17.119141 22.589844 C 16.579141 22.569844 15.820703 22.609375 14.720703 22.609375 L 13.470703 22.609375 L 14.769531 23.679688 C 14.869531 23.749688 14.950703 23.879766 14.970703 24.009766 C 14.990703 24.169766 14.909531 24.310156 14.769531 24.410156 L 13.439453 25.509766 L 14.720703 25.509766 C 15.129702 25.509766 15.41841 25.778986 15.433594 26.199219 C 15.752266 26.097283 16.084896 26.027344 16.435547 26.027344 L 16.578125 26.027344 C 17.236645 26.027344 17.848901 26.228565 18.369141 26.5625 L 18.369141 26.240234 C 18.369141 23.090234 18.769141 22.620078 17.119141 22.580078 z M 16.435547 27.027344 C 15.143818 27.027344 14.083984 28.085184 14.083984 29.376953 L 14.083984 30.607422 L 13.570312 30.607422 C 13.375452 30.607422 13.210603 30.704118 13.119141 30.791016 C 13.027691 30.877916 12.983569 30.958238 12.951172 31.03125 C 12.886382 31.177277 12.867184 31.304789 12.867188 31.441406 L 12.867188 32.523438 L 12.867188 33.119141 L 12.867188 34.677734 L 12.867188 35.509766 L 13.570312 35.509766 L 19.472656 35.509766 L 20.173828 35.509766 L 20.173828 34.677734 L 20.173828 32.523438 L 20.173828 31.441406 C 20.173828 31.304794 20.156597 31.177281 20.091797 31.03125 C 20.059397 30.95824 20.015299 30.877916 19.923828 30.791016 C 19.832368 30.704116 19.667509 30.607422 19.472656 30.607422 L 18.927734 30.607422 L 18.927734 29.376953 C 18.927734 28.085184 17.867902 27.027344 16.576172 27.027344 L 16.435547 27.027344 z M 16.435547 28.220703 L 16.576172 28.220703 C 17.22782 28.220703 17.734375 28.725101 17.734375 29.376953 L 17.734375 30.607422 L 15.277344 30.607422 L 15.277344 29.376953 C 15.277344 28.725101 15.7839 28.220703 16.435547 28.220703 z M 13.109375 29.150391 L 8.9199219 32.509766 C 8.6599219 32.689766 8.6599219 33.109063 8.9199219 33.289062 L 11.869141 35.648438 L 11.869141 34.677734 L 11.869141 33.119141 L 11.869141 32.523438 L 11.869141 31.441406 C 11.869141 31.217489 11.912641 30.907486 12.037109 30.626953 C 12.093758 30.499284 12.228597 30.257492 12.429688 30.066406 C 12.580253 29.92335 12.859197 29.887344 13.085938 29.802734 L 13.085938 29.378906 C 13.085938 29.300761 13.104 29.227272 13.109375 29.150391 z M 16.435547 29.220703 C 16.301234 29.220703 16.277344 29.244432 16.277344 29.378906 L 16.277344 29.607422 L 16.734375 29.607422 L 16.734375 29.378906 C 16.734375 29.244433 16.712442 29.220703 16.578125 29.220703 L 16.435547 29.220703 z M 12.943359 36.509766 L 13.820312 37.210938 C 14.090314 37.460938 14.639141 37.210078 14.619141 36.830078 L 14.619141 36.509766 L 13.570312 36.509766 L 12.943359 36.509766 z M 10.330078 38.650391 L 10.339844 38.660156 C 10.099844 38.680156 9.9001562 38.910156 9.9101562 39.160156 L 9.9101562 41.630859 L 7.3007812 41.630859 C 6.2207812 41.630859 5.4403906 41.589844 4.9003906 41.589844 C 3.2603906 41.589844 3.6503906 42.020234 3.6503906 45.240234 L 3.6503906 49.710938 C 3.6503906 53.370936 3.4202344 53.409141 5.9902344 53.369141 L 4.6503906 52.269531 C 4.5503906 52.189531 4.4692187 52.070703 4.4492188 51.970703 C 4.4492188 51.800703 4.5203906 51.619531 4.6503906 51.519531 L 6.609375 49.919922 C 6.579375 49.859922 6.5703125 49.790703 6.5703125 49.720703 L 6.5703125 45.240234 C 6.5703125 44.800234 6.8490625 44.519531 7.2890625 44.519531 L 9.9003906 44.519531 L 9.9003906 47.019531 C 9.9003906 47.379531 10.399219 47.620391 10.699219 47.400391 L 15.630859 43.470703 C 15.870859 43.290703 15.870859 42.869453 15.630859 42.689453 L 10.689453 38.769531 C 10.589453 38.689531 10.460078 38.640391 10.330078 38.650391 z M 16.869141 41.585938 C 16.616211 41.581522 16.322969 41.584844 15.980469 41.589844 L 15.970703 41.589844 L 17.310547 42.689453 C 17.410547 42.759453 17.489766 42.889531 17.509766 43.019531 C 17.529766 43.179531 17.479609 43.319922 17.349609 43.419922 L 15.390625 45.019531 C 15.406724 45.075878 15.427133 45.132837 15.4375 45.197266 C 15.754974 45.096169 16.086404 45.027344 16.435547 45.027344 L 16.578125 45.027344 C 17.24129 45.027344 17.858323 45.230088 18.380859 45.568359 L 18.380859 45.25 C 18.380859 42.0475 18.639648 41.616836 16.869141 41.585938 z M 16.435547 46.027344 C 15.143818 46.027344 14.083984 47.085184 14.083984 48.376953 L 14.083984 49.607422 L 13.570312 49.607422 C 13.375448 49.607422 13.210603 49.704118 13.119141 49.791016 C 13.027691 49.877916 12.983569 49.958238 12.951172 50.03125 C 12.886382 50.177277 12.867187 50.304789 12.867188 50.441406 L 12.867188 51.523438 L 12.867188 52.119141 L 12.867188 53.677734 L 12.867188 54.509766 L 13.570312 54.509766 L 19.472656 54.509766 L 20.173828 54.509766 L 20.173828 53.677734 L 20.173828 51.523438 L 20.173828 50.441406 C 20.173828 50.304794 20.156597 50.177281 20.091797 50.03125 C 20.059397 49.95824 20.015299 49.877916 19.923828 49.791016 C 19.832368 49.704116 19.667509 49.607422 19.472656 49.607422 L 18.927734 49.607422 L 18.927734 48.376953 C 18.927734 47.085184 17.867902 46.027344 16.576172 46.027344 L 16.435547 46.027344 z M 16.435547 47.220703 L 16.576172 47.220703 C 17.22782 47.220703 17.734375 47.725101 17.734375 48.376953 L 17.734375 49.607422 L 15.277344 49.607422 L 15.277344 48.376953 C 15.277344 47.725101 15.7839 47.220703 16.435547 47.220703 z M 11.470703 47.490234 C 11.410703 47.510234 11.349063 47.539844 11.289062 47.589844 L 6.3496094 51.519531 C 6.1096094 51.699531 6.1096094 52.120781 6.3496094 52.300781 L 11.289062 56.220703 C 11.569064 56.440703 12.070312 56.199844 12.070312 55.839844 L 12.070312 55.509766 L 11.869141 55.509766 L 11.869141 53.677734 L 11.869141 52.119141 L 11.869141 51.523438 L 11.869141 50.441406 C 11.869141 50.217489 11.912641 49.907486 12.037109 49.626953 C 12.043809 49.611855 12.061451 49.584424 12.070312 49.566406 L 12.070312 47.960938 C 12.070312 47.660938 11.770703 47.430234 11.470703 47.490234 z M 16.435547 48.220703 C 16.301234 48.220703 16.277344 48.244432 16.277344 48.378906 L 16.277344 48.607422 L 16.734375 48.607422 L 16.734375 48.378906 C 16.734375 48.244433 16.712442 48.220703 16.578125 48.220703 L 16.435547 48.220703 z M 13.060547 57.650391 L 13.060547 57.660156 C 12.830547 57.690156 12.660156 57.920156 12.660156 58.160156 L 12.660156 60.630859 L 7.2792969 60.630859 C 6.1992969 60.630859 5.4208594 60.589844 4.8808594 60.589844 C 3.2408594 60.589844 3.6308594 61.020234 3.6308594 64.240234 L 3.6308594 69.109375 L 6.5605469 66.740234 L 6.5605469 64.240234 C 6.5605469 63.800234 6.8392969 63.519531 7.2792969 63.519531 L 12.660156 63.519531 L 12.660156 66.019531 C 12.660156 66.299799 12.960394 66.500006 13.226562 66.474609 C 13.625751 65.076914 14.904956 64.035678 16.421875 64.029297 L 18.380859 62.470703 C 18.620859 62.290703 18.620859 61.869453 18.380859 61.689453 L 13.439453 57.769531 C 13.339453 57.669531 13.200547 57.630391 13.060547 57.650391 z M 18.359375 63.810547 L 17.800781 64.269531 C 18.004793 64.350836 18.198411 64.450249 18.380859 64.568359 L 18.380859 64.25 L 18.380859 63.810547 L 18.359375 63.810547 z M 16.435547 65.027344 C 15.143818 65.027344 14.083984 66.085184 14.083984 67.376953 L 14.083984 68.607422 L 13.570312 68.607422 C 13.375448 68.607422 13.210603 68.704118 13.119141 68.791016 C 13.027691 68.877916 12.983569 68.958238 12.951172 69.03125 C 12.886382 69.177277 12.867187 69.304789 12.867188 69.441406 L 12.867188 70.523438 L 12.867188 71.119141 L 12.867188 72.677734 L 12.867188 73.509766 L 13.570312 73.509766 L 19.472656 73.509766 L 20.173828 73.509766 L 20.173828 72.677734 L 20.173828 70.523438 L 20.173828 69.441406 C 20.173828 69.304794 20.156597 69.177281 20.091797 69.03125 C 20.059397 68.95824 20.015299 68.877916 19.923828 68.791016 C 19.832368 68.704116 19.667509 68.607422 19.472656 68.607422 L 18.927734 68.607422 L 18.927734 67.376953 C 18.927734 66.085184 17.867902 65.027344 16.576172 65.027344 L 16.435547 65.027344 z M 16.435547 66.220703 L 16.576172 66.220703 C 17.22782 66.220703 17.734375 66.725101 17.734375 67.376953 L 17.734375 68.607422 L 15.277344 68.607422 L 15.277344 67.376953 C 15.277344 66.725101 15.7839 66.220703 16.435547 66.220703 z M 8.7207031 66.509766 C 8.6507031 66.529766 8.5895312 66.559375 8.5195312 66.609375 L 3.5996094 70.519531 C 3.3496094 70.699531 3.3496094 71.120781 3.5996094 71.300781 L 8.5292969 75.220703 C 8.8092969 75.440703 9.3105469 75.199844 9.3105469 74.839844 L 9.3105469 72.339844 L 11.869141 72.339844 L 11.869141 71.119141 L 11.869141 70.523438 L 11.869141 69.449219 L 9.3203125 69.449219 L 9.3203125 66.980469 C 9.3203125 66.680469 9.0007031 66.449766 8.7207031 66.509766 z M 16.435547 67.220703 C 16.301234 67.220703 16.277344 67.244432 16.277344 67.378906 L 16.277344 67.607422 L 16.734375 67.607422 L 16.734375 67.378906 C 16.734375 67.244433 16.712442 67.220703 16.578125 67.220703 L 16.435547 67.220703 z M 19.248047 78.800781 C 19.148558 78.831033 19.050295 78.90106 18.970703 78.970703 L 18.070312 79.869141 C 17.630312 79.569141 16.710703 79.619141 14.720703 79.619141 L 7.2792969 79.619141 C 6.1992969 79.619141 5.4208594 79.589844 4.8808594 79.589844 C 3.2408594 79.589844 3.6308594 80.020234 3.6308594 83.240234 L 3.6308594 83.939453 L 6.5605469 84.240234 L 6.5605469 83.240234 C 6.5605469 82.800234 6.8392969 82.519531 7.2792969 82.519531 L 14.720703 82.519531 C 14.920703 82.519531 15.090703 82.600703 15.220703 82.720703 L 13.419922 84.519531 C 13.279464 84.665607 13.281282 84.881022 13.363281 85.054688 C 13.880838 83.867655 15.067337 83.027344 16.435547 83.027344 L 16.578125 83.027344 C 18.290465 83.027344 19.703357 84.345788 19.890625 86.011719 L 19.960938 86.019531 C 20.240938 86.049531 20.520234 85.770234 20.490234 85.490234 L 19.789062 79.240234 C 19.789062 78.973661 19.498025 78.767523 19.25 78.800781 L 19.248047 78.800781 z M 16.435547 84.027344 C 15.143818 84.027344 14.083984 85.085184 14.083984 86.376953 L 14.083984 87.607422 L 13.570312 87.607422 C 13.375448 87.607422 13.210603 87.704118 13.119141 87.791016 C 13.027691 87.877916 12.983569 87.958238 12.951172 88.03125 C 12.886382 88.177277 12.867187 88.304789 12.867188 88.441406 L 12.867188 89.523438 L 12.867188 90.119141 L 12.867188 91.677734 L 12.867188 92.509766 L 13.570312 92.509766 L 19.472656 92.509766 L 20.173828 92.509766 L 20.173828 91.677734 L 20.173828 89.523438 L 20.173828 88.441406 C 20.173828 88.304794 20.156597 88.177281 20.091797 88.03125 C 20.059397 87.95824 20.015299 87.877916 19.923828 87.791016 C 19.832368 87.704116 19.667509 87.607422 19.472656 87.607422 L 18.927734 87.607422 L 18.927734 86.376953 C 18.927734 85.085184 17.867902 84.027344 16.576172 84.027344 L 16.435547 84.027344 z M 2.0507812 84.900391 C 1.8507824 84.970391 1.6907031 85.199453 1.7207031 85.439453 L 2.4199219 91.689453 C 2.4399219 92.049453 3 92.240929 3.25 91.960938 L 4.0507812 91.160156 C 4.0707812 91.160156 4.0898437 91.140156 4.0898438 91.160156 C 4.5498437 91.400156 5.4595313 91.330078 7.2695312 91.330078 L 11.869141 91.330078 L 11.869141 90.119141 L 11.869141 89.523438 L 11.869141 88.441406 C 11.869141 88.437991 11.871073 88.433136 11.871094 88.429688 L 7.2792969 88.429688 C 7.1292969 88.429688 6.9808594 88.400078 6.8808594 88.330078 L 8.8007812 86.400391 C 9.1007822 86.160391 8.8992969 85.600547 8.5292969 85.560547 L 2.25 84.910156 L 2.0507812 84.910156 L 2.0507812 84.900391 z M 16.435547 85.220703 L 16.576172 85.220703 C 17.22782 85.220703 17.734375 85.725101 17.734375 86.376953 L 17.734375 87.607422 L 15.277344 87.607422 L 15.277344 86.376953 C 15.277344 85.725101 15.7839 85.220703 16.435547 85.220703 z M 4.8808594 98.599609 C 3.5508594 98.599609 3.5400781 99.080402 3.5800781 100.90039 L 4.7207031 99.529297 C 4.8007031 99.429297 4.9405469 99.360078 5.0605469 99.330078 C 5.2205469 99.330078 5.4 99.409297 5.5 99.529297 L 7.1601562 101.56055 C 7.2001563 101.56055 7.2292969 101.5293 7.2792969 101.5293 L 14.720703 101.5293 C 15.060703 101.5293 15.289141 101.7293 15.369141 102.0293 L 12.939453 102.0293 C 12.599453 102.0793 12.410625 102.55055 12.640625 102.81055 L 13.470703 103.85742 C 14.029941 102.77899 15.146801 102.02734 16.435547 102.02734 L 16.578125 102.02734 C 18.158418 102.02734 19.491598 103.14879 19.835938 104.63086 L 21.279297 102.82031 C 21.499297 102.55031 21.260156 102.06078 20.910156 102.05078 L 18.400391 102.05078 C 18.420391 98.150792 19.000234 98.650391 14.740234 98.650391 L 7.2792969 98.650391 C 6.1992969 98.650391 5.4208594 98.609375 4.8808594 98.609375 L 4.8808594 98.599609 z M 5.0292969 101.06055 C 4.9292969 101.09055 4.83 101.15977 4.75 101.25977 L 0.81054688 106.16016 C 0.61054688 106.44016 0.8409375 106.92945 1.2109375 106.93945 L 3.5996094 106.93945 C 3.5796094 110.87945 3.1497656 110.33984 7.2597656 110.33984 L 11.869141 110.33984 L 11.869141 109.11914 L 11.869141 108.52344 L 11.869141 107.44141 L 11.869141 107.43945 L 7.2792969 107.43945 C 6.9292969 107.43945 6.7091406 107.23945 6.6191406 106.93945 L 9.0605469 106.93945 C 9.4305469 106.93945 9.6909375 106.44016 9.4609375 106.16016 L 5.5 101.25977 C 5.4 101.10977 5.1992969 101.03055 5.0292969 101.06055 z M 16.435547 103.02734 C 15.143818 103.02734 14.083984 104.08518 14.083984 105.37695 L 14.083984 106.60742 L 13.570312 106.60742 C 13.375448 106.60742 13.210603 106.70409 13.119141 106.79102 C 13.027691 106.87792 12.983569 106.95823 12.951172 107.03125 C 12.886382 107.17727 12.867187 107.30479 12.867188 107.44141 L 12.867188 108.52344 L 12.867188 109.11914 L 12.867188 110.67773 L 12.867188 111.50977 L 13.570312 111.50977 L 19.472656 111.50977 L 20.173828 111.50977 L 20.173828 110.67773 L 20.173828 108.52344 L 20.173828 107.44141 C 20.173828 107.3048 20.156597 107.17728 20.091797 107.03125 C 20.059397 106.95825 20.015299 106.87792 19.923828 106.79102 C 19.832368 106.70412 19.667509 106.60742 19.472656 106.60742 L 18.927734 106.60742 L 18.927734 105.37695 C 18.927734 104.08518 17.867902 103.02734 16.576172 103.02734 L 16.435547 103.02734 z M 16.435547 104.2207 L 16.576172 104.2207 C 17.22782 104.2207 17.734375 104.7251 17.734375 105.37695 L 17.734375 106.60742 L 15.277344 106.60742 L 15.277344 105.37695 C 15.277344 104.7251 15.7839 104.2207 16.435547 104.2207 z M 16.435547 105.2207 C 16.301234 105.2207 16.277344 105.24444 16.277344 105.37891 L 16.277344 105.60742 L 16.734375 105.60742 L 16.734375 105.37891 C 16.734375 105.24441 16.712442 105.2207 16.578125 105.2207 L 16.435547 105.2207 z M 4.8808594 117.58984 L 4.8808594 117.59961 C 3.7208594 117.59961 3.5800781 117.90016 3.5800781 119.16016 L 4.7207031 117.7793 C 4.8007031 117.6793 4.9405469 117.63914 5.0605469 117.61914 C 5.2205469 117.61914 5.4 117.6593 5.5 117.7793 L 7.7207031 120.5293 L 14.720703 120.5293 C 15.123595 120.5293 15.408576 120.79174 15.431641 121.20117 C 15.750992 121.09876 16.08404 121.02734 16.435547 121.02734 L 16.578125 121.02734 C 17.24903 121.02734 17.874081 121.23262 18.400391 121.57812 L 18.400391 121.25 C 18.400391 117.05 19.120234 117.61914 14.740234 117.61914 L 7.2792969 117.61914 C 6.1992969 117.61914 5.4208594 117.58984 4.8808594 117.58984 z M 4.9804688 119.33984 C 4.8804688 119.36984 4.81 119.44 4.75 119.5 L 0.80078125 124.43945 C 0.60078125 124.71945 0.8292182 125.2107 1.1992188 125.2207 L 3.5996094 125.2207 L 3.5996094 125.7207 C 3.5996094 129.9807 3.0497656 129.33984 7.2597656 129.33984 L 11.869141 129.33984 L 11.869141 128.11914 L 11.869141 127.52344 L 11.869141 126.44141 C 11.869141 126.43799 11.871073 126.43314 11.871094 126.42969 L 7.2792969 126.42969 C 6.8392969 126.42969 6.5605469 126.13094 6.5605469 125.71094 L 6.5605469 125.21094 L 9.0605469 125.21094 C 9.4305469 125.23094 9.6909375 124.70969 9.4609375 124.42969 L 5.5 119.5 C 5.3820133 119.35252 5.1682348 119.28513 4.9804688 119.33984 z M 12.839844 121.7793 C 12.539844 121.8793 12.410625 122.32055 12.640625 122.56055 L 13.267578 123.34375 C 13.473522 122.72168 13.852237 122.1828 14.353516 121.7793 L 12.839844 121.7793 z M 18.658203 121.7793 C 19.393958 122.37155 19.878978 123.25738 19.916016 124.25781 L 21.279297 122.56055 C 21.499297 122.28055 21.260156 121.7893 20.910156 121.7793 L 18.658203 121.7793 z M 16.435547 122.02734 C 15.143818 122.02734 14.083984 123.08518 14.083984 124.37695 L 14.083984 125.60742 L 13.570312 125.60742 C 13.375448 125.60742 13.210603 125.70409 13.119141 125.79102 C 13.027691 125.87792 12.983569 125.95823 12.951172 126.03125 C 12.886382 126.17727 12.867187 126.30479 12.867188 126.44141 L 12.867188 127.52344 L 12.867188 128.11914 L 12.867188 129.67773 L 12.867188 130.50977 L 13.570312 130.50977 L 19.472656 130.50977 L 20.173828 130.50977 L 20.173828 129.67773 L 20.173828 127.52344 L 20.173828 126.44141 C 20.173828 126.3048 20.156597 126.17728 20.091797 126.03125 C 20.059397 125.95825 20.015299 125.87792 19.923828 125.79102 C 19.832368 125.70412 19.667509 125.60742 19.472656 125.60742 L 18.927734 125.60742 L 18.927734 124.37695 C 18.927734 123.08518 17.867902 122.02734 16.576172 122.02734 L 16.435547 122.02734 z M 16.435547 123.2207 L 16.576172 123.2207 C 17.22782 123.2207 17.734375 123.7251 17.734375 124.37695 L 17.734375 125.60742 L 15.277344 125.60742 L 15.277344 124.37695 C 15.277344 123.7251 15.7839 123.2207 16.435547 123.2207 z M 16.435547 124.2207 C 16.301234 124.2207 16.277344 124.24444 16.277344 124.37891 L 16.277344 124.60742 L 16.734375 124.60742 L 16.734375 124.37891 C 16.734375 124.24441 16.712442 124.2207 16.578125 124.2207 L 16.435547 124.2207 z M 5.9394531 136.58984 L 5.9394531 136.59961 L 8.3105469 139.5293 L 14.730469 139.5293 C 15.131912 139.5293 15.414551 139.79039 15.439453 140.19727 C 15.756409 140.09653 16.087055 140.02734 16.435547 140.02734 L 16.578125 140.02734 C 17.24903 140.02734 17.874081 140.23261 18.400391 140.57812 L 18.400391 140.25 C 18.400391 136.05 19.120234 136.61914 14.740234 136.61914 L 7.2792969 136.61914 C 6.6792969 136.61914 6.3594531 136.59984 5.9394531 136.58984 z M 4.2207031 136.66016 C 3.8207031 136.74016 3.6791406 136.96016 3.6191406 137.41016 L 4.2207031 136.66992 L 4.2207031 136.66016 z M 5.0605469 137.57031 L 5.0605469 137.58984 C 4.9405469 137.58984 4.8197656 137.66953 4.7597656 137.76953 L 0.81054688 142.66992 C 0.57054688 142.96992 0.8109375 143.50023 1.2109375 143.49023 L 3.5996094 143.49023 L 3.5996094 144.71094 C 3.5996094 148.97094 3.0497656 148.33008 7.2597656 148.33008 L 11.869141 148.33008 L 11.869141 147.11914 L 11.869141 146.52344 L 11.869141 145.44141 C 11.869141 145.43799 11.871073 145.43314 11.871094 145.42969 L 7.2792969 145.42969 C 6.8392969 145.42969 6.5605469 145.13094 6.5605469 144.71094 L 6.5605469 143.49023 L 9.0605469 143.49023 C 9.4605469 143.53023 9.7309375 142.95945 9.4609375 142.68945 L 5.5 137.76953 C 5.4 137.63953 5.2305469 137.57031 5.0605469 137.57031 z M 16.435547 141.02734 C 15.143818 141.02734 14.083984 142.08518 14.083984 143.37695 L 14.083984 144.60742 L 13.570312 144.60742 C 13.375448 144.60742 13.210603 144.70409 13.119141 144.79102 C 13.027691 144.87792 12.983569 144.95823 12.951172 145.03125 C 12.886382 145.17727 12.867187 145.30479 12.867188 145.44141 L 12.867188 146.52344 L 12.867188 147.11914 L 12.867188 148.67773 L 12.867188 149.50977 L 13.570312 149.50977 L 19.472656 149.50977 L 20.173828 149.50977 L 20.173828 148.67773 L 20.173828 146.52344 L 20.173828 145.44141 C 20.173828 145.3048 20.156597 145.17728 20.091797 145.03125 C 20.059397 144.95825 20.015299 144.87792 19.923828 144.79102 C 19.832368 144.70412 19.667509 144.60742 19.472656 144.60742 L 18.927734 144.60742 L 18.927734 143.37695 C 18.927734 142.08518 17.867902 141.02734 16.576172 141.02734 L 16.435547 141.02734 z M 12.849609 141.5 C 12.549609 141.6 12.420391 142.0393 12.650391 142.2793 L 13.136719 142.88672 C 13.213026 142.38119 13.390056 141.90696 13.667969 141.5 L 12.849609 141.5 z M 19.34375 141.5 C 19.710704 142.03735 19.927734 142.68522 19.927734 143.37891 L 19.927734 143.79102 C 19.965561 143.80421 20.005506 143.81448 20.044922 143.82617 L 21.289062 142.2793 C 21.509062 141.9993 21.269922 141.51 20.919922 141.5 L 19.34375 141.5 z M 16.435547 142.2207 L 16.576172 142.2207 C 17.22782 142.2207 17.734375 142.7251 17.734375 143.37695 L 17.734375 144.60742 L 15.277344 144.60742 L 15.277344 143.37695 C 15.277344 142.7251 15.7839 142.2207 16.435547 142.2207 z M 16.435547 143.2207 C 16.301234 143.2207 16.277344 143.24444 16.277344 143.37891 L 16.277344 143.60742 L 16.734375 143.60742 L 16.734375 143.37891 C 16.734375 143.24441 16.712442 143.2207 16.578125 143.2207 L 16.435547 143.2207 z M 17.130859 155.59961 C 16.580859 155.57961 15.810469 155.63086 14.730469 155.63086 L 6.5292969 155.63086 L 8.9101562 158.5293 L 14.730469 158.5293 C 15.131912 158.5293 15.414551 158.79039 15.439453 159.19727 C 15.756409 159.09653 16.087055 159.02734 16.435547 159.02734 L 16.578125 159.02734 C 17.24903 159.02734 17.874081 159.23261 18.400391 159.57812 L 18.400391 159.25977 C 18.400391 156.10977 18.800391 155.63961 17.150391 155.59961 L 17.130859 155.59961 z M 5.0292969 155.86914 L 5.0292969 155.88086 C 4.9292969 155.90086 4.83 155.98055 4.75 156.06055 L 0.81054688 160.96094 C 0.61054688 161.26094 0.8409375 161.73977 1.2109375 161.75977 L 3.5996094 161.75977 L 3.5996094 163.7207 C 3.5996094 167.9807 3.0497656 167.33984 7.2597656 167.33984 L 11.869141 167.33984 L 11.869141 166.11914 L 11.869141 165.52344 L 11.869141 164.44141 L 11.869141 164.43945 L 7.2792969 164.43945 C 6.8392969 164.43945 6.5605469 164.1407 6.5605469 163.7207 L 6.5605469 161.75 L 9.0605469 161.75 C 9.4305469 161.77 9.6909375 161.2507 9.4609375 160.9707 L 5.5 156.07031 C 5.4 155.92031 5.1992969 155.84914 5.0292969 155.86914 z M 16.435547 160.02734 C 15.143818 160.02734 14.083984 161.08518 14.083984 162.37695 L 14.083984 163.60742 L 13.570312 163.60742 C 13.375448 163.60742 13.210603 163.70409 13.119141 163.79102 C 13.027691 163.87792 12.983569 163.95823 12.951172 164.03125 C 12.886382 164.17727 12.867187 164.30479 12.867188 164.44141 L 12.867188 165.52344 L 12.867188 166.11914 L 12.867188 167.67773 L 12.867188 168.50977 L 13.570312 168.50977 L 19.472656 168.50977 L 20.173828 168.50977 L 20.173828 167.67773 L 20.173828 165.52344 L 20.173828 164.44141 C 20.173828 164.3048 20.156597 164.17728 20.091797 164.03125 C 20.059397 163.95825 20.015299 163.87792 19.923828 163.79102 C 19.832368 163.70412 19.667509 163.60742 19.472656 163.60742 L 18.927734 163.60742 L 18.927734 162.37695 C 18.927734 161.08518 17.867902 160.02734 16.576172 160.02734 L 16.435547 160.02734 z M 12.900391 161.2207 C 12.580391 161.2807 12.419141 161.74 12.619141 162 L 13.085938 162.58594 L 13.085938 162.37891 C 13.085938 161.97087 13.170592 161.58376 13.306641 161.2207 L 12.900391 161.2207 z M 16.435547 161.2207 L 16.576172 161.2207 C 17.22782 161.2207 17.734375 161.7251 17.734375 162.37695 L 17.734375 163.60742 L 15.277344 163.60742 L 15.277344 162.37695 C 15.277344 161.7251 15.7839 161.2207 16.435547 161.2207 z M 19.708984 161.23047 C 19.842743 161.59081 19.927734 161.97449 19.927734 162.37891 L 19.927734 162.79102 C 20.119162 162.85779 20.322917 162.91147 20.484375 163 L 21.279297 162.00977 C 21.499297 161.72977 21.260156 161.24047 20.910156 161.23047 L 19.708984 161.23047 z M 16.435547 162.2207 C 16.301234 162.2207 16.277344 162.24444 16.277344 162.37891 L 16.277344 162.60742 L 16.734375 162.60742 L 16.734375 162.37891 C 16.734375 162.24441 16.712442 162.2207 16.578125 162.2207 L 16.435547 162.2207 z M 5.0996094 174.49023 L 5.1308594 174.5 C 4.9808594 174.5 4.83 174.56922 4.75 174.69922 L 0.80078125 179.59961 C 0.56078125 179.86961 0.7992182 180.42039 1.1992188 180.40039 L 3.5996094 180.40039 L 3.5996094 182.7207 C 3.5996094 186.9807 3.0497656 186.33984 7.2597656 186.33984 L 11.869141 186.33984 L 11.869141 185.11914 L 11.869141 184.52344 L 11.869141 183.44141 L 11.869141 183.43945 L 7.25 183.43945 C 6.82 183.43945 6.5507814 183.1407 6.5507812 182.7207 L 6.5507812 180.41992 L 9.0507812 180.41992 C 9.4307824 180.44992 9.7092187 179.87984 9.4492188 179.58984 L 5.4804688 174.68945 C 5.3804688 174.55945 5.2496094 174.49023 5.0996094 174.49023 z M 17.150391 174.58008 L 17.130859 174.59961 C 16.580859 174.57961 15.810469 174.63086 14.730469 174.63086 L 6.8300781 174.63086 L 9.1796875 177.5293 L 14.699219 177.5293 C 15.104107 177.5293 15.391475 177.79407 15.412109 178.20703 C 15.737096 178.1006 16.076913 178.02734 16.435547 178.02734 L 16.578125 178.02734 C 17.24903 178.02734 17.874081 178.2326 18.400391 178.57812 L 18.400391 178.24023 C 18.400391 175.09023 18.800391 174.62008 17.150391 174.58008 z M 16.435547 179.02734 C 15.143818 179.02734 14.083984 180.08518 14.083984 181.37695 L 14.083984 182.60742 L 13.570312 182.60742 C 13.375448 182.60742 13.210603 182.70409 13.119141 182.79102 C 13.027691 182.87792 12.983569 182.95823 12.951172 183.03125 C 12.886382 183.17727 12.867187 183.30479 12.867188 183.44141 L 12.867188 184.52344 L 12.867188 185.11914 L 12.867188 186.67773 L 12.867188 187.50977 L 13.570312 187.50977 L 19.472656 187.50977 L 20.173828 187.50977 L 20.173828 186.67773 L 20.173828 184.52344 L 20.173828 183.44141 C 20.173828 183.3048 20.156597 183.17728 20.091797 183.03125 C 20.059397 182.95825 20.015299 182.87792 19.923828 182.79102 C 19.832368 182.70412 19.667509 182.60742 19.472656 182.60742 L 18.927734 182.60742 L 18.927734 181.37695 C 18.927734 180.08518 17.867902 179.02734 16.576172 179.02734 L 16.435547 179.02734 z M 16.435547 180.2207 L 16.576172 180.2207 C 17.22782 180.2207 17.734375 180.7251 17.734375 181.37695 L 17.734375 182.60742 L 15.277344 182.60742 L 15.277344 181.37695 C 15.277344 180.7251 15.7839 180.2207 16.435547 180.2207 z M 19.816406 180.57031 C 19.882311 180.83091 19.927734 181.09907 19.927734 181.37891 L 19.927734 181.79102 C 20.168811 181.87511 20.455966 181.91694 20.613281 182.06641 C 20.630645 182.0829 20.639883 182.10199 20.65625 182.11914 L 21.259766 181.36914 C 21.479766 181.06914 21.240625 180.59031 20.890625 180.57031 L 19.816406 180.57031 z M 12.820312 180.58984 C 12.520316 180.68984 12.389141 181.11914 12.619141 181.36914 L 12.990234 181.83203 C 13.022029 181.82207 13.055579 181.81406 13.085938 181.80273 L 13.085938 181.37891 C 13.085938 181.10616 13.128698 180.84442 13.191406 180.58984 L 12.820312 180.58984 z M 16.435547 181.2207 C 16.301234 181.2207 16.277344 181.24444 16.277344 181.37891 L 16.277344 181.60742 L 16.734375 181.60742 L 16.734375 181.37891 C 16.734375 181.24441 16.712442 181.2207 16.578125 181.2207 L 16.435547 181.2207 z M 4.9609375 193.15039 L 4.9707031 193.16016 C 4.8707031 193.19016 4.8 193.25984 4.75 193.33984 L 0.81054688 198.24023 C 0.61054688 198.54023 0.8409375 199.01906 1.2109375 199.03906 L 3.5996094 199.03906 L 3.5996094 201.7207 C 3.5996094 205.9807 3.0497656 205.33984 7.2597656 205.33984 L 11.869141 205.33984 L 11.869141 204.11914 L 11.869141 203.52344 L 11.869141 202.44141 C 11.869141 202.44141 11.869141 202.43945 11.869141 202.43945 L 7.2695312 202.43945 C 6.8295312 202.43945 6.5507814 202.1407 6.5507812 201.7207 L 6.5507812 199.01953 L 9.0507812 199.01953 C 9.4207814 199.04953 9.6792188 198.54 9.4492188 198.25 L 5.4902344 193.34961 C 5.3702344 193.17961 5.1509375 193.10039 4.9609375 193.15039 z M 17.150391 193.58008 L 17.130859 193.58984 C 16.580859 193.56984 15.810469 193.61914 14.730469 193.61914 L 7.0996094 193.61914 L 9.4199219 196.46094 L 9.4492188 196.51953 L 14.699219 196.51953 C 15.106887 196.51953 15.397075 196.78718 15.414062 197.20508 C 15.738375 197.09913 16.077769 197.02734 16.435547 197.02734 L 16.578125 197.02734 C 17.24903 197.02734 17.874081 197.23259 18.400391 197.57812 L 18.400391 197.24023 C 18.400391 194.09023 18.800391 193.62008 17.150391 193.58008 z M 16.435547 198.02734 C 15.143818 198.02734 14.083984 199.08518 14.083984 200.37695 L 14.083984 201.60742 L 13.570312 201.60742 C 13.375448 201.60742 13.210603 201.70409 13.119141 201.79102 C 13.027691 201.87792 12.983569 201.95823 12.951172 202.03125 C 12.886382 202.17727 12.867187 202.30479 12.867188 202.44141 L 12.867188 203.52344 L 12.867188 204.11914 L 12.867188 205.67773 L 12.867188 206.50977 L 13.570312 206.50977 L 19.472656 206.50977 L 20.173828 206.50977 L 20.173828 205.67773 L 20.173828 203.52344 L 20.173828 202.44141 C 20.173828 202.3048 20.156597 202.17728 20.091797 202.03125 C 20.059397 201.95825 20.015299 201.87792 19.923828 201.79102 C 19.832368 201.70412 19.667509 201.60742 19.472656 201.60742 L 18.927734 201.60742 L 18.927734 200.37695 C 18.927734 199.08518 17.867902 198.02734 16.576172 198.02734 L 16.435547 198.02734 z M 16.435547 199.2207 L 16.576172 199.2207 C 17.22782 199.2207 17.734375 199.7251 17.734375 200.37695 L 17.734375 201.60742 L 15.277344 201.60742 L 15.277344 200.37695 C 15.277344 199.7251 15.7839 199.2207 16.435547 199.2207 z M 12.919922 199.93945 C 12.559922 199.95945 12.359141 200.48023 12.619141 200.74023 L 12.751953 200.9043 C 12.862211 200.87013 12.980058 200.84224 13.085938 200.80273 L 13.085938 200.37891 C 13.085938 200.22863 13.111295 200.08474 13.130859 199.93945 L 12.919922 199.93945 z M 19.882812 199.93945 C 19.902378 200.08474 19.927734 200.22863 19.927734 200.37891 L 19.927734 200.79102 C 20.168811 200.87511 20.455966 200.91694 20.613281 201.06641 C 20.691227 201.14046 20.749315 201.22305 20.806641 201.30273 L 21.259766 200.74023 C 21.519766 200.46023 21.260625 199.90945 20.890625 199.93945 L 19.882812 199.93945 z M 16.435547 200.2207 C 16.301234 200.2207 16.277344 200.24444 16.277344 200.37891 L 16.277344 200.60742 L 16.734375 200.60742 L 16.734375 200.37891 C 16.734375 200.24441 16.712442 200.2207 16.578125 200.2207 L 16.435547 200.2207 z ' fill='#{hex-color($highlight-text-color)}' stroke-width='0' /></svg>");
}
&:hover i.fa-retweet {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' height='209' width='22'><path d='M 4.9707031 3.1503906 L 4.9707031 3.1601562 C 4.8707031 3.1901563 4.8 3.2598438 4.75 3.3398438 L 0.80078125 8.2402344 C 0.60078125 8.5402344 0.8292187 9.0190625 1.1992188 9.0390625 L 3.5996094 9.0390625 L 3.5996094 11.720703 C 3.5996094 15.980703 3.0497656 15.339844 7.2597656 15.339844 L 11.869141 15.339844 L 11.869141 14.119141 L 11.869141 13.523438 L 11.869141 12.441406 C 11.869141 12.441406 11.869141 12.439453 11.869141 12.439453 L 7.2695312 12.439453 C 6.8295312 12.439453 6.5507814 12.140703 6.5507812 11.720703 L 6.5507812 9.0195312 L 9.0507812 9.0195312 C 9.4207813 9.0495313 9.6792188 8.54 9.4492188 8.25 L 5.5 3.3496094 C 5.38 3.1796094 5.1607031 3.1003906 4.9707031 3.1503906 z M 17.150391 3.5800781 L 17.130859 3.5898438 C 16.580859 3.5698436 15.810469 3.609375 14.730469 3.609375 L 7.0996094 3.609375 L 9.4199219 6.4609375 L 9.4492188 6.5195312 L 14.699219 6.5195312 C 15.106887 6.5195312 15.397113 6.7872181 15.414062 7.2050781 C 15.738375 7.0991315 16.077769 7.0273437 16.435547 7.0273438 L 16.578125 7.0273438 C 17.24903 7.0273438 17.874081 7.2325787 18.400391 7.578125 L 18.400391 7.2402344 C 18.400391 4.0902344 18.800391 3.6200781 17.150391 3.5800781 z M 16.435547 8.0273438 C 15.143818 8.0273438 14.083984 9.0851838 14.083984 10.376953 L 14.083984 11.607422 L 13.570312 11.607422 C 13.375448 11.607422 13.210603 11.704118 13.119141 11.791016 C 13.027691 11.877916 12.983569 11.958238 12.951172 12.03125 C 12.886382 12.177277 12.867187 12.304789 12.867188 12.441406 L 12.867188 13.523438 L 12.867188 14.119141 L 12.867188 15.677734 L 12.867188 16.509766 L 13.570312 16.509766 L 19.472656 16.509766 L 20.173828 16.509766 L 20.173828 15.677734 L 20.173828 13.523438 L 20.173828 12.441406 C 20.173828 12.304794 20.156597 12.177281 20.091797 12.03125 C 20.059397 11.95824 20.015299 11.877916 19.923828 11.791016 C 19.832368 11.704116 19.667509 11.607422 19.472656 11.607422 L 18.927734 11.607422 L 18.927734 10.376953 C 18.927734 9.0851838 17.867902 8.0273438 16.576172 8.0273438 L 16.435547 8.0273438 z M 16.435547 9.2207031 L 16.576172 9.2207031 C 17.22782 9.2207031 17.734375 9.7251013 17.734375 10.376953 L 17.734375 11.607422 L 15.277344 11.607422 L 15.277344 10.376953 C 15.277344 9.7251013 15.7839 9.2207031 16.435547 9.2207031 z M 12.919922 9.9394531 C 12.559922 9.9594531 12.359141 10.480234 12.619141 10.740234 L 12.751953 10.904297 C 12.862211 10.870135 12.980058 10.842244 13.085938 10.802734 L 13.085938 10.378906 C 13.085938 10.228632 13.111295 10.084741 13.130859 9.9394531 L 12.919922 9.9394531 z M 19.882812 9.9394531 C 19.902378 10.084741 19.927734 10.228632 19.927734 10.378906 L 19.927734 10.791016 C 20.168811 10.875098 20.455966 10.916935 20.613281 11.066406 C 20.691227 11.140457 20.749315 11.223053 20.806641 11.302734 L 21.259766 10.740234 C 21.519766 10.460234 21.260625 9.9094531 20.890625 9.9394531 L 19.882812 9.9394531 z M 16.435547 10.220703 C 16.301234 10.220703 16.277344 10.244432 16.277344 10.378906 L 16.277344 10.607422 L 16.734375 10.607422 L 16.734375 10.378906 C 16.734375 10.244433 16.712442 10.220703 16.578125 10.220703 L 16.435547 10.220703 z ' fill='#{hex-color(lighten($action-button-color, 7%))}' stroke-width='0'/><path d='M 7.7792969 19.650391 L 7.7792969 19.660156 C 7.5392969 19.680156 7.3398437 19.910156 7.3398438 20.160156 L 7.3398438 22.619141 L 7.2792969 22.619141 C 6.1992969 22.619141 5.4208594 22.589844 4.8808594 22.589844 C 3.2408594 22.589844 3.6308594 23.020234 3.6308594 26.240234 L 3.6308594 30.710938 C 3.6308594 34.970937 3.0692969 34.330078 7.2792969 34.330078 L 8.5 34.330078 L 7.1992188 33.269531 C 7.0992188 33.189531 7.02 33.070703 7 32.970703 C 6.98 32.800703 7.0592186 32.619531 7.1992188 32.519531 L 8.5292969 31.419922 L 7.2792969 31.419922 C 6.8392969 31.419922 6.5605469 31.120703 6.5605469 30.720703 L 6.5605469 26.240234 C 6.5605469 25.800234 6.8392969 25.519531 7.2792969 25.519531 L 7.3398438 25.519531 L 7.3398438 28.019531 C 7.3398438 28.399531 7.8801564 28.650391 8.1601562 28.400391 L 13.060547 24.470703 C 13.310547 24.290703 13.310547 23.869453 13.060547 23.689453 L 8.1601562 19.769531 C 8.0601563 19.669531 7.9192969 19.630391 7.7792969 19.650391 z M 17.119141 22.580078 L 17.119141 22.589844 C 16.579141 22.569844 15.820703 22.609375 14.720703 22.609375 L 13.470703 22.609375 L 14.769531 23.679688 C 14.869531 23.749688 14.950703 23.879766 14.970703 24.009766 C 14.990703 24.169766 14.909531 24.310156 14.769531 24.410156 L 13.439453 25.509766 L 14.720703 25.509766 C 15.129702 25.509766 15.41841 25.778986 15.433594 26.199219 C 15.752266 26.097283 16.084896 26.027344 16.435547 26.027344 L 16.578125 26.027344 C 17.236645 26.027344 17.848901 26.228565 18.369141 26.5625 L 18.369141 26.240234 C 18.369141 23.090234 18.769141 22.620078 17.119141 22.580078 z M 16.435547 27.027344 C 15.143818 27.027344 14.083984 28.085184 14.083984 29.376953 L 14.083984 30.607422 L 13.570312 30.607422 C 13.375452 30.607422 13.210603 30.704118 13.119141 30.791016 C 13.027691 30.877916 12.983569 30.958238 12.951172 31.03125 C 12.886382 31.177277 12.867184 31.304789 12.867188 31.441406 L 12.867188 32.523438 L 12.867188 33.119141 L 12.867188 34.677734 L 12.867188 35.509766 L 13.570312 35.509766 L 19.472656 35.509766 L 20.173828 35.509766 L 20.173828 34.677734 L 20.173828 32.523438 L 20.173828 31.441406 C 20.173828 31.304794 20.156597 31.177281 20.091797 31.03125 C 20.059397 30.95824 20.015299 30.877916 19.923828 30.791016 C 19.832368 30.704116 19.667509 30.607422 19.472656 30.607422 L 18.927734 30.607422 L 18.927734 29.376953 C 18.927734 28.085184 17.867902 27.027344 16.576172 27.027344 L 16.435547 27.027344 z M 16.435547 28.220703 L 16.576172 28.220703 C 17.22782 28.220703 17.734375 28.725101 17.734375 29.376953 L 17.734375 30.607422 L 15.277344 30.607422 L 15.277344 29.376953 C 15.277344 28.725101 15.7839 28.220703 16.435547 28.220703 z M 13.109375 29.150391 L 8.9199219 32.509766 C 8.6599219 32.689766 8.6599219 33.109063 8.9199219 33.289062 L 11.869141 35.648438 L 11.869141 34.677734 L 11.869141 33.119141 L 11.869141 32.523438 L 11.869141 31.441406 C 11.869141 31.217489 11.912641 30.907486 12.037109 30.626953 C 12.093758 30.499284 12.228597 30.257492 12.429688 30.066406 C 12.580253 29.92335 12.859197 29.887344 13.085938 29.802734 L 13.085938 29.378906 C 13.085938 29.300761 13.104 29.227272 13.109375 29.150391 z M 16.435547 29.220703 C 16.301234 29.220703 16.277344 29.244432 16.277344 29.378906 L 16.277344 29.607422 L 16.734375 29.607422 L 16.734375 29.378906 C 16.734375 29.244433 16.712442 29.220703 16.578125 29.220703 L 16.435547 29.220703 z M 12.943359 36.509766 L 13.820312 37.210938 C 14.090314 37.460938 14.639141 37.210078 14.619141 36.830078 L 14.619141 36.509766 L 13.570312 36.509766 L 12.943359 36.509766 z M 10.330078 38.650391 L 10.339844 38.660156 C 10.099844 38.680156 9.9001562 38.910156 9.9101562 39.160156 L 9.9101562 41.630859 L 7.3007812 41.630859 C 6.2207812 41.630859 5.4403906 41.589844 4.9003906 41.589844 C 3.2603906 41.589844 3.6503906 42.020234 3.6503906 45.240234 L 3.6503906 49.710938 C 3.6503906 53.370936 3.4202344 53.409141 5.9902344 53.369141 L 4.6503906 52.269531 C 4.5503906 52.189531 4.4692187 52.070703 4.4492188 51.970703 C 4.4492188 51.800703 4.5203906 51.619531 4.6503906 51.519531 L 6.609375 49.919922 C 6.579375 49.859922 6.5703125 49.790703 6.5703125 49.720703 L 6.5703125 45.240234 C 6.5703125 44.800234 6.8490625 44.519531 7.2890625 44.519531 L 9.9003906 44.519531 L 9.9003906 47.019531 C 9.9003906 47.379531 10.399219 47.620391 10.699219 47.400391 L 15.630859 43.470703 C 15.870859 43.290703 15.870859 42.869453 15.630859 42.689453 L 10.689453 38.769531 C 10.589453 38.689531 10.460078 38.640391 10.330078 38.650391 z M 16.869141 41.585938 C 16.616211 41.581522 16.322969 41.584844 15.980469 41.589844 L 15.970703 41.589844 L 17.310547 42.689453 C 17.410547 42.759453 17.489766 42.889531 17.509766 43.019531 C 17.529766 43.179531 17.479609 43.319922 17.349609 43.419922 L 15.390625 45.019531 C 15.406724 45.075878 15.427133 45.132837 15.4375 45.197266 C 15.754974 45.096169 16.086404 45.027344 16.435547 45.027344 L 16.578125 45.027344 C 17.24129 45.027344 17.858323 45.230088 18.380859 45.568359 L 18.380859 45.25 C 18.380859 42.0475 18.639648 41.616836 16.869141 41.585938 z M 16.435547 46.027344 C 15.143818 46.027344 14.083984 47.085184 14.083984 48.376953 L 14.083984 49.607422 L 13.570312 49.607422 C 13.375448 49.607422 13.210603 49.704118 13.119141 49.791016 C 13.027691 49.877916 12.983569 49.958238 12.951172 50.03125 C 12.886382 50.177277 12.867187 50.304789 12.867188 50.441406 L 12.867188 51.523438 L 12.867188 52.119141 L 12.867188 53.677734 L 12.867188 54.509766 L 13.570312 54.509766 L 19.472656 54.509766 L 20.173828 54.509766 L 20.173828 53.677734 L 20.173828 51.523438 L 20.173828 50.441406 C 20.173828 50.304794 20.156597 50.177281 20.091797 50.03125 C 20.059397 49.95824 20.015299 49.877916 19.923828 49.791016 C 19.832368 49.704116 19.667509 49.607422 19.472656 49.607422 L 18.927734 49.607422 L 18.927734 48.376953 C 18.927734 47.085184 17.867902 46.027344 16.576172 46.027344 L 16.435547 46.027344 z M 16.435547 47.220703 L 16.576172 47.220703 C 17.22782 47.220703 17.734375 47.725101 17.734375 48.376953 L 17.734375 49.607422 L 15.277344 49.607422 L 15.277344 48.376953 C 15.277344 47.725101 15.7839 47.220703 16.435547 47.220703 z M 11.470703 47.490234 C 11.410703 47.510234 11.349063 47.539844 11.289062 47.589844 L 6.3496094 51.519531 C 6.1096094 51.699531 6.1096094 52.120781 6.3496094 52.300781 L 11.289062 56.220703 C 11.569064 56.440703 12.070312 56.199844 12.070312 55.839844 L 12.070312 55.509766 L 11.869141 55.509766 L 11.869141 53.677734 L 11.869141 52.119141 L 11.869141 51.523438 L 11.869141 50.441406 C 11.869141 50.217489 11.912641 49.907486 12.037109 49.626953 C 12.043809 49.611855 12.061451 49.584424 12.070312 49.566406 L 12.070312 47.960938 C 12.070312 47.660938 11.770703 47.430234 11.470703 47.490234 z M 16.435547 48.220703 C 16.301234 48.220703 16.277344 48.244432 16.277344 48.378906 L 16.277344 48.607422 L 16.734375 48.607422 L 16.734375 48.378906 C 16.734375 48.244433 16.712442 48.220703 16.578125 48.220703 L 16.435547 48.220703 z M 13.060547 57.650391 L 13.060547 57.660156 C 12.830547 57.690156 12.660156 57.920156 12.660156 58.160156 L 12.660156 60.630859 L 7.2792969 60.630859 C 6.1992969 60.630859 5.4208594 60.589844 4.8808594 60.589844 C 3.2408594 60.589844 3.6308594 61.020234 3.6308594 64.240234 L 3.6308594 69.109375 L 6.5605469 66.740234 L 6.5605469 64.240234 C 6.5605469 63.800234 6.8392969 63.519531 7.2792969 63.519531 L 12.660156 63.519531 L 12.660156 66.019531 C 12.660156 66.299799 12.960394 66.500006 13.226562 66.474609 C 13.625751 65.076914 14.904956 64.035678 16.421875 64.029297 L 18.380859 62.470703 C 18.620859 62.290703 18.620859 61.869453 18.380859 61.689453 L 13.439453 57.769531 C 13.339453 57.669531 13.200547 57.630391 13.060547 57.650391 z M 18.359375 63.810547 L 17.800781 64.269531 C 18.004793 64.350836 18.198411 64.450249 18.380859 64.568359 L 18.380859 64.25 L 18.380859 63.810547 L 18.359375 63.810547 z M 16.435547 65.027344 C 15.143818 65.027344 14.083984 66.085184 14.083984 67.376953 L 14.083984 68.607422 L 13.570312 68.607422 C 13.375448 68.607422 13.210603 68.704118 13.119141 68.791016 C 13.027691 68.877916 12.983569 68.958238 12.951172 69.03125 C 12.886382 69.177277 12.867187 69.304789 12.867188 69.441406 L 12.867188 70.523438 L 12.867188 71.119141 L 12.867188 72.677734 L 12.867188 73.509766 L 13.570312 73.509766 L 19.472656 73.509766 L 20.173828 73.509766 L 20.173828 72.677734 L 20.173828 70.523438 L 20.173828 69.441406 C 20.173828 69.304794 20.156597 69.177281 20.091797 69.03125 C 20.059397 68.95824 20.015299 68.877916 19.923828 68.791016 C 19.832368 68.704116 19.667509 68.607422 19.472656 68.607422 L 18.927734 68.607422 L 18.927734 67.376953 C 18.927734 66.085184 17.867902 65.027344 16.576172 65.027344 L 16.435547 65.027344 z M 16.435547 66.220703 L 16.576172 66.220703 C 17.22782 66.220703 17.734375 66.725101 17.734375 67.376953 L 17.734375 68.607422 L 15.277344 68.607422 L 15.277344 67.376953 C 15.277344 66.725101 15.7839 66.220703 16.435547 66.220703 z M 8.7207031 66.509766 C 8.6507031 66.529766 8.5895312 66.559375 8.5195312 66.609375 L 3.5996094 70.519531 C 3.3496094 70.699531 3.3496094 71.120781 3.5996094 71.300781 L 8.5292969 75.220703 C 8.8092969 75.440703 9.3105469 75.199844 9.3105469 74.839844 L 9.3105469 72.339844 L 11.869141 72.339844 L 11.869141 71.119141 L 11.869141 70.523438 L 11.869141 69.449219 L 9.3203125 69.449219 L 9.3203125 66.980469 C 9.3203125 66.680469 9.0007031 66.449766 8.7207031 66.509766 z M 16.435547 67.220703 C 16.301234 67.220703 16.277344 67.244432 16.277344 67.378906 L 16.277344 67.607422 L 16.734375 67.607422 L 16.734375 67.378906 C 16.734375 67.244433 16.712442 67.220703 16.578125 67.220703 L 16.435547 67.220703 z M 19.248047 78.800781 C 19.148558 78.831033 19.050295 78.90106 18.970703 78.970703 L 18.070312 79.869141 C 17.630312 79.569141 16.710703 79.619141 14.720703 79.619141 L 7.2792969 79.619141 C 6.1992969 79.619141 5.4208594 79.589844 4.8808594 79.589844 C 3.2408594 79.589844 3.6308594 80.020234 3.6308594 83.240234 L 3.6308594 83.939453 L 6.5605469 84.240234 L 6.5605469 83.240234 C 6.5605469 82.800234 6.8392969 82.519531 7.2792969 82.519531 L 14.720703 82.519531 C 14.920703 82.519531 15.090703 82.600703 15.220703 82.720703 L 13.419922 84.519531 C 13.279464 84.665607 13.281282 84.881022 13.363281 85.054688 C 13.880838 83.867655 15.067337 83.027344 16.435547 83.027344 L 16.578125 83.027344 C 18.290465 83.027344 19.703357 84.345788 19.890625 86.011719 L 19.960938 86.019531 C 20.240938 86.049531 20.520234 85.770234 20.490234 85.490234 L 19.789062 79.240234 C 19.789062 78.973661 19.498025 78.767523 19.25 78.800781 L 19.248047 78.800781 z M 16.435547 84.027344 C 15.143818 84.027344 14.083984 85.085184 14.083984 86.376953 L 14.083984 87.607422 L 13.570312 87.607422 C 13.375448 87.607422 13.210603 87.704118 13.119141 87.791016 C 13.027691 87.877916 12.983569 87.958238 12.951172 88.03125 C 12.886382 88.177277 12.867187 88.304789 12.867188 88.441406 L 12.867188 89.523438 L 12.867188 90.119141 L 12.867188 91.677734 L 12.867188 92.509766 L 13.570312 92.509766 L 19.472656 92.509766 L 20.173828 92.509766 L 20.173828 91.677734 L 20.173828 89.523438 L 20.173828 88.441406 C 20.173828 88.304794 20.156597 88.177281 20.091797 88.03125 C 20.059397 87.95824 20.015299 87.877916 19.923828 87.791016 C 19.832368 87.704116 19.667509 87.607422 19.472656 87.607422 L 18.927734 87.607422 L 18.927734 86.376953 C 18.927734 85.085184 17.867902 84.027344 16.576172 84.027344 L 16.435547 84.027344 z M 2.0507812 84.900391 C 1.8507824 84.970391 1.6907031 85.199453 1.7207031 85.439453 L 2.4199219 91.689453 C 2.4399219 92.049453 3 92.240929 3.25 91.960938 L 4.0507812 91.160156 C 4.0707812 91.160156 4.0898437 91.140156 4.0898438 91.160156 C 4.5498437 91.400156 5.4595313 91.330078 7.2695312 91.330078 L 11.869141 91.330078 L 11.869141 90.119141 L 11.869141 89.523438 L 11.869141 88.441406 C 11.869141 88.437991 11.871073 88.433136 11.871094 88.429688 L 7.2792969 88.429688 C 7.1292969 88.429688 6.9808594 88.400078 6.8808594 88.330078 L 8.8007812 86.400391 C 9.1007822 86.160391 8.8992969 85.600547 8.5292969 85.560547 L 2.25 84.910156 L 2.0507812 84.910156 L 2.0507812 84.900391 z M 16.435547 85.220703 L 16.576172 85.220703 C 17.22782 85.220703 17.734375 85.725101 17.734375 86.376953 L 17.734375 87.607422 L 15.277344 87.607422 L 15.277344 86.376953 C 15.277344 85.725101 15.7839 85.220703 16.435547 85.220703 z M 4.8808594 98.599609 C 3.5508594 98.599609 3.5400781 99.080402 3.5800781 100.90039 L 4.7207031 99.529297 C 4.8007031 99.429297 4.9405469 99.360078 5.0605469 99.330078 C 5.2205469 99.330078 5.4 99.409297 5.5 99.529297 L 7.1601562 101.56055 C 7.2001563 101.56055 7.2292969 101.5293 7.2792969 101.5293 L 14.720703 101.5293 C 15.060703 101.5293 15.289141 101.7293 15.369141 102.0293 L 12.939453 102.0293 C 12.599453 102.0793 12.410625 102.55055 12.640625 102.81055 L 13.470703 103.85742 C 14.029941 102.77899 15.146801 102.02734 16.435547 102.02734 L 16.578125 102.02734 C 18.158418 102.02734 19.491598 103.14879 19.835938 104.63086 L 21.279297 102.82031 C 21.499297 102.55031 21.260156 102.06078 20.910156 102.05078 L 18.400391 102.05078 C 18.420391 98.150792 19.000234 98.650391 14.740234 98.650391 L 7.2792969 98.650391 C 6.1992969 98.650391 5.4208594 98.609375 4.8808594 98.609375 L 4.8808594 98.599609 z M 5.0292969 101.06055 C 4.9292969 101.09055 4.83 101.15977 4.75 101.25977 L 0.81054688 106.16016 C 0.61054688 106.44016 0.8409375 106.92945 1.2109375 106.93945 L 3.5996094 106.93945 C 3.5796094 110.87945 3.1497656 110.33984 7.2597656 110.33984 L 11.869141 110.33984 L 11.869141 109.11914 L 11.869141 108.52344 L 11.869141 107.44141 L 11.869141 107.43945 L 7.2792969 107.43945 C 6.9292969 107.43945 6.7091406 107.23945 6.6191406 106.93945 L 9.0605469 106.93945 C 9.4305469 106.93945 9.6909375 106.44016 9.4609375 106.16016 L 5.5 101.25977 C 5.4 101.10977 5.1992969 101.03055 5.0292969 101.06055 z M 16.435547 103.02734 C 15.143818 103.02734 14.083984 104.08518 14.083984 105.37695 L 14.083984 106.60742 L 13.570312 106.60742 C 13.375448 106.60742 13.210603 106.70409 13.119141 106.79102 C 13.027691 106.87792 12.983569 106.95823 12.951172 107.03125 C 12.886382 107.17727 12.867187 107.30479 12.867188 107.44141 L 12.867188 108.52344 L 12.867188 109.11914 L 12.867188 110.67773 L 12.867188 111.50977 L 13.570312 111.50977 L 19.472656 111.50977 L 20.173828 111.50977 L 20.173828 110.67773 L 20.173828 108.52344 L 20.173828 107.44141 C 20.173828 107.3048 20.156597 107.17728 20.091797 107.03125 C 20.059397 106.95825 20.015299 106.87792 19.923828 106.79102 C 19.832368 106.70412 19.667509 106.60742 19.472656 106.60742 L 18.927734 106.60742 L 18.927734 105.37695 C 18.927734 104.08518 17.867902 103.02734 16.576172 103.02734 L 16.435547 103.02734 z M 16.435547 104.2207 L 16.576172 104.2207 C 17.22782 104.2207 17.734375 104.7251 17.734375 105.37695 L 17.734375 106.60742 L 15.277344 106.60742 L 15.277344 105.37695 C 15.277344 104.7251 15.7839 104.2207 16.435547 104.2207 z M 16.435547 105.2207 C 16.301234 105.2207 16.277344 105.24444 16.277344 105.37891 L 16.277344 105.60742 L 16.734375 105.60742 L 16.734375 105.37891 C 16.734375 105.24441 16.712442 105.2207 16.578125 105.2207 L 16.435547 105.2207 z M 4.8808594 117.58984 L 4.8808594 117.59961 C 3.7208594 117.59961 3.5800781 117.90016 3.5800781 119.16016 L 4.7207031 117.7793 C 4.8007031 117.6793 4.9405469 117.63914 5.0605469 117.61914 C 5.2205469 117.61914 5.4 117.6593 5.5 117.7793 L 7.7207031 120.5293 L 14.720703 120.5293 C 15.123595 120.5293 15.408576 120.79174 15.431641 121.20117 C 15.750992 121.09876 16.08404 121.02734 16.435547 121.02734 L 16.578125 121.02734 C 17.24903 121.02734 17.874081 121.23262 18.400391 121.57812 L 18.400391 121.25 C 18.400391 117.05 19.120234 117.61914 14.740234 117.61914 L 7.2792969 117.61914 C 6.1992969 117.61914 5.4208594 117.58984 4.8808594 117.58984 z M 4.9804688 119.33984 C 4.8804688 119.36984 4.81 119.44 4.75 119.5 L 0.80078125 124.43945 C 0.60078125 124.71945 0.8292182 125.2107 1.1992188 125.2207 L 3.5996094 125.2207 L 3.5996094 125.7207 C 3.5996094 129.9807 3.0497656 129.33984 7.2597656 129.33984 L 11.869141 129.33984 L 11.869141 128.11914 L 11.869141 127.52344 L 11.869141 126.44141 C 11.869141 126.43799 11.871073 126.43314 11.871094 126.42969 L 7.2792969 126.42969 C 6.8392969 126.42969 6.5605469 126.13094 6.5605469 125.71094 L 6.5605469 125.21094 L 9.0605469 125.21094 C 9.4305469 125.23094 9.6909375 124.70969 9.4609375 124.42969 L 5.5 119.5 C 5.3820133 119.35252 5.1682348 119.28513 4.9804688 119.33984 z M 12.839844 121.7793 C 12.539844 121.8793 12.410625 122.32055 12.640625 122.56055 L 13.267578 123.34375 C 13.473522 122.72168 13.852237 122.1828 14.353516 121.7793 L 12.839844 121.7793 z M 18.658203 121.7793 C 19.393958 122.37155 19.878978 123.25738 19.916016 124.25781 L 21.279297 122.56055 C 21.499297 122.28055 21.260156 121.7893 20.910156 121.7793 L 18.658203 121.7793 z M 16.435547 122.02734 C 15.143818 122.02734 14.083984 123.08518 14.083984 124.37695 L 14.083984 125.60742 L 13.570312 125.60742 C 13.375448 125.60742 13.210603 125.70409 13.119141 125.79102 C 13.027691 125.87792 12.983569 125.95823 12.951172 126.03125 C 12.886382 126.17727 12.867187 126.30479 12.867188 126.44141 L 12.867188 127.52344 L 12.867188 128.11914 L 12.867188 129.67773 L 12.867188 130.50977 L 13.570312 130.50977 L 19.472656 130.50977 L 20.173828 130.50977 L 20.173828 129.67773 L 20.173828 127.52344 L 20.173828 126.44141 C 20.173828 126.3048 20.156597 126.17728 20.091797 126.03125 C 20.059397 125.95825 20.015299 125.87792 19.923828 125.79102 C 19.832368 125.70412 19.667509 125.60742 19.472656 125.60742 L 18.927734 125.60742 L 18.927734 124.37695 C 18.927734 123.08518 17.867902 122.02734 16.576172 122.02734 L 16.435547 122.02734 z M 16.435547 123.2207 L 16.576172 123.2207 C 17.22782 123.2207 17.734375 123.7251 17.734375 124.37695 L 17.734375 125.60742 L 15.277344 125.60742 L 15.277344 124.37695 C 15.277344 123.7251 15.7839 123.2207 16.435547 123.2207 z M 16.435547 124.2207 C 16.301234 124.2207 16.277344 124.24444 16.277344 124.37891 L 16.277344 124.60742 L 16.734375 124.60742 L 16.734375 124.37891 C 16.734375 124.24441 16.712442 124.2207 16.578125 124.2207 L 16.435547 124.2207 z M 5.9394531 136.58984 L 5.9394531 136.59961 L 8.3105469 139.5293 L 14.730469 139.5293 C 15.131912 139.5293 15.414551 139.79039 15.439453 140.19727 C 15.756409 140.09653 16.087055 140.02734 16.435547 140.02734 L 16.578125 140.02734 C 17.24903 140.02734 17.874081 140.23261 18.400391 140.57812 L 18.400391 140.25 C 18.400391 136.05 19.120234 136.61914 14.740234 136.61914 L 7.2792969 136.61914 C 6.6792969 136.61914 6.3594531 136.59984 5.9394531 136.58984 z M 4.2207031 136.66016 C 3.8207031 136.74016 3.6791406 136.96016 3.6191406 137.41016 L 4.2207031 136.66992 L 4.2207031 136.66016 z M 5.0605469 137.57031 L 5.0605469 137.58984 C 4.9405469 137.58984 4.8197656 137.66953 4.7597656 137.76953 L 0.81054688 142.66992 C 0.57054688 142.96992 0.8109375 143.50023 1.2109375 143.49023 L 3.5996094 143.49023 L 3.5996094 144.71094 C 3.5996094 148.97094 3.0497656 148.33008 7.2597656 148.33008 L 11.869141 148.33008 L 11.869141 147.11914 L 11.869141 146.52344 L 11.869141 145.44141 C 11.869141 145.43799 11.871073 145.43314 11.871094 145.42969 L 7.2792969 145.42969 C 6.8392969 145.42969 6.5605469 145.13094 6.5605469 144.71094 L 6.5605469 143.49023 L 9.0605469 143.49023 C 9.4605469 143.53023 9.7309375 142.95945 9.4609375 142.68945 L 5.5 137.76953 C 5.4 137.63953 5.2305469 137.57031 5.0605469 137.57031 z M 16.435547 141.02734 C 15.143818 141.02734 14.083984 142.08518 14.083984 143.37695 L 14.083984 144.60742 L 13.570312 144.60742 C 13.375448 144.60742 13.210603 144.70409 13.119141 144.79102 C 13.027691 144.87792 12.983569 144.95823 12.951172 145.03125 C 12.886382 145.17727 12.867187 145.30479 12.867188 145.44141 L 12.867188 146.52344 L 12.867188 147.11914 L 12.867188 148.67773 L 12.867188 149.50977 L 13.570312 149.50977 L 19.472656 149.50977 L 20.173828 149.50977 L 20.173828 148.67773 L 20.173828 146.52344 L 20.173828 145.44141 C 20.173828 145.3048 20.156597 145.17728 20.091797 145.03125 C 20.059397 144.95825 20.015299 144.87792 19.923828 144.79102 C 19.832368 144.70412 19.667509 144.60742 19.472656 144.60742 L 18.927734 144.60742 L 18.927734 143.37695 C 18.927734 142.08518 17.867902 141.02734 16.576172 141.02734 L 16.435547 141.02734 z M 12.849609 141.5 C 12.549609 141.6 12.420391 142.0393 12.650391 142.2793 L 13.136719 142.88672 C 13.213026 142.38119 13.390056 141.90696 13.667969 141.5 L 12.849609 141.5 z M 19.34375 141.5 C 19.710704 142.03735 19.927734 142.68522 19.927734 143.37891 L 19.927734 143.79102 C 19.965561 143.80421 20.005506 143.81448 20.044922 143.82617 L 21.289062 142.2793 C 21.509062 141.9993 21.269922 141.51 20.919922 141.5 L 19.34375 141.5 z M 16.435547 142.2207 L 16.576172 142.2207 C 17.22782 142.2207 17.734375 142.7251 17.734375 143.37695 L 17.734375 144.60742 L 15.277344 144.60742 L 15.277344 143.37695 C 15.277344 142.7251 15.7839 142.2207 16.435547 142.2207 z M 16.435547 143.2207 C 16.301234 143.2207 16.277344 143.24444 16.277344 143.37891 L 16.277344 143.60742 L 16.734375 143.60742 L 16.734375 143.37891 C 16.734375 143.24441 16.712442 143.2207 16.578125 143.2207 L 16.435547 143.2207 z M 17.130859 155.59961 C 16.580859 155.57961 15.810469 155.63086 14.730469 155.63086 L 6.5292969 155.63086 L 8.9101562 158.5293 L 14.730469 158.5293 C 15.131912 158.5293 15.414551 158.79039 15.439453 159.19727 C 15.756409 159.09653 16.087055 159.02734 16.435547 159.02734 L 16.578125 159.02734 C 17.24903 159.02734 17.874081 159.23261 18.400391 159.57812 L 18.400391 159.25977 C 18.400391 156.10977 18.800391 155.63961 17.150391 155.59961 L 17.130859 155.59961 z M 5.0292969 155.86914 L 5.0292969 155.88086 C 4.9292969 155.90086 4.83 155.98055 4.75 156.06055 L 0.81054688 160.96094 C 0.61054688 161.26094 0.8409375 161.73977 1.2109375 161.75977 L 3.5996094 161.75977 L 3.5996094 163.7207 C 3.5996094 167.9807 3.0497656 167.33984 7.2597656 167.33984 L 11.869141 167.33984 L 11.869141 166.11914 L 11.869141 165.52344 L 11.869141 164.44141 L 11.869141 164.43945 L 7.2792969 164.43945 C 6.8392969 164.43945 6.5605469 164.1407 6.5605469 163.7207 L 6.5605469 161.75 L 9.0605469 161.75 C 9.4305469 161.77 9.6909375 161.2507 9.4609375 160.9707 L 5.5 156.07031 C 5.4 155.92031 5.1992969 155.84914 5.0292969 155.86914 z M 16.435547 160.02734 C 15.143818 160.02734 14.083984 161.08518 14.083984 162.37695 L 14.083984 163.60742 L 13.570312 163.60742 C 13.375448 163.60742 13.210603 163.70409 13.119141 163.79102 C 13.027691 163.87792 12.983569 163.95823 12.951172 164.03125 C 12.886382 164.17727 12.867187 164.30479 12.867188 164.44141 L 12.867188 165.52344 L 12.867188 166.11914 L 12.867188 167.67773 L 12.867188 168.50977 L 13.570312 168.50977 L 19.472656 168.50977 L 20.173828 168.50977 L 20.173828 167.67773 L 20.173828 165.52344 L 20.173828 164.44141 C 20.173828 164.3048 20.156597 164.17728 20.091797 164.03125 C 20.059397 163.95825 20.015299 163.87792 19.923828 163.79102 C 19.832368 163.70412 19.667509 163.60742 19.472656 163.60742 L 18.927734 163.60742 L 18.927734 162.37695 C 18.927734 161.08518 17.867902 160.02734 16.576172 160.02734 L 16.435547 160.02734 z M 12.900391 161.2207 C 12.580391 161.2807 12.419141 161.74 12.619141 162 L 13.085938 162.58594 L 13.085938 162.37891 C 13.085938 161.97087 13.170592 161.58376 13.306641 161.2207 L 12.900391 161.2207 z M 16.435547 161.2207 L 16.576172 161.2207 C 17.22782 161.2207 17.734375 161.7251 17.734375 162.37695 L 17.734375 163.60742 L 15.277344 163.60742 L 15.277344 162.37695 C 15.277344 161.7251 15.7839 161.2207 16.435547 161.2207 z M 19.708984 161.23047 C 19.842743 161.59081 19.927734 161.97449 19.927734 162.37891 L 19.927734 162.79102 C 20.119162 162.85779 20.322917 162.91147 20.484375 163 L 21.279297 162.00977 C 21.499297 161.72977 21.260156 161.24047 20.910156 161.23047 L 19.708984 161.23047 z M 16.435547 162.2207 C 16.301234 162.2207 16.277344 162.24444 16.277344 162.37891 L 16.277344 162.60742 L 16.734375 162.60742 L 16.734375 162.37891 C 16.734375 162.24441 16.712442 162.2207 16.578125 162.2207 L 16.435547 162.2207 z M 5.0996094 174.49023 L 5.1308594 174.5 C 4.9808594 174.5 4.83 174.56922 4.75 174.69922 L 0.80078125 179.59961 C 0.56078125 179.86961 0.7992182 180.42039 1.1992188 180.40039 L 3.5996094 180.40039 L 3.5996094 182.7207 C 3.5996094 186.9807 3.0497656 186.33984 7.2597656 186.33984 L 11.869141 186.33984 L 11.869141 185.11914 L 11.869141 184.52344 L 11.869141 183.44141 L 11.869141 183.43945 L 7.25 183.43945 C 6.82 183.43945 6.5507814 183.1407 6.5507812 182.7207 L 6.5507812 180.41992 L 9.0507812 180.41992 C 9.4307824 180.44992 9.7092187 179.87984 9.4492188 179.58984 L 5.4804688 174.68945 C 5.3804688 174.55945 5.2496094 174.49023 5.0996094 174.49023 z M 17.150391 174.58008 L 17.130859 174.59961 C 16.580859 174.57961 15.810469 174.63086 14.730469 174.63086 L 6.8300781 174.63086 L 9.1796875 177.5293 L 14.699219 177.5293 C 15.104107 177.5293 15.391475 177.79407 15.412109 178.20703 C 15.737096 178.1006 16.076913 178.02734 16.435547 178.02734 L 16.578125 178.02734 C 17.24903 178.02734 17.874081 178.2326 18.400391 178.57812 L 18.400391 178.24023 C 18.400391 175.09023 18.800391 174.62008 17.150391 174.58008 z M 16.435547 179.02734 C 15.143818 179.02734 14.083984 180.08518 14.083984 181.37695 L 14.083984 182.60742 L 13.570312 182.60742 C 13.375448 182.60742 13.210603 182.70409 13.119141 182.79102 C 13.027691 182.87792 12.983569 182.95823 12.951172 183.03125 C 12.886382 183.17727 12.867187 183.30479 12.867188 183.44141 L 12.867188 184.52344 L 12.867188 185.11914 L 12.867188 186.67773 L 12.867188 187.50977 L 13.570312 187.50977 L 19.472656 187.50977 L 20.173828 187.50977 L 20.173828 186.67773 L 20.173828 184.52344 L 20.173828 183.44141 C 20.173828 183.3048 20.156597 183.17728 20.091797 183.03125 C 20.059397 182.95825 20.015299 182.87792 19.923828 182.79102 C 19.832368 182.70412 19.667509 182.60742 19.472656 182.60742 L 18.927734 182.60742 L 18.927734 181.37695 C 18.927734 180.08518 17.867902 179.02734 16.576172 179.02734 L 16.435547 179.02734 z M 16.435547 180.2207 L 16.576172 180.2207 C 17.22782 180.2207 17.734375 180.7251 17.734375 181.37695 L 17.734375 182.60742 L 15.277344 182.60742 L 15.277344 181.37695 C 15.277344 180.7251 15.7839 180.2207 16.435547 180.2207 z M 19.816406 180.57031 C 19.882311 180.83091 19.927734 181.09907 19.927734 181.37891 L 19.927734 181.79102 C 20.168811 181.87511 20.455966 181.91694 20.613281 182.06641 C 20.630645 182.0829 20.639883 182.10199 20.65625 182.11914 L 21.259766 181.36914 C 21.479766 181.06914 21.240625 180.59031 20.890625 180.57031 L 19.816406 180.57031 z M 12.820312 180.58984 C 12.520316 180.68984 12.389141 181.11914 12.619141 181.36914 L 12.990234 181.83203 C 13.022029 181.82207 13.055579 181.81406 13.085938 181.80273 L 13.085938 181.37891 C 13.085938 181.10616 13.128698 180.84442 13.191406 180.58984 L 12.820312 180.58984 z M 16.435547 181.2207 C 16.301234 181.2207 16.277344 181.24444 16.277344 181.37891 L 16.277344 181.60742 L 16.734375 181.60742 L 16.734375 181.37891 C 16.734375 181.24441 16.712442 181.2207 16.578125 181.2207 L 16.435547 181.2207 z M 4.9609375 193.15039 L 4.9707031 193.16016 C 4.8707031 193.19016 4.8 193.25984 4.75 193.33984 L 0.81054688 198.24023 C 0.61054688 198.54023 0.8409375 199.01906 1.2109375 199.03906 L 3.5996094 199.03906 L 3.5996094 201.7207 C 3.5996094 205.9807 3.0497656 205.33984 7.2597656 205.33984 L 11.869141 205.33984 L 11.869141 204.11914 L 11.869141 203.52344 L 11.869141 202.44141 C 11.869141 202.44141 11.869141 202.43945 11.869141 202.43945 L 7.2695312 202.43945 C 6.8295312 202.43945 6.5507814 202.1407 6.5507812 201.7207 L 6.5507812 199.01953 L 9.0507812 199.01953 C 9.4207814 199.04953 9.6792188 198.54 9.4492188 198.25 L 5.4902344 193.34961 C 5.3702344 193.17961 5.1509375 193.10039 4.9609375 193.15039 z M 17.150391 193.58008 L 17.130859 193.58984 C 16.580859 193.56984 15.810469 193.61914 14.730469 193.61914 L 7.0996094 193.61914 L 9.4199219 196.46094 L 9.4492188 196.51953 L 14.699219 196.51953 C 15.106887 196.51953 15.397075 196.78718 15.414062 197.20508 C 15.738375 197.09913 16.077769 197.02734 16.435547 197.02734 L 16.578125 197.02734 C 17.24903 197.02734 17.874081 197.23259 18.400391 197.57812 L 18.400391 197.24023 C 18.400391 194.09023 18.800391 193.62008 17.150391 193.58008 z M 16.435547 198.02734 C 15.143818 198.02734 14.083984 199.08518 14.083984 200.37695 L 14.083984 201.60742 L 13.570312 201.60742 C 13.375448 201.60742 13.210603 201.70409 13.119141 201.79102 C 13.027691 201.87792 12.983569 201.95823 12.951172 202.03125 C 12.886382 202.17727 12.867187 202.30479 12.867188 202.44141 L 12.867188 203.52344 L 12.867188 204.11914 L 12.867188 205.67773 L 12.867188 206.50977 L 13.570312 206.50977 L 19.472656 206.50977 L 20.173828 206.50977 L 20.173828 205.67773 L 20.173828 203.52344 L 20.173828 202.44141 C 20.173828 202.3048 20.156597 202.17728 20.091797 202.03125 C 20.059397 201.95825 20.015299 201.87792 19.923828 201.79102 C 19.832368 201.70412 19.667509 201.60742 19.472656 201.60742 L 18.927734 201.60742 L 18.927734 200.37695 C 18.927734 199.08518 17.867902 198.02734 16.576172 198.02734 L 16.435547 198.02734 z M 16.435547 199.2207 L 16.576172 199.2207 C 17.22782 199.2207 17.734375 199.7251 17.734375 200.37695 L 17.734375 201.60742 L 15.277344 201.60742 L 15.277344 200.37695 C 15.277344 199.7251 15.7839 199.2207 16.435547 199.2207 z M 12.919922 199.93945 C 12.559922 199.95945 12.359141 200.48023 12.619141 200.74023 L 12.751953 200.9043 C 12.862211 200.87013 12.980058 200.84224 13.085938 200.80273 L 13.085938 200.37891 C 13.085938 200.22863 13.111295 200.08474 13.130859 199.93945 L 12.919922 199.93945 z M 19.882812 199.93945 C 19.902378 200.08474 19.927734 200.22863 19.927734 200.37891 L 19.927734 200.79102 C 20.168811 200.87511 20.455966 200.91694 20.613281 201.06641 C 20.691227 201.14046 20.749315 201.22305 20.806641 201.30273 L 21.259766 200.74023 C 21.519766 200.46023 21.260625 199.90945 20.890625 199.93945 L 19.882812 199.93945 z M 16.435547 200.2207 C 16.301234 200.2207 16.277344 200.24444 16.277344 200.37891 L 16.277344 200.60742 L 16.734375 200.60742 L 16.734375 200.37891 C 16.734375 200.24441 16.712442 200.2207 16.578125 200.2207 L 16.435547 200.2207 z ' fill='#{hex-color($highlight-text-color)}' stroke-width='0' /></svg>");
}
}
&.disabled {
i.fa-retweet,
&:hover i.fa-retweet {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' height='209' width='22'><path d='M 18.972656 1.2011719 C 18.829825 1.1881782 18.685932 1.2302188 18.572266 1.3300781 L 15.990234 3.5996094 C 15.58109 3.6070661 15.297269 3.609375 14.730469 3.609375 L 7.0996094 3.609375 L 9.4199219 6.4609375 L 9.4492188 6.5195312 L 12.664062 6.5195312 L 6.5761719 11.867188 C 6.5674697 11.818249 6.5507813 11.773891 6.5507812 11.720703 L 6.5507812 9.0195312 L 9.0507812 9.0195312 C 9.4207813 9.0495313 9.6792188 8.54 9.4492188 8.25 L 5.5 3.3496094 C 5.38 3.1796094 5.1607031 3.1003906 4.9707031 3.1503906 L 4.9707031 3.1601562 C 4.8707031 3.1901563 4.8 3.2598438 4.75 3.3398438 L 0.80078125 8.2402344 C 0.60078125 8.5402344 0.8292187 9.0190625 1.1992188 9.0390625 L 3.5996094 9.0390625 L 3.5996094 11.720703 C 3.5996094 13.045739 3.5690668 13.895038 3.6503906 14.4375 L 2.6152344 15.347656 C 2.3879011 15.547375 2.3754917 15.901081 2.5859375 16.140625 L 3.1464844 16.78125 C 3.3569308 17.020794 3.7101667 17.053234 3.9375 16.853516 L 19.892578 2.8359375 C 20.119911 2.6362188 20.134275 2.282513 19.923828 2.0429688 L 19.361328 1.4023438 C 19.256105 1.282572 19.115488 1.2141655 18.972656 1.2011719 z M 18.410156 6.7753906 L 15.419922 9.4042969 L 15.419922 9.9394531 L 14.810547 9.9394531 L 13.148438 11.400391 L 16.539062 15.640625 C 16.719062 15.890625 17.140313 15.890625 17.320312 15.640625 L 21.259766 10.740234 C 21.519766 10.460234 21.260625 9.9094531 20.890625 9.9394531 L 18.400391 9.9394531 L 18.400391 7.2402344 C 18.400391 7.0470074 18.407711 6.9489682 18.410156 6.7753906 z M 11.966797 12.439453 L 8.6679688 15.339844 L 14.919922 15.339844 L 12.619141 12.5 C 12.589141 12.48 12.590313 12.459453 12.570312 12.439453 L 11.966797 12.439453 z' fill='#{hex-color(darken($action-button-color, 13%))}' stroke-width='0'/></svg>");
}
}
.media-modal__overlay .picture-in-picture__footer & {
i.fa-retweet {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='22' height='209'><path d='M4.97 3.16c-.1.03-.17.1-.22.18L.8 8.24c-.2.3.03.78.4.8H3.6v2.68c0 4.26-.55 3.62 3.66 3.62h7.66l-2.3-2.84c-.03-.02-.03-.04-.05-.06H7.27c-.44 0-.72-.3-.72-.72v-2.7h2.5c.37.03.63-.48.4-.77L5.5 3.35c-.12-.17-.34-.25-.53-.2zm12.16.43c-.55-.02-1.32.02-2.4.02H7.1l2.32 2.85.03.06h5.25c.42 0 .72.28.72.72v2.7h-2.5c-.36.02-.56.54-.3.8l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.26-.28 0-.83-.37-.8H18.4v-2.7c0-3.15.4-3.62-1.25-3.66z' fill='#{hex-color($white)}' stroke-width='0'/><path d='M7.78 19.66c-.24.02-.44.25-.44.5v2.46h-.06c-1.08 0-1.86-.03-2.4-.03-1.64 0-1.25.43-1.25 3.65v4.47c0 4.26-.56 3.62 3.65 3.62H8.5l-1.3-1.06c-.1-.08-.18-.2-.2-.3-.02-.17.06-.35.2-.45l1.33-1.1H7.28c-.44 0-.72-.3-.72-.7v-4.48c0-.44.28-.72.72-.72h.06v2.5c0 .38.54.63.82.38l4.9-3.93c.25-.18.25-.6 0-.78l-4.9-3.92c-.1-.1-.24-.14-.38-.12zm9.34 2.93c-.54-.02-1.3.02-2.4.02h-1.25l1.3 1.07c.1.07.18.2.2.33.02.16-.06.3-.2.4l-1.33 1.1h1.28c.42 0 .72.28.72.72v4.47c0 .42-.3.72-.72.72h-.1v-2.47c0-.3-.3-.53-.6-.47-.07 0-.14.05-.2.1l-4.9 3.93c-.26.18-.26.6 0 .78l4.9 3.92c.27.25.82 0 .8-.38v-2.5h.1c4.27 0 3.65.67 3.65-3.62v-4.47c0-3.15.4-3.62-1.25-3.66zM10.34 38.66c-.24.02-.44.25-.43.5v2.47H7.3c-1.08 0-1.86-.04-2.4-.04-1.64 0-1.25.43-1.25 3.65v4.47c0 3.66-.23 3.7 2.34 3.66l-1.34-1.1c-.1-.08-.18-.2-.2-.3 0-.17.07-.35.2-.45l1.96-1.6c-.03-.06-.04-.13-.04-.2v-4.48c0-.44.28-.72.72-.72H9.9v2.5c0 .36.5.6.8.38l4.93-3.93c.24-.18.24-.6 0-.78l-4.94-3.92c-.1-.08-.23-.13-.36-.12zm5.63 2.93l1.34 1.1c.1.07.18.2.2.33.02.16-.03.3-.16.4l-1.96 1.6c.02.07.06.13.06.22v4.47c0 .42-.3.72-.72.72h-2.66v-2.47c0-.3-.3-.53-.6-.47-.06.02-.12.05-.18.1l-4.94 3.93c-.24.18-.24.6 0 .78l4.94 3.92c.28.22.78-.02.78-.38v-2.5h2.66c4.27 0 3.65.67 3.65-3.62v-4.47c0-3.66.34-3.7-2.4-3.66zM13.06 57.66c-.23.03-.4.26-.4.5v2.47H7.28c-1.08 0-1.86-.04-2.4-.04-1.64 0-1.25.43-1.25 3.65v4.87l2.93-2.37v-2.5c0-.44.28-.72.72-.72h5.38v2.5c0 .36.5.6.78.38l4.94-3.93c.24-.18.24-.6 0-.78l-4.94-3.92c-.1-.1-.24-.14-.38-.12zm5.3 6.15l-2.92 2.4v2.52c0 .42-.3.72-.72.72h-5.4v-2.47c0-.3-.32-.53-.6-.47-.07.02-.13.05-.2.1L3.6 70.52c-.25.18-.25.6 0 .78l4.93 3.92c.28.22.78-.02.78-.38v-2.5h5.42c4.27 0 3.65.67 3.65-3.62v-4.47-.44zM19.25 78.8c-.1.03-.2.1-.28.17l-.9.9c-.44-.3-1.36-.25-3.35-.25H7.28c-1.08 0-1.86-.03-2.4-.03-1.64 0-1.25.43-1.25 3.65v.7l2.93.3v-1c0-.44.28-.72.72-.72h7.44c.2 0 .37.08.5.2l-1.8 1.8c-.25.26-.08.76.27.8l6.27.7c.28.03.56-.25.53-.53l-.7-6.25c0-.27-.3-.48-.55-.44zm-17.2 6.1c-.2.07-.36.3-.33.54l.7 6.25c.02.36.58.55.83.27l.8-.8c.02 0 .04-.02.04 0 .46.24 1.37.17 3.18.17h7.44c4.27 0 3.65.67 3.65-3.62v-.75l-2.93-.3v1.05c0 .42-.3.72-.72.72H7.28c-.15 0-.3-.03-.4-.1L8.8 86.4c.3-.24.1-.8-.27-.84l-6.28-.65h-.2zM4.88 98.6c-1.33 0-1.34.48-1.3 2.3l1.14-1.37c.08-.1.22-.17.34-.2.16 0 .34.08.44.2l1.66 2.03c.04 0 .07-.03.12-.03h7.44c.34 0 .57.2.65.5h-2.43c-.34.05-.53.52-.3.78l3.92 4.95c.18.24.6.24.78 0l3.94-4.94c.22-.27-.02-.76-.37-.77H18.4c.02-3.9.6-3.4-3.66-3.4H7.28c-1.08 0-1.86-.04-2.4-.04zm.15 2.46c-.1.03-.2.1-.28.2l-3.94 4.9c-.2.28.03.77.4.78H3.6c-.02 3.94-.45 3.4 3.66 3.4h7.44c3.65 0 3.74.3 3.7-2.25l-1.1 1.34c-.1.1-.2.17-.32.2-.16 0-.34-.08-.44-.2l-1.65-2.03c-.06.02-.1.04-.18.04H7.28c-.35 0-.57-.2-.66-.5h2.44c.37 0 .63-.5.4-.78l-3.96-4.9c-.1-.15-.3-.23-.47-.2zM4.88 117.6c-1.16 0-1.3.3-1.3 1.56l1.14-1.38c.08-.1.22-.14.34-.16.16 0 .34.04.44.16l2.22 2.75h7c.42 0 .72.28.72.72v.53h-2.6c-.3.1-.43.54-.2.78l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-.53c0-4.2.72-3.63-3.66-3.63H7.28c-1.08 0-1.86-.03-2.4-.03zm.1 1.74c-.1.03-.17.1-.23.16L.8 124.44c-.2.28.03.77.4.78H3.6v.5c0 4.26-.55 3.62 3.66 3.62h7.44c1.03 0 1.74.02 2.28 0-.16.02-.34-.03-.44-.15l-2.22-2.76H7.28c-.44 0-.72-.3-.72-.72v-.5h2.5c.37.02.63-.5.4-.78L5.5 119.5c-.12-.15-.34-.22-.53-.16zm12.02 10c1.2-.02 1.4-.25 1.4-1.53l-1.1 1.36c-.07.1-.17.17-.3.18zM5.94 136.6l2.37 2.93h6.42c.42 0 .72.28.72.72v1.25h-2.6c-.3.1-.43.54-.2.78l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-1.25c0-4.2.72-3.63-3.66-3.63H7.28c-.6 0-.92-.02-1.34-.03zm-1.72.06c-.4.08-.54.3-.6.75l.6-.74zm.84.93c-.12 0-.24.08-.3.18l-3.95 4.9c-.24.3 0 .83.4.82H3.6v1.22c0 4.26-.55 3.62 3.66 3.62h7.44c.63 0 .97.02 1.4.03l-2.37-2.93H7.28c-.44 0-.72-.3-.72-.72v-1.22h2.5c.4.04.67-.53.4-.8l-3.96-4.92c-.1-.13-.27-.2-.44-.2zm13.28 10.03l-.56.7c.36-.07.5-.3.56-.7zM17.13 155.6c-.55-.02-1.32.03-2.4.03h-8.2l2.38 2.9h5.82c.42 0 .72.28.72.72v1.97H12.9c-.32.06-.48.52-.28.78l3.94 4.94c.2.23.6.22.78-.03l3.94-4.9c.22-.28-.02-.77-.37-.78H18.4v-1.97c0-3.15.4-3.62-1.25-3.66zm-12.1.28c-.1.02-.2.1-.28.18l-3.94 4.9c-.2.3.03.78.4.8H3.6v1.96c0 4.26-.55 3.62 3.66 3.62h8.24l-2.36-2.9H7.28c-.44 0-.72-.3-.72-.72v-1.97h2.5c.37.02.63-.5.4-.78l-3.96-4.9c-.1-.15-.3-.22-.47-.2zM5.13 174.5c-.15 0-.3.07-.38.2L.8 179.6c-.24.27 0 .82.4.8H3.6v2.32c0 4.26-.55 3.62 3.66 3.62h7.94l-2.35-2.9h-5.6c-.43 0-.7-.3-.7-.72v-2.3h2.5c.38.03.66-.54.4-.83l-3.97-4.9c-.1-.13-.23-.2-.38-.2zm12 .1c-.55-.02-1.32.03-2.4.03H6.83l2.35 2.9h5.52c.42 0 .72.28.72.72v2.34h-2.6c-.3.1-.43.53-.2.78l3.92 4.9c.18.24.6.24.78 0l3.94-4.9c.22-.3-.02-.78-.37-.8H18.4v-2.33c0-3.15.4-3.62-1.25-3.66zM4.97 193.16c-.1.03-.17.1-.22.18l-3.94 4.9c-.2.3.03.78.4.8H3.6v2.68c0 4.26-.55 3.62 3.66 3.62h7.66l-2.3-2.84c-.03-.02-.03-.04-.05-.06H7.27c-.44 0-.72-.3-.72-.72v-2.7h2.5c.37.03.63-.48.4-.77l-3.96-4.9c-.12-.17-.34-.25-.53-.2zm12.16.43c-.55-.02-1.32.03-2.4.03H7.1l2.32 2.84.03.06h5.25c.42 0 .72.28.72.72v2.7h-2.5c-.36.02-.56.54-.3.8l3.92 4.9c.18.25.6.25.78 0l3.94-4.9c.26-.28 0-.83-.37-.8H18.4v-2.7c0-3.15.4-3.62-1.25-3.66z' fill='#{hex-color($highlight-text-color)}' stroke-width='0'/></svg>");
}
&.reblogPrivate {
i.fa-retweet {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' height='209' width='22'><path d='M 4.9707031 3.1503906 L 4.9707031 3.1601562 C 4.8707031 3.1901563 4.8 3.2598438 4.75 3.3398438 L 0.80078125 8.2402344 C 0.60078125 8.5402344 0.8292187 9.0190625 1.1992188 9.0390625 L 3.5996094 9.0390625 L 3.5996094 11.720703 C 3.5996094 15.980703 3.0497656 15.339844 7.2597656 15.339844 L 11.869141 15.339844 L 11.869141 14.119141 L 11.869141 13.523438 L 11.869141 12.441406 C 11.869141 12.441406 11.869141 12.439453 11.869141 12.439453 L 7.2695312 12.439453 C 6.8295312 12.439453 6.5507814 12.140703 6.5507812 11.720703 L 6.5507812 9.0195312 L 9.0507812 9.0195312 C 9.4207813 9.0495313 9.6792188 8.54 9.4492188 8.25 L 5.5 3.3496094 C 5.38 3.1796094 5.1607031 3.1003906 4.9707031 3.1503906 z M 17.150391 3.5800781 L 17.130859 3.5898438 C 16.580859 3.5698436 15.810469 3.609375 14.730469 3.609375 L 7.0996094 3.609375 L 9.4199219 6.4609375 L 9.4492188 6.5195312 L 14.699219 6.5195312 C 15.106887 6.5195312 15.397113 6.7872181 15.414062 7.2050781 C 15.738375 7.0991315 16.077769 7.0273437 16.435547 7.0273438 L 16.578125 7.0273438 C 17.24903 7.0273438 17.874081 7.2325787 18.400391 7.578125 L 18.400391 7.2402344 C 18.400391 4.0902344 18.800391 3.6200781 17.150391 3.5800781 z M 16.435547 8.0273438 C 15.143818 8.0273438 14.083984 9.0851838 14.083984 10.376953 L 14.083984 11.607422 L 13.570312 11.607422 C 13.375448 11.607422 13.210603 11.704118 13.119141 11.791016 C 13.027691 11.877916 12.983569 11.958238 12.951172 12.03125 C 12.886382 12.177277 12.867187 12.304789 12.867188 12.441406 L 12.867188 13.523438 L 12.867188 14.119141 L 12.867188 15.677734 L 12.867188 16.509766 L 13.570312 16.509766 L 19.472656 16.509766 L 20.173828 16.509766 L 20.173828 15.677734 L 20.173828 13.523438 L 20.173828 12.441406 C 20.173828 12.304794 20.156597 12.177281 20.091797 12.03125 C 20.059397 11.95824 20.015299 11.877916 19.923828 11.791016 C 19.832368 11.704116 19.667509 11.607422 19.472656 11.607422 L 18.927734 11.607422 L 18.927734 10.376953 C 18.927734 9.0851838 17.867902 8.0273438 16.576172 8.0273438 L 16.435547 8.0273438 z M 16.435547 9.2207031 L 16.576172 9.2207031 C 17.22782 9.2207031 17.734375 9.7251013 17.734375 10.376953 L 17.734375 11.607422 L 15.277344 11.607422 L 15.277344 10.376953 C 15.277344 9.7251013 15.7839 9.2207031 16.435547 9.2207031 z M 12.919922 9.9394531 C 12.559922 9.9594531 12.359141 10.480234 12.619141 10.740234 L 12.751953 10.904297 C 12.862211 10.870135 12.980058 10.842244 13.085938 10.802734 L 13.085938 10.378906 C 13.085938 10.228632 13.111295 10.084741 13.130859 9.9394531 L 12.919922 9.9394531 z M 19.882812 9.9394531 C 19.902378 10.084741 19.927734 10.228632 19.927734 10.378906 L 19.927734 10.791016 C 20.168811 10.875098 20.455966 10.916935 20.613281 11.066406 C 20.691227 11.140457 20.749315 11.223053 20.806641 11.302734 L 21.259766 10.740234 C 21.519766 10.460234 21.260625 9.9094531 20.890625 9.9394531 L 19.882812 9.9394531 z M 16.435547 10.220703 C 16.301234 10.220703 16.277344 10.244432 16.277344 10.378906 L 16.277344 10.607422 L 16.734375 10.607422 L 16.734375 10.378906 C 16.734375 10.244433 16.712442 10.220703 16.578125 10.220703 L 16.435547 10.220703 z ' fill='#{hex-color($white)}' stroke-width='0'/><path d='M 7.7792969 19.650391 L 7.7792969 19.660156 C 7.5392969 19.680156 7.3398437 19.910156 7.3398438 20.160156 L 7.3398438 22.619141 L 7.2792969 22.619141 C 6.1992969 22.619141 5.4208594 22.589844 4.8808594 22.589844 C 3.2408594 22.589844 3.6308594 23.020234 3.6308594 26.240234 L 3.6308594 30.710938 C 3.6308594 34.970937 3.0692969 34.330078 7.2792969 34.330078 L 8.5 34.330078 L 7.1992188 33.269531 C 7.0992188 33.189531 7.02 33.070703 7 32.970703 C 6.98 32.800703 7.0592186 32.619531 7.1992188 32.519531 L 8.5292969 31.419922 L 7.2792969 31.419922 C 6.8392969 31.419922 6.5605469 31.120703 6.5605469 30.720703 L 6.5605469 26.240234 C 6.5605469 25.800234 6.8392969 25.519531 7.2792969 25.519531 L 7.3398438 25.519531 L 7.3398438 28.019531 C 7.3398438 28.399531 7.8801564 28.650391 8.1601562 28.400391 L 13.060547 24.470703 C 13.310547 24.290703 13.310547 23.869453 13.060547 23.689453 L 8.1601562 19.769531 C 8.0601563 19.669531 7.9192969 19.630391 7.7792969 19.650391 z M 17.119141 22.580078 L 17.119141 22.589844 C 16.579141 22.569844 15.820703 22.609375 14.720703 22.609375 L 13.470703 22.609375 L 14.769531 23.679688 C 14.869531 23.749688 14.950703 23.879766 14.970703 24.009766 C 14.990703 24.169766 14.909531 24.310156 14.769531 24.410156 L 13.439453 25.509766 L 14.720703 25.509766 C 15.129702 25.509766 15.41841 25.778986 15.433594 26.199219 C 15.752266 26.097283 16.084896 26.027344 16.435547 26.027344 L 16.578125 26.027344 C 17.236645 26.027344 17.848901 26.228565 18.369141 26.5625 L 18.369141 26.240234 C 18.369141 23.090234 18.769141 22.620078 17.119141 22.580078 z M 16.435547 27.027344 C 15.143818 27.027344 14.083984 28.085184 14.083984 29.376953 L 14.083984 30.607422 L 13.570312 30.607422 C 13.375452 30.607422 13.210603 30.704118 13.119141 30.791016 C 13.027691 30.877916 12.983569 30.958238 12.951172 31.03125 C 12.886382 31.177277 12.867184 31.304789 12.867188 31.441406 L 12.867188 32.523438 L 12.867188 33.119141 L 12.867188 34.677734 L 12.867188 35.509766 L 13.570312 35.509766 L 19.472656 35.509766 L 20.173828 35.509766 L 20.173828 34.677734 L 20.173828 32.523438 L 20.173828 31.441406 C 20.173828 31.304794 20.156597 31.177281 20.091797 31.03125 C 20.059397 30.95824 20.015299 30.877916 19.923828 30.791016 C 19.832368 30.704116 19.667509 30.607422 19.472656 30.607422 L 18.927734 30.607422 L 18.927734 29.376953 C 18.927734 28.085184 17.867902 27.027344 16.576172 27.027344 L 16.435547 27.027344 z M 16.435547 28.220703 L 16.576172 28.220703 C 17.22782 28.220703 17.734375 28.725101 17.734375 29.376953 L 17.734375 30.607422 L 15.277344 30.607422 L 15.277344 29.376953 C 15.277344 28.725101 15.7839 28.220703 16.435547 28.220703 z M 13.109375 29.150391 L 8.9199219 32.509766 C 8.6599219 32.689766 8.6599219 33.109063 8.9199219 33.289062 L 11.869141 35.648438 L 11.869141 34.677734 L 11.869141 33.119141 L 11.869141 32.523438 L 11.869141 31.441406 C 11.869141 31.217489 11.912641 30.907486 12.037109 30.626953 C 12.093758 30.499284 12.228597 30.257492 12.429688 30.066406 C 12.580253 29.92335 12.859197 29.887344 13.085938 29.802734 L 13.085938 29.378906 C 13.085938 29.300761 13.104 29.227272 13.109375 29.150391 z M 16.435547 29.220703 C 16.301234 29.220703 16.277344 29.244432 16.277344 29.378906 L 16.277344 29.607422 L 16.734375 29.607422 L 16.734375 29.378906 C 16.734375 29.244433 16.712442 29.220703 16.578125 29.220703 L 16.435547 29.220703 z M 12.943359 36.509766 L 13.820312 37.210938 C 14.090314 37.460938 14.639141 37.210078 14.619141 36.830078 L 14.619141 36.509766 L 13.570312 36.509766 L 12.943359 36.509766 z M 10.330078 38.650391 L 10.339844 38.660156 C 10.099844 38.680156 9.9001562 38.910156 9.9101562 39.160156 L 9.9101562 41.630859 L 7.3007812 41.630859 C 6.2207812 41.630859 5.4403906 41.589844 4.9003906 41.589844 C 3.2603906 41.589844 3.6503906 42.020234 3.6503906 45.240234 L 3.6503906 49.710938 C 3.6503906 53.370936 3.4202344 53.409141 5.9902344 53.369141 L 4.6503906 52.269531 C 4.5503906 52.189531 4.4692187 52.070703 4.4492188 51.970703 C 4.4492188 51.800703 4.5203906 51.619531 4.6503906 51.519531 L 6.609375 49.919922 C 6.579375 49.859922 6.5703125 49.790703 6.5703125 49.720703 L 6.5703125 45.240234 C 6.5703125 44.800234 6.8490625 44.519531 7.2890625 44.519531 L 9.9003906 44.519531 L 9.9003906 47.019531 C 9.9003906 47.379531 10.399219 47.620391 10.699219 47.400391 L 15.630859 43.470703 C 15.870859 43.290703 15.870859 42.869453 15.630859 42.689453 L 10.689453 38.769531 C 10.589453 38.689531 10.460078 38.640391 10.330078 38.650391 z M 16.869141 41.585938 C 16.616211 41.581522 16.322969 41.584844 15.980469 41.589844 L 15.970703 41.589844 L 17.310547 42.689453 C 17.410547 42.759453 17.489766 42.889531 17.509766 43.019531 C 17.529766 43.179531 17.479609 43.319922 17.349609 43.419922 L 15.390625 45.019531 C 15.406724 45.075878 15.427133 45.132837 15.4375 45.197266 C 15.754974 45.096169 16.086404 45.027344 16.435547 45.027344 L 16.578125 45.027344 C 17.24129 45.027344 17.858323 45.230088 18.380859 45.568359 L 18.380859 45.25 C 18.380859 42.0475 18.639648 41.616836 16.869141 41.585938 z M 16.435547 46.027344 C 15.143818 46.027344 14.083984 47.085184 14.083984 48.376953 L 14.083984 49.607422 L 13.570312 49.607422 C 13.375448 49.607422 13.210603 49.704118 13.119141 49.791016 C 13.027691 49.877916 12.983569 49.958238 12.951172 50.03125 C 12.886382 50.177277 12.867187 50.304789 12.867188 50.441406 L 12.867188 51.523438 L 12.867188 52.119141 L 12.867188 53.677734 L 12.867188 54.509766 L 13.570312 54.509766 L 19.472656 54.509766 L 20.173828 54.509766 L 20.173828 53.677734 L 20.173828 51.523438 L 20.173828 50.441406 C 20.173828 50.304794 20.156597 50.177281 20.091797 50.03125 C 20.059397 49.95824 20.015299 49.877916 19.923828 49.791016 C 19.832368 49.704116 19.667509 49.607422 19.472656 49.607422 L 18.927734 49.607422 L 18.927734 48.376953 C 18.927734 47.085184 17.867902 46.027344 16.576172 46.027344 L 16.435547 46.027344 z M 16.435547 47.220703 L 16.576172 47.220703 C 17.22782 47.220703 17.734375 47.725101 17.734375 48.376953 L 17.734375 49.607422 L 15.277344 49.607422 L 15.277344 48.376953 C 15.277344 47.725101 15.7839 47.220703 16.435547 47.220703 z M 11.470703 47.490234 C 11.410703 47.510234 11.349063 47.539844 11.289062 47.589844 L 6.3496094 51.519531 C 6.1096094 51.699531 6.1096094 52.120781 6.3496094 52.300781 L 11.289062 56.220703 C 11.569064 56.440703 12.070312 56.199844 12.070312 55.839844 L 12.070312 55.509766 L 11.869141 55.509766 L 11.869141 53.677734 L 11.869141 52.119141 L 11.869141 51.523438 L 11.869141 50.441406 C 11.869141 50.217489 11.912641 49.907486 12.037109 49.626953 C 12.043809 49.611855 12.061451 49.584424 12.070312 49.566406 L 12.070312 47.960938 C 12.070312 47.660938 11.770703 47.430234 11.470703 47.490234 z M 16.435547 48.220703 C 16.301234 48.220703 16.277344 48.244432 16.277344 48.378906 L 16.277344 48.607422 L 16.734375 48.607422 L 16.734375 48.378906 C 16.734375 48.244433 16.712442 48.220703 16.578125 48.220703 L 16.435547 48.220703 z M 13.060547 57.650391 L 13.060547 57.660156 C 12.830547 57.690156 12.660156 57.920156 12.660156 58.160156 L 12.660156 60.630859 L 7.2792969 60.630859 C 6.1992969 60.630859 5.4208594 60.589844 4.8808594 60.589844 C 3.2408594 60.589844 3.6308594 61.020234 3.6308594 64.240234 L 3.6308594 69.109375 L 6.5605469 66.740234 L 6.5605469 64.240234 C 6.5605469 63.800234 6.8392969 63.519531 7.2792969 63.519531 L 12.660156 63.519531 L 12.660156 66.019531 C 12.660156 66.299799 12.960394 66.500006 13.226562 66.474609 C 13.625751 65.076914 14.904956 64.035678 16.421875 64.029297 L 18.380859 62.470703 C 18.620859 62.290703 18.620859 61.869453 18.380859 61.689453 L 13.439453 57.769531 C 13.339453 57.669531 13.200547 57.630391 13.060547 57.650391 z M 18.359375 63.810547 L 17.800781 64.269531 C 18.004793 64.350836 18.198411 64.450249 18.380859 64.568359 L 18.380859 64.25 L 18.380859 63.810547 L 18.359375 63.810547 z M 16.435547 65.027344 C 15.143818 65.027344 14.083984 66.085184 14.083984 67.376953 L 14.083984 68.607422 L 13.570312 68.607422 C 13.375448 68.607422 13.210603 68.704118 13.119141 68.791016 C 13.027691 68.877916 12.983569 68.958238 12.951172 69.03125 C 12.886382 69.177277 12.867187 69.304789 12.867188 69.441406 L 12.867188 70.523438 L 12.867188 71.119141 L 12.867188 72.677734 L 12.867188 73.509766 L 13.570312 73.509766 L 19.472656 73.509766 L 20.173828 73.509766 L 20.173828 72.677734 L 20.173828 70.523438 L 20.173828 69.441406 C 20.173828 69.304794 20.156597 69.177281 20.091797 69.03125 C 20.059397 68.95824 20.015299 68.877916 19.923828 68.791016 C 19.832368 68.704116 19.667509 68.607422 19.472656 68.607422 L 18.927734 68.607422 L 18.927734 67.376953 C 18.927734 66.085184 17.867902 65.027344 16.576172 65.027344 L 16.435547 65.027344 z M 16.435547 66.220703 L 16.576172 66.220703 C 17.22782 66.220703 17.734375 66.725101 17.734375 67.376953 L 17.734375 68.607422 L 15.277344 68.607422 L 15.277344 67.376953 C 15.277344 66.725101 15.7839 66.220703 16.435547 66.220703 z M 8.7207031 66.509766 C 8.6507031 66.529766 8.5895312 66.559375 8.5195312 66.609375 L 3.5996094 70.519531 C 3.3496094 70.699531 3.3496094 71.120781 3.5996094 71.300781 L 8.5292969 75.220703 C 8.8092969 75.440703 9.3105469 75.199844 9.3105469 74.839844 L 9.3105469 72.339844 L 11.869141 72.339844 L 11.869141 71.119141 L 11.869141 70.523438 L 11.869141 69.449219 L 9.3203125 69.449219 L 9.3203125 66.980469 C 9.3203125 66.680469 9.0007031 66.449766 8.7207031 66.509766 z M 16.435547 67.220703 C 16.301234 67.220703 16.277344 67.244432 16.277344 67.378906 L 16.277344 67.607422 L 16.734375 67.607422 L 16.734375 67.378906 C 16.734375 67.244433 16.712442 67.220703 16.578125 67.220703 L 16.435547 67.220703 z M 19.248047 78.800781 C 19.148558 78.831033 19.050295 78.90106 18.970703 78.970703 L 18.070312 79.869141 C 17.630312 79.569141 16.710703 79.619141 14.720703 79.619141 L 7.2792969 79.619141 C 6.1992969 79.619141 5.4208594 79.589844 4.8808594 79.589844 C 3.2408594 79.589844 3.6308594 80.020234 3.6308594 83.240234 L 3.6308594 83.939453 L 6.5605469 84.240234 L 6.5605469 83.240234 C 6.5605469 82.800234 6.8392969 82.519531 7.2792969 82.519531 L 14.720703 82.519531 C 14.920703 82.519531 15.090703 82.600703 15.220703 82.720703 L 13.419922 84.519531 C 13.279464 84.665607 13.281282 84.881022 13.363281 85.054688 C 13.880838 83.867655 15.067337 83.027344 16.435547 83.027344 L 16.578125 83.027344 C 18.290465 83.027344 19.703357 84.345788 19.890625 86.011719 L 19.960938 86.019531 C 20.240938 86.049531 20.520234 85.770234 20.490234 85.490234 L 19.789062 79.240234 C 19.789062 78.973661 19.498025 78.767523 19.25 78.800781 L 19.248047 78.800781 z M 16.435547 84.027344 C 15.143818 84.027344 14.083984 85.085184 14.083984 86.376953 L 14.083984 87.607422 L 13.570312 87.607422 C 13.375448 87.607422 13.210603 87.704118 13.119141 87.791016 C 13.027691 87.877916 12.983569 87.958238 12.951172 88.03125 C 12.886382 88.177277 12.867187 88.304789 12.867188 88.441406 L 12.867188 89.523438 L 12.867188 90.119141 L 12.867188 91.677734 L 12.867188 92.509766 L 13.570312 92.509766 L 19.472656 92.509766 L 20.173828 92.509766 L 20.173828 91.677734 L 20.173828 89.523438 L 20.173828 88.441406 C 20.173828 88.304794 20.156597 88.177281 20.091797 88.03125 C 20.059397 87.95824 20.015299 87.877916 19.923828 87.791016 C 19.832368 87.704116 19.667509 87.607422 19.472656 87.607422 L 18.927734 87.607422 L 18.927734 86.376953 C 18.927734 85.085184 17.867902 84.027344 16.576172 84.027344 L 16.435547 84.027344 z M 2.0507812 84.900391 C 1.8507824 84.970391 1.6907031 85.199453 1.7207031 85.439453 L 2.4199219 91.689453 C 2.4399219 92.049453 3 92.240929 3.25 91.960938 L 4.0507812 91.160156 C 4.0707812 91.160156 4.0898437 91.140156 4.0898438 91.160156 C 4.5498437 91.400156 5.4595313 91.330078 7.2695312 91.330078 L 11.869141 91.330078 L 11.869141 90.119141 L 11.869141 89.523438 L 11.869141 88.441406 C 11.869141 88.437991 11.871073 88.433136 11.871094 88.429688 L 7.2792969 88.429688 C 7.1292969 88.429688 6.9808594 88.400078 6.8808594 88.330078 L 8.8007812 86.400391 C 9.1007822 86.160391 8.8992969 85.600547 8.5292969 85.560547 L 2.25 84.910156 L 2.0507812 84.910156 L 2.0507812 84.900391 z M 16.435547 85.220703 L 16.576172 85.220703 C 17.22782 85.220703 17.734375 85.725101 17.734375 86.376953 L 17.734375 87.607422 L 15.277344 87.607422 L 15.277344 86.376953 C 15.277344 85.725101 15.7839 85.220703 16.435547 85.220703 z M 4.8808594 98.599609 C 3.5508594 98.599609 3.5400781 99.080402 3.5800781 100.90039 L 4.7207031 99.529297 C 4.8007031 99.429297 4.9405469 99.360078 5.0605469 99.330078 C 5.2205469 99.330078 5.4 99.409297 5.5 99.529297 L 7.1601562 101.56055 C 7.2001563 101.56055 7.2292969 101.5293 7.2792969 101.5293 L 14.720703 101.5293 C 15.060703 101.5293 15.289141 101.7293 15.369141 102.0293 L 12.939453 102.0293 C 12.599453 102.0793 12.410625 102.55055 12.640625 102.81055 L 13.470703 103.85742 C 14.029941 102.77899 15.146801 102.02734 16.435547 102.02734 L 16.578125 102.02734 C 18.158418 102.02734 19.491598 103.14879 19.835938 104.63086 L 21.279297 102.82031 C 21.499297 102.55031 21.260156 102.06078 20.910156 102.05078 L 18.400391 102.05078 C 18.420391 98.150792 19.000234 98.650391 14.740234 98.650391 L 7.2792969 98.650391 C 6.1992969 98.650391 5.4208594 98.609375 4.8808594 98.609375 L 4.8808594 98.599609 z M 5.0292969 101.06055 C 4.9292969 101.09055 4.83 101.15977 4.75 101.25977 L 0.81054688 106.16016 C 0.61054688 106.44016 0.8409375 106.92945 1.2109375 106.93945 L 3.5996094 106.93945 C 3.5796094 110.87945 3.1497656 110.33984 7.2597656 110.33984 L 11.869141 110.33984 L 11.869141 109.11914 L 11.869141 108.52344 L 11.869141 107.44141 L 11.869141 107.43945 L 7.2792969 107.43945 C 6.9292969 107.43945 6.7091406 107.23945 6.6191406 106.93945 L 9.0605469 106.93945 C 9.4305469 106.93945 9.6909375 106.44016 9.4609375 106.16016 L 5.5 101.25977 C 5.4 101.10977 5.1992969 101.03055 5.0292969 101.06055 z M 16.435547 103.02734 C 15.143818 103.02734 14.083984 104.08518 14.083984 105.37695 L 14.083984 106.60742 L 13.570312 106.60742 C 13.375448 106.60742 13.210603 106.70409 13.119141 106.79102 C 13.027691 106.87792 12.983569 106.95823 12.951172 107.03125 C 12.886382 107.17727 12.867187 107.30479 12.867188 107.44141 L 12.867188 108.52344 L 12.867188 109.11914 L 12.867188 110.67773 L 12.867188 111.50977 L 13.570312 111.50977 L 19.472656 111.50977 L 20.173828 111.50977 L 20.173828 110.67773 L 20.173828 108.52344 L 20.173828 107.44141 C 20.173828 107.3048 20.156597 107.17728 20.091797 107.03125 C 20.059397 106.95825 20.015299 106.87792 19.923828 106.79102 C 19.832368 106.70412 19.667509 106.60742 19.472656 106.60742 L 18.927734 106.60742 L 18.927734 105.37695 C 18.927734 104.08518 17.867902 103.02734 16.576172 103.02734 L 16.435547 103.02734 z M 16.435547 104.2207 L 16.576172 104.2207 C 17.22782 104.2207 17.734375 104.7251 17.734375 105.37695 L 17.734375 106.60742 L 15.277344 106.60742 L 15.277344 105.37695 C 15.277344 104.7251 15.7839 104.2207 16.435547 104.2207 z M 16.435547 105.2207 C 16.301234 105.2207 16.277344 105.24444 16.277344 105.37891 L 16.277344 105.60742 L 16.734375 105.60742 L 16.734375 105.37891 C 16.734375 105.24441 16.712442 105.2207 16.578125 105.2207 L 16.435547 105.2207 z M 4.8808594 117.58984 L 4.8808594 117.59961 C 3.7208594 117.59961 3.5800781 117.90016 3.5800781 119.16016 L 4.7207031 117.7793 C 4.8007031 117.6793 4.9405469 117.63914 5.0605469 117.61914 C 5.2205469 117.61914 5.4 117.6593 5.5 117.7793 L 7.7207031 120.5293 L 14.720703 120.5293 C 15.123595 120.5293 15.408576 120.79174 15.431641 121.20117 C 15.750992 121.09876 16.08404 121.02734 16.435547 121.02734 L 16.578125 121.02734 C 17.24903 121.02734 17.874081 121.23262 18.400391 121.57812 L 18.400391 121.25 C 18.400391 117.05 19.120234 117.61914 14.740234 117.61914 L 7.2792969 117.61914 C 6.1992969 117.61914 5.4208594 117.58984 4.8808594 117.58984 z M 4.9804688 119.33984 C 4.8804688 119.36984 4.81 119.44 4.75 119.5 L 0.80078125 124.43945 C 0.60078125 124.71945 0.8292182 125.2107 1.1992188 125.2207 L 3.5996094 125.2207 L 3.5996094 125.7207 C 3.5996094 129.9807 3.0497656 129.33984 7.2597656 129.33984 L 11.869141 129.33984 L 11.869141 128.11914 L 11.869141 127.52344 L 11.869141 126.44141 C 11.869141 126.43799 11.871073 126.43314 11.871094 126.42969 L 7.2792969 126.42969 C 6.8392969 126.42969 6.5605469 126.13094 6.5605469 125.71094 L 6.5605469 125.21094 L 9.0605469 125.21094 C 9.4305469 125.23094 9.6909375 124.70969 9.4609375 124.42969 L 5.5 119.5 C 5.3820133 119.35252 5.1682348 119.28513 4.9804688 119.33984 z M 12.839844 121.7793 C 12.539844 121.8793 12.410625 122.32055 12.640625 122.56055 L 13.267578 123.34375 C 13.473522 122.72168 13.852237 122.1828 14.353516 121.7793 L 12.839844 121.7793 z M 18.658203 121.7793 C 19.393958 122.37155 19.878978 123.25738 19.916016 124.25781 L 21.279297 122.56055 C 21.499297 122.28055 21.260156 121.7893 20.910156 121.7793 L 18.658203 121.7793 z M 16.435547 122.02734 C 15.143818 122.02734 14.083984 123.08518 14.083984 124.37695 L 14.083984 125.60742 L 13.570312 125.60742 C 13.375448 125.60742 13.210603 125.70409 13.119141 125.79102 C 13.027691 125.87792 12.983569 125.95823 12.951172 126.03125 C 12.886382 126.17727 12.867187 126.30479 12.867188 126.44141 L 12.867188 127.52344 L 12.867188 128.11914 L 12.867188 129.67773 L 12.867188 130.50977 L 13.570312 130.50977 L 19.472656 130.50977 L 20.173828 130.50977 L 20.173828 129.67773 L 20.173828 127.52344 L 20.173828 126.44141 C 20.173828 126.3048 20.156597 126.17728 20.091797 126.03125 C 20.059397 125.95825 20.015299 125.87792 19.923828 125.79102 C 19.832368 125.70412 19.667509 125.60742 19.472656 125.60742 L 18.927734 125.60742 L 18.927734 124.37695 C 18.927734 123.08518 17.867902 122.02734 16.576172 122.02734 L 16.435547 122.02734 z M 16.435547 123.2207 L 16.576172 123.2207 C 17.22782 123.2207 17.734375 123.7251 17.734375 124.37695 L 17.734375 125.60742 L 15.277344 125.60742 L 15.277344 124.37695 C 15.277344 123.7251 15.7839 123.2207 16.435547 123.2207 z M 16.435547 124.2207 C 16.301234 124.2207 16.277344 124.24444 16.277344 124.37891 L 16.277344 124.60742 L 16.734375 124.60742 L 16.734375 124.37891 C 16.734375 124.24441 16.712442 124.2207 16.578125 124.2207 L 16.435547 124.2207 z M 5.9394531 136.58984 L 5.9394531 136.59961 L 8.3105469 139.5293 L 14.730469 139.5293 C 15.131912 139.5293 15.414551 139.79039 15.439453 140.19727 C 15.756409 140.09653 16.087055 140.02734 16.435547 140.02734 L 16.578125 140.02734 C 17.24903 140.02734 17.874081 140.23261 18.400391 140.57812 L 18.400391 140.25 C 18.400391 136.05 19.120234 136.61914 14.740234 136.61914 L 7.2792969 136.61914 C 6.6792969 136.61914 6.3594531 136.59984 5.9394531 136.58984 z M 4.2207031 136.66016 C 3.8207031 136.74016 3.6791406 136.96016 3.6191406 137.41016 L 4.2207031 136.66992 L 4.2207031 136.66016 z M 5.0605469 137.57031 L 5.0605469 137.58984 C 4.9405469 137.58984 4.8197656 137.66953 4.7597656 137.76953 L 0.81054688 142.66992 C 0.57054688 142.96992 0.8109375 143.50023 1.2109375 143.49023 L 3.5996094 143.49023 L 3.5996094 144.71094 C 3.5996094 148.97094 3.0497656 148.33008 7.2597656 148.33008 L 11.869141 148.33008 L 11.869141 147.11914 L 11.869141 146.52344 L 11.869141 145.44141 C 11.869141 145.43799 11.871073 145.43314 11.871094 145.42969 L 7.2792969 145.42969 C 6.8392969 145.42969 6.5605469 145.13094 6.5605469 144.71094 L 6.5605469 143.49023 L 9.0605469 143.49023 C 9.4605469 143.53023 9.7309375 142.95945 9.4609375 142.68945 L 5.5 137.76953 C 5.4 137.63953 5.2305469 137.57031 5.0605469 137.57031 z M 16.435547 141.02734 C 15.143818 141.02734 14.083984 142.08518 14.083984 143.37695 L 14.083984 144.60742 L 13.570312 144.60742 C 13.375448 144.60742 13.210603 144.70409 13.119141 144.79102 C 13.027691 144.87792 12.983569 144.95823 12.951172 145.03125 C 12.886382 145.17727 12.867187 145.30479 12.867188 145.44141 L 12.867188 146.52344 L 12.867188 147.11914 L 12.867188 148.67773 L 12.867188 149.50977 L 13.570312 149.50977 L 19.472656 149.50977 L 20.173828 149.50977 L 20.173828 148.67773 L 20.173828 146.52344 L 20.173828 145.44141 C 20.173828 145.3048 20.156597 145.17728 20.091797 145.03125 C 20.059397 144.95825 20.015299 144.87792 19.923828 144.79102 C 19.832368 144.70412 19.667509 144.60742 19.472656 144.60742 L 18.927734 144.60742 L 18.927734 143.37695 C 18.927734 142.08518 17.867902 141.02734 16.576172 141.02734 L 16.435547 141.02734 z M 12.849609 141.5 C 12.549609 141.6 12.420391 142.0393 12.650391 142.2793 L 13.136719 142.88672 C 13.213026 142.38119 13.390056 141.90696 13.667969 141.5 L 12.849609 141.5 z M 19.34375 141.5 C 19.710704 142.03735 19.927734 142.68522 19.927734 143.37891 L 19.927734 143.79102 C 19.965561 143.80421 20.005506 143.81448 20.044922 143.82617 L 21.289062 142.2793 C 21.509062 141.9993 21.269922 141.51 20.919922 141.5 L 19.34375 141.5 z M 16.435547 142.2207 L 16.576172 142.2207 C 17.22782 142.2207 17.734375 142.7251 17.734375 143.37695 L 17.734375 144.60742 L 15.277344 144.60742 L 15.277344 143.37695 C 15.277344 142.7251 15.7839 142.2207 16.435547 142.2207 z M 16.435547 143.2207 C 16.301234 143.2207 16.277344 143.24444 16.277344 143.37891 L 16.277344 143.60742 L 16.734375 143.60742 L 16.734375 143.37891 C 16.734375 143.24441 16.712442 143.2207 16.578125 143.2207 L 16.435547 143.2207 z M 17.130859 155.59961 C 16.580859 155.57961 15.810469 155.63086 14.730469 155.63086 L 6.5292969 155.63086 L 8.9101562 158.5293 L 14.730469 158.5293 C 15.131912 158.5293 15.414551 158.79039 15.439453 159.19727 C 15.756409 159.09653 16.087055 159.02734 16.435547 159.02734 L 16.578125 159.02734 C 17.24903 159.02734 17.874081 159.23261 18.400391 159.57812 L 18.400391 159.25977 C 18.400391 156.10977 18.800391 155.63961 17.150391 155.59961 L 17.130859 155.59961 z M 5.0292969 155.86914 L 5.0292969 155.88086 C 4.9292969 155.90086 4.83 155.98055 4.75 156.06055 L 0.81054688 160.96094 C 0.61054688 161.26094 0.8409375 161.73977 1.2109375 161.75977 L 3.5996094 161.75977 L 3.5996094 163.7207 C 3.5996094 167.9807 3.0497656 167.33984 7.2597656 167.33984 L 11.869141 167.33984 L 11.869141 166.11914 L 11.869141 165.52344 L 11.869141 164.44141 L 11.869141 164.43945 L 7.2792969 164.43945 C 6.8392969 164.43945 6.5605469 164.1407 6.5605469 163.7207 L 6.5605469 161.75 L 9.0605469 161.75 C 9.4305469 161.77 9.6909375 161.2507 9.4609375 160.9707 L 5.5 156.07031 C 5.4 155.92031 5.1992969 155.84914 5.0292969 155.86914 z M 16.435547 160.02734 C 15.143818 160.02734 14.083984 161.08518 14.083984 162.37695 L 14.083984 163.60742 L 13.570312 163.60742 C 13.375448 163.60742 13.210603 163.70409 13.119141 163.79102 C 13.027691 163.87792 12.983569 163.95823 12.951172 164.03125 C 12.886382 164.17727 12.867187 164.30479 12.867188 164.44141 L 12.867188 165.52344 L 12.867188 166.11914 L 12.867188 167.67773 L 12.867188 168.50977 L 13.570312 168.50977 L 19.472656 168.50977 L 20.173828 168.50977 L 20.173828 167.67773 L 20.173828 165.52344 L 20.173828 164.44141 C 20.173828 164.3048 20.156597 164.17728 20.091797 164.03125 C 20.059397 163.95825 20.015299 163.87792 19.923828 163.79102 C 19.832368 163.70412 19.667509 163.60742 19.472656 163.60742 L 18.927734 163.60742 L 18.927734 162.37695 C 18.927734 161.08518 17.867902 160.02734 16.576172 160.02734 L 16.435547 160.02734 z M 12.900391 161.2207 C 12.580391 161.2807 12.419141 161.74 12.619141 162 L 13.085938 162.58594 L 13.085938 162.37891 C 13.085938 161.97087 13.170592 161.58376 13.306641 161.2207 L 12.900391 161.2207 z M 16.435547 161.2207 L 16.576172 161.2207 C 17.22782 161.2207 17.734375 161.7251 17.734375 162.37695 L 17.734375 163.60742 L 15.277344 163.60742 L 15.277344 162.37695 C 15.277344 161.7251 15.7839 161.2207 16.435547 161.2207 z M 19.708984 161.23047 C 19.842743 161.59081 19.927734 161.97449 19.927734 162.37891 L 19.927734 162.79102 C 20.119162 162.85779 20.322917 162.91147 20.484375 163 L 21.279297 162.00977 C 21.499297 161.72977 21.260156 161.24047 20.910156 161.23047 L 19.708984 161.23047 z M 16.435547 162.2207 C 16.301234 162.2207 16.277344 162.24444 16.277344 162.37891 L 16.277344 162.60742 L 16.734375 162.60742 L 16.734375 162.37891 C 16.734375 162.24441 16.712442 162.2207 16.578125 162.2207 L 16.435547 162.2207 z M 5.0996094 174.49023 L 5.1308594 174.5 C 4.9808594 174.5 4.83 174.56922 4.75 174.69922 L 0.80078125 179.59961 C 0.56078125 179.86961 0.7992182 180.42039 1.1992188 180.40039 L 3.5996094 180.40039 L 3.5996094 182.7207 C 3.5996094 186.9807 3.0497656 186.33984 7.2597656 186.33984 L 11.869141 186.33984 L 11.869141 185.11914 L 11.869141 184.52344 L 11.869141 183.44141 L 11.869141 183.43945 L 7.25 183.43945 C 6.82 183.43945 6.5507814 183.1407 6.5507812 182.7207 L 6.5507812 180.41992 L 9.0507812 180.41992 C 9.4307824 180.44992 9.7092187 179.87984 9.4492188 179.58984 L 5.4804688 174.68945 C 5.3804688 174.55945 5.2496094 174.49023 5.0996094 174.49023 z M 17.150391 174.58008 L 17.130859 174.59961 C 16.580859 174.57961 15.810469 174.63086 14.730469 174.63086 L 6.8300781 174.63086 L 9.1796875 177.5293 L 14.699219 177.5293 C 15.104107 177.5293 15.391475 177.79407 15.412109 178.20703 C 15.737096 178.1006 16.076913 178.02734 16.435547 178.02734 L 16.578125 178.02734 C 17.24903 178.02734 17.874081 178.2326 18.400391 178.57812 L 18.400391 178.24023 C 18.400391 175.09023 18.800391 174.62008 17.150391 174.58008 z M 16.435547 179.02734 C 15.143818 179.02734 14.083984 180.08518 14.083984 181.37695 L 14.083984 182.60742 L 13.570312 182.60742 C 13.375448 182.60742 13.210603 182.70409 13.119141 182.79102 C 13.027691 182.87792 12.983569 182.95823 12.951172 183.03125 C 12.886382 183.17727 12.867187 183.30479 12.867188 183.44141 L 12.867188 184.52344 L 12.867188 185.11914 L 12.867188 186.67773 L 12.867188 187.50977 L 13.570312 187.50977 L 19.472656 187.50977 L 20.173828 187.50977 L 20.173828 186.67773 L 20.173828 184.52344 L 20.173828 183.44141 C 20.173828 183.3048 20.156597 183.17728 20.091797 183.03125 C 20.059397 182.95825 20.015299 182.87792 19.923828 182.79102 C 19.832368 182.70412 19.667509 182.60742 19.472656 182.60742 L 18.927734 182.60742 L 18.927734 181.37695 C 18.927734 180.08518 17.867902 179.02734 16.576172 179.02734 L 16.435547 179.02734 z M 16.435547 180.2207 L 16.576172 180.2207 C 17.22782 180.2207 17.734375 180.7251 17.734375 181.37695 L 17.734375 182.60742 L 15.277344 182.60742 L 15.277344 181.37695 C 15.277344 180.7251 15.7839 180.2207 16.435547 180.2207 z M 19.816406 180.57031 C 19.882311 180.83091 19.927734 181.09907 19.927734 181.37891 L 19.927734 181.79102 C 20.168811 181.87511 20.455966 181.91694 20.613281 182.06641 C 20.630645 182.0829 20.639883 182.10199 20.65625 182.11914 L 21.259766 181.36914 C 21.479766 181.06914 21.240625 180.59031 20.890625 180.57031 L 19.816406 180.57031 z M 12.820312 180.58984 C 12.520316 180.68984 12.389141 181.11914 12.619141 181.36914 L 12.990234 181.83203 C 13.022029 181.82207 13.055579 181.81406 13.085938 181.80273 L 13.085938 181.37891 C 13.085938 181.10616 13.128698 180.84442 13.191406 180.58984 L 12.820312 180.58984 z M 16.435547 181.2207 C 16.301234 181.2207 16.277344 181.24444 16.277344 181.37891 L 16.277344 181.60742 L 16.734375 181.60742 L 16.734375 181.37891 C 16.734375 181.24441 16.712442 181.2207 16.578125 181.2207 L 16.435547 181.2207 z M 4.9609375 193.15039 L 4.9707031 193.16016 C 4.8707031 193.19016 4.8 193.25984 4.75 193.33984 L 0.81054688 198.24023 C 0.61054688 198.54023 0.8409375 199.01906 1.2109375 199.03906 L 3.5996094 199.03906 L 3.5996094 201.7207 C 3.5996094 205.9807 3.0497656 205.33984 7.2597656 205.33984 L 11.869141 205.33984 L 11.869141 204.11914 L 11.869141 203.52344 L 11.869141 202.44141 C 11.869141 202.44141 11.869141 202.43945 11.869141 202.43945 L 7.2695312 202.43945 C 6.8295312 202.43945 6.5507814 202.1407 6.5507812 201.7207 L 6.5507812 199.01953 L 9.0507812 199.01953 C 9.4207814 199.04953 9.6792188 198.54 9.4492188 198.25 L 5.4902344 193.34961 C 5.3702344 193.17961 5.1509375 193.10039 4.9609375 193.15039 z M 17.150391 193.58008 L 17.130859 193.58984 C 16.580859 193.56984 15.810469 193.61914 14.730469 193.61914 L 7.0996094 193.61914 L 9.4199219 196.46094 L 9.4492188 196.51953 L 14.699219 196.51953 C 15.106887 196.51953 15.397075 196.78718 15.414062 197.20508 C 15.738375 197.09913 16.077769 197.02734 16.435547 197.02734 L 16.578125 197.02734 C 17.24903 197.02734 17.874081 197.23259 18.400391 197.57812 L 18.400391 197.24023 C 18.400391 194.09023 18.800391 193.62008 17.150391 193.58008 z M 16.435547 198.02734 C 15.143818 198.02734 14.083984 199.08518 14.083984 200.37695 L 14.083984 201.60742 L 13.570312 201.60742 C 13.375448 201.60742 13.210603 201.70409 13.119141 201.79102 C 13.027691 201.87792 12.983569 201.95823 12.951172 202.03125 C 12.886382 202.17727 12.867187 202.30479 12.867188 202.44141 L 12.867188 203.52344 L 12.867188 204.11914 L 12.867188 205.67773 L 12.867188 206.50977 L 13.570312 206.50977 L 19.472656 206.50977 L 20.173828 206.50977 L 20.173828 205.67773 L 20.173828 203.52344 L 20.173828 202.44141 C 20.173828 202.3048 20.156597 202.17728 20.091797 202.03125 C 20.059397 201.95825 20.015299 201.87792 19.923828 201.79102 C 19.832368 201.70412 19.667509 201.60742 19.472656 201.60742 L 18.927734 201.60742 L 18.927734 200.37695 C 18.927734 199.08518 17.867902 198.02734 16.576172 198.02734 L 16.435547 198.02734 z M 16.435547 199.2207 L 16.576172 199.2207 C 17.22782 199.2207 17.734375 199.7251 17.734375 200.37695 L 17.734375 201.60742 L 15.277344 201.60742 L 15.277344 200.37695 C 15.277344 199.7251 15.7839 199.2207 16.435547 199.2207 z M 12.919922 199.93945 C 12.559922 199.95945 12.359141 200.48023 12.619141 200.74023 L 12.751953 200.9043 C 12.862211 200.87013 12.980058 200.84224 13.085938 200.80273 L 13.085938 200.37891 C 13.085938 200.22863 13.111295 200.08474 13.130859 199.93945 L 12.919922 199.93945 z M 19.882812 199.93945 C 19.902378 200.08474 19.927734 200.22863 19.927734 200.37891 L 19.927734 200.79102 C 20.168811 200.87511 20.455966 200.91694 20.613281 201.06641 C 20.691227 201.14046 20.749315 201.22305 20.806641 201.30273 L 21.259766 200.74023 C 21.519766 200.46023 21.260625 199.90945 20.890625 199.93945 L 19.882812 199.93945 z M 16.435547 200.2207 C 16.301234 200.2207 16.277344 200.24444 16.277344 200.37891 L 16.277344 200.60742 L 16.734375 200.60742 L 16.734375 200.37891 C 16.734375 200.24441 16.712442 200.2207 16.578125 200.2207 L 16.435547 200.2207 z ' fill='#{hex-color($highlight-text-color)}' stroke-width='0' /></svg>");
}
}
&.disabled {
i.fa-retweet {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' height='209' width='22'><path d='M 18.972656 1.2011719 C 18.829825 1.1881782 18.685932 1.2302188 18.572266 1.3300781 L 15.990234 3.5996094 C 15.58109 3.6070661 15.297269 3.609375 14.730469 3.609375 L 7.0996094 3.609375 L 9.4199219 6.4609375 L 9.4492188 6.5195312 L 12.664062 6.5195312 L 6.5761719 11.867188 C 6.5674697 11.818249 6.5507813 11.773891 6.5507812 11.720703 L 6.5507812 9.0195312 L 9.0507812 9.0195312 C 9.4207813 9.0495313 9.6792188 8.54 9.4492188 8.25 L 5.5 3.3496094 C 5.38 3.1796094 5.1607031 3.1003906 4.9707031 3.1503906 L 4.9707031 3.1601562 C 4.8707031 3.1901563 4.8 3.2598438 4.75 3.3398438 L 0.80078125 8.2402344 C 0.60078125 8.5402344 0.8292187 9.0190625 1.1992188 9.0390625 L 3.5996094 9.0390625 L 3.5996094 11.720703 C 3.5996094 13.045739 3.5690668 13.895038 3.6503906 14.4375 L 2.6152344 15.347656 C 2.3879011 15.547375 2.3754917 15.901081 2.5859375 16.140625 L 3.1464844 16.78125 C 3.3569308 17.020794 3.7101667 17.053234 3.9375 16.853516 L 19.892578 2.8359375 C 20.119911 2.6362188 20.134275 2.282513 19.923828 2.0429688 L 19.361328 1.4023438 C 19.256105 1.282572 19.115488 1.2141655 18.972656 1.2011719 z M 18.410156 6.7753906 L 15.419922 9.4042969 L 15.419922 9.9394531 L 14.810547 9.9394531 L 13.148438 11.400391 L 16.539062 15.640625 C 16.719062 15.890625 17.140313 15.890625 17.320312 15.640625 L 21.259766 10.740234 C 21.519766 10.460234 21.260625 9.9094531 20.890625 9.9394531 L 18.400391 9.9394531 L 18.400391 7.2402344 C 18.400391 7.0470074 18.407711 6.9489682 18.410156 6.7753906 z M 11.966797 12.439453 L 8.6679688 15.339844 L 14.919922 15.339844 L 12.619141 12.5 C 12.589141 12.48 12.590313 12.459453 12.570312 12.439453 L 11.966797 12.439453 z' fill='#{hex-color($white)}' stroke-width='0'/></svg>");
}
}
}
}

View File

@ -53,10 +53,7 @@
box-sizing: border-box;
color: $ui-button-color;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
display: inline-block;
font-family: inherit;
font-size: 15px;
font-weight: 500;
@ -170,13 +167,9 @@
}
&.button--block {
display: block;
width: 100%;
}
.icon {
width: 18px;
height: 18px;
}
}
.column__wrapper {
@ -185,30 +178,15 @@
position: relative;
}
.icon {
flex: 0 0 auto;
width: 20px;
height: 20px;
aspect-ratio: 1;
path {
fill: currentColor;
}
}
.icon-button {
display: inline-flex;
display: inline-block;
padding: 0;
color: $action-button-color;
border: 0;
padding: 2px;
border-radius: 4px;
background: transparent;
cursor: pointer;
align-items: center;
justify-content: center;
text-decoration: none;
gap: 4px;
flex: 0 0 auto;
a {
color: inherit;
@ -280,9 +258,17 @@
}
}
&--with-counter {
display: inline-flex;
align-items: center;
width: auto !important;
padding: 0 4px 0 2px;
}
&__counter {
display: block;
display: inline-block;
width: auto;
margin-inline-start: 4px;
font-size: 12px;
font-weight: 500;
}
@ -632,11 +618,6 @@ body > [data-popper-placement] {
padding: 10px;
font-family: inherit;
.icon {
width: 15px;
height: 15px;
}
&:hover,
&:focus,
&:active {
@ -682,11 +663,6 @@ body > [data-popper-placement] {
.compose-form__buttons {
display: flex;
gap: 2px;
.icon-button {
height: 100%;
}
.compose-form__upload-button-icon {
line-height: 27px;
@ -761,6 +737,10 @@ body > [data-popper-placement] {
&:hover {
text-decoration: underline;
.fa {
color: lighten($dark-text-color, 7%);
}
}
}
}
@ -873,6 +853,10 @@ body > [data-popper-placement] {
&:hover {
text-decoration: underline;
.fa {
color: lighten($dark-text-color, 7%);
}
}
&.mention {
@ -884,6 +868,10 @@ body > [data-popper-placement] {
}
}
}
.fa {
color: $dark-text-color;
}
}
a.unhandled-link {
@ -968,8 +956,7 @@ body > [data-popper-placement] {
.status__content__read-more-button,
.status__content__translate-button {
display: flex;
align-items: center;
display: block;
font-size: 15px;
line-height: 22px;
color: $highlight-text-color;
@ -983,11 +970,6 @@ body > [data-popper-placement] {
&:active {
text-decoration: underline;
}
.icon {
width: 15px;
height: 15px;
}
}
.translate-button {
@ -1199,12 +1181,6 @@ body > [data-popper-placement] {
.status__visibility-icon {
padding: 0 4px;
.icon {
width: 1em;
height: 1em;
margin-bottom: -2px;
}
}
.status__display-name {
@ -1383,13 +1359,6 @@ body > [data-popper-placement] {
color: $dark-text-color;
font-size: 14px;
line-height: 18px;
.icon {
width: 15px;
height: 15px;
position: relative;
top: 0.145em;
}
}
.detailed-status__action-bar {
@ -1428,24 +1397,18 @@ body > [data-popper-placement] {
}
.detailed-status__link {
display: inline-flex;
align-items: center;
color: inherit;
text-decoration: none;
gap: 6px;
position: relative;
top: 0.145em;
.icon {
top: 0;
}
white-space: nowrap;
}
.detailed-status__favorites,
.detailed-status__reblogs {
display: inline-block;
font-weight: 500;
font-size: 12px;
line-height: 18px;
line-height: 17px;
margin-inline-start: 6px;
}
.reply-indicator__content {
@ -1786,17 +1749,10 @@ a.account__display-name {
line-height: 22px;
font-weight: 500;
display: flex;
align-items: center;
gap: 10px;
.icon {
.fa {
color: $highlight-text-color;
width: 18px;
height: 18px;
}
.icon-star {
color: $gold-star;
}
> span {
@ -1806,6 +1762,12 @@ a.account__display-name {
}
}
.notification__favourite-icon-wrapper {
.star-icon {
color: $gold-star;
}
}
.icon-button.star-icon.active {
color: $gold-star;
}
@ -1816,13 +1778,13 @@ a.account__display-name {
.no-reduce-motion .icon-button.star-icon {
&.activate {
& > .icon {
& > .fa-star {
animation: spring-rotate-in 1s linear;
}
}
&.deactivate {
& > .icon {
& > .fa-star {
animation: spring-rotate-out 1s linear;
}
}
@ -1947,11 +1909,6 @@ a.account__display-name {
pointer-events: auto;
transform: scale(1, 1) translate(0, 0);
opacity: 1;
.icon {
width: 24px;
height: 24px;
}
}
}
}
@ -2018,8 +1975,7 @@ a.account__display-name {
z-index: 9999;
&__text-button {
display: inline-flex;
align-items: center;
display: inline;
color: inherit;
background: transparent;
border: 0;
@ -2032,11 +1988,6 @@ a.account__display-name {
&:focus-visible {
outline: 1px dotted;
}
.icon {
width: 15px;
height: 15px;
}
}
&__container {
@ -2240,11 +2191,6 @@ $ui-header-height: 55px;
.button-tertiary {
flex-shrink: 1;
}
.icon {
width: 22px;
height: 22px;
}
}
}
@ -2259,6 +2205,14 @@ $ui-header-height: 55px;
padding-top: 10px;
top: 0;
}
.tabs-bar {
margin-bottom: 0;
@media screen and (min-width: $no-gap-breakpoint) {
margin-bottom: 10px;
}
}
}
.react-swipeable-view-container {
@ -2308,15 +2262,13 @@ $ui-header-height: 55px;
}
.drawer__tab {
display: flex;
display: block;
flex: 1 1 auto;
padding: 15px 5px 13px;
color: $darker-text-color;
text-decoration: none;
text-align: center;
font-size: 16px;
align-items: center;
justify-content: center;
border-bottom: 2px solid transparent;
}
@ -2356,6 +2308,61 @@ $ui-header-height: 55px;
}
}
.tabs-bar {
box-sizing: border-box;
display: flex;
background: lighten($ui-base-color, 8%);
flex: 0 0 auto;
overflow-y: auto;
}
.tabs-bar__link {
display: block;
flex: 1 1 auto;
padding: 15px 10px;
padding-bottom: 13px;
color: $primary-text-color;
text-decoration: none;
text-align: center;
font-size: 14px;
font-weight: 500;
border-bottom: 2px solid lighten($ui-base-color, 8%);
transition: all 50ms linear;
transition-property: border-bottom, background, color;
.fa {
font-weight: 400;
font-size: 16px;
}
&:hover,
&:focus,
&:active {
@media screen and (width >= 631px) {
background: lighten($ui-base-color, 14%);
border-bottom-color: lighten($ui-base-color, 14%);
}
}
&.active {
border-bottom: 2px solid $highlight-text-color;
color: $highlight-text-color;
}
span {
margin-inline-start: 5px;
display: none;
}
}
@media screen and (width >= 600px) {
.tabs-bar__link {
span {
display: inline;
}
}
}
.columns-area--mobile {
flex-direction: column;
width: 100%;
@ -2408,6 +2415,10 @@ $ui-header-height: 55px;
}
@media screen and (min-width: $no-gap-breakpoint) {
.tabs-bar {
width: 100%;
}
.react-swipeable-view-container .columns-area--mobile {
height: calc(100% - 10px) !important;
}
@ -2416,6 +2427,10 @@ $ui-header-height: 55px;
margin-bottom: 10px;
}
.tabs-bar__link.optional {
display: none;
}
.search-page .search {
display: none;
}
@ -2515,7 +2530,6 @@ $ui-header-height: 55px;
}
.icon-with-badge {
display: inline-flex;
position: relative;
&__badge {
@ -2981,14 +2995,13 @@ $ui-header-height: 55px;
position: relative;
overflow: hidden;
display: flex;
border-radius: 4px;
}
.drawer__inner {
position: absolute;
top: 0;
inset-inline-start: 0;
background: $ui-base-color;
background: lighten($ui-base-color, 13%);
box-sizing: border-box;
padding: 0;
display: flex;
@ -3004,7 +3017,7 @@ $ui-header-height: 55px;
}
.drawer__inner__mastodon {
background: $ui-base-color
background: lighten($ui-base-color, 13%)
url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-color)}"/></svg>')
no-repeat bottom / 100% auto;
flex: 1;
@ -3035,15 +3048,20 @@ $ui-header-height: 55px;
.drawer__header {
flex: 0 0 auto;
font-size: 16px;
background: $ui-base-color;
background: lighten($ui-base-color, 8%);
margin-bottom: 10px;
display: flex;
flex-direction: row;
border-radius: 4px;
overflow: hidden;
a:hover {
background: lighten($ui-base-color, 3%);
a {
transition: background 100ms ease-in;
&:hover {
background: lighten($ui-base-color, 3%);
transition: background 200ms ease-out;
}
}
}
@ -3102,8 +3120,6 @@ $ui-header-height: 55px;
margin: 0;
z-index: 3;
outline: 0;
display: flex;
align-items: center;
&:hover {
text-decoration: underline;
@ -3111,8 +3127,6 @@ $ui-header-height: 55px;
}
.column-header__back-button {
display: flex;
align-items: center;
background: $ui-base-color;
border: 0;
font-family: inherit;
@ -3137,6 +3151,20 @@ $ui-header-height: 55px;
margin-inline-end: 5px;
}
.column-back-button--slim {
position: relative;
}
.column-back-button--slim-button {
cursor: pointer;
flex: 0 0 auto;
font-size: 16px;
padding: 15px;
position: absolute;
inset-inline-end: 0;
top: -50px;
}
.react-toggle {
display: inline-block;
position: relative;
@ -3264,9 +3292,7 @@ $ui-header-height: 55px;
.column-link {
background: lighten($ui-base-color, 8%);
color: $primary-text-color;
display: flex;
align-items: center;
gap: 5px;
display: block;
font-size: 16px;
padding: 15px;
text-decoration: none;
@ -3318,6 +3344,11 @@ $ui-header-height: 55px;
}
}
.column-link__icon {
display: inline-block;
margin-inline-end: 5px;
}
.column-link__badge {
display: inline-block;
border-radius: 4px;
@ -3477,6 +3508,29 @@ $ui-header-height: 55px;
}
}
button.icon-button i.fa-retweet {
background-position: 0 0;
height: 19px;
transition: background-position 0.9s steps(10);
transition-duration: 0s;
vertical-align: middle;
width: 22px;
&::before {
display: none !important;
}
}
button.icon-button.active i.fa-retweet {
transition-duration: 0.9s;
background-position: 0 100%;
}
.reduce-motion button.icon-button i.fa-retweet,
.reduce-motion button.icon-button.active i.fa-retweet {
transition: none;
}
.status-card {
display: flex;
align-items: center;
@ -3653,9 +3707,8 @@ a.status-card {
background: lighten($ui-base-color, 8%);
position: relative;
& > .icon {
width: 18px;
height: 18px;
& > .fa {
font-size: 21px;
position: absolute;
transform-origin: 50% 50%;
top: 50%;
@ -3862,9 +3915,6 @@ a.status-card {
outline: 0;
& > button {
display: flex;
align-items: center;
gap: 5px;
margin: 0;
border: 0;
padding: 15px;
@ -3914,9 +3964,6 @@ a.status-card {
}
.column-header__button {
display: flex;
justify-content: center;
align-items: center;
background: $ui-base-color;
border: 0;
color: $darker-text-color;
@ -4023,9 +4070,7 @@ a.status-card {
}
.text-btn {
display: inline-flex;
align-items: center;
gap: 4px;
display: inline-block;
padding: 0;
font-family: inherit;
font-size: inherit;
@ -4033,11 +4078,6 @@ a.status-card {
border: 0;
background: transparent;
cursor: pointer;
.icon {
width: 13px;
height: 13px;
}
}
.column-header__issue-btn {
@ -4049,6 +4089,11 @@ a.status-card {
}
}
.column-header__icon {
display: inline-block;
margin-inline-end: 5px;
}
.loading-indicator {
color: $dark-text-color;
font-size: 12px;
@ -4707,11 +4752,10 @@ a.status-card {
color: $lighter-text-color;
overflow: hidden;
display: flex;
gap: 10px;
.icon {
width: 24px;
height: 24px;
.fa {
font-size: 34px;
margin-inline-end: 10px;
}
span {
@ -4859,6 +4903,22 @@ a.status-card {
}
}
.privacy-dropdown.active {
.privacy-dropdown__value {
background: $simple-background-color;
border-radius: 4px 4px 0 0;
}
&.top .privacy-dropdown__value {
border-radius: 0 0 4px 4px;
}
.privacy-dropdown__dropdown {
display: block;
box-shadow: var(--dropdown-shadow);
}
}
.language-dropdown {
&__dropdown {
background: $simple-background-color;
@ -4894,9 +4954,6 @@ a.status-card {
font-weight: 500;
padding: 10px;
border-radius: 4px;
display: flex;
gap: 6px;
align-items: center;
&:focus,
&:active,
@ -4952,15 +5009,6 @@ a.status-card {
margin-bottom: 10px;
}
.icon-button {
padding: 0;
}
.icon {
width: 18px;
height: 18px;
}
&__menu {
margin-bottom: 20px;
@ -5069,16 +5117,17 @@ a.status-card {
outline: 0 !important;
}
.icon {
.fa {
position: absolute;
top: 13px;
top: 16px;
inset-inline-end: 10px;
display: inline-block;
opacity: 0;
transition: all 100ms linear;
transition-property: transform, opacity;
width: 24px;
height: 24px;
font-size: 18px;
width: 18px;
height: 18px;
color: $secondary-text-color;
cursor: default;
pointer-events: none;
@ -5089,7 +5138,7 @@ a.status-card {
}
}
.icon-search {
.fa-search {
transform: rotate(90deg);
&.active {
@ -5098,7 +5147,8 @@ a.status-card {
}
}
.icon-times-circle {
.fa-times-circle {
top: 17px;
transform: rotate(0deg);
color: $action-button-color;
cursor: pointer;
@ -5121,9 +5171,11 @@ a.status-card {
font-weight: 500;
font-size: 16px;
cursor: default;
display: flex;
align-items: center;
gap: 5px;
.fa {
display: inline-block;
margin-inline-end: 5px;
}
}
.search-results__section {
@ -5143,10 +5195,8 @@ a.status-card {
display: flex;
justify-content: space-between;
h3 {
display: flex;
align-items: center;
gap: 5px;
h3 .fa {
margin-inline-end: 5px;
}
button {
@ -5573,6 +5623,19 @@ a.status-card {
flex-direction: column;
}
.actions-modal {
.status {
background: $white;
border-bottom-color: $ui-secondary-color;
padding-top: 10px;
padding-bottom: 10px;
}
.dropdown-menu__separator {
border-bottom-color: $ui-secondary-color;
}
}
.boost-modal__container {
overflow-x: scroll;
padding: 10px;
@ -5943,6 +6006,11 @@ a.status-card {
max-height: 80vh;
max-width: 80vw;
.status {
overflow-y: auto;
max-height: 300px;
}
.actions-modal__item-label {
font-weight: 500;
}
@ -6149,9 +6217,7 @@ a.status-card {
}
.media-gallery__gifv__label {
display: flex;
align-items: center;
justify-content: center;
display: block;
color: $white;
background: rgba($black, 0.65);
backdrop-filter: blur(10px) saturate(180%) contrast(75%) brightness(70%);
@ -6162,11 +6228,6 @@ a.status-card {
z-index: 1;
pointer-events: none;
line-height: 18px;
.icon {
width: 15px;
height: 15px;
}
}
.attachment-list {
@ -6188,6 +6249,10 @@ a.status-card {
align-items: center;
justify-content: center;
font-size: 26px;
.fa {
display: block;
}
}
&__list {
@ -6222,7 +6287,7 @@ a.status-card {
display: block;
}
.icon {
.fa {
color: $dark-text-color;
}
}
@ -6517,17 +6582,18 @@ a.status-card {
flex: 0 1 auto;
min-width: 30px;
align-items: center;
font-size: 16px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
gap: 5px;
.player-button {
display: inline-block;
outline: 0;
padding: 5px;
flex: 0 0 auto;
background: transparent;
padding: 5px;
font-size: 16px;
border: 0;
color: rgba($white, 0.75);
@ -6918,6 +6984,7 @@ noscript {
$duration: 400ms;
$delay: 100ms;
.tabs-bar,
.search {
will-change: margin-top;
transition: margin-top $duration $delay;
@ -6960,6 +7027,7 @@ noscript {
}
.is-composing {
.tabs-bar,
.search {
margin-top: -50px;
}
@ -7420,12 +7488,7 @@ noscript {
border: 1px solid lighten($ui-base-color, 12%);
border-radius: 4px;
box-sizing: content-box;
padding: 5px;
.icon {
width: 24px;
height: 24px;
}
padding: 2px;
}
}
@ -7508,11 +7571,6 @@ noscript {
color: lighten($ui-highlight-color, 8%);
}
.icon {
width: 18px;
height: 18px;
}
.verified {
border: 1px solid rgba($valid-value-color, 0.5);
margin-top: -1px;
@ -7533,16 +7591,6 @@ noscript {
color: $valid-value-color;
}
dd {
display: flex;
align-items: center;
gap: 4px;
span {
display: flex;
}
}
a {
color: $valid-value-color;
}
@ -7645,14 +7693,24 @@ noscript {
font-weight: 500;
text-decoration: none;
}
.icon {
width: 16px;
height: 16px;
}
}
.trends {
&__header {
color: $dark-text-color;
background: lighten($ui-base-color, 2%);
border-bottom: 1px solid darken($ui-base-color, 4%);
font-weight: 500;
padding: 15px;
font-size: 16px;
cursor: default;
.fa {
display: inline-block;
margin-inline-end: 5px;
}
}
&__item {
display: flex;
align-items: center;
@ -8143,9 +8201,10 @@ noscript {
color: $darker-text-color;
aspect-ratio: 16 / 9;
.icon {
width: 24px;
height: 24px;
i {
display: block;
font-size: 24px;
font-weight: 400;
margin-bottom: 10px;
}
@ -8206,11 +8265,15 @@ noscript {
border: 1px solid lighten($ui-base-color, 8%);
}
.search .icon {
top: 9px;
.search .fa {
top: 10px;
inset-inline-end: 10px;
color: $dark-text-color;
}
.search .fa-times-circle {
top: 12px;
}
}
.explore__search-results {
@ -9135,9 +9198,6 @@ noscript {
margin-bottom: 10px;
&__title {
display: flex;
align-items: center;
gap: 6px;
font-size: 17px;
font-weight: 600;
line-height: 22px;

View File

@ -20,14 +20,6 @@ declare module '*.png' {
}
declare module '*.svg' {
import type React from 'react';
interface SVGPropsWithTitle extends React.SVGProps<SVGSVGElement> {
title?: string;
}
export const ReactComponent: React.FC<SVGPropsWithTitle>;
const path: string;
export default path;
}

View File

@ -75,12 +75,7 @@ class AttachmentBatch
end
when :fog
logger.debug { "Deleting #{attachment.path(style)}" }
begin
attachment.send(:directory).files.new(key: attachment.path(style)).destroy
rescue Fog::Storage::OpenStack::NotFound
# Ignore failure to delete a file that has already been deleted
end
attachment.directory.files.new(key: attachment.path(style)).destroy
when :azure
logger.debug { "Deleting #{attachment.path(style)}" }
attachment.destroy

View File

@ -2,7 +2,7 @@
class CacheBuster
def initialize(options = {})
Rails.application.deprecators[:mastodon].warn('Default values for the cache buster secret header name and values will be removed in Mastodon 4.3. Please set them explicitely if you rely on those.') unless options[:http_method] || (options[:secret] && options[:secret_header])
ActiveSupport::Deprecation.warn('Default values for the cache buster secret header name and values will be removed in Mastodon 4.3. Please set them explicitely if you rely on those.') unless options[:http_method] || (options[:secret] && options[:secret_header])
@secret_header = options[:secret_header] ||
(options[:http_method] ? nil : 'Secret-Header')

View File

@ -1,59 +0,0 @@
# frozen_string_literal: true
class ContentSecurityPolicy
def base_host
Rails.configuration.x.web_domain
end
def assets_host
url_from_configured_asset_host || url_from_base_host
end
def media_host
cdn_host_value || assets_host
end
private
def url_from_configured_asset_host
Rails.configuration.action_controller.asset_host
end
def cdn_host_value
s3_alias_host || s3_cloudfront_host || azure_alias_host || s3_hostname_host
end
def url_from_base_host
host_to_url(base_host)
end
def host_to_url(host_string)
uri_from_configuration_and_string(host_string) if host_string.present?
end
def s3_alias_host
host_to_url ENV.fetch('S3_ALIAS_HOST', nil)
end
def s3_cloudfront_host
host_to_url ENV.fetch('S3_CLOUDFRONT_HOST', nil)
end
def azure_alias_host
host_to_url ENV.fetch('AZURE_ALIAS_HOST', nil)
end
def s3_hostname_host
host_to_url ENV.fetch('S3_HOSTNAME', nil)
end
def uri_from_configuration_and_string(host_string)
Addressable::URI.parse("#{host_protocol}://#{host_string}").tap do |uri|
uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/')
end.to_s
end
def host_protocol
Rails.configuration.x.use_https ? 'https' : 'http'
end
end

View File

@ -8,15 +8,13 @@ class UserMailer < Devise::Mailer
helper :instance
helper :statuses
helper :formatting
helper :routing
before_action :set_instance
default to: -> { @resource.email }
helper RoutingHelper
def confirmation_instructions(user, token, *, **)
@resource = user
@token = token
@instance = Rails.configuration.x.local_domain
return unless @resource.active_for_authentication?
@ -30,177 +28,185 @@ class UserMailer < Devise::Mailer
def reset_password_instructions(user, token, *, **)
@resource = user
@token = token
@instance = Rails.configuration.x.local_domain
return unless @resource.active_for_authentication?
I18n.with_locale(locale) do
mail subject: default_devise_subject
mail to: @resource.email, subject: I18n.t('devise.mailer.reset_password_instructions.subject')
end
end
def password_change(user, *, **)
@resource = user
@instance = Rails.configuration.x.local_domain
return unless @resource.active_for_authentication?
I18n.with_locale(locale) do
mail subject: default_devise_subject
mail to: @resource.email, subject: I18n.t('devise.mailer.password_change.subject')
end
end
def email_changed(user, *, **)
@resource = user
@instance = Rails.configuration.x.local_domain
return unless @resource.active_for_authentication?
I18n.with_locale(locale) do
mail subject: default_devise_subject
mail to: @resource.email, subject: I18n.t('devise.mailer.email_changed.subject')
end
end
def two_factor_enabled(user, *, **)
@resource = user
@instance = Rails.configuration.x.local_domain
return unless @resource.active_for_authentication?
I18n.with_locale(locale) do
mail subject: default_devise_subject
mail to: @resource.email, subject: I18n.t('devise.mailer.two_factor_enabled.subject')
end
end
def two_factor_disabled(user, *, **)
@resource = user
@instance = Rails.configuration.x.local_domain
return unless @resource.active_for_authentication?
I18n.with_locale(locale) do
mail subject: default_devise_subject
mail to: @resource.email, subject: I18n.t('devise.mailer.two_factor_disabled.subject')
end
end
def two_factor_recovery_codes_changed(user, *, **)
@resource = user
@instance = Rails.configuration.x.local_domain
return unless @resource.active_for_authentication?
I18n.with_locale(locale) do
mail subject: default_devise_subject
mail to: @resource.email, subject: I18n.t('devise.mailer.two_factor_recovery_codes_changed.subject')
end
end
def webauthn_enabled(user, *, **)
@resource = user
@instance = Rails.configuration.x.local_domain
return unless @resource.active_for_authentication?
I18n.with_locale(locale) do
mail subject: default_devise_subject
mail to: @resource.email, subject: I18n.t('devise.mailer.webauthn_enabled.subject')
end
end
def webauthn_disabled(user, *, **)
@resource = user
@instance = Rails.configuration.x.local_domain
return unless @resource.active_for_authentication?
I18n.with_locale(locale) do
mail subject: default_devise_subject
mail to: @resource.email, subject: I18n.t('devise.mailer.webauthn_disabled.subject')
end
end
def webauthn_credential_added(user, webauthn_credential)
@resource = user
@instance = Rails.configuration.x.local_domain
@webauthn_credential = webauthn_credential
return unless @resource.active_for_authentication?
I18n.with_locale(locale) do
mail subject: I18n.t('devise.mailer.webauthn_credential.added.subject')
mail to: @resource.email, subject: I18n.t('devise.mailer.webauthn_credential.added.subject')
end
end
def webauthn_credential_deleted(user, webauthn_credential)
@resource = user
@instance = Rails.configuration.x.local_domain
@webauthn_credential = webauthn_credential
return unless @resource.active_for_authentication?
I18n.with_locale(locale) do
mail subject: I18n.t('devise.mailer.webauthn_credential.deleted.subject')
mail to: @resource.email, subject: I18n.t('devise.mailer.webauthn_credential.deleted.subject')
end
end
def welcome(user)
@resource = user
@instance = Rails.configuration.x.local_domain
return unless @resource.active_for_authentication?
I18n.with_locale(locale) do
mail subject: default_i18n_subject
mail to: @resource.email, subject: I18n.t('user_mailer.welcome.subject')
end
end
def backup_ready(user, backup)
@resource = user
@instance = Rails.configuration.x.local_domain
@backup = backup
return unless @resource.active_for_authentication?
I18n.with_locale(locale) do
mail subject: default_i18n_subject
mail to: @resource.email, subject: I18n.t('user_mailer.backup_ready.subject')
end
end
def warning(user, warning)
@resource = user
@warning = warning
@instance = Rails.configuration.x.local_domain
@statuses = @warning.statuses.includes(:account, :preloadable_poll, :media_attachments, active_mentions: [:account])
I18n.with_locale(locale) do
mail subject: I18n.t("user_mailer.warning.subject.#{@warning.action}", acct: "@#{user.account.local_username_and_domain}")
mail to: @resource.email, subject: I18n.t("user_mailer.warning.subject.#{@warning.action}", acct: "@#{user.account.local_username_and_domain}")
end
end
def appeal_approved(user, appeal)
@resource = user
@instance = Rails.configuration.x.local_domain
@appeal = appeal
I18n.with_locale(locale) do
mail subject: default_i18n_subject(date: l(@appeal.created_at))
mail to: @resource.email, subject: I18n.t('user_mailer.appeal_approved.subject', date: l(@appeal.created_at))
end
end
def appeal_rejected(user, appeal)
@resource = user
@instance = Rails.configuration.x.local_domain
@appeal = appeal
I18n.with_locale(locale) do
mail subject: default_i18n_subject(date: l(@appeal.created_at))
mail to: @resource.email, subject: I18n.t('user_mailer.appeal_rejected.subject', date: l(@appeal.created_at))
end
end
def suspicious_sign_in(user, remote_ip, user_agent, timestamp)
@resource = user
@instance = Rails.configuration.x.local_domain
@remote_ip = remote_ip
@user_agent = user_agent
@detection = Browser.new(user_agent)
@timestamp = timestamp.to_time.utc
I18n.with_locale(locale) do
mail subject: default_i18n_subject
mail to: @resource.email, subject: I18n.t('user_mailer.suspicious_sign_in.subject')
end
end
private
def default_devise_subject
I18n.t(:subject, scope: ['devise.mailer', action_name])
end
def set_instance
@instance = Rails.configuration.x.local_domain
end
def locale
@resource.locale.presence || I18n.default_locale
end

View File

@ -23,7 +23,10 @@ class AccountAlias < ApplicationRecord
after_create :add_to_account
after_destroy :remove_from_account
normalizes :acct, with: ->(acct) { acct.strip.delete_prefix('@') }
def acct=(val)
val = val.to_s.strip
super(val.start_with?('@') ? val[1..] : val)
end
def pretty_acct
username, domain = acct.split('@', 2)

View File

@ -25,8 +25,6 @@ class AccountMigration < ApplicationRecord
before_validation :set_target_account
before_validation :set_followers_count
normalizes :acct, with: ->(acct) { acct.strip.delete_prefix('@') }
validates :acct, presence: true, domain: { acct: true }
validate :validate_migration_cooldown
validate :validate_target_account
@ -53,6 +51,10 @@ class AccountMigration < ApplicationRecord
created_at + COOLDOWN_PERIOD
end
def acct=(val)
super(val.to_s.strip.gsub(/\A@/, ''))
end
private
def set_target_account

View File

@ -27,7 +27,7 @@ class AccountWarning < ApplicationRecord
suspend: 4_000,
}, _suffix: :action
normalizes :text, with: ->(text) { text.to_s }, apply_to_nil: true
before_validation :before_validate
belongs_to :account, inverse_of: :account_warnings
belongs_to :target_account, class_name: 'Account', inverse_of: :strikes
@ -50,4 +50,10 @@ class AccountWarning < ApplicationRecord
def to_log_human_identifier
target_account.acct
end
private
def before_validate
self.text = '' if text.blank?
end
end

View File

@ -4,7 +4,7 @@ module HasUserSettings
extend ActiveSupport::Concern
included do
serialize :settings, coder: UserSettingsSerializer
serialize :settings, UserSettingsSerializer
end
def settings_attributes=(attributes)

View File

@ -15,7 +15,7 @@ module StatusSafeReblogInsert
#
# The code is kept similar to ActiveRecord::Persistence code and calls it
# directly when we are not handling a reblog.
def _insert_record(values, returning)
def _insert_record(values)
return super unless values.is_a?(Hash) && values['reblog_of_id']&.value.present?
primary_key = self.primary_key
@ -34,7 +34,7 @@ module StatusSafeReblogInsert
# Instead, we use a custom builder when a reblog is happening:
im = _compile_reblog_insert(values)
connection.insert(im, "#{self} Create", primary_key || false, primary_key_value, returning: returning).tap do |result|
connection.insert(im, "#{self} Create", primary_key || false, primary_key_value).tap do |result|
# Since we are using SELECT instead of VALUES, a non-error `nil` return is possible.
# For our purposes, it's equivalent to a foreign key constraint violation
raise ActiveRecord::InvalidForeignKey, "(reblog_of_id)=(#{values['reblog_of_id'].value}) is not present in table \"statuses\"" if result.nil?

View File

@ -23,7 +23,7 @@ class FeaturedTag < ApplicationRecord
validate :validate_tag_uniqueness, on: :create
validate :validate_featured_tags_limit, on: :create
normalizes :name, with: ->(name) { name.strip.delete_prefix('#') }
before_validation :strip_name
before_create :set_tag
before_create :reset_data
@ -50,6 +50,10 @@ class FeaturedTag < ApplicationRecord
private
def strip_name
self.name = name&.strip&.delete_prefix('#')
end
def set_tag
self.tag = Tag.find_or_create_by_names(name)&.first
end

View File

@ -19,8 +19,7 @@ class Relay < ApplicationRecord
scope :enabled, -> { accepted }
normalizes :inbox_url, with: ->(inbox_url) { inbox_url.strip }
before_validation :strip_url
before_destroy :ensure_disabled
alias enabled? accepted?
@ -77,4 +76,8 @@ class Relay < ApplicationRecord
def ensure_disabled
disable! if enabled?
end
def strip_url
inbox_url&.strip!
end
end

View File

@ -142,11 +142,6 @@ class Report < ApplicationRecord
target_type: 'Status',
target_id: status_ids
).unscope(:order).arel,
Admin::ActionLog.where(
target_type: 'AccountWarning',
target_id: AccountWarning.where(report_id: id).select(:id)
).unscope(:order).arel,
].reduce { |union, query| Arel::Nodes::UnionAll.new(union, query) }
Admin::ActionLog.from(Arel::Nodes::As.new(subquery, Admin::ActionLog.arel_table))

View File

@ -35,7 +35,7 @@ class Tag < ApplicationRecord
HASHTAG_LAST_SEQUENCE = '([[:word:]_]*[[:alpha:]][[:word:]_]*)'
HASHTAG_NAME_PAT = "#{HASHTAG_FIRST_SEQUENCE}|#{HASHTAG_LAST_SEQUENCE}"
HASHTAG_RE = %r{(?<![=/)\w])#(#{HASHTAG_NAME_PAT})}i
HASHTAG_RE = %r{(?:^|[^/)\w])#(#{HASHTAG_NAME_PAT})}i
HASHTAG_NAME_RE = /\A(#{HASHTAG_NAME_PAT})\z/i
HASHTAG_INVALID_CHARS_RE = /[^[:alnum:]#{HASHTAG_SEPARATORS}]/

View File

@ -488,7 +488,7 @@ class User < ApplicationRecord
end
def validate_email_dns?
email_changed? && !external? && !Rails.env.local? # rubocop:disable Rails/UnknownEnv
email_changed? && !external? && !(Rails.env.test? || Rails.env.development?)
end
def validate_role_elevation

View File

@ -10,9 +10,7 @@ class REST::FeaturedTagSerializer < ActiveModel::Serializer
end
def url
# The path is hardcoded because we have to deal with both local and
# remote users, which are different routes
account_with_domain_url(object.account, "tagged/#{object.tag.to_param}")
short_account_tag_url(object.account, object.tag)
end
def name

View File

@ -37,8 +37,6 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService
end
def process_items(items)
return if items.nil?
process_note_items(items) if @options[:note]
process_hashtag_items(items) if @options[:hashtag]
end

View File

@ -71,7 +71,7 @@ class FollowService < BaseService
if @target_account.local?
LocalNotificationWorker.perform_async(@target_account.id, follow_request.id, follow_request.class.name, 'follow_request')
elsif @target_account.activitypub?
ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), @source_account.id, @target_account.inbox_url, { 'bypass_availability' => true })
ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), @source_account.id, @target_account.inbox_url)
end
follow_request

View File

@ -1,5 +0,0 @@
inherit_from: ../../.rubocop.yml
# Disable for the `Rubocop` lints in haml-lint
Style/IfUnlessModifier:
Enabled: false

View File

@ -1,5 +1,5 @@
- content_for :page_title do
#{display_name(@account)} (#{acct(@account)})
= "#{display_name(@account)} (#{acct(@account)})"
- content_for :header_tags do
- if @account.user_prefers_noindex?

View File

@ -30,6 +30,6 @@
\-
%br/
%samp.ellipsized-ip= relevant_account_ip(account, params[:ip])
- if !account.suspended? && account.user_pending? && account.user&.invite_request&.text.present?
- if !account.suspended? && account.user_pending? && account.user&.invite_request&.text&.present?
.batch-table__row__content__quote
%p= account.user&.invite_request&.text

View File

@ -22,10 +22,9 @@
.fields-group
- %i(username by_domain display_name email ip).each do |key|
- next if key == :by_domain && params[:origin] != 'remote'
.input.string.optional
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.accounts.#{key}")
- unless key == :by_domain && params[:origin] != 'remote'
.input.string.optional
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.accounts.#{key}")
.actions
%button.button= t('admin.accounts.search')

View File

@ -73,7 +73,7 @@
%hr.spacer/
- if @account.user&.invite_request&.text.present?
- if @account.user&.invite_request&.text&.present?
.speech-bubble
.speech-bubble__bubble
= @account.user&.invite_request&.text

View File

@ -6,7 +6,7 @@
= custom_emoji_tag(custom_emoji)
.batch-table__row__content__text
%samp :#{custom_emoji.shortcode}:
%samp= ":#{custom_emoji.shortcode}:"
- if custom_emoji.local?
%span.information-badge= custom_emoji.category&.name || t('admin.custom_emojis.uncategorized')

View File

@ -2,6 +2,7 @@
= t('.title', domain: Addressable::IDNA.to_unicode(@domain_block.domain))
= simple_form_for @domain_block, url: admin_domain_blocks_path, method: :post do |f|
%p.hint= t('.preamble_html', domain: Addressable::IDNA.to_unicode(@domain_block.domain))
%ul.hint
%li= t('.stop_communication')

View File

@ -7,31 +7,27 @@
= ' - '
= l(@time_period.last)
- if @instance.persisted?
%p
= fa_icon 'info fw'
= t('admin.instances.totals_time_period_hint_html')
%p
= fa_icon 'info fw'
= t('admin.instances.totals_time_period_hint_html')
.dashboard
.dashboard__item
= react_admin_component :counter, measure: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_accounts_measure'), href: admin_accounts_path(origin: 'remote', by_domain: @instance.domain)
.dashboard__item
= react_admin_component :counter, measure: 'instance_statuses', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_statuses_measure')
.dashboard__item
= react_admin_component :counter, measure: 'instance_media_attachments', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_media_attachments_measure')
.dashboard__item
= react_admin_component :counter, measure: 'instance_follows', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_follows_measure')
.dashboard__item
= react_admin_component :counter, measure: 'instance_followers', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_followers_measure')
.dashboard__item
= react_admin_component :counter, measure: 'instance_reports', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_reports_measure'), href: admin_reports_path(by_target_domain: @instance.domain)
.dashboard__item
= react_admin_component :dimension, dimension: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_accounts_dimension')
.dashboard__item
= react_admin_component :dimension, dimension: 'instance_languages', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_languages_dimension')
- else
%p
= t('admin.instances.unknown_instance')
.dashboard
.dashboard__item
= react_admin_component :counter, measure: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_accounts_measure'), href: admin_accounts_path(origin: 'remote', by_domain: @instance.domain)
.dashboard__item
= react_admin_component :counter, measure: 'instance_statuses', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_statuses_measure')
.dashboard__item
= react_admin_component :counter, measure: 'instance_media_attachments', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_media_attachments_measure')
.dashboard__item
= react_admin_component :counter, measure: 'instance_follows', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_follows_measure')
.dashboard__item
= react_admin_component :counter, measure: 'instance_followers', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_followers_measure')
.dashboard__item
= react_admin_component :counter, measure: 'instance_reports', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_reports_measure'), href: admin_reports_path(by_target_domain: @instance.domain)
.dashboard__item
= react_admin_component :dimension, dimension: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_accounts_dimension')
.dashboard__item
= react_admin_component :dimension, dimension: 'instance_languages', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_languages_dimension')
%hr.spacer/
@ -66,34 +62,33 @@
- else
= link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @instance.domain), class: 'button'
- if @instance.persisted?
%hr.spacer/
%hr.spacer/
%h3= t('admin.instances.availability.title')
%h3= t('admin.instances.availability.title')
%p
= t('admin.instances.availability.description_html', count: DeliveryFailureTracker::FAILURE_DAYS_THRESHOLD)
%p
= t('admin.instances.availability.description_html', count: DeliveryFailureTracker::FAILURE_DAYS_THRESHOLD)
.availability-indicator
%ul.availability-indicator__graphic
- @instance.availability_over_days(14).each do |(date, failing)|
%li.availability-indicator__graphic__item{ class: failing ? 'negative' : 'neutral', title: l(date) }
.availability-indicator__hint
- if @instance.unavailable?
%span.negative-hint
= t('admin.instances.availability.failure_threshold_reached', date: l(@instance.unavailable_domain.created_at.to_date))
= link_to t('admin.instances.delivery.restart'), restart_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }
- elsif @instance.exhausted_deliveries_days.empty?
%span.positive-hint
= t('admin.instances.availability.no_failures_recorded')
= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }
- else
%span.negative-hint
= t('admin.instances.availability.failures_recorded', count: @instance.delivery_failure_tracker.days)
%span= link_to t('admin.instances.delivery.clear'), clear_delivery_errors_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } unless @instance.exhausted_deliveries_days.empty?
%span= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }
.availability-indicator
%ul.availability-indicator__graphic
- @instance.availability_over_days(14).each do |(date, failing)|
%li.availability-indicator__graphic__item{ class: failing ? 'negative' : 'neutral', title: l(date) }
.availability-indicator__hint
- if @instance.unavailable?
%span.negative-hint
= t('admin.instances.availability.failure_threshold_reached', date: l(@instance.unavailable_domain.created_at.to_date))
= link_to t('admin.instances.delivery.restart'), restart_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }
- elsif @instance.exhausted_deliveries_days.empty?
%span.positive-hint
= t('admin.instances.availability.no_failures_recorded')
= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }
- else
%span.negative-hint
= t('admin.instances.availability.failures_recorded', count: @instance.delivery_failure_tracker.days)
%span= link_to t('admin.instances.delivery.clear'), clear_delivery_errors_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } unless @instance.exhausted_deliveries_days.empty?
%span= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post }
- if @instance.purgeable?
%p= t('admin.instances.purge_description_html')
- if @instance.purgeable?
%p= t('admin.instances.purge_description_html')
= link_to t('admin.instances.purge'), admin_instance_path(@instance), data: { confirm: t('admin.instances.confirm_purge'), method: :delete }, class: 'button button--destructive'
= link_to t('admin.instances.purge'), admin_instance_path(@instance), data: { confirm: t('admin.instances.confirm_purge'), method: :delete }, class: 'button button--destructive'

View File

@ -5,16 +5,16 @@
- if relay.accepted?
%span.positive-hint
= fa_icon('check')
&nbsp;
= ' '
= t 'admin.relays.enabled'
- elsif relay.pending?
= fa_icon('hourglass')
&nbsp;
= ' '
= t 'admin.relays.pending'
- else
%span.negative-hint
= fa_icon('times')
&nbsp;
= ' '
= t 'admin.relays.disabled'
%td
- if relay.accepted?

View File

@ -1,6 +1,6 @@
.announcements-list__item
= link_to edit_admin_rule_path(rule), class: 'announcements-list__item__title' do
#{rule_counter + 1}.
= "#{rule_counter + 1}."
= truncate(rule.text)
.announcements-list__item__action-bar

View File

@ -23,7 +23,7 @@
%td= update.version
%td= t("admin.software_updates.types.#{update.type}")
- if update.urgent?
%td.critical= t('admin.software_updates.critical_update')
%td.critical= t("admin.software_updates.critical_update")
- else
%td
%td= table_link_to 'link', t('admin.software_updates.release_notes'), update.release_notes

View File

@ -1,7 +1,7 @@
- content_for :page_title do
= t('admin.statuses.title')
\-
@#{@account.pretty_acct}
= "@#{@account.pretty_acct}"
.filters
.filter-subset

View File

@ -35,6 +35,7 @@
%span= t('admin.trends.tags.not_trendable')
= fa_icon 'lock fw'
= link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.listable? ? 'positive' : 'negative'] do
- if @tag.listable?
%span= t('admin.trends.tags.listable')

View File

@ -10,7 +10,7 @@
%br/
= link_to tag_path(tag), target: '_blank', rel: 'noopener noreferrer' do
= link_to tag_path(tag), target: '_blank' do
= t('admin.trends.tags.used_by_over_week', count: tag.history.reduce(0) { |sum, day| sum + day.accounts })
- if tag.trendable? && (rank = Trends.tags.rank(tag.id))

View File

@ -1,29 +1,13 @@
- content_for :page_title do
= t('auth.resend_confirmation')
- if resource.errors.of_kind?(:email, :already_confirmed)
.simple_form
= render 'auth/shared/progress', stage: resource.approved? ? 'completed' : 'confirmed'
= simple_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
= render 'shared/error_messages', object: resource
- if resource.approved?
%h1.title= t('auth.confirmations.welcome_title', name: resource.account.username)
%p.lead= t('auth.confirmations.registration_complete', domain: site_hostname)
- if resource.created_by_application && redirect_to_app?
- app = resource.created_by_application
%p.lead= t('auth.confirmations.redirect_to_app_html', app_name: app.name, clicking_this_link: link_to(t('auth.confirmations.clicking_this_link'), app.confirmation_redirect_uri))
- else
%p.lead= t('auth.confirmations.proceed_to_login_html', login_link: link_to_login(t('auth.confirmations.login_link')))
- else
%h1.title= t('auth.confirmations.awaiting_review_title')
%p.lead= t('auth.confirmations.awaiting_review', domain: site_hostname)
- else
= simple_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
= render 'shared/error_messages', object: resource
.fields-group
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, readonly: current_user.present?, hint: current_user.present? && t('auth.confirmations.wrong_email_hint')
.fields-group
= f.input :email, autofocus: true, wrapper: :with_label, label: t('simple_form.labels.defaults.email'), input_html: { 'aria-label': t('simple_form.labels.defaults.email') }, readonly: current_user.present?, hint: current_user.present? && t('auth.confirmations.wrong_email_hint')
.actions
= f.button :button, t('auth.resend_confirmation'), type: :submit
.actions
= f.button :button, t('auth.resend_confirmation'), type: :submit
.form-footer= render 'auth/shared/links'

View File

@ -2,7 +2,7 @@
%td
%span{ title: session.user_agent }<
= fa_icon "#{session_device_icon(session)} fw", 'aria-label': session_device_icon(session)
&nbsp;
= ' '
= t 'sessions.description', browser: t("sessions.browsers.#{session.browser}", default: session.browser.to_s), platform: t("sessions.platforms.#{session.platform}", default: session.platform.to_s)
%td
%samp= session.ip

View File

@ -1,11 +1,7 @@
- content_for :page_title do
= t('settings.account_settings')
- if self_destruct?
.flash-message.warning
= t('auth.status.self_destruct', domain: ENV.fetch('LOCAL_DOMAIN'))
- else
= render partial: 'status', locals: { user: @user, strikes: @strikes }
= render partial: 'status', locals: { user: @user, strikes: @strikes }
%h3= t('auth.security')
@ -36,7 +32,7 @@
= render partial: 'sessions', object: @sessions
- unless current_account.suspended? || self_destruct?
- unless current_account.suspended?
%hr.spacer/
%h3= t('auth.migrate_account')

View File

@ -33,6 +33,7 @@
= f.simple_fields_for :invite_request, resource.invite_request || resource.build_invite_request do |invite_request_fields|
= invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: Setting.require_invite_text, label: false, hint: false
= hidden_field_tag :accept, params[:accept]
= f.input :invite_code, as: :hidden

View File

@ -1,4 +1,4 @@
- progress_index = { rules: 0, details: 1, confirm: 2, confirmed: 3, completed: 4 }[stage.to_sym]
- progress_index = { rules: 0, details: 1, confirm: 2 }[stage.to_sym]
%ol.progress-tracker
%li{ class: progress_index.positive? ? 'completed' : 'active' }
@ -20,8 +20,6 @@
.label= t('auth.progress.confirm')
- if approved_registrations?
%li.separator{ class: progress_index > 2 ? 'completed' : nil }
%li{ class: [progress_index > 3 && 'completed', progress_index == 3 && 'active'] }
%li
.circle
- if progress_index > 3
= check_icon
.label= t('auth.progress.review')

View File

@ -10,13 +10,13 @@
%p.hint
%span.positive-hint
= fa_icon 'check'
&nbsp;
= ' '
= t 'disputes.strikes.appeal_approved'
- elsif @appeal.persisted? && @appeal.rejected?
%p.hint
%span.negative-hint
= fa_icon 'times'
&nbsp;
= ' '
= t 'disputes.strikes.appeal_rejected'
.report-header

View File

@ -1,20 +0,0 @@
- content_for :page_title do
= t('self_destruct.title')
.simple_form
%h1.title= t('self_destruct.title')
%p.lead= t('self_destruct.lead_html', domain: ENV.fetch('LOCAL_DOMAIN'))
.form-footer
%ul.no-list
- if user_signed_in?
%li= link_to t('settings.account_settings'), edit_user_registration_path
- else
- if controller_name != 'sessions'
%li= link_to_login t('auth.login')
- if controller_name != 'passwords' && controller_name != 'registrations'
%li= link_to t('auth.forgot_password'), new_user_password_path
- if user_signed_in?
%li= link_to t('auth.logout'), destroy_user_session_path, data: { method: :delete }

View File

@ -1,7 +1,7 @@
!!!
%html{ lang: I18n.locale }
%head
%meta{ 'content' => 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type' }/
%meta{ content: 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type' }/
%meta{ charset: 'utf-8' }/
%title= safe_join([yield(:page_title), Setting.default_settings['site_title']], ' - ')
%meta{ content: 'width=device-width,initial-scale=1', name: 'viewport' }/

View File

@ -23,7 +23,7 @@
= image_tag full_asset_url(status.account.avatar.url), alt: ''
%td{ align: 'left' }
%bdi= display_name(status.account)
@#{status.account.pretty_acct}
= "@#{status.account.pretty_acct}"
- if status.spoiler_text?
.auto-dir

View File

@ -1,3 +1,3 @@
.form-container
.flash-message
.flash-message#error_explanation
= @pre_auth.error_response.body[:error_description]

View File

@ -24,14 +24,14 @@
%th= t('admin.accounts.followers')
%td= number_with_delimiter @export.total_followers
%td
%tr
%th= t('exports.mutes')
%td= number_with_delimiter @export.total_mutes
%td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv)
%tr
%th= t('exports.blocks')
%td= number_with_delimiter @export.total_blocks
%td= table_link_to 'download', t('exports.csv'), settings_exports_blocks_path(format: :csv)
%tr
%th= t('exports.mutes')
%td= number_with_delimiter @export.total_mutes
%td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv)
%tr
%th= t('exports.domain_blocks')
%td= number_with_delimiter @export.total_domain_blocks

View File

@ -7,7 +7,7 @@
%p.hint
%span.positive-hint
= fa_icon 'check'
&nbsp;
= ' '
= t 'two_factor_authentication.enabled'
.table-wrapper

View File

@ -1,5 +1,5 @@
- if object.errors.any?
.flash-message.alert
.flash-message.alert#error_explanation
%strong= t('generic.validation_errors', count: object.errors.count)
- object.errors[:base].each do |error|
.flash-message.alert

View File

@ -62,18 +62,18 @@
- else
= fa_icon('reply-all')
%span.detailed-status__reblogs>= friendly_number_to_human status.replies_count
&nbsp;
= ' '
·
- if status.public_visibility? || status.unlisted_visibility?
%span.detailed-status__link
= fa_icon('retweet')
%span.detailed-status__reblogs>= friendly_number_to_human status.reblogs_count
&nbsp;
= ' '
·
%span.detailed-status__link
= fa_icon('star')
%span.detailed-status__favorites>= friendly_number_to_human status.favourites_count
&nbsp;
= ' '
- if user_signed_in?
·

View File

@ -11,7 +11,7 @@
- percent = total_votes_count.positive? ? 100 * option.votes_count / total_votes_count : 0
%label.poll__option><
%span.poll__number><
#{percent.round}%
= "#{percent.round}%"
%span.poll__option__text
= prerender_custom_emojis(h(option.title), status.emojis)
- if own_votes.include?(index)

View File

@ -23,7 +23,7 @@
%span.display-name
%bdi
%strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: prefers_autoplay?)
&nbsp;
= ' '
%span.display-name__account
= acct(status.account)
= fa_icon('lock') if status.account.locked?

View File

@ -5,6 +5,7 @@
= button_tag t('generic.save_changes'), class: 'button', form: 'edit_policy'
= simple_form_for @policy, url: statuses_cleanup_path, method: :put, html: { id: 'edit_policy' } do |f|
.fields-row
.fields-row__column.fields-row__column-6.fields-group
= f.input :enabled, as: :boolean, wrapper: :with_label, label: t('statuses_cleanup.enabled'), hint: t('statuses_cleanup.enabled_hint')

View File

@ -41,10 +41,10 @@
%tr
%td.column-cell.text-center
%p
%strong #{t('sessions.ip')}:
%strong= "#{t('sessions.ip')}:"
= @remote_ip
%br/
%strong #{t('sessions.browser')}:
%strong= "#{t('sessions.browser')}:"
%span{ title: @user_agent }= t 'sessions.description', browser: t("sessions.browsers.#{@detection.id}", default: @detection.id.to_s), platform: t("sessions.platforms.#{@detection.platform.id}", default: @detection.platform.id.to_s)
%br/
= l(@timestamp.in_time_zone(@resource.time_zone.presence), format: :with_time_zone)

View File

@ -20,7 +20,7 @@
= image_tag full_pack_url('media/images/mailer/icon_lock_open.png'), alt: ''
%h1= t 'devise.mailer.webauthn_credential.added.title'
%p.lead #{t('devise.mailer.webauthn_credential.added.explanation')}:
%p.lead= "#{t('devise.mailer.webauthn_credential.added.explanation')}:"
%p.lead= @webauthn_credential.nickname
%table.email-table{ cellspacing: 0, cellpadding: 0 }

View File

@ -20,7 +20,7 @@
= image_tag full_pack_url('media/images/mailer/icon_lock_open.png'), alt: ''
%h1= t 'devise.mailer.webauthn_credential.deleted.title'
%p.lead #{t('devise.mailer.webauthn_credential.deleted.explanation')}:
%p.lead= "#{t('devise.mailer.webauthn_credential.deleted.explanation')}:"
%p.lead= @webauthn_credential.nickname
%table.email-table{ cellspacing: 0, cellpadding: 0 }

View File

@ -41,7 +41,7 @@
%table.input{ align: 'center', cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td @#{@resource.account.username}@#{@instance}
%td= "@#{@resource.account.username}@#{@instance}"
.col-3
%table.column{ cellspacing: 0, cellpadding: 0 }
%tbody

View File

@ -23,10 +23,9 @@ class ActivityPub::DeliveryWorker
HEADERS = { 'Content-Type' => 'application/activity+json' }.freeze
def perform(json, source_account_id, inbox_url, options = {})
return unless DeliveryFailureTracker.available?(inbox_url)
@options = options.with_indifferent_access
return unless @options[:bypass_availability] || DeliveryFailureTracker.available?(inbox_url)
@json = json
@source_account = Account.find(source_account_id)
@inbox_url = inbox_url

View File

@ -1,72 +0,0 @@
# frozen_string_literal: true
class Scheduler::SelfDestructScheduler
include Sidekiq::Worker
include SelfDestructHelper
MAX_ENQUEUED = 10_000
MAX_REDIS_MEM_USAGE = 0.5
MAX_ACCOUNT_DELETIONS_PER_JOB = 50
sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 1.day.to_i
def perform
return unless self_destruct?
return if sidekiq_overwhelmed?
delete_accounts!
end
private
def sidekiq_overwhelmed?
redis_mem_info = Sidekiq.redis_info
Sidekiq::Stats.new.enqueued > MAX_ENQUEUED || redis_mem_info['used_memory'].to_f > redis_mem_info['total_system_memory'].to_f * MAX_REDIS_MEM_USAGE
end
def delete_accounts!
# We currently do not distinguish between deleted accounts and suspended
# accounts, and we do not want to remove the records in this scheduler, as
# we still rely on it for account delivery and don't want to perform
# needless work when the database can be outright dropped after the
# self-destruct.
# Deleted accounts are suspended accounts that do not have a pending
# deletion request.
# This targets accounts that have not been deleted nor marked for deletion yet
Account.local.without_suspended.reorder(id: :asc).take(MAX_ACCOUNT_DELETIONS_PER_JOB).each do |account|
delete_account!(account)
end
return if sidekiq_overwhelmed?
# This targets accounts that have been marked for deletion but have not been
# deleted yet
Account.local.suspended.joins(:deletion_request).take(MAX_ACCOUNT_DELETIONS_PER_JOB).each do |account|
delete_account!(account)
account.deletion_request&.destroy
end
end
def inboxes
@inboxes ||= Account.inboxes
end
def delete_account!(account)
payload = ActiveModelSerializers::SerializableResource.new(
account,
serializer: ActivityPub::DeleteActorSerializer,
adapter: ActivityPub::Adapter
).as_json
json = Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(account))
ActivityPub::DeliveryWorker.push_bulk(inboxes, limit: 1_000) do |inbox_url|
[json, account.id, inbox_url]
end
# Do not call `Account#suspend!` because we don't want to issue a deletion request
account.update!(suspended_at: Time.now.utc, suspension_origin: :local)
end
end

View File

@ -71,20 +71,15 @@ module Mastodon
# https://github.com/mastodon/mastodon/pull/24241#discussion_r1162890242
config.active_support.cache_format_version = 6.1
# Please, add to the `ignore` list any other `lib` subdirectories that do
# not contain `.rb` files, or that should not be reloaded or eager loaded.
# Common ones are `templates`, `generators`, or `middleware`, for example.
# config.autoload_lib(ignore: %w(assets tasks templates generators))
# TODO: We should enable this eventually, but for now there are many things
# in the wrong path from the perspective of zeitwerk.
config.add_autoload_paths_to_load_path = false
# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
# in config/environments, which are processed later.
#
# config.time_zone = "Central Time (US & Canada)"
# config.eager_load_paths << Rails.root.join("extras")
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
# All translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
@ -201,19 +196,15 @@ module Mastodon
config.active_job.queue_adapter = :sidekiq
config.action_mailer.deliver_later_queue_name = 'mailers'
config.action_mailer.preview_paths << Rails.root.join('spec', 'mailers', 'previews')
config.action_mailer.preview_path = Rails.root.join('spec', 'mailers', 'previews')
# We use our own middleware for this
config.public_file_server.enabled = false
config.middleware.use PublicFileServerMiddleware if Rails.env.local? || ENV['RAILS_SERVE_STATIC_FILES'] == 'true' # rubocop:disable Rails/UnknownEnv
config.middleware.use PublicFileServerMiddleware if Rails.env.development? || Rails.env.test? || ENV['RAILS_SERVE_STATIC_FILES'] == 'true'
config.middleware.use Rack::Attack
config.middleware.use Mastodon::RackMiddleware
initializer :deprecator do |app|
app.deprecators[:mastodon] = ActiveSupport::Deprecation.new('4.3', 'mastodon/mastodon')
end
config.to_prepare do
Doorkeeper::AuthorizationsController.layout 'modal'
Doorkeeper::AuthorizedApplicationsController.layout 'admin'

View File

@ -68,9 +68,6 @@ Rails.application.configure do
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true
# Highlight code that enqueued background job in logs.
config.active_job.verbose_enqueue_logs = true
# Debug mode disables concatenation and preprocessing of assets.
config.assets.debug = true
@ -101,9 +98,6 @@ Rails.application.configure do
# We provide a default secret for the development environment here.
# This value should not be used in production environments!
config.x.otp_secret = ENV.fetch('OTP_SECRET', '1fc2b87989afa6351912abeebe31ffc5c476ead9bf8b3d74cbc4a302c7b69a45b40b1bbef3506ddad73e942e15ed5ca4b402bf9a66423626051104f4b5f05109')
# Raise error when a before_action's only/except options reference missing actions
config.action_controller.raise_on_missing_callback_actions = true
end
Redis.raise_deprecations = true

View File

@ -6,7 +6,7 @@ Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.enable_reloading = false
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
@ -19,8 +19,8 @@ Rails.application.configure do
config.action_controller.perform_caching = true
config.action_controller.asset_host = ENV['CDN_HOST'] if ENV['CDN_HOST'].present?
# Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment
# key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files).
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
# config.require_master_key = true
# Compress CSS using a preprocessor.
@ -48,9 +48,10 @@ Rails.application.configure do
}
}
# Info include generic and useful information about system operation, but avoids logging too much
# information to avoid inadvertent exposure of personally identifiable information (PII). If you
# want to log everything, set the level to "debug".
# Include generic and useful information about system operation, but avoid logging too much
# information to avoid inadvertent exposure of personally identifiable information (PII).
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info').to_sym
# Prepend all log lines with the following tags.
@ -71,13 +72,10 @@ Rails.application.configure do
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# English when a translation cannot be found).
# This setting would typically be `true` to use the `I18n.default_locale`.
# Some locales are missing translation entries and would have errors:
# https://github.com/mastodon/mastodon/pull/24727
config.i18n.fallbacks = [:en]
# Don't log any deprecations.
config.active_support.report_deprecations = false
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
@ -95,10 +93,10 @@ Rails.application.configure do
# require "syslog/logger"
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name")
# Log to STDOUT by default
config.logger = ActiveSupport::Logger.new(STDOUT)
.tap { |logger| logger.formatter = ::Logger::Formatter.new }
.then { |logger| ActiveSupport::TaggedLogging.new(logger) }
ActiveSupport::Logger.new(STDOUT).tap do |logger|
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
@ -158,12 +156,4 @@ Rails.application.configure do
}
config.x.otp_secret = ENV.fetch('OTP_SECRET')
# Enable DNS rebinding protection and other `Host` header attacks.
# config.hosts = [
# "example.com", # Allow requests from example.com
# /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
# ]
# Skip DNS rebinding protection for the default health check endpoint.
# config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
end

View File

@ -10,13 +10,12 @@ require 'active_support/core_ext/integer/time'
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# While tests run files are not watched, reloading is not necessary.
config.enable_reloading = false
# Turn false under Spring and add config.action_view.cache_template_loading = true.
config.cache_classes = true
# Eager loading loads your entire application. When running a single test locally,
# this is usually not necessary, and can slow down your test suite. However, it's
# recommended that you enable it in continuous integration systems to ensure eager
# loading is working properly before deploying your code.
# Eager loading loads your whole application. When running a single test locally,
# this probably isn't necessary. It's a good idea to do in a continuous integration
# system, or in some way before deploying your code.
config.eager_load = ENV['CI'].present?
config.assets_digest = false
@ -27,7 +26,7 @@ Rails.application.configure do
config.cache_store = :memory_store
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = :rescuable
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
@ -74,14 +73,11 @@ Rails.application.configure do
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
# Raise error when a before_action's only/except options reference missing actions
config.action_controller.raise_on_missing_callback_actions = true
end
Paperclip::Attachment.default_options[:path] = Rails.root.join('spec', 'test_files', ':class', ':id_partition', ':style.:extension')
# Enable fake_data for PAM
# set fake_data for pam, don't do real calls, just use fake data
if ENV['PAM_ENABLED'] == 'true'
Rpam2.fake_data =
{

View File

@ -64,7 +64,6 @@ ignore_unused:
- 'statuses.attached.*'
- 'move_handler.carry_{mutes,blocks}_over_text'
- 'admin_mailer.*.subject'
- 'user_mailer.*.subject'
- 'notification_mailer.*'
- 'imports.overwrite_preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html'
- 'imports.preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html'

View File

@ -1,16 +1,23 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Define an application-wide content security policy
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
# Define an application-wide content security policy.
# See the Securing Rails Applications Guide for more information:
# https://guides.rubyonrails.org/security.html#content-security-policy-header
def host_to_url(str)
"http#{Rails.configuration.x.use_https ? 's' : ''}://#{str.split('/').first}" if str.present?
end
require_relative '../../app/lib/content_security_policy'
base_host = Rails.configuration.x.web_domain
policy = ContentSecurityPolicy.new
assets_host = policy.assets_host
media_host = policy.media_host
assets_host = Rails.configuration.action_controller.asset_host
assets_host ||= host_to_url(base_host)
media_host = host_to_url(ENV['S3_ALIAS_HOST'])
media_host ||= host_to_url(ENV['S3_CLOUDFRONT_HOST'])
media_host ||= host_to_url(ENV['AZURE_ALIAS_HOST'])
media_host ||= host_to_url(ENV['S3_HOSTNAME']) if ENV['S3_ENABLED'] == 'true'
media_host ||= assets_host
def sso_host
return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true'

View File

@ -3,7 +3,7 @@
# Be sure to restart your server when you modify this file.
# Avoid CORS issues when API is called from the frontend app.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin Ajax requests.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.
# Read more: https://github.com/cyu/rack-cors

View File

@ -2,9 +2,9 @@
# Be sure to restart your server when you modify this file.
# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file.
# Use this to limit dissemination of sensitive information.
# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors.
# Configure parameters to be filtered from the log file. Use this to limit dissemination of
# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported
# notations and behaviors.
Rails.application.config.filter_parameters += [
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
]

View File

@ -6,9 +6,9 @@
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, "\\1en"
# inflect.singular /^(ox)en/i, "\\1"
# inflect.irregular "person", "people"
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
@ -32,8 +32,3 @@ ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.singular 'data', 'data'
end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.acronym "RESTful"
# end

View File

@ -1,225 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
#
# This file eases your Rails 7.1 framework defaults upgrade.
#
# Uncomment each configuration one by one to switch to the new default.
# Once your application is ready to run with all new defaults, you can remove
# this file and set the `config.load_defaults` to `7.1`.
#
# Read the Guide for Upgrading Ruby on Rails for more info on each option.
# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html
# No longer add autoloaded paths into `$LOAD_PATH`. This means that you won't be able
# to manually require files that are managed by the autoloader, which you shouldn't do anyway.
# This will reduce the size of the load path, making `require` faster if you don't use bootsnap, or reduce the size
# of the bootsnap cache if you use it.
Rails.application.config.add_autoload_paths_to_load_path = false
# Remove the default X-Download-Options headers since it is used only by Internet Explorer.
# If you need to support Internet Explorer, add back `"X-Download-Options" => "noopen"`.
# Rails.application.config.action_dispatch.default_headers = {
# "X-Frame-Options" => "SAMEORIGIN",
# "X-XSS-Protection" => "0",
# "X-Content-Type-Options" => "nosniff",
# "X-Permitted-Cross-Domain-Policies" => "none",
# "Referrer-Policy" => "strict-origin-when-cross-origin"
# }
# Do not treat an `ActionController::Parameters` instance
# as equal to an equivalent `Hash` by default.
# Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false
# Active Record Encryption now uses SHA-256 as its hash digest algorithm. Important: If you have
# data encrypted with previous Rails versions, there are two scenarios to consider:
#
# 1. If you have +config.active_support.key_generator_hash_digest_class+ configured as SHA1 (the default
# before Rails 7.0), you need to configure SHA-1 for Active Record Encryption too:
# Rails.application.config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA1
# 2. If you have +config.active_support.key_generator_hash_digest_class+ configured as SHA256 (the new default
# in 7.0), then you need to configure SHA-256 for Active Record Encryption:
# Rails.application.config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA256
#
# If you don't currently have data encrypted with Active Record encryption, you can disable this setting to
# configure the default behavior starting 7.1+:
# Rails.application.config.active_record.encryption.support_sha1_for_non_deterministic_encryption = false
# No longer run after_commit callbacks on the first of multiple Active Record
# instances to save changes to the same database row within a transaction.
# Instead, run these callbacks on the instance most likely to have internal
# state which matches what was committed to the database, typically the last
# instance to save.
# Rails.application.config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction = false
# Configures SQLite with a strict strings mode, which disables double-quoted string literals.
#
# SQLite has some quirks around double-quoted string literals.
# It first tries to consider double-quoted strings as identifier names, but if they don't exist
# it then considers them as string literals. Because of this, typos can silently go unnoticed.
# For example, it is possible to create an index for a non existing column.
# See https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted for more details.
# Rails.application.config.active_record.sqlite3_adapter_strict_strings_by_default = true
# Disable deprecated singular associations names
# Rails.application.config.active_record.allow_deprecated_singular_associations_name = false
# Enable the Active Job `BigDecimal` argument serializer, which guarantees
# roundtripping. Without this serializer, some queue adapters may serialize
# `BigDecimal` arguments as simple (non-roundtrippable) strings.
#
# When deploying an application with multiple replicas, old (pre-Rails 7.1)
# replicas will not be able to deserialize `BigDecimal` arguments from this
# serializer. Therefore, this setting should only be enabled after all replicas
# have been successfully upgraded to Rails 7.1.
# Rails.application.config.active_job.use_big_decimal_serializer = true
# Specify if an `ArgumentError` should be raised if `Rails.cache` `fetch` or
# `write` are given an invalid `expires_at` or `expires_in` time.
# Options are `true`, and `false`. If `false`, the exception will be reported
# as `handled` and logged instead.
# Rails.application.config.active_support.raise_on_invalid_cache_expiration_time = true
# Specify whether Query Logs will format tags using the SQLCommenter format
# (https://open-telemetry.github.io/opentelemetry-sqlcommenter/), or using the legacy format.
# Options are `:legacy` and `:sqlcommenter`.
# Rails.application.config.active_record.query_log_tags_format = :sqlcommenter
# Specify the default serializer used by `MessageEncryptor` and `MessageVerifier`
# instances.
#
# The legacy default is `:marshal`, which is a potential vector for
# deserialization attacks in cases where a message signing secret has been
# leaked.
#
# In Rails 7.1, the new default is `:json_allow_marshal` which serializes and
# deserializes with `ActiveSupport::JSON`, but can fall back to deserializing
# with `Marshal` so that legacy messages can still be read.
#
# In Rails 7.2, the default will become `:json` which serializes and
# deserializes with `ActiveSupport::JSON` only.
#
# Alternatively, you can choose `:message_pack` or `:message_pack_allow_marshal`,
# which serialize with `ActiveSupport::MessagePack`. `ActiveSupport::MessagePack`
# can roundtrip some Ruby types that are not supported by JSON, and may provide
# improved performance, but it requires the `msgpack` gem.
#
# For more information, see
# https://guides.rubyonrails.org/v7.1/configuring.html#config-active-support-message-serializer
#
# If you are performing a rolling deploy of a Rails 7.1 upgrade, wherein servers
# that have not yet been upgraded must be able to read messages from upgraded
# servers, first deploy without changing the serializer, then set the serializer
# in a subsequent deploy.
# Rails.application.config.active_support.message_serializer = :json_allow_marshal
# Enable a performance optimization that serializes message data and metadata
# together. This changes the message format, so messages serialized this way
# cannot be read by older versions of Rails. However, messages that use the old
# format can still be read, regardless of whether this optimization is enabled.
#
# To perform a rolling deploy of a Rails 7.1 upgrade, wherein servers that have
# not yet been upgraded must be able to read messages from upgraded servers,
# leave this optimization off on the first deploy, then enable it on a
# subsequent deploy.
# Rails.application.config.active_support.use_message_serializer_for_metadata = true
# Set the maximum size for Rails log files.
#
# `config.load_defaults 7.1` does not set this value for environments other than
# development and test.
#
# if Rails.env.local?
# Rails.application.config.log_file_size = 100 * 1024 * 1024
# end
# Enable raising on assignment to attr_readonly attributes. The previous
# behavior would allow assignment but silently not persist changes to the
# database.
# Rails.application.config.active_record.raise_on_assign_to_attr_readonly = true
# Enable validating only parent-related columns for presence when the parent is mandatory.
# The previous behavior was to validate the presence of the parent record, which performed an extra query
# to get the parent every time the child record was updated, even when parent has not changed.
# Rails.application.config.active_record.belongs_to_required_validates_foreign_key = false
# Enable precompilation of `config.filter_parameters`. Precompilation can
# improve filtering performance, depending on the quantity and types of filters.
# Rails.application.config.precompile_filter_parameters = true
# Enable before_committed! callbacks on all enrolled records in a transaction.
# The previous behavior was to only run the callbacks on the first copy of a record
# if there were multiple copies of the same record enrolled in the transaction.
# Rails.application.config.active_record.before_committed_on_all_records = true
# Disable automatic column serialization into YAML.
# To keep the historic behavior, you can set it to `YAML`, however it is
# recommended to explicitly define the serialization method for each column
# rather than to rely on a global default.
# Rails.application.config.active_record.default_column_serializer = nil
# Enable a performance optimization that serializes Active Record models
# in a faster and more compact way.
#
# To perform a rolling deploy of a Rails 7.1 upgrade, wherein servers that have
# not yet been upgraded must be able to read caches from upgraded servers,
# leave this optimization off on the first deploy, then enable it on a
# subsequent deploy.
# Rails.application.config.active_record.marshalling_format_version = 7.1
# Run `after_commit` and `after_*_commit` callbacks in the order they are defined in a model.
# This matches the behaviour of all other callbacks.
# In previous versions of Rails, they ran in the inverse order.
# Rails.application.config.active_record.run_after_transaction_callbacks_in_order_defined = true
# Whether a `transaction` block is committed or rolled back when exited via `return`, `break` or `throw`.
#
# Rails.application.config.active_record.commit_transaction_on_non_local_return = true
# Controls when to generate a value for <tt>has_secure_token</tt> declarations.
#
# Rails.application.config.active_record.generate_secure_token_on = :initialize
# ** Please read carefully, this must be configured in config/application.rb **
# Change the format of the cache entry.
# Changing this default means that all new cache entries added to the cache
# will have a different format that is not supported by Rails 7.0
# applications.
# Only change this value after your application is fully deployed to Rails 7.1
# and you have no plans to rollback.
# When you're ready to change format, add this to `config/application.rb` (NOT
# this file):
# config.active_support.cache_format_version = 7.1
# Configure Action View to use HTML5 standards-compliant sanitizers when they are supported on your
# platform.
#
# `Rails::HTML::Sanitizer.best_supported_vendor` will cause Action View to use HTML5-compliant
# sanitizers if they are supported, else fall back to HTML4 sanitizers.
#
# In previous versions of Rails, Action View always used `Rails::HTML4::Sanitizer` as its vendor.
#
# Rails.application.config.action_view.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor
# Configure Action Text to use an HTML5 standards-compliant sanitizer when it is supported on your
# platform.
#
# `Rails::HTML::Sanitizer.best_supported_vendor` will cause Action Text to use HTML5-compliant
# sanitizers if they are supported, else fall back to HTML4 sanitizers.
#
# In previous versions of Rails, Action Text always used `Rails::HTML4::Sanitizer` as its vendor.
#
# Rails.application.config.action_text.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor
# Configure the log level used by the DebugExceptions middleware when logging
# uncaught exceptions during requests
# Rails.application.config.action_dispatch.debug_exception_log_level = :error
# Configure the test helpers in Action View, Action Dispatch, and rails-dom-testing to use HTML5
# parsers.
#
# Nokogiri::HTML5 isn't supported on JRuby, so JRuby applications must set this to :html4.
#
# In previous versions of Rails, these test helpers always used an HTML4 parser.
#
# Rails.application.config.dom_testing_default_html_version = :html5

View File

@ -1,15 +1,12 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Define an application-wide HTTP permissions policy. For further
# information see: https://developers.google.com/web/updates/2018/06/feature-policy
# Rails.application.config.permissions_policy do |policy|
# policy.camera :none
# policy.gyroscope :none
# policy.microphone :none
# policy.usb :none
# policy.fullscreen :self
# policy.payment :self, "https://secure.example.com"
# information see https://developers.google.com/web/updates/2018/06/feature-policy
#
# Rails.application.config.permissions_policy do |f|
# f.camera :none
# f.gyroscope :none
# f.microphone :none
# f.usb :none
# f.fullscreen :self
# f.payment :self, "https://secure.example.com"
# end

View File

@ -17,18 +17,6 @@ Sidekiq.configure_server do |config|
chain.add SidekiqUniqueJobs::Middleware::Client
end
config.on(:startup) do
if SelfDestructHelper.self_destruct?
Sidekiq.schedule = {
'self_destruct_scheduler' => {
'interval' => ['1m'],
'class' => 'Scheduler::SelfDestructScheduler',
'queue' => 'scheduler',
},
}
end
end
SidekiqUniqueJobs::Server.configure(config)
end

View File

@ -1,4 +1,4 @@
# frozen_string_literal: true
StrongMigrations.start_after = 2017_09_24_022025
StrongMigrations.target_version = 12
StrongMigrations.target_version = 10

View File

@ -9,7 +9,7 @@ he:
agreement: הסכם שירות
email: כתובת דוא"ל
locale: הגדרות אזוריות
password: סיסמה
password: סיסמא
user/account:
username: שם משתמש/ת
user/invite_request:

View File

@ -556,7 +556,6 @@ cs:
total_reported: Hlášení o nich
total_storage: Mediální přílohy
totals_time_period_hint_html: Níže zobrazené součty zahrnují data za celou dobu.
unknown_instance: Na tomto serveru momentálně neexistuje žádný záznam o této doméně.
invites:
deactivate_all: Deaktivovat vše
filter:
@ -1135,7 +1134,6 @@ cs:
functional: Váš účet je plně funkční.
pending: Vaše žádost čeká na posouzení naším personálem. To může nějakou dobu trvat. Pokud bude váš požadavek schválen, obdržíte e-mail.
redirecting_to: Váš účet je neaktivní, protože je právě přesměrován na účet %{acct}.
self_destruct: Protože %{domain} končí, budete mít k účtu jen omezený přístup.
view_strikes: Zobrazit minulé prohřešky vašeho účtu
too_fast: Formulář byl odeslán příliš rychle, zkuste to znovu.
use_security_key: Použít bezpečnostní klíč
@ -1587,9 +1585,6 @@ cs:
over_daily_limit: Pro dnešek jste překročili limit %{limit} naplánovaných příspěvků
over_total_limit: Překročili jste limit %{limit} naplánovaných příspěvků
too_soon: Plánované datum musí být v budoucnosti
self_destruct:
lead_html: "<strong>%{domain}</strong> bohužel končí nadobro. Pokud jste tam měli účet, nebudete jej moci dále používat, ale stále si můžete vyžádat zálohu vašich dat."
title: Tento server končí
sessions:
activity: Nejnovější aktivita
browser: Prohlížeč

View File

@ -578,7 +578,6 @@ cy:
total_reported: Adroddiadau amdanyn nhw
total_storage: Atodiadau cyfryngau
totals_time_period_hint_html: Mae'r cyfansymiau sy'n cael eu dangos isod yn cynnwys data am y cyfnod cyfan.
unknown_instance: Nid oes cofnod o'r parth hwn ar y gweinydd hwn ar hyn o bryd.
invites:
deactivate_all: Dadweithredu popeth
filter:
@ -1174,7 +1173,6 @@ cy:
functional: Mae eich cyfrif nawr yn weithredol.
pending: Mae'ch cais yn aros i gael ei adolygu gan ein staff. Gall hyn gymryd cryn amser. Byddwch yn derbyn e-bost os caiff eich cais ei gymeradwyo.
redirecting_to: Mae eich cyfrif yn anweithredol oherwydd ei fod ar hyn o bryd yn ailgyfeirio i %{acct}.
self_destruct: Gab fod parth %{domain} yn cau, dim ond mynediad cyfyngedig fyddwch yn ei gael i'ch cyfrif.
view_strikes: Gweld rybuddion y gorffennol yn erbyn eich cyfrif
too_fast: Cafodd y ffurflen ei chyflwyno'n rhy gyflym, ceisiwch eto.
use_security_key: Defnyddiwch allwedd diogelwch
@ -1676,9 +1674,6 @@ cy:
over_daily_limit: Rydych wedi mynd dros y terfyn o %{limit} postiad a drefnwyd ar gyfer heddiw
over_total_limit: Rydych wedi mynd dros y terfyn o %{limit} postiad a drefnwyd
too_soon: Rhaid i'r dyddiad a drefnwyd fod yn y dyfodol
self_destruct:
lead_html: Yn anffodus mae <strong>%{domain}</strong> yn cau'n barhaol. Os oedd gennych gyfrif yno, ni fydd modd i chi barhau i'w ddefnyddio, ond mae dal modd gofyn i gael copi wrth gefn o'ch data.
title: Mae'r gweinydd hwn yn cau
sessions:
activity: Gweithgaredd ddiwethaf
browser: Porwr

View File

@ -534,7 +534,6 @@ da:
total_reported: Anmeldelser om dem
total_storage: Medievedhæftninger
totals_time_period_hint_html: Nedenfor viste totaler omfatter data for alle tidsperioder.
unknown_instance: Der er i pt. ingen post for dette domæne på denne server.
invites:
deactivate_all: Deaktivér alle
filter:
@ -1041,14 +1040,6 @@ da:
hint_html: Bare en ting mere! Vi er nødt til at bekræfte, at du er et menneske (dette er for at vi kan holde spam ude!). Løs CAPTCHA'en nedenfor og klik på "Fortsæt".
title: Sikkerhedstjek
confirmations:
awaiting_review: E-mailadressen er bekræftet! %{domain}-personalet gennemgår nu registreringen. En e-mail fremsendes, såfremt din konto godkendes!
awaiting_review_title: Registreringen er ved at blive gennemgået
clicking_this_link: klikke på dette link
login_link: log ind
proceed_to_login_html: Der kan nu fortsættes til %{login_link}.
redirect_to_app_html: En omdirigering til <strong>%{app_name}</strong>-appen burde være sket. Er det ikke tilfældet, prøv da %{clicking_this_link} eller returnér manuelt til appen.
registration_complete: Registreringen på %{domain} er nu fuldført!
welcome_title: Velkommen %{name}!
wrong_email_hint: Er denne e-mailadresse ikke korrekt, kan den ændres i kontoindstillinger.
delete_account: Slet konto
delete_account_html: Ønsker du at slette din konto, kan du <a href="%{path}">gøre dette hér</a>. Du vil blive bedt om bekræftelse.

View File

@ -534,7 +534,6 @@ de:
total_reported: Beschwerden über sie
total_storage: Medienanhänge
totals_time_period_hint_html: Die unten angezeigten Summen enthalten Daten für alle Zeiten.
unknown_instance: Auf diesem Server gibt es derzeit keinen Eintrag dieser Domain.
invites:
deactivate_all: Alle deaktivieren
filter:
@ -1041,14 +1040,6 @@ de:
hint_html: Fast geschafft! Wir müssen uns vergewissern, dass du ein Mensch bist (damit wir Spam verhindern können!). Bitte löse das CAPTCHA und klicke auf „Weiter“.
title: Sicherheitsüberprüfung
confirmations:
awaiting_review: Deine E-Mail-Adresse wurde bestätigt und das Team von %{domain} überprüft nun deine Registrierung. Sobald es dein Konto genehmigt, wirst du eine E-Mail erhalten.
awaiting_review_title: Deine Registrierung wird überprüft
clicking_this_link: Klick auf diesen Link
login_link: anmelden
proceed_to_login_html: Du kannst dich nun %{login_link}.
redirect_to_app_html: Du hättest zur <strong>%{app_name}</strong>-App weitergeleitet werden sollen. Wenn das nicht geschehen ist, versuche es mit einem %{clicking_this_link} oder kehre manuell zur App zurück.
registration_complete: Deine Registrierung auf %{domain} ist nun abgeschlossen!
welcome_title: Willkommen, %{name}!
wrong_email_hint: Sollte diese E-Mail-Adresse nicht korrekt sein, kannst du sie in den Kontoeinstellungen ändern.
delete_account: Konto löschen
delete_account_html: Falls du dein Konto endgültig löschen möchtest, kannst du das <a href="%{path}">hier vornehmen</a>. Du musst dies zusätzlich bestätigen.
@ -1110,7 +1101,6 @@ de:
functional: Dein Konto ist voll funktionsfähig.
pending: Die Prüfung deiner Bewerbung steht noch aus. Dies kann einige Zeit in Anspruch nehmen. Sobald deine Bewerbung genehmigt wurde, erhältst du eine E-Mail.
redirecting_to: Dein Konto ist inaktiv, weil es zu %{acct} umgezogen ist.
self_destruct: Da %{domain} den Betrieb einstellen wird, wirst du nur begrenzten Zugriff auf dein Konto haben.
view_strikes: Vorherige Verstöße deines Kontos ansehen
too_fast: Formular zu schnell übermittelt. Bitte versuche es erneut.
use_security_key: Sicherheitsschlüssel verwenden
@ -1580,9 +1570,6 @@ de:
over_daily_limit: Du hast das Limit von %{limit} geplanten Beiträgen für heute erreicht
over_total_limit: Du hast das Limit für geplante Beiträge, das %{limit} beträgt, erreicht
too_soon: Das geplante Datum muss in der Zukunft liegen
self_destruct:
lead_html: Bedauerlicherweise wird <strong>%{domain}</strong> den Betrieb für immer einstellen. Wenn du dort ein Konto angelegt hast, wirst du es nicht weiter verwenden können. Du kannst allerdings eine Sicherung deiner Daten anfordern.
title: Dieser Server wird den Betrieb einstellen
sessions:
activity: Letzte Aktivität
browser: Browser
@ -1782,7 +1769,7 @@ de:
subject: Dein Einspruch vom %{date} wurde abgelehnt
title: Einspruch abgelehnt
backup_ready:
explanation: Du hast eine vollständige Sicherung deines Mastodon-Kontos angefordert. Die Sicherung kann jetzt heruntergeladen werden!
explanation: Du hast eine vollständige Sicherung deines Mastodon-Kontos angefordert. Das Backup kann jetzt heruntergeladen werden!
subject: Dein persönliches Archiv kann heruntergeladen werden
title: Archiv-Download
suspicious_sign_in:

View File

@ -8,10 +8,10 @@ he:
failure:
already_authenticated: חשבון זה כבר מחובר.
inactive: חשבון זה טרם הופעל.
invalid: "%{authentication_keys} או סיסמה לא נכונים."
invalid: "%{authentication_keys} או סיסמא לא נכונים."
last_attempt: יש לך עוד ניסיון אחד לפני נעילת החשבון.
locked: חשבון זה נעול.
not_found_in_database: "%{authentication_keys} או סיסמה לא נכונים."
not_found_in_database: "%{authentication_keys} או סיסמא לא נכונים."
pending: חשבונך נמצא עדיין בבדיקה.
timeout: פג תוקף השהיה בחשבון. נא להכנס מחדש על מנת להמשיך.
unauthenticated: יש להרשם או להכנס לחשבון על מנת להמשיך.
@ -27,24 +27,24 @@ he:
title: אימות כתובת דוא״ל
email_changed:
explanation: 'כתובת הדוא"ל של חשבונך שונתה ל:'
extra: אם לא שינית את כתובת הדוא"ל שלך, יכול להיות שמישהו השתלט על חשבונך. נא לשנות את הסיסמה שלך מיידית או ליצור קשר עם מנהלי השרת אם ננעלת מחוץ לחשבונך.
extra: אם לא שינית את כתובת הדוא"ל שלך, יכול להיות שמישהו השתלט על חשבונך. נא לשנות את הסיסמא מיידית או ליצור קשר עם מנהלי השרת אם ננעלת מחוץ לחשבון.
subject: 'מסטודון: כתובת הדוא"ל שונתה'
title: כתובת דוא״ל חדשה
password_change:
explanation: הסיסמה לחשבונך שונתה.
extra: אם לא שינית את סיסמתך, יכול להיות שמישהו השתלט על חשבונך. נא לשנות את הסיסמה שלך מיידית או ליצור קשר עם מנהלי השרת אם ננעלת מחוץ לחשבונך.
subject: 'מסטודון: הסיסמה שונתה'
title: הסיסמה שונתה
explanation: הסיסמא לחשבונך שונתה.
extra: אם לא שינית את סיסמתך, יכול להיות שמישהו השתלט על חשבונך. נא לשנות את הסיסמא מיידית או ליצור קשר עם מנהלי השרת אם ננעלת מחוץ לחשבון.
subject: 'מסטודון: הסיסמא שונתה'
title: הסיסמא שונתה
reconfirmation_instructions:
explanation: נא לאמת את הכתובת הדוא"ל החדשה על מנת לשנותה.
extra: אם שינוי זה לא בוצע על ידך, נא להתעלם מדוא"ל זה. כתובת הדוא"ל של חשבון המסטודון שלך לא תשונה אלא אם תלחץ הקישורית לעיל.
subject: 'מסטודון: נא לאשר כתובת דוא"ל עבור %{instance}'
title: אימות כתובת דוא״ל
reset_password_instructions:
action: שינוי סיסמה
explanation: ביקשת סיסמה חדשה לחשבון שלך.
extra: אם לא ביקשת זאת, נא להתעלם מדוא"ל זה. סיסמתך לא תשתנה עוד שתלחץ הקישורית לעיל ותיוצר סיסמה חדשה.
subject: 'מסטודון: הוראות לאיפוס סיסמה'
action: שינוי סיסמא
explanation: ביקשת סיסמא חדשה לחשבון.
extra: אם לא ביקשת את זה, נא להתעלם מדוא"ל זה. סיסמתך לא תשתנה עוד שתלחץ הקישורית לעיל ותיוצר סיסמא חדשה.
subject: 'מסטודון: הוראות לאיפוס סיסמא'
title: איפוס סיסמה
two_factor_disabled:
explanation: האימות הדו-גורמי לחשבונך בוטל. ניתן עתה להכנס לחשבון עם כתובת דוא"ל וסיסמא בלבד.
@ -81,7 +81,7 @@ he:
failure: 'לא ניתן לאמת את חשבונך מ־%{kind} מהסיבה: "%{reason}".'
success: נכשל אימות מחשבון %{kind}.
passwords:
no_token: לא ניתן לגשת לעמוד זה, אלא מדוא"ל איפוס סיסמה. אם הגעת מדוא"ל איפוס סיסמה, יש לוודא שכתובת הקישורית הוקלדה בשלמותה.
no_token: לא ניתן לגשת לעמוד זה, אלא מדוא"ל איפוס סיסמא. אם לא הגעת מדוא"ל איפוס סיסמא, יש לוודא שכתובת הקישורית הוקלדה בשלמותה.
send_instructions: בדקות הקרובות יתקבל דוא"ל עם הוראות לאיפוס סיסמתך. יש לבדוק את תיבת הספאם ליתר בטחון אם ההודעה לא הגיעה תוך דקות ספורות.
send_paranoid_instructions: אם כתובת הדוא"ל שלך קיימת במסד הנתונים, יתקבל בדקות הקרובות דוא"ל עם הוראות לאחזור סיסמא. יש לבדוק את תיבת הספאם ליתר בטחון אם ההודעה לא הגיעה תוך דקות ספורות.
updated: סיסמתך שונתה בהצלחה. הינך כעת במצב מחובר.

View File

@ -88,7 +88,7 @@ sr-Latn:
updated_not_active: Vaša lozinka nije uspešno promenjena.
registrations:
destroyed: Ćao! Vaš nalog je uspešno obrisan. Nadamo se da ćete se uskoro vratiti.
signed_up: Dobro došli! Uspešno ste se registrovali.
signed_up: Dobrodošli! Uspešno ste se registrovali.
signed_up_but_inactive: Uspešno ste se registrovali. Nažalost ne možete se prijaviti zato što Vaš nalog još nije aktiviran.
signed_up_but_locked: Uspešno ste se registrovali. Nažalost ne možete se prijaviti zato što je Vaš nalog zaključan.
signed_up_but_pending: Na vaš imejl poslata je poruka sa vezom za potvrdu. Nakon što kliknete na vezu, pregledaćemo vašu prijavu. Bićete obavešteni ako bude odobreno.

View File

@ -88,7 +88,7 @@ sr:
updated_not_active: Ваша лозинка није успешно промењена.
registrations:
destroyed: Ћао! Ваш налог је успешно обрисан. Надамо се да ћете се ускоро вратити.
signed_up: Добро дошли! Успешно сте се регистровали.
signed_up: Добродошли! Успешно сте се регистровали.
signed_up_but_inactive: Успешно сте се регистровали. Нажалост не можете се пријавити зато што Ваш налог још није активиран.
signed_up_but_locked: Успешно сте се регистровали. Нажалост не можете се пријавити зато што је Ваш налог закључан.
signed_up_but_pending: На ваш имејл послата је порука са везом за потврду. Након што кликнете на везу, прегледаћемо вашу пријаву. Бићете обавештени ако буде одобрено.

View File

@ -534,7 +534,6 @@ en:
total_reported: Reports about them
total_storage: Media attachments
totals_time_period_hint_html: The totals displayed below include data for all time.
unknown_instance: There is currently no record of this domain on this server.
invites:
deactivate_all: Deactivate all
filter:
@ -1041,14 +1040,6 @@ en:
hint_html: Just one more thing! We need to confirm you're a human (this is so we can keep the spam out!). Solve the CAPTCHA below and click "Continue".
title: Security check
confirmations:
awaiting_review: Your e-mail address is confirmed! The %{domain} staff is now reviewing your registration. You will receive an e-mail if they approve your account!
awaiting_review_title: Your registration is being reviewed
clicking_this_link: clicking this link
login_link: log in
proceed_to_login_html: You can now proceed to %{login_link}.
redirect_to_app_html: You should have been redirected to the <strong>%{app_name}</strong> app. If that did not happen, try %{clicking_this_link} or manually return to the app.
registration_complete: Your registration on %{domain} is now complete!
welcome_title: Welcome, %{name}!
wrong_email_hint: If that e-mail address is not correct, you can change it in account settings.
delete_account: Delete account
delete_account_html: If you wish to delete your account, you can <a href="%{path}">proceed here</a>. You will be asked for confirmation.
@ -1110,7 +1101,6 @@ en:
functional: Your account is fully operational.
pending: Your application is pending review by our staff. This may take some time. You will receive an e-mail if your application is approved.
redirecting_to: Your account is inactive because it is currently redirecting to %{acct}.
self_destruct: As %{domain} is closing down, you will only get limited access to your account.
view_strikes: View past strikes against your account
too_fast: Form submitted too fast, try again.
use_security_key: Use security key
@ -1581,9 +1571,6 @@ en:
over_daily_limit: You have exceeded the limit of %{limit} scheduled posts for today
over_total_limit: You have exceeded the limit of %{limit} scheduled posts
too_soon: The scheduled date must be in the future
self_destruct:
lead_html: Unfortunately, <strong>%{domain}</strong> is permanently closing down. If you had an account there, you will not be able to continue using it, but you can still request a backup of your data.
title: This server is closing down
sessions:
activity: Last activity
browser: Browser

View File

@ -534,7 +534,6 @@ es-AR:
total_reported: Denuncias sobre ellas
total_storage: Adjuntos
totals_time_period_hint_html: Los datos totales mostrados a continuación incluyen datos para todo el tiempo.
unknown_instance: Actualmente no hay ningún registro de este dominio en este servidor.
invites:
deactivate_all: Desactivar todas
filter:
@ -1041,14 +1040,6 @@ es-AR:
hint_html: ¡Sólo una cosa más! Necesitamos confirmar que sos humano (¡esto es para que podamos mantener el spam fuera!). Resuelvé la CAPTCHA abajo y hacé clic en "Continuar".
title: Comprobación de seguridad
confirmations:
awaiting_review: "¡Tu dirección de correo electrónico fue confirmada! El equipo de %{domain} está revisando tu registro. ¡Recibirás un correo electrónico si aprueban tu cuenta!"
awaiting_review_title: Tu registro está siendo revisado
clicking_this_link: haciendo clic en este enlace
login_link: iniciar sesión
proceed_to_login_html: Ahora podés %{login_link}.
redirect_to_app_html: Deberías haber sido redirigido a la aplicación <strong>%{app_name}</strong>. Si eso no sucedió, probá %{clicking_this_link} o volvé a la aplicación manualmente.
registration_complete: "¡Tu registro en %{domain} fue completado!"
welcome_title: "¡Te damos la bienvenida, %{name}!"
wrong_email_hint: Si esa dirección de correo electrónico no es correcta, podés cambiarla en la configuración de la cuenta.
delete_account: Eliminar cuenta
delete_account_html: Si querés eliminar tu cuenta, podés <a href="%{path}">seguir por acá</a>. Se te va a pedir una confirmación.
@ -1110,7 +1101,6 @@ es-AR:
functional: Tu cuenta está totalmente operativa.
pending: Tu solicitud está pendiente de revisión por nuestra administración. Eso puede tardar algún tiempo. Si se aprueba tu solicitud, vas a recibir un correo electrónico.
redirecting_to: Tu cuenta se encuentra inactiva porque está siendo redirigida a %{acct}.
self_destruct: Como %{domain} está en proceso de cierre, solo tendrás acceso limitado a tu cuenta.
view_strikes: Ver incumplimientos pasados contra tu cuenta
too_fast: Formulario enviado demasiado rápido, probá de nuevo.
use_security_key: Usar la llave de seguridad
@ -1580,9 +1570,6 @@ es-AR:
over_daily_limit: Superaste el límite de %{limit} mensajes programados para ese día
over_total_limit: Superaste el límite de %{limit} mensajes programados
too_soon: La fecha programada debe estar en el futuro
self_destruct:
lead_html: Desafortunadamente, <strong>%{domain}</strong> va a cerrar permanentemente. Si tenías una cuenta ahí, no podrás continuar usándola, pero aún podés solicitar una copia de tus datos.
title: Este servidor está cerrando
sessions:
activity: Última actividad
browser: Navegador web

View File

@ -534,7 +534,6 @@ es-MX:
total_reported: Informes sobre ellas
total_storage: Archivos multimedia
totals_time_period_hint_html: Los totales mostrados a continuación incluyen datos para todo el tiempo.
unknown_instance: Actualmente no hay registros de este dominio en el servidor.
invites:
deactivate_all: Desactivar todos
filter:
@ -1041,14 +1040,6 @@ es-MX:
hint_html: ¡Una última cosita! Necesitamos confirmar que eres humano (¡así podemos evitar el spam!). Resuelve este CAPTCHA de debajo y pulsa en "Continuar".
title: Comprobación de seguridad
confirmations:
awaiting_review: "¡Tu dirección de correo electrónico ha sido confirmada! El personal de %{domain} está revisando tu registro. ¡Recibirás un correo electrónico si aprueban tu cuenta!"
awaiting_review_title: Su registro está siendo revisado
clicking_this_link: presionando este enlace
login_link: iniciar sesión
proceed_to_login_html: Ahora puedes proceder a %{login_link}.
redirect_to_app_html: Deberías haber sido redirigido a la aplicación <strong>%{app_name}</strong>. Si eso no sucedió, prueba %{clicking_this_link} o vuelve a la aplicación manualmente.
registration_complete: "¡Tu registro en %{domain} ha sido completado!"
welcome_title: "¡Bienvenido, %{name}!"
wrong_email_hint: Si esa dirección de correo electrónico no es correcta, puedes cambiarla en la configuración de la cuenta.
delete_account: Borrar cuenta
delete_account_html: Si desea eliminar su cuenta, puede <a href="%{path}">proceder aquí</a>. Será pedido de una confirmación.
@ -1110,7 +1101,6 @@ es-MX:
functional: Tu cuenta está completamente operativa.
pending: Su solicitud está pendiente de revisión por nuestros administradores. Eso puede tardar algún tiempo. Usted recibirá un correo electrónico si el solicitud sea aprobada.
redirecting_to: Tu cuenta se encuentra inactiva porque está siendo redirigida a %{acct}.
self_destruct: Como %{domain} está cerrando, solo tendrás acceso limitado a tu cuenta.
view_strikes: Ver amonestaciones pasadas contra tu cuenta
too_fast: Formulario enviado demasiado rápido, inténtelo de nuevo.
use_security_key: Usar la clave de seguridad
@ -1580,9 +1570,6 @@ es-MX:
over_daily_limit: Ha superado el límite de %{limit} toots programados para ese día
over_total_limit: Ha superado el límite de %{limit} toots programados
too_soon: La fecha programada debe estar en el futuro
self_destruct:
lead_html: Desafortunadamente, <strong>%{domain}</strong> está cerrando de manera permanente. Si tenías una cuenta ahí, no puedes continuar utilizándolo, pero puedes solicitar un respaldo de tus datos.
title: Este servidor está cerrando
sessions:
activity: Última actividad
browser: Navegador

View File

@ -534,7 +534,6 @@ es:
total_reported: Informes sobre ellas
total_storage: Archivos multimedia
totals_time_period_hint_html: Los totales mostrados a continuación incluyen datos para todo el tiempo.
unknown_instance: Actualmente no hay ningún registro de este dominio en este servidor.
invites:
deactivate_all: Desactivar todos
filter:
@ -1041,14 +1040,6 @@ es:
hint_html: ¡Una última cosita! Necesitamos confirmar que eres humano (¡así podemos evitar el spam!). Resuelve este CAPTCHA de debajo y pulsa en "Continuar".
title: Comprobación de seguridad
confirmations:
awaiting_review: "¡Tu dirección de correo electrónico ha sido confirmada! El personal de %{domain} está revisando tu registro. ¡Recibirás un correo electrónico cuando aprueben tu cuenta!"
awaiting_review_title: Estamos revisando tu registro
clicking_this_link: haciendo clic en este enlace
login_link: iniciar sesión
proceed_to_login_html: Ahora puedes proceder a %{login_link}.
redirect_to_app_html: Serás redirigido a la aplicación <strong>%{app_name}</strong>. Si esto no sucede, prueba %{clicking_this_link} o regresa manualmente a la aplicación.
registration_complete: "¡Has completado tu registro en %{domain}!"
welcome_title: "¡Bienvenido, %{name}!"
wrong_email_hint: Si esa dirección de correo electrónico no es correcta, puedes cambiarla en la configuración de la cuenta.
delete_account: Borrar cuenta
delete_account_html: Si desea eliminar su cuenta, puede <a href="%{path}">proceder aquí</a>. Será pedido de una confirmación.
@ -1108,9 +1099,8 @@ es:
account_status: Estado de la cuenta
confirming: Esperando confirmación de correo electrónico.
functional: Tu cuenta está completamente operativa.
pending: Tu solicitud está pendiente de revisión por nuestro personal. Eso puede tardar un tiempo. Recibirás un correo electrónico cuando tu solicitud sea aprobada.
pending: Su solicitud está pendiente de revisión por nuestros administradores. Eso puede tardar algún tiempo. Usted recibirá un correo electrónico si el solicitud sea aprobada.
redirecting_to: Tu cuenta se encuentra inactiva porque está siendo redirigida a %{acct}.
self_destruct: Como %{domain} está en proceso de cierre, solo tendrás acceso limitado a tu cuenta.
view_strikes: Ver amonestaciones pasadas contra tu cuenta
too_fast: Formulario enviado demasiado rápido, inténtelo de nuevo.
use_security_key: Usar la clave de seguridad
@ -1580,9 +1570,6 @@ es:
over_daily_limit: Ha superado el límite de %{limit} publicaciones programadas para ese día
over_total_limit: Ha superado el límite de %{limit} publicaciones programadas
too_soon: La fecha programada debe estar en el futuro
self_destruct:
lead_html: Desafortunadamente, <strong>%{domain}</strong> va a cerrar permanentemente. Si tenías una cuenta allí, no podrás continuar usándola, pero aún puedes solicitar una copia de tus datos.
title: Este servidor está cerrando
sessions:
activity: Última actividad
browser: Navegador
@ -1794,7 +1781,7 @@ es:
title: Un nuevo inicio de sesión
warning:
appeal: Enviar una apelación
appeal_description: Si crees que esto es un error, puedes enviar una apelación al personal de %{instance}.
appeal_description: Si crees que esto es un error, puedes enviar una apelación al equipo de %{instance}.
categories:
spam: Spam
violation: El contenido viola las siguientes directrices de la comunidad

View File

@ -536,7 +536,6 @@ eu:
total_reported: Heiei buruzko txostenak
total_storage: Multimedia eranskinak
totals_time_period_hint_html: Behean bistaratutako guztizkoek datu guztiak hartzen dituzte barne.
unknown_instance: Ez dago domeinu honen erregistrorik zerbitzarian orain.
invites:
deactivate_all: Desgaitu guztiak
filter:
@ -1094,7 +1093,6 @@ eu:
functional: Zure kontua guztiz erabilgarri dago.
pending: Zure eskaera gainbegiratzeko dago oraindik. Honek denbora behar lezake. Zure eskaera onartzen bada e-mail bat jasoko duzu.
redirecting_to: Zure kontua ez dago aktibo orain %{acct} kontura birbideratzen duelako.
self_destruct: "%{domain} domeinua itxiko denez, konturako sarbide mugatua soilik izango duzu."
view_strikes: Ikusi zure kontuaren aurkako neurriak
too_fast: Formularioa azkarregi bidali duzu, saiatu berriro.
use_security_key: Erabili segurtasun gakoa
@ -1566,9 +1564,6 @@ eu:
over_daily_limit: 'Egun horretarako programatutako bidalketa kopuruaren muga gainditu duzu: %{limit}'
over_total_limit: 'Programatutako bidalketa kopuruaren muga gainditu duzu: %{limit}'
too_soon: Programatutako data etorkizunean egon behar du
self_destruct:
lead_html: Zoritxarrez, <strong>%{domain}</strong> betirako itxiko da. Kontu bat baduzu bertan, ezin izango duzu erabiltzen jarraitu, baina, oraindik zure datuen babeskopia bat eska dezakezu.
title: Zerbitzari hau ixtear dago
sessions:
activity: Azken jarduera
browser: Nabigatzailea
@ -1738,10 +1733,6 @@ eu:
month: "%Y(e)ko %b"
time: "%H:%M"
with_time_zone: "%Y(e)ko %b %d, %H:%M %Z"
translation:
errors:
quota_exceeded: Zerbitzari osoko itzulpen-zerbitzuaren erabileraren kuota gainditu da.
too_many_requests: Itzulpen-zerbitzurako eskaera gehiegi egon dira berriki.
two_factor_authentication:
add: Gehitu
disable: Desgaitu

View File

@ -534,7 +534,6 @@ fi:
total_reported: Niitä koskevat raportit
total_storage: Medialiitteet
totals_time_period_hint_html: Alla näkyvät yhteenlasketut tiedot sisältävät koko ajan.
unknown_instance: Tällä palvelimella ei tällä hetkellä ole tähän verkkotunnukseen liittyviä tietueita.
invites:
deactivate_all: Poista kaikki käytöstä
filter:
@ -1041,14 +1040,6 @@ fi:
hint_html: Vielä yksi juttu! Meidän on vahvistettava, että olet ihminen (tämän avulla pidämme roskapostin poissa!). Ratkaise alla oleva CAPTCHA-vahvistus ja paina "Jatka".
title: Turvatarkastus
confirmations:
awaiting_review: Sähköpostiosoitteesi on vahvistettu! Seuraavaksi palvelimen %{domain} ylläpito tarkistaa rekisteröitymisesi ja saat lopuksi ilmoituksen sähköpostitse, jos tilisi hyväksytään!
awaiting_review_title: Rekisteröitymisesi on tarkistettavana
clicking_this_link: tästä linkistä
login_link: kirjautumalla sisään
proceed_to_login_html: Voit nyt jatkaa %{login_link}.
redirect_to_app_html: Sinun olisi pitänyt ohjautua sovellukseen <strong>%{app_name}</strong>. Jos näin ei tapahtunut, yritä avata se %{clicking_this_link} tai palaa sovellukseen manuaalisesti.
registration_complete: Rekisteröitymisesi palvelimelle %{domain} on suoritettu!
welcome_title: Tervetuloa, %{name}!
wrong_email_hint: Jos sähköpostiosoite ei ole oikein, voit muuttaa sen tilin asetuksista.
delete_account: Poista tili
delete_account_html: Jos haluat poistaa tilisi, voit <a href="%{path}">edetä tästä</a>. Sinua pyydetään vahvistamaan poisto.
@ -1108,9 +1099,8 @@ fi:
account_status: Tilin tila
confirming: Odotetaan sähköpostivahvistuksen valmistumista.
functional: Tilisi on täysin toiminnassa.
pending: Hakemuksesi odottaa palvelimen ylläpidon tarkastusta. Tämä voi kestää jonkin aikaa. Saat sähköpostiviestin, jos hakemuksesi hyväksytään.
pending: Hakemuksesi odottaa henkilökuntamme tarkastusta. Tämä voi kestää jonkin aikaa. Saat sähköpostiviestin, jos hakemuksesi hyväksytään.
redirecting_to: Tilisi ei ole aktiivinen, koska se ohjaa tällä hetkellä tilille %{acct}.
self_destruct: Koska %{domain} sulkeutuu, voit käyttää tiliäsi vain rajoitetusti.
view_strikes: Näytä tiliäsi koskevia aiempia varoituksia
too_fast: Lomake lähetettiin liian nopeasti, yritä uudelleen.
use_security_key: Käytä suojausavainta
@ -1171,7 +1161,7 @@ fi:
approve_appeal: Hyväksy valitus
associated_report: Liittyvä raportti
created_at: Päivätty
description_html: Nämä ovat tiliäsi koskevia toimia ja varoituksia, jotka instanssin %{instance} ylläpito on lähettänyt sinulle.
description_html: Nämä ovat tiliäsi koskevia toimia ja varoituksia, jotka instanssin %{instance} henkilökunta on lähettänyt sinulle.
recipient: Osoitettu
reject_appeal: Hylkää valitus
status: 'Julkaisu #%{id}'
@ -1580,9 +1570,6 @@ fi:
over_daily_limit: Olet ylittänyt %{limit} ajoitetun julkaisun rajan tälle päivälle
over_total_limit: Olet ylittänyt %{limit} ajoitetun julkaisun rajan
too_soon: Ajoitetun päiväyksen pitää olla tulevaisuudessa
self_destruct:
lead_html: Valitettavasti <strong>%{domain}</strong> sulkeutuu pysyvästi. Jos sinulla on siellä tili, et voi jatkaa sen käyttöä mutta voit yhä pyytää varmuuskopiota tiedoistasi.
title: Tämä palvelin sulkeutuu
sessions:
activity: Viimeisin toiminta
browser: Selain
@ -1794,7 +1781,7 @@ fi:
title: Uusi kirjautuminen
warning:
appeal: Lähetä valitus
appeal_description: Jos uskot, että tämä on virhe, voit hakea muutosta instanssin %{instance} ylläpidolta.
appeal_description: Jos uskot, että tämä on virhe, voit hakea muutosta instanssin %{instance} henkilökunnalta.
categories:
spam: Roskaposti
violation: Sisältö rikkoo seuraavia yhteisön sääntöjä

View File

@ -534,7 +534,6 @@ fo:
total_reported: Meldingar um tey
total_storage: Viðheftir miðlar
totals_time_period_hint_html: Við í samanteljingunum niðanfyri eru dátur frá byrjan av.
unknown_instance: Í løtuni er hetta navnaøkið ikki skrásett á hesum ambætaranum.
invites:
deactivate_all: Ger allar óvirknar
filter:
@ -1041,14 +1040,6 @@ fo:
hint_html: Bara eitt afturat! Tað er neyðugt hjá okkum at vátta, at tú ert eitt menniskja (fyri at sleppa undan ruskposti!). Loys CAPTCHA niðanfyri og trýst á "Halt fram".
title: Trygdarkanning
confirmations:
awaiting_review: Teldupostadressan hjá góðkend! Nú kanna %{domain} ábyrgdarfólk skrásetingina hjá tær. Góðkenna tey kontu tína, so senda tey tær eitt teldubræv!
awaiting_review_title: Skrásetingin hjá tær verður viðgjørd
clicking_this_link: við at klikkja á hetta leinki
login_link: rita inn
proceed_to_login_html: Nú kanst tú fara víðari til %{login_link}.
redirect_to_app_html: Tú skuldi verið send/ur víðari til <strong>%{app_name}</strong> appina. Hendi tað ikki, so kanst tú royna %{clicking_this_link} ella fara manuelt aftur til appina.
registration_complete: Skráseting tín á %{domain} er nú avgreidd!
welcome_title: Vælkomin, %{name}!
wrong_email_hint: Um hesin teldupoststaðurin ikki er rættur, so kanst tú broyta hann í kontustillingunum.
delete_account: Strika kontu
delete_account_html: Ynskir tú at strika kontuna, so kanst tú <a href="%{path}">halda fram her</a>. Tú verður spurd/ur um váttan.
@ -1110,7 +1101,6 @@ fo:
functional: Konta tín er fult virkin.
pending: Umsókn tín verður eftirkannað av okkara starvsfeløgum. Tað kann taka eina løtu. Tú móttekur eitt teldubræv, um umsóknin er góðkend.
redirecting_to: Konta tín er óvirkin, tí í løtuni verður hon víðaribeind til %{acct}.
self_destruct: Av tí at %{domain} er í ferð við at lukka, fært tú einans avmarkaða atgongd til tína kontu.
view_strikes: Vís eldri atsóknir móti tíni kontu
too_fast: Oyðublaðið innsent ov skjótt, royn aftur.
use_security_key: Brúka trygdarlykil
@ -1580,9 +1570,6 @@ fo:
over_daily_limit: Tú er komin at markinum, sum er %{limit} skrálagdir postar, í dag
over_total_limit: Tú er komin at markinum, sum er %{limit} skrálagdir postar
too_soon: Ætlanardagfestingin má vera í framtíðini
self_destruct:
lead_html: Tíverri, <strong>%{domain}</strong> er í ferð við at blíva lukkað niður med alla. Um tú hevði eina kontu har, so ber ikki til framhaldandi at brúka hana, men tú kann framvegis biðja um trygdaravrit av tínum dátum.
title: Hesin ambætarin er í ferð við at lukka
sessions:
activity: Seinasta virksemi
browser: Kagi

View File

@ -534,7 +534,6 @@ fr-QC:
total_reported: Signalements à leur sujet
total_storage: Attachements de média
totals_time_period_hint_html: Les totaux affichés ci-dessous incluent des données sans limite de temps.
unknown_instance: Il ny a actuellement aucune trace de ce domaine sur ce serveur.
invites:
deactivate_all: Tout désactiver
filter:
@ -1041,14 +1040,6 @@ fr-QC:
hint_html: Juste une autre chose! Nous avons besoin de confirmer que vous êtes un humain (pour que nous puissions empêcher les spams!). Résolvez le CAPTCHA ci-dessous et cliquez sur "Continuer".
title: Vérification de sécurité
confirmations:
awaiting_review: Votre adresse e-mail est confirmée ! Léquipe de %{domain} vérifie désormais votre inscription. Vous recevrez un e-mail si votre compte est approuvé !
awaiting_review_title: Votre inscription est en cours de validation
clicking_this_link: cliquer sur ce lien
login_link: vous connecter
proceed_to_login_html: Vous pouvez désormais %{login_link}.
redirect_to_app_html: Vous auriez dû être redirigé vers lapplication <strong>%{app_name}</strong>. Si cela ne sest pas produit, essayez de %{clicking_this_link} ou de revenir manuellement à lapplication.
registration_complete: Votre inscription sur %{domain} est désormais terminée !
welcome_title: Bienvenue, %{name} !
wrong_email_hint: Si cette adresse de courriel est incorrecte, vous pouvez la modifier dans vos paramètres de compte.
delete_account: Supprimer le compte
delete_account_html: Si vous désirez supprimer votre compte, vous pouvez <a href="%{path}">cliquer ici</a>. Il vous sera demandé de confirmer cette action.
@ -1110,7 +1101,6 @@ fr-QC:
functional: Votre compte est entièrement opérationnel.
pending: Votre demande est en attente d'examen par notre personnel. Cela peut prendre un certain temps. Vous recevrez un courriel si votre demande est approuvée.
redirecting_to: Votre compte est inactif car il est actuellement redirigé vers %{acct}.
self_destruct: Comme %{domain} est en train de fermer, vous naurez quun accès limité à votre compte.
view_strikes: Voir les sanctions précédemment appliquées à votre compte
too_fast: Formulaire envoyé trop rapidement, veuillez réessayer.
use_security_key: Utiliser la clé de sécurité
@ -1580,9 +1570,6 @@ fr-QC:
over_daily_limit: Vous avez dépassé la limite de %{limit} messages planifiés par jour
over_total_limit: Vous avez dépassé la limite de %{limit} messages planifiés
too_soon: La date planifiée doit être dans le futur
self_destruct:
lead_html: Malheureusement, <strong>%{domain}</strong> ferme définitivement. Si vous y aviez un compte, vous ne pourrez pas continuer à lutiliser, mais vous pouvez toujours demander une sauvegarde de vos données.
title: Ce serveur est en cours de fermeture
sessions:
activity: Dernière activité
browser: Navigateur

View File

@ -534,7 +534,6 @@ fr:
total_reported: Signalements à leur sujet
total_storage: Attachements de média
totals_time_period_hint_html: Les totaux affichés ci-dessous incluent des données sans limite de temps.
unknown_instance: Il ny a actuellement aucune trace de ce domaine sur ce serveur.
invites:
deactivate_all: Tout désactiver
filter:
@ -1041,14 +1040,6 @@ fr:
hint_html: Encore une chose ! Nous avons besoin de confirmer que vous êtes un humain (c'est pour que nous puissions empêcher les spams !). Résolvez le CAPTCHA ci-dessous et cliquez sur "Continuer".
title: Vérification de sécurité
confirmations:
awaiting_review: Votre adresse e-mail est confirmée ! Léquipe de %{domain} vérifie désormais votre inscription. Vous recevrez un e-mail si votre compte est approuvé !
awaiting_review_title: Votre inscription est en cours de validation
clicking_this_link: cliquer sur ce lien
login_link: vous connecter
proceed_to_login_html: Vous pouvez désormais %{login_link}.
redirect_to_app_html: Vous auriez dû être redirigé vers lapplication <strong>%{app_name}</strong>. Si cela ne sest pas produit, essayez de %{clicking_this_link} ou de revenir manuellement à lapplication.
registration_complete: Votre inscription sur %{domain} est désormais terminée !
welcome_title: Bienvenue, %{name} !
wrong_email_hint: Si cette adresse de courriel est incorrecte, vous pouvez la modifier dans vos paramètres de compte.
delete_account: Supprimer le compte
delete_account_html: Si vous désirez supprimer votre compte, vous pouvez <a href="%{path}">cliquer ici</a>. Il vous sera demandé de confirmer cette action.
@ -1110,7 +1101,6 @@ fr:
functional: Votre compte est entièrement opérationnel.
pending: Votre demande est en attente d'examen par notre personnel. Cela peut prendre un certain temps. Vous recevrez un courriel si votre demande est approuvée.
redirecting_to: Votre compte est inactif car il est actuellement redirigé vers %{acct}.
self_destruct: Comme %{domain} est en train de fermer, vous naurez quun accès limité à votre compte.
view_strikes: Voir les sanctions précédemment appliquées à votre compte
too_fast: Formulaire envoyé trop rapidement, veuillez réessayer.
use_security_key: Utiliser la clé de sécurité
@ -1580,9 +1570,6 @@ fr:
over_daily_limit: Vous avez dépassé la limite de %{limit} messages planifiés par jour
over_total_limit: Vous avez dépassé la limite de %{limit} messages planifiés
too_soon: La date planifiée doit être dans le futur
self_destruct:
lead_html: Malheureusement, <strong>%{domain}</strong> ferme définitivement. Si vous y aviez un compte, vous ne pourrez pas continuer à lutiliser, mais vous pouvez toujours demander une sauvegarde de vos données.
title: Ce serveur est en cours de fermeture
sessions:
activity: Dernière activité
browser: Navigateur

View File

@ -534,7 +534,6 @@ fy:
total_reported: Rapportaazjes oer harren
total_storage: Mediabylagen
totals_time_period_hint_html: De hjirûnder toande totalen befetsje gegevens sûnt it begjin.
unknown_instance: Der binne op dit stuit gjin gegevens fan dit domein op dizze server.
invites:
deactivate_all: Alles deaktivearje
filter:
@ -1041,14 +1040,6 @@ fy:
hint_html: Noch ien ding! Jo moatte befêstigje dat jo in minske binne (dit is om de spam bûten de doar te hâlden!). Los de ûndersteande CAPTCHA op en klik op Trochgean.
title: Befeiligingskontrôle
confirmations:
awaiting_review: Jo e-mailadres is befêstige! De %{domain}-meiwurkers binne no dwaande mei it besjen fan jo registraasje. Jo ûntfange in e-mailberjocht as de jo account goedkarre!
awaiting_review_title: Jo registraasje wurdt beoardield
clicking_this_link: klik op dizze keppeling
login_link: oanmelde
proceed_to_login_html: Jo kinne no fierder gean nei %{login_link}.
redirect_to_app_html: Jo soene omlaad wêze moatte nei de <strong>%{app_name}</strong> app. As dat net bard is, probearje dan %{clicking_this_link} of kear hânmjittich werom nei de app.
registration_complete: Jo registraasje op %{domain} is no foltôge!
welcome_title: Wolkom, %{name}!
wrong_email_hint: As it e-mailadres net korrekt is, kinne jo dat wizigje yn de accountynstellingen.
delete_account: Account fuortsmite
delete_account_html: Wanneart jo jo account graach fuortsmite wolle, kinne jo dat <a href="%{path}">hjir dwaan</a>. Wy freegje jo dêr om in befêstiging.
@ -1110,7 +1101,6 @@ fy:
functional: Jo account kin folslein brûkt wurde.
pending: Jo oanfraach moat noch beoardiele wurde troch ien fan ús meiwurkers. Dit kin miskien efkes duorje. Jo ûntfangt in e-mailberjocht wanneart jo oanfraach goedkard is.
redirecting_to: Jo account is ynaktyf, omdat it op dit stuit trochferwezen wurdt nei %{acct}.
self_destruct: Omdat %{domain} sluten sil, krije jo mar beheind tagong ta jo account.
view_strikes: Besjoch de earder troch moderatoaren fêststelde skeiningen dyt jo makke hawwe
too_fast: Formulier is te fluch yntsjinne. Probearje it nochris.
use_security_key: Befeiligingskaai brûke
@ -1580,9 +1570,6 @@ fy:
over_daily_limit: Jo binne oer de limyt fan %{limit} yn te plannen berjochten foar hjoed
over_total_limit: Jo binne oer de limyt fan %{limit} yn te plannen berjochten
too_soon: De datum foar it ynplande berjocht moat yn de takomst lizze
self_destruct:
lead_html: Spitigernôch sil <strong>%{domain}</strong> permanint ôfslute. As jo dêr in account hiene, kinne jo dizze net mear brûke, mar jo kinne noch hieltyd in reservekopy fan jo gegevens opfreegje.
title: Deze server sil ôfslute
sessions:
activity: Lêst warber
browser: Browser

View File

@ -556,7 +556,6 @@ gd:
total_reported: Gearanan mun dèidhinn
total_storage: Ceanglachain mheadhanan
totals_time_period_hint_html: Gabhaidh na h-iomlanan gu h-ìosal a-staigh an dàta o chian nan cian.
unknown_instance: Chan eil clàr dhen àrainn seo air an fhrithealaiche seo.
invites:
deactivate_all: Cuir na h-uile à gnìomh
filter:
@ -1138,7 +1137,6 @@ gd:
functional: Tha an cunntas agad ag obair gu slàn.
pending: Feumaidh an sgioba againn lèirmheas a dhèanamh air d iarrtas. Dhfhaoidte gun doir seo greis. Gheibh thu post-d nuair a bhios sinn air aontachadh ri d iarrtas.
redirecting_to: Chan eil an cunntas gad gnìomhach on a tha e ga ath-stiùireadh gu %{acct}.
self_destruct: On a tha %{domain} gu bhith dùnadh, chan fhaigh thu ach inntrigeadh cuingichte dhan chunntas agad.
view_strikes: Seall na rabhaidhean a fhuair an cunntas agad roimhe
too_fast: Chaidh am foirm a chur a-null ro luath, feuch ris a-rithist.
use_security_key: Cleachd iuchair tèarainteachd
@ -1624,9 +1622,6 @@ gd:
over_daily_limit: Chaidh thu thar na crìoch de %{limit} post(aichean) sgeidealaichte an-diugh
over_total_limit: Chaidh thu thar na crìoch de %{limit} post(aichean) sgeidealaichte
too_soon: Feumaidh ceann-latha an sgeideil a bhith san àm ri teachd
self_destruct:
lead_html: Gu mì-fhortanach, thèid <strong>%{domain}</strong> a dhùnadh gu buan. Ma tha cunntas agad ann, chan urrainn dhut cumail a gol ga chleachdadh ach s urrainn dhut lethbhreac-glèidhidh dhen dàta agad iarraidh fhathast.
title: Tha am frithealaiche seo gu bhith dùnadh
sessions:
activity: A ghnìomhachd mu dheireadh
browser: Brabhsair

View File

@ -534,7 +534,6 @@ gl:
total_reported: Denuncias sobre eles
total_storage: Adxuntos multimedia
totals_time_period_hint_html: Os totais aquí mostrados inclúen todo o historial de datos.
unknown_instance: Actualmente non temos constancia deste rexistro no servidor.
invites:
deactivate_all: Desactivar todo
filter:
@ -1041,14 +1040,6 @@ gl:
hint_html: Unha cousa máis! Temos que confirmar que es un ser humano (para poder evitar contas de spam!). Resolve o CAPTCHA de aquí embaixo e preme en "Continuar".
title: Comprobación de seguridade
confirmations:
awaiting_review: O teu correo está verificado! A administración de %{domain} está revisando a túa solicitude. Recibirás outro correo se aproban a túa conta!
awaiting_review_title: Estamos revisando a solicitude de rexistro
clicking_this_link: premendo nesta ligazón
login_link: acceder
proceed_to_login_html: Xa podes %{login_link}.
redirect_to_app_html: Ímoste redirixir á app <strong>%{app_name}</strong>. Se iso non acontece, proba %{clicking_this_link} ou volve ti manualmente á app.
registration_complete: Completouse a creación da conta en %{domain}!
welcome_title: Benvida, %{name}!
wrong_email_hint: Se o enderezo de email non é correcto, podes cambialo nos axustes da conta.
delete_account: Eliminar conta
delete_account_html: Se queres eliminar a túa conta, podes <a href="%{path}">facelo aquí</a>. Deberás confirmar a acción.
@ -1110,7 +1101,6 @@ gl:
functional: A túa conta está completamente operativa.
pending: A túa solicitude está pendente de revisión. Poderíanos levar algún tempo. Recibirás un correo se a solicitude está aprobada.
redirecting_to: A túa conta está inactiva porque está redirixida a %{acct}.
self_destruct: Como %{domain} vai fechar, tes acceso restrinxido á túa conta.
view_strikes: Ver avisos anteriores respecto da túa conta
too_fast: Formulario enviado demasiado rápido, inténtao outra vez.
use_security_key: Usa chave de seguridade
@ -1580,9 +1570,6 @@ gl:
over_daily_limit: Excedeches o límite de %{limit} publicacións programadas para ese día
over_total_limit: Excedeches o límite de %{limit} publicacións programadas
too_soon: A data de programación debe estar no futuro
self_destruct:
lead_html: Desafortunadamente, <strong>%{domain}</strong> vai deixar de dar servizo. Se tes unha conta aquí non poderás seguir usándoa, mais podes solicitar un ficheiro cos teus datos.
title: Este servidor vai fechar
sessions:
activity: Última actividade
browser: Navegador

View File

@ -556,7 +556,6 @@ he:
total_reported: דוחות אודותיהם
total_storage: קבצי מדיה מצורפים
totals_time_period_hint_html: הסכומים המוצגים להלן כוללים מידע מכל הזמנים.
unknown_instance: אין כרגע תיעוד של שם המתחם הזה על שרת זה.
invites:
deactivate_all: להשבית הכל
filter:
@ -1077,14 +1076,6 @@ he:
hint_html: עוד דבר אחד, עלינו לאשרר שאת(ה) אנושיים (לצורך סינון ספאם). נא לפתור את הקאפצ'ה להלן וללחוץ "המשך".
title: בדיקות אבטחה
confirmations:
awaiting_review: כתובת הדואל שלך אושרה! צוות %{domain} עכשיו יבדוק את הרשמתך. תשלח אליך הודעת דואל אם הצוות יאשר את החשבון!
awaiting_review_title: הרשמתך עוברת בדיקה
clicking_this_link: לחיצה על קישור זה
login_link: כניסה
proceed_to_login_html: ניתן להמשיך עכשיו אל %{login_link}.
redirect_to_app_html: כאן אמורה היתה להיות הפניה אוטמטית ליישומון <strong>%{app_name}</strong>. אם זה לא קרה, ניתן לנסות שוב על ידי %{clicking_this_link} או חזרה ידנית אל היישומון.
registration_complete: הרשמתך לשרת %{domain} הושלמה כעת!
welcome_title: ברוך/ה הבא/ה, %{name}!
wrong_email_hint: אם כתובת הדואל הזו איננה נכונה, ניתן לשנות אותה בעמוד ההגדרות.
delete_account: מחיקת חשבון
delete_account_html: אם ברצונך למחוק את החשבון, ניתן <a href="%{path}">להמשיך כאן</a>. תתבקש/י לספק אישור נוסף.
@ -1134,7 +1125,7 @@ he:
new_confirmation_instructions_sent: אתם עומדים לקבל הודעת דואל חדשה עם קיש/ור אימות בדקות הקרובות!
title: בדוק/בדקי את תיבת הדואר הנכנס שלך
sign_in:
preamble_html: הכנס.י עם שם וסיסמה מאתר <strong>%{domain}</strong>. אם חשבונך מתארח בשרת אחר, לא ניתן להתחבר איתו פה.
preamble_html: הכנס.י עם שם וסיסמא מאתר <strong>%{domain}</strong>. אם חשבונך מתארח בשרת אחר, לא ניתן להתחבר איתו פה.
title: התחבר אל %{domain}
sign_up:
manual_review: פתיחת חשבון אצל %{domain} עוברת בדיקה ידנית על ידי הצוות שלנו. כדי לסייע בתהליך הרישום שלכןם, כתבו לנו על עצמכןם ולמה אתןם רוצותים חשבון בשרת %{domain}.
@ -1146,7 +1137,6 @@ he:
functional: החשבון שלכם פעיל לגמרי.
pending: בקשתך ממתינה לאישור על ידי הצוות שלנו. זה עשוי לקחת זמן מה. דוא"ל יישלח אליך אם בקשתך התקבלה.
redirecting_to: חשבונכם לא פעיל כעת מכיוון שמפנה ל%{acct}.
self_destruct: מכיוון שהשרת %{domain} בתהליכי סגירה, תהיה לך גישה מוגבלת בלבד לחשבונך.
view_strikes: צפיה בעברות קודמות שנרשמו נגד חשבונך
too_fast: הטופס הוגש מהר מדי, נסה/י שוב.
use_security_key: שימוש במפתח אבטחה
@ -1632,9 +1622,6 @@ he:
over_daily_limit: חרגת מהמספר המקסימלי של הודעות מתוזמנות להיום, שהוא %{limit}
over_total_limit: חרגת מהמספר המקסימלי של הודעות מתוזמנות, שהוא %{limit}
too_soon: תאריך התזמון חייב להיות בעתיד
self_destruct:
lead_html: לרוע המזל, <strong>%{domain}</strong> עומד לרדת באופן סופי. אם היה לך חשבון כאן, לא תהיה אפשרות להמשיך להשתמש בו, אבל ניתן לבקש גיבוי של כל המידע שלך.
title: שרת זה בתהליכי סגירה
sessions:
activity: פעילות אחרונה
browser: דפדפן

View File

@ -534,7 +534,6 @@ hu:
total_reported: Bejelentés róluk
total_storage: Média csatolmány
totals_time_period_hint_html: Az alább mutatott összesítések minden eddigi adatot tartalmaznak.
unknown_instance: Jelenleg nincs rekord erről a domainről ezen a kiszolgálón.
invites:
deactivate_all: Összes deaktiválása
filter:
@ -1041,14 +1040,6 @@ hu:
hint_html: Még egy dolog! Meg kell győződnünk róla, hogy tényleg valós személy vagy (így távol tarthatjuk a spam-et). Oldd meg az alábbi CAPTCHA-t és kattints a "Folytatás"-ra.
title: Biztonsági ellenőrzés
confirmations:
awaiting_review: Az email címed megerősítésre került. %{domain} stábja jelenleg áttekinti a regisztrációdat. Ha jóváhagyásra került a fiókod, egy emailt küldenek majd!
awaiting_review_title: A regisztrációd áttekintés alatt áll
clicking_this_link: kattintás erre a hivatkozásra
login_link: bejelentkezés
proceed_to_login_html: 'Most továbbléphetsz: %{login_link}.'
redirect_to_app_html: Át kellett volna irányítsunk a <strong>%{app_name}</strong> alkalmazáshoz. Ha ez nem történt meg, próbálkozz a %{clicking_this_link} lehetőséggel vagy térj vissza manuálisan az alkalmazáshoz.
registration_complete: A regisztrációd %{domain} domainen befejeződött!
welcome_title: Üdvözlet, %{name}!
wrong_email_hint: Ha az emailcím nem helyes, a fiókbeállításokban megváltoztathatod.
delete_account: Felhasználói fiók törlése
delete_account_html: Felhasználói fiókod törléséhez <a href="%{path}">kattints ide</a>. A rendszer újbóli megerősítést fog kérni.
@ -1110,7 +1101,6 @@ hu:
functional: A fiókod teljesen működőképes.
pending: A jelentkezésed engedélyezésre vár. Ez eltarthat egy ideig. Kapsz egy e-mailt, ha a kérelmedet jóváhagyták.
redirecting_to: A fiókod inaktív, mert jelenleg ide %{acct} van átirányítva.
self_destruct: Mivel a %{domain} bezár, csak korlátozott elérésed lesz a fiókodhoz.
view_strikes: Fiókod ellen felrótt korábbi vétségek megtekintése
too_fast: Túl gyorsan küldted el az űrlapot, próbáld később.
use_security_key: Biztonsági kulcs használata
@ -1580,9 +1570,6 @@ hu:
over_daily_limit: Túllépted az időzített bejegyzésekre vonatkozó %{limit} db-os napi limitet
over_total_limit: Túllépted az időzített bejegyzésekre vonatkozó %{limit} db-os limitet
too_soon: Az időzített időpontnak a jövőben kell lennie
self_destruct:
lead_html: Sajnos a <strong>%{domain}</strong> végleg bezár. Ha volt itt fiókod, nem fogod tudni tovább használni, de kérheted majd az adataid biztonsági mentését.
title: A kiszolgáló bezár
sessions:
activity: Legutóbbi tevékenység
browser: Böngésző

View File

@ -534,7 +534,6 @@ is:
total_reported: Kærur um þá
total_storage: Myndaviðhengi
totals_time_period_hint_html: Samtölurnar sem birtar eru hér fyrir neðan innihalda gögn frá upphafi.
unknown_instance: Í augnablikinu er engin færsla um þetta lén á þessum netþjóni.
invites:
deactivate_all: Gera allt óvirkt
filter:
@ -1045,14 +1044,6 @@ is:
Leystu Turing skynprófið og smelltu á "Áfram".
title: Öryggisathugun
confirmations:
awaiting_review: Tölvupóstfangið þitt er staðfest. Umsjónarfólk %{domain} er núna að yfirfara skráninguna þína. Þú munt fá tölvupóst ef þau samþykkja skráninguna þína!
awaiting_review_title: Verið er að yfirfara skráninguna þína
clicking_this_link: smella á þennan tengil
login_link: skrá þig inn
proceed_to_login_html: Þú getur núna farið í að %{login_link}.
redirect_to_app_html: Þér ætti að hafa verið endurbeint í <strong>%{app_name}</strong> forritið. Ef það gerðist ekki, skaltu prófa að %{clicking_this_link} eða fara aftur í forritið.
registration_complete: Skráning þín á %{domain} er núna tilbúin!
welcome_title: Velkomin/n %{name}!
wrong_email_hint: Ef það tölvupóstfang er ekki rétt geturðu breytt því í stillingum notandaaðgangsins.
delete_account: Eyða notandaaðgangi
delete_account_html: Ef þú vilt eyða notandaaðgangnum þínum, þá geturðu <a href="%{path}">farið í það hér</a>. Þú verður beðin/n um staðfestingu.
@ -1114,7 +1105,6 @@ is:
functional: Notandaaðgangurinn þinn er með fulla virkni.
pending: Umsóknin þín bíður eftir að starfsfólkið okkar fari yfir hana. Það gæti tekið nokkurn tíma. Þú munt fá tölvupóst ef umsóknin er samþykkt.
redirecting_to: Notandaaðgangurinn þinn er óvirkur vegna þess að hann endurbeinist á %{acct}.
self_destruct: Þar sem %{domain} er að hætta starfsemi, muntu aðeins halda takmörkuðum aðgangi að aðgangnum þínum.
view_strikes: Skoða fyrri bönn notandaaðgangsins þíns
too_fast: Innfyllingarform sent inn of hratt, prófaðu aftur.
use_security_key: Nota öryggislykil
@ -1584,9 +1574,6 @@ is:
over_daily_limit: Þú hefur farið fram úr hámarkinu með %{limit} áætlaðar færslur fyrir þennan dag
over_total_limit: Þú hefur farið fram úr hámarkinu með %{limit} áætlaðar færslur
too_soon: Áætluð dagsetning verður að vera í framtíðinni
self_destruct:
lead_html: Því miður, <strong>%{domain}</strong> er að hætta starfsemi endanlega. Ef þú varst með aðgang þar, muntu ekki geta haldið áfram að nota hann, en þú getur áfram beðið um afrit af gögnunum þínum.
title: Þessi netþjónn er að hætta starfsemi
sessions:
activity: Síðasta virkni
browser: Vafri

View File

@ -534,7 +534,6 @@ it:
total_reported: Segnalazioni su di loro
total_storage: Media allegati
totals_time_period_hint_html: I totali sotto visualizzati includono i dati per tutti i tempi.
unknown_instance: Al momento non c'è alcun documento di questo dominio su questo server.
invites:
deactivate_all: Disattiva tutto
filter:
@ -1043,14 +1042,6 @@ it:
hint_html: Solamente un'altra cosa! Dobbiamo confermare che tu sia un essere umano (così possiamo tenere fuori lo spam!). Risolvi il CAPTCHA sottostante e fai clic su "Continua".
title: Controllo di sicurezza
confirmations:
awaiting_review: Il tuo indirizzo e-mail è confermato! Lo staff di %{domain} sta esaminando la tua registrazione. Riceverai una e-mail se il tuo account sarà approvato!
awaiting_review_title: La tua registrazione è in corso di revisione
clicking_this_link: cliccando su questo link
login_link: accedi
proceed_to_login_html: Ora puoi procedere con il %{login_link}.
redirect_to_app_html: Avresti dovuto essere reindirizzato all'app <strong>%{app_name}</strong>. Se ciò non fosse avvenuto, prova %{clicking_this_link} o torna manualmente all'app.
registration_complete: La tua registrazione su %{domain} è ora completata!
welcome_title: Benvenutə, %{name}!
wrong_email_hint: Se l'indirizzo e-mail non è corretto, puoi modificarlo nelle impostazioni dell'account.
delete_account: Elimina account
delete_account_html: Se desideri cancellare il tuo account, puoi <a href="%{path}">farlo qui</a>. Ti sarà chiesta conferma.
@ -1112,7 +1103,6 @@ it:
functional: Il tuo profilo è completamente operativo.
pending: La tua richiesta è in attesa di esame da parte del nostro staff. Potrebbe richiedere un po' di tempo. Riceverai una e-mail se la richiesta è approvata.
redirecting_to: Il tuo account è inattivo perché attualmente reindirizza a %{acct}.
self_destruct: Poiché %{domain} sta chiudendo, otterrai solo un accesso limitato al tuo account.
view_strikes: Visualizza le sanzioni precedenti prese nei confronti del tuo account
too_fast: Modulo inviato troppo velocemente, riprova.
use_security_key: Usa la chiave di sicurezza
@ -1582,9 +1572,6 @@ it:
over_daily_limit: Hai superato il limite di %{limit} post programmati per questo giorno
over_total_limit: Hai superato il limite di %{limit} post programmati
too_soon: La data di pubblicazione deve essere nel futuro
self_destruct:
lead_html: Sfortunatamente, <strong>%{domain}</strong> sta chiudendo definitivamente. Se hai un account lì, non potrai continuare a usarlo, ma puoi ancora richiedere un backup dei tuoi dati.
title: Questo server sta chiudendo
sessions:
activity: Ultima attività
browser: Browser

View File

@ -523,7 +523,6 @@ ja:
total_reported: 通報合計
total_storage: 添付されたメディア
totals_time_period_hint_html: 以下に表示される合計には、すべての時間のデータが含まれています。
unknown_instance: 今のところ、このドメインについては何も記録されていません。
invites:
deactivate_all: すべて無効化
filter:
@ -1023,14 +1022,6 @@ ja:
hint_html: もう一つだけ!あなたが人間であることを確認する必要があります(スパムを防ぐためです!)。 以下のCAPTCHAを解き、「続ける」をクリックします。
title: セキュリティチェック
confirmations:
awaiting_review: メールアドレスは確認済みです。%{domain} のモデレーターによりアカウント登録の審査が完了すると、メールでお知らせします。
awaiting_review_title: 登録の審査待ちです
clicking_this_link: こちらのリンク
login_link: こちらのリンク
proceed_to_login_html: "%{login_link}から早速ログインしてみましょう。"
redirect_to_app_html: "<strong>%{app_name}</strong>に戻ります。自動で移動しない場合は%{clicking_this_link}を押すか、手動でアプリを切り替えてください。"
registration_complete: "%{domain} へのアカウント登録が完了しました。"
welcome_title: Mastodonへようこそ、%{name}さん
wrong_email_hint: メールアドレスが正しくない場合は、アカウント設定で変更できます。
delete_account: アカウントの削除
delete_account_html: アカウントを削除したい場合、<a href="%{path}">こちら</a>から手続きが行えます。削除する前に、確認画面があります。
@ -1092,7 +1083,6 @@ ja:
functional: アカウントは完全に機能しています。
pending: あなたの申請は現在サーバー管理者による審査待ちです。これにはしばらくかかります。申請が承認されるとメールが届きます。
redirecting_to: アカウントは%{acct}に引っ越し設定されているため非アクティブになっています。
self_destruct: "%{domain} は閉鎖されるため、今後このアカウントでは限られた操作しかできません。"
view_strikes: 過去のストライクを表示
too_fast: フォームの送信が速すぎます。もう一度やり直してください。
use_security_key: セキュリティキーを使用
@ -1554,9 +1544,6 @@ ja:
over_daily_limit: その日予約できる投稿数 %{limit}を超えています
over_total_limit: 予約できる投稿数 %{limit}を超えています
too_soon: より先の時間を指定してください
self_destruct:
lead_html: 残念ながら、<strong>%{domain}</strong> は恒久的に閉鎖されます。ここにお持ちだったアカウントを今後使うことはできませんが、これまでのデータのバックアップを要求することはまだ可能です。
title: このサーバーは閉鎖されます
sessions:
activity: 最後のアクティビティ
browser: ブラウザ

View File

@ -525,7 +525,6 @@ ko:
total_reported: 이들에 대한 신고
total_storage: 미디어 첨부
totals_time_period_hint_html: 아래에 표시된 총계에는 모든 시간에 대한 데이터가 포함됩니다.
unknown_instance: 현재 이 서버에서 해당 도메인에 대한 기록은 없습니다.
invites:
deactivate_all: 전부 비활성화
filter:
@ -779,7 +778,7 @@ ko:
types:
major: 메이저 릴리스
minor: 마이너 릴리스
patch: 패치 릴리스 — 버그픽스이며 변경을 적용하기 쉽습니다
patch: 패치 릴리스 — 버그픽스 그리고 변경점의 빠른 적용
version: 버전
statuses:
account: 작성자
@ -1025,14 +1024,6 @@ ko:
hint_html: 하나만 더! 당신이 사람인지 확인이 필요합니다 (스팸 계정을 거르기 위해서 필요한 과정입니다). 아래에 있는 CAPTCHA를 풀고 "계속"을 누르세요
title: 보안 체크
confirmations:
awaiting_review: 이메일 주소가 확인되었습니다! 이제 %{domain} 스태프가 가입을 검토할 것입니다. 계정이 승인되면 이메일을 받게 됩니다!
awaiting_review_title: 가입 신청을 검토 중입니다
clicking_this_link: 이 링크를 클릭
login_link: 로그인
proceed_to_login_html: 이제 %{login_link} 할 수 있습니다.
redirect_to_app_html: 곧 <strong>%{app_name}</strong>으로 리디렉션 됩니다. 안 된다면, %{clicking_this_link}하거나 직접 앱으로 돌아가세요.
registration_complete: 지금 막 %{domain} 가입이 완료되었습니다!
welcome_title: "%{name} 님 반갑습니다!"
wrong_email_hint: 만약 이메일 주소가 올바르지 않다면, 계정 설정에서 수정할 수 있습니다.
delete_account: 계정 삭제
delete_account_html: 계정을 삭제하고 싶은 경우, <a href="%{path}">여기서</a> 삭제할 수 있습니다. 삭제 전 확인 화면이 표시됩니다.
@ -1094,7 +1085,6 @@ ko:
functional: 계정이 완벽히 작동합니다.
pending: 당신의 가입 신청은 스태프의 검사를 위해 대기 중입니다. 시간이 조금 걸릴 수 있습니다. 가입 신청이 승인되면 이메일을 받게 됩니다.
redirecting_to: 계정이 %{acct}로 리다이렉트 중이기 때문에 비활성 상태입니다.
self_destruct: "%{domain} 도메인 폐쇄가 진행중이기 때문에, 계정에는 제한된 접근만 할 수 있습니다."
view_strikes: 내 계정에 대한 과거 중재 기록 보기
too_fast: 너무 빠르게 양식이 제출되었습니다, 다시 시도하세요.
use_security_key: 보안 키 사용
@ -1556,9 +1546,6 @@ ko:
over_daily_limit: 그 날짜에 대한 %{limit}개의 예약 게시물 제한을 초과합니다
over_total_limit: 예약 게시물 제한 %{limit}을 초과합니다
too_soon: 예약 날짜는 미래여야 합니다
self_destruct:
lead_html: 안타깝게도, <strong>%{domain}</strong> 도메인을 영구히 폐쇄합니다. 이곳의 계정을 가졌다면, 이제 이용할 수 없으며, 당분간 백업 데이터를 요청할 수 있습니다.
title: 이 서버는 폐쇄중입니다
sessions:
activity: 최근 활동
browser: 브라우저

View File

@ -534,7 +534,6 @@ nl:
total_reported: Rapportages over hun
total_storage: Mediabijlagen
totals_time_period_hint_html: De hieronder getoonde totalen bevatten gegevens sinds het begin.
unknown_instance: Er zijn momenteel geen gegevens van dit domein op deze server.
invites:
deactivate_all: Alles deactiveren
filter:
@ -1041,14 +1040,6 @@ nl:
hint_html: Nog maar één ding! Je moet bevestigen dat je een mens bent (dit is om de spam buiten de deur te houden!). Los de onderstaande CAPTCHA op en klik op "Doorgaan".
title: Veiligheidscontrole
confirmations:
awaiting_review: Je e-mailadres is bevestigd! De medewerkers van %{domain} zijn nu bezig met het beoordelen van jouw registratie. Je ontvangt een e-mailbericht wanneer ze jouw account goedkeuren!
awaiting_review_title: Je registratie wordt beoordeeld
clicking_this_link: op deze link te klikken
login_link: inloggen
proceed_to_login_html: Je kunt nu verder gaan naar %{login_link}.
redirect_to_app_html: Je zou omgeleid moeten zijn naar de <strong>%{app_name}</strong> app. Als dat niet is gebeurd, probeer dan %{clicking_this_link} of keer handmatig terug naar de app.
registration_complete: Je registratie op %{domain} is nu voltooid!
welcome_title: Welkom %{name}!
wrong_email_hint: Als dat e-mailadres niet correct is, kun je het wijzigen in je accountinstellingen.
delete_account: Account verwijderen
delete_account_html: Wanneer je jouw account graag wilt verwijderen, kun je dat <a href="%{path}">hier doen</a>. We vragen jou daar om een bevestiging.
@ -1110,7 +1101,6 @@ nl:
functional: Jouw account kan in diens geheel gebruikt worden.
pending: Jouw aanvraag moet nog worden beoordeeld door een van onze medewerkers. Dit kan misschien eventjes duren. Je ontvangt een e-mail wanneer jouw aanvraag is goedgekeurd.
redirecting_to: Jouw account is inactief omdat het momenteel wordt doorverwezen naar %{acct}.
self_destruct: Omdat %{domain} gaat sluiten, krijgt u slechts beperkt toegang tot uw account.
view_strikes: Bekijk de eerder door moderatoren vastgestelde overtredingen die je hebt gemaakt
too_fast: Formulier is te snel ingediend. Probeer het nogmaals.
use_security_key: Beveiligingssleutel gebruiken
@ -1580,9 +1570,6 @@ nl:
over_daily_limit: Je hebt de limiet van %{limit} in te plannen berichten voor vandaag overschreden
over_total_limit: Je hebt de limiet van %{limit} in te plannen berichten overschreden
too_soon: De datum voor het ingeplande bericht moet in de toekomst liggen
self_destruct:
lead_html: Helaas gaat <strong>%{domain}</strong> permanent sluiten. Als je daar een account had, kun je deze niet meer gebruiken, maar je kunt nog steeds een back-up van je gegevens opvragen.
title: Deze server gaat sluiten
sessions:
activity: Laatst actief
browser: Webbrowser

View File

@ -556,7 +556,6 @@ pl:
total_reported: Zgłoszenia dotyczące ich
total_storage: Załączniki multimedialne
totals_time_period_hint_html: Poniższe sumy zawierają dane od początku serwera.
unknown_instance: Obecnie ta domena jest nieznana na tym serwerze.
invites:
deactivate_all: Unieważnij wszystkie
filter:
@ -1077,14 +1076,6 @@ pl:
hint_html: Jeszcze jedno! Potrzebujemy potwierdzić twoje człowieczeństwo, żeby ograniczyć spam. Rozwiąż poniższą CAPTCHA-ę i naciśnij "Kontynuuj".
title: Kontrola bezpieczeństwa
confirmations:
awaiting_review: Twój adres e-mail został potwierdzony! Administracja %{domain} sprawdza Twoją rejestrację. Otrzymasz e-mail w momencie, gdy zaakceptują Twoje konto!
awaiting_review_title: Twoja rejestracja jest obecnie sprawdzana
clicking_this_link: kliknąć ten link
login_link: zaloguj się
proceed_to_login_html: Teraz możesz przejść do %{login_link}.
redirect_to_app_html: Powinieneś zostać przekierowany do aplikacji <strong>%{app_name}</strong>. Jeśli tak się nie stało, spróbuj %{clicking_this_link} lub ręcznie wróć do aplikacji.
registration_complete: Twoja rejestracja na %{domain} została zakończona!
welcome_title: Witaj, %{name}!
wrong_email_hint: Jeśli ten adres e-mail nie jest poprawny, możesz go zmienić w ustawieniach konta.
delete_account: Usunięcie konta
delete_account_html: Jeżeli chcesz usunąć konto, <a href="%{path}">przejdź tutaj</a>. Otrzymasz prośbę o potwierdzenie.
@ -1146,7 +1137,6 @@ pl:
functional: Twoje konto jest w pełni funkcjonalne.
pending: Twoje zgłoszenie czeka na zatwierdzenie przez nas. Może to trochę potrwać. Jeżeli zgłoszenie zostanie przyjęte, otrzymasz wiadomość e-mail.
redirecting_to: Twoje konto jest nieaktywne, ponieważ obecnie przekierowuje je na %{acct}.
self_destruct: "%{domain} jest zamykane, dostęp do konta będzie ograniczony."
view_strikes: Zobacz dawne ostrzeżenia nałożone na twoje konto
too_fast: Zbyt szybko przesłano formularz, spróbuj ponownie.
use_security_key: Użyj klucza bezpieczeństwa
@ -1632,9 +1622,6 @@ pl:
over_daily_limit: Przekroczyłeś(-aś) limit %{limit} zaplanowanych wpisów na ten dzień
over_total_limit: Przekroczyłeś(-aś) limit %{limit} zaplanowanych wpisów
too_soon: Zaplanowana data musi wypadać w przyszłości
self_destruct:
lead_html: Niestety, <strong>%{domain}</strong> jest permanentnie zamykane. Konta z tego serwera nie będą dostępne, ale można jeszcze odzyskać kopię zapasową danych.
title: Ten serwer jest zamykany
sessions:
activity: Ostatnia aktywność
browser: Przeglądarka

View File

@ -1040,8 +1040,6 @@ pt-BR:
hint_html: Só mais uma coisa! Precisamos confirmar que você é um humano (isso é para que possamos evitar o spam!). Resolva o CAPTCHA abaixo e clique em "Continuar".
title: Verificação de segurança
confirmations:
registration_complete: Seu cadastro no %{domain} foi concluído!
welcome_title: Boas vindas, %{name}!
wrong_email_hint: Se esse endereço de e-mail não estiver correto, você pode alterá-lo nas configurações da conta.
delete_account: Excluir conta
delete_account_html: Se você deseja excluir sua conta, você pode <a href="%{path}">fazer isso aqui</a>. Uma confirmação será solicitada.
@ -1103,7 +1101,6 @@ pt-BR:
functional: Sua conta está totalmente operacional.
pending: Sua solicitação está com revisão pendente por parte de nossa equipe. Você receberá um e-mail se ela for aprovada.
redirecting_to: Sua conta está inativa porque atualmente está redirecionando para %{acct}.
self_destruct: Como %{domain} está se encerrando, você só terá acesso limitado à sua conta.
view_strikes: Veja os avisos anteriores em relação à sua conta
too_fast: O formulário foi enviado muito rapidamente, tente novamente.
use_security_key: Usar chave de segurança
@ -1573,9 +1570,6 @@ pt-BR:
over_daily_limit: Você excedeu o limite de %{limit} publicações agendadas para esse dia
over_total_limit: Você excedeu o limite de %{limit} publicações agendadas
too_soon: A data agendada precisa ser no futuro
self_destruct:
lead_html: Infelizmente, <strong>%{domain}</strong> está se encerrando de forma permanente. Se você tem uma conta lá, não poderá continuar a usá-la, mas ainda pode solicitar uma cópia dos seus dados.
title: Este servidor está sendo fechado
sessions:
activity: Última atividade
browser: Navegador

View File

@ -534,7 +534,6 @@ pt-PT:
total_reported: Denúncias sobre eles
total_storage: Anexos de media
totals_time_period_hint_html: Os totais exibidos abaixo incluem dados referentes ao tempo total.
unknown_instance: Atualmente não há registo deste domínio neste servidor.
invites:
deactivate_all: Desativar todos
filter:
@ -1041,14 +1040,6 @@ pt-PT:
hint_html: Só mais uma coisa! Precisamos confirmar que você é um humano (isto para que possamos evitar spam!). Resolva o CAPTCHA abaixo e clique em "Continuar".
title: Verificação de segurança
confirmations:
awaiting_review: O seu endereço de correio eletrónico foi confirmado! A equipa %{domain} está agora a rever a sua inscrição. Receberá uma mensagem de correio eletrónico se aprovarem a sua conta!
awaiting_review_title: A sua inscrição está a ser revista
clicking_this_link: clicar nesta hiperligação
login_link: iniciar sessão
proceed_to_login_html: Pode agora prosseguir para %{login_link}.
redirect_to_app_html: Devia ter sido reencaminhado para a aplicação <strong>%{app_name}</strong>. Se isso não aconteceu, tente %{clicking_this_link} ou volte manualmente para a aplicação.
registration_complete: O seu registo sem %{domain} está agora concluído!
welcome_title: Bem-vindo(a), %{name}!
wrong_email_hint: Se esse endereço de e-mail não estiver correto, você pode alterá-lo nas configurações da conta.
delete_account: Eliminar conta
delete_account_html: Se deseja eliminar a sua conta, pode <a href="%{path}">continuar aqui</a>. Uma confirmação será solicitada.
@ -1110,7 +1101,6 @@ pt-PT:
functional: A sua conta está totalmente operacional.
pending: A sua inscrição está pendente de revisão pela nossa equipa. Isso pode demorar algum tempo. Receberá um e-mail se a sua conta for aprovada.
redirecting_to: A sua conta está inativa porque está atualmente a ser redirecionada para %{acct}.
self_destruct: Como %{domain} vai fechar, só terá acesso limitado à sua conta.
view_strikes: Veja as reprimendas anteriores sobre a sua conta
too_fast: Formulário enviado demasiado rapidamente, tente novamente.
use_security_key: Usar chave de segurança
@ -1580,9 +1570,6 @@ pt-PT:
over_daily_limit: Excedeste o limite de %{limit} publicações agendadas para esse dia
over_total_limit: Tu excedeste o limite de %{limit} publicações agendadas
too_soon: A data de agendamento tem de ser futura
self_destruct:
lead_html: Infelizmente, <strong>%{domain}</strong> vai fechar definitivamente. Se lá tinha conta, não pode continuar a usá-la, mas ainda pode pedir uma cópia dos seus dados.
title: Este servidor vai fechar
sessions:
activity: Última atividade
browser: Navegador

View File

@ -556,7 +556,6 @@ ru:
total_reported: Жалобы на них
total_storage: Медиафайлы
totals_time_period_hint_html: Итоги, показанные ниже, включают данные за всё время.
unknown_instance: На данный момент нет записей об этом домене на этом сервере.
invites:
deactivate_all: Отключить все
filter:
@ -1077,12 +1076,6 @@ ru:
hint_html: Еще одна вещь! Нам нужно подтвердить, что вы человек (так что мы можем держать спам!). Решите капчу ниже и нажмите кнопку «Продолжить».
title: Проверка безопасности
confirmations:
awaiting_review: Ваш адрес электронной почты подтвержден! Сотрудники %{domain} проверяют вашу регистрацию. Вы получите письмо, если они подтвердят вашу учетную запись!
awaiting_review_title: Ваша регистрация проверяется
login_link: войти
proceed_to_login_html: Теперь вы можете перейти к %{login_link}.
registration_complete: Ваша регистрация на %{domain} завершена!
welcome_title: Добро пожаловать, %{name}!
wrong_email_hint: Если этот адрес электронной почты неверен, вы можете изменить его в настройках аккаунта.
delete_account: Удалить учётную запись
delete_account_html: Удалить свою учётную запись <a href="%{path}">можно в два счёта здесь</a>, но прежде у вас будет спрошено подтверждение.
@ -1144,7 +1137,6 @@ ru:
functional: Ваша учётная запись в полном порядке.
pending: Ваша заявка ожидает одобрения администраторами, это может занять немного времени. Вы получите письмо, как только заявку одобрят.
redirecting_to: Ваша учётная запись деактивированна, потому что вы настроили перенаправление на %{acct}.
self_destruct: Поскольку %{domain} закрывается, вы получите ограниченный доступ к вашей учетной записи.
view_strikes: Просмотр предыдущих замечаний в адрес вашей учетной записи
too_fast: Форма отправлена слишком быстро, попробуйте еще раз.
use_security_key: Использовать ключ безопасности
@ -1630,8 +1622,6 @@ ru:
over_daily_limit: Вы превысили лимит в %{limit} запланированных постов на указанный день
over_total_limit: Вы превысили лимит на %{limit} запланированных постов
too_soon: Запланированная дата должна быть в будущем
self_destruct:
title: Этот сервер закрывается
sessions:
activity: Последняя активность
browser: Браузер

View File

@ -180,9 +180,9 @@ he:
bot: זהו חשבון מסוג בוט
chosen_languages: סינון שפות
confirm_new_password: אישור סיסמא חדשה
confirm_password: אישור סיסמה
confirm_password: אישור סיסמא
context: סינון לפי הקשר
current_password: סיסמה נוכחית
current_password: סיסמא נוכחית
data: מידע
display_name: שם להצגה
email: כתובת דוא"ל
@ -194,10 +194,10 @@ he:
irreversible: הסרה במקום הסתרה
locale: שפה
max_uses: מספר מרבי של שימושים
new_password: סיסמה חדשה
new_password: סיסמא חדשה
note: אודות
otp_attempt: קוד אימות דו-שלבי
password: סיסמה
password: סיסמא
phrase: מילת מפתח או ביטוי
setting_advanced_layout: אפשר ממשק ווב מתקדם
setting_aggregate_reblogs: קבץ הדהודים זהים

View File

@ -116,7 +116,7 @@ zh-TW:
sign_up_requires_approval: 新註冊申請需要先經過您的審核
severity: 請選擇將如何處理來自這個 IP 位址的請求
rule:
text: 說明使用者此伺服器上需遵守的規則或條款。試著維持各項條款簡短而明瞭。
text: 說明使用者此伺服器上需遵守的規則或條款。試著維持各項條款簡短而明瞭。
sessions:
otp: 請輸入產生自您手機 App 的兩階段驗證碼,或輸入其中一個備用驗證碼:
webauthn: 如果它是 USB 安全金鑰的話,請確認已正確插入,如有需要請觸擊。

View File

@ -125,8 +125,6 @@ sk:
removed_header_msg: Úspešne odstránený obrázok hlavičky %{username}
resend_confirmation:
already_confirmed: Tento užívateľ je už potvrdený
send: Odošli potvrdzovací odkaz znovu
success: Potvrdzovací email úspešne odoslaný!
reset: Resetuj
reset_password: Obnov heslo
resubscribe: Znovu odoberaj
@ -230,7 +228,6 @@ sk:
create_account_warning_html: "%{name} poslal/a upozornenie užívateľovi %{target}"
create_announcement_html: "%{name} vytvoril/a nové oboznámenie %{target}"
create_custom_emoji_html: "%{name} nahral/a novú emotikonu %{target}"
create_domain_allow_html: "%{name} povolil/a federáciu s doménou %{target}"
create_domain_block_html: "%{name} zablokoval/a doménu %{target}"
create_email_domain_block_html: "%{name} zablokoval/a e-mailovú doménu %{target}"
create_user_role_html: "%{name} vytvoril/a rolu pre %{target}"
@ -244,7 +241,6 @@ sk:
destroy_ip_block_html: "%{name} vymazal/a pravidlo pre IP %{target}"
destroy_status_html: "%{name} zmazal/a príspevok od %{target}"
destroy_user_role_html: "%{name} vymazal/a rolu pre %{target}"
enable_user_html: "%{name} povolil/a prihlásenie pre používateľa %{target}"
memorialize_account_html: "%{name} zmenil/a účet %{target} na pamätnú stránku"
reject_appeal_html: "%{name} zamietol/la námietku moderovacieho rozhodnutia od %{target}"
reopen_report_html: "%{name} znovu otvoril/a nahlásenie %{target}"
@ -1042,7 +1038,6 @@ sk:
confirm_remove_selected_followers: Si si istý/á, že chceš odstrániť vybraných sledovateľov?
confirm_remove_selected_follows: Si si istý/á, že chceš odstrániť vybraných sledovaných?
dormant: Spiace
follow_failure: Nemožno nasledovať niektoré z vybraných účtov.
follow_selected_followers: Následuj označených sledovatelov
followers: Následovatelia
following: Následovaní

View File

@ -1,7 +1,7 @@
---
sl:
about:
about_mastodon_html: 'Družbeno omrežje prihodnosti: brez oglasov, brez nadzora korporacij, etično oblikovano in decentralizirano! Ohranite lastništvo nad svojimi podatki z Mastodonom!'
about_mastodon_html: 'Družbeno omrežje prihodnosti: brez oglasov, brez nadzora korporacij, etično oblikovanje in decentralizacija! Ohranite lastništvo nad svojimi podatki z Mastodonom!'
contact_missing: Ni nastavljeno
contact_unavailable: Ni na voljo
hosted_on: Mastodon gostuje na %{domain}
@ -401,11 +401,9 @@ sl:
cancel: Prekliči
confirm: Suspendiraj
permanent_action: Z razveljavitvijo suzpenza ne boste obnovili nobenih podatkov ali razmerij.
preamble_html: Suspendirali boste <strong>%{domain}</strong> in njene poddomene.
remove_all_data: S tem boste odstranili celotno vsebino, medijske vsebine ter podatke iz profila za rčune te domene na vašem strežniku.
stop_communication: Vaš strežnik bo prenehal komunicirati s temi strežniki.
title: Potrdi domenski blok za %{domain}
undo_relationships: To bo prekinilo vse odnose sledenja med računi na teh strežnikih in na vašem strežniku.
created_msg: Domenski blok se sedaj obdeluje
destroyed_msg: Domenski blok je bil razveljavljen
domain: Domena
@ -556,7 +554,6 @@ sl:
total_reported: Prijave o njih
total_storage: Predstavnostne priloge
totals_time_period_hint_html: Spodaj prikazani seštevki vključujejo podatke za celotno obdobje.
unknown_instance: Trenutno ne obstaja zapis te domene na tem strežniku.
invites:
deactivate_all: Onemogoči vse
filter:
@ -770,9 +767,6 @@ sl:
branding:
preamble: Blagovna znamka vašega strežnika ga loči od drugih strežnikov v omrežju. Podatki se lahko prikžejo prek številnih okolij, kot so spletni vmesnik Mastodona, domorodni programi, predogledi povezav na drugih spletiščih, aplikacije za sporočanje itn. Zatorej je najbolje, da te podatke ohranite jasne, kratke in pomenljive.
title: Blagovne znamke
captcha_enabled:
desc_html: To se zanaša na zunanje skripte hCaptcha in lahko predstavlja tveganje za varnost in zasebnost. Poleg tega <strong>to lahko nekaterim ljudem (posebno invalidom) občutno oteži dostopnost registracijskega postopka</strong>. Zato svetujemo, da razmislite o drugih ukrepih, kot je na primer registracija na podlagi odobritve ali povabila.
title: Od novih uporabnikov zahtevaj reševanje CAPTCHA za potrditev računov
content_retention:
preamble: Nazdor nad hrambo vsebine uporabnikov v Mastodonu.
title: Hramba vsebin
@ -801,17 +795,13 @@ sl:
none: Nihče se ne more prijaviti
open: Vsakdo se lahko prijavi
security:
authorized_fetch: Od drugih strežnikov v federaciji zahtevaj overitev pristnosti
authorized_fetch_hint: Zahtevanje overitve pristnosti od drugih strežnikov v federaciji omogoči strožje uveljavljanje uporabniških in strežniških blokad. Vendar je cena za to počasnejše delovanje, zmanjšanje dosega vaših odgovorov in morebitne težave z združljivostjo z nekaterimi storitvami v federaciji. Poleg tega to odločenim akterjem ne bo preprečilo pridobivanja vaših javnih objav in računov.
authorized_fetch_overridden_hint: Trenutno ne morete spremeniti te nastavitve, ker jo preglasi okoljska spremenljivka.
federation_authentication: Izvršba overitve pristnosti v federaciji
title: Nastavitve strežnika
site_uploads:
delete: Izbriši naloženo datoteko
destroyed_msg: Prenos na strežnik uspešno izbrisan!
software_updates:
critical_update: Kritično — čim prej posodobite
description: Vašo namestitev Mastodona je priporočeno vedno imeti posodobljeno in tako koristiti najnovejše popravke ter zmožnosti. Poleg tega je včasih nujno čim prej posodobiti Mastodon in se s tem izogniti varnostnim težavam. Zato Mastodon vsakih 30 minut preverja razpoložljivost posodobitev in vas o njih obvešča glede na vaše nastavitve obveščanja po e-pošti.
documentation_link: Več o tem
release_notes: Opombe ob izdaji
title: Razpoložljive posodobitve
@ -861,20 +851,10 @@ sl:
system_checks:
database_schema_check:
message_html: Na čakanju so migracije zbirke podatkov. Prosimo, izvedite jih, da zagotovite, da se program vede pričakovano
elasticsearch_health_red:
message_html: Z gručo Elasticsearch ni vse v redu (rdeče stanje), zmožnosti iskanja niso na voljo
elasticsearch_health_yellow:
message_html: Z gručo Elasticsearch ni vse v redu (rumeno stanje), priporočeno je ugotoviti razlog
elasticsearch_index_mismatch:
message_html: Preslikave kazala Elasticsearch so zastarele. Poženite <code>tootctl search deploy --only=%{value}</code>
elasticsearch_preset:
action: Glejte dokumentacijo
message_html: Vaša gruča Elasticsearch vsebuje več kot eno vozlišče, vendar Mastodon ni nastavljen, da bi jih uporabljal.
elasticsearch_preset_single_node:
action: Glejte dokumentacijo
message_html: Vaša gruča Elasticsearch vsebuje samo eno vozlišče, <code>ES_PRESET</code> bi moralo biti nastavljeno na <code>single_node_cluster</code>.
elasticsearch_reset_chewy:
message_html: Sistemsko kazalo Elasticsearch je zastarelo zaradi spremembe nastavitve. Za posodobitev poženite <code>tootctl search deploy --reset-chewy</code>.
elasticsearch_running_check:
message_html: Povezava z Elasticsearch ni uspela. Preverite, da deluje, ali onemogočite iskanje po vsem besedilu
elasticsearch_version_check:
@ -887,7 +867,6 @@ sl:
message_html: Noben proces Sidekiq ne poteka za %{value} vrst. Preglejte svojo prilagoditev Sidekiq
software_version_critical_check:
action: Glejte razpoložljive posodobitve
message_html: Na voljo je kritična posodobitev Mastodona. Posodobite čim prej.
software_version_patch_check:
action: Glejte razpoložljive posodobitve
message_html: Na voljo je posodobitev Mastodona s popravki hroščev.
@ -1012,9 +991,6 @@ sl:
body: "%{target} se pritožuje na moderatorsko odločitev %{action_taken_by} z dne %{date}, ki je bila %{type}. Zapisal/a je:"
next_steps: Pritožbi lahko ugodite in s tem razveljavite moderatorsko odločitev ali pa jo prezrete.
subject: "%{username} se je pritožil na moderatorsko odločitev na %{instance}"
new_critical_software_updates:
body: Izdane so bile nove kritične različice Mastodona. Priporočena je čimprejšnja posodobitev.
subject: Za %{instance} so na voljo kritične posodobitve Mastodona!
new_pending_account:
body: Podrobnosti o novem računu so navedene spodaj. To aplikacijo lahko odobrite ali zavrnete.
subject: Nov račun za pregled na %{instance} (%{username})
@ -1022,9 +998,6 @@ sl:
body: "%{reporter} je prijavil %{target}"
body_remote: Nekdo iz %{domain} je prijavil %{target}
subject: Nove prijave za %{instance} (#%{id})
new_software_updates:
body: Izdane so bile nove različice Mastodona. Priporočena je posodobitev.
subject: Za %{instance} so na voljo nove različice Mastodona.
new_trends:
body: 'Naslednji elementi potrebujejo pregled, preden jih je možno javno prikazati:'
new_trending_links:
@ -1073,18 +1046,8 @@ sl:
auth:
apply_for_account: Zaprosite za račun
captcha_confirmation:
help_html: Če imate težave pri reševanju CAPTCHA, lahko prek %{email} stopite v stik z nami in pomagali vam bomo.
hint_html: Samo še nekaj. Moramo se prepričati, da ste človek (to nam pomaga pri preprečevanju neželenih vsebin). Rešite spodnji CAPTCHA in kliknite »Nadaljuj«.
title: Varnostno preverjanje
confirmations:
awaiting_review: Vaš e-poštni naslov je potrjen. Skrbniki %{domain} bodo pregledali vašo prijavo. Če odobrijo vaš račun, boste o tem prejeli e-pošto.
awaiting_review_title: Vaša prijava se pregleduje
clicking_this_link: s klikom na to povezavo
login_link: prijavo
proceed_to_login_html: Sedaj lahko nadaljujete na %{login_link}.
redirect_to_app_html: Morali bi biti preusmerjeni na aplikacijo <strong>%{app_name}</strong>. Če se to ni zgodilo, poskusite %{clicking_this_link} ali pa se ročno vrnite na aplikacijo.
registration_complete: Vaša prijava na %{domain} je sedaj zaključena.
welcome_title: Pozdravljeni, %{name}!
wrong_email_hint: Če ta e-poštni naslov ni pravilen, ga lahko spremenite v nastavitvah računa.
delete_account: Izbriši račun
delete_account_html: Če želite izbrisati svoj račun, lahko nadaljujete <a href="%{path}">tukaj</a>. Prosili vas bomo za potrditev.
@ -1120,9 +1083,7 @@ sl:
rules:
accept: Sprejmi
back: Nazaj
invited_by: "%{domain} se lahko pridružite zahvaljujoč povabilu, ki ste ga prejeli od:"
preamble: Slednje določajo in njihovo spoštovanje zagotavljajo moderatorji %{domain}.
preamble_invited: Preden nadaljujete, si preberite osnovna pravila, ki so jih postavili moderatorji na %{domain}.
title: Nekaj osnovnih pravil.
title_invited: Ste povabljeni.
security: Varnost
@ -1146,7 +1107,6 @@ sl:
functional: Vaš račun je polno opravilen.
pending: Naše osebje preverja vašo prijavo. To lahko traja nekaj časa. Če bo vaša prijava odobrena, boste prejeli e-pošto.
redirecting_to: Vaš račun ni dejaven, ker trenutno preusmerja na račun %{acct}.
self_destruct: Ker se %{domain} zapira, boste imeli omejen dostop da svojega računa.
view_strikes: Pokaži pretekle ukrepe proti mojemu računu
too_fast: Obrazec oddan prehitro, poskusite znova.
use_security_key: Uporabi varnostni ključ
@ -1228,7 +1188,6 @@ sl:
invalid_domain: ni veljavno ime domene
edit_profile:
basic_information: Osnovni podatki
hint_html: "<strong>Prilagodite, kaj ljudje vidijo na vašem javnem profilu in poleg vaših objav.</strong> Drugi vam bodo raje sledili nazaj in z vami klepetali, če boste imeli izpolnjen profil in nastavljeno profilno sliko."
other: Drugo
errors:
'400': Zahteva, ki ste jo oddali, je neveljavna ali nepravilno oblikovana.
@ -1363,20 +1322,6 @@ sl:
merge_long: Ohrani obstoječe zapise in dodaj nove
overwrite: Prepiši
overwrite_long: Zamenjaj trenutne zapise z novimi
overwrite_preambles:
blocking_html: Svoj <strong>seznam blokiranih računov boste nadomestili</strong> z največ <strong>%{total_items} računi</strong> iz <strong>%{filename}</strong>.
bookmarks_html: Svoje <strong>zaznamke boste nadomestili</strong> z največ <strong>%{total_items} objavami</strong> iz <strong>%{filename}</strong>.
domain_blocking_html: Svoj <strong>seznam blokiranih domen boste nadomestili</strong> z največ <strong>%{total_items} domenami</strong> iz <strong>%{filename}</strong>.
following_html: "<strong>Začeli boste slediti</strong> največ <strong>%{total_items} računom</strong> iz <strong>%{filename}</strong> in <strong>prenehali slediti vsem ostalim</strong>."
lists_html: Svoje <strong>sezname boste nadomestili</strong> z vsebino datoteke <strong>%{filename}</strong>. Največ <strong>%{total_items} računov</strong> bo dodanih na nove sezname.
muting_html: Svoj <strong>seznam utišanih računov boste nadomestili</strong> z največ <strong>%{total_items} računi</strong> iz <strong>%{filename}</strong>.
preambles:
blocking_html: "<strong>Blokirali boste</strong> največ <strong>%{total_items} računov</strong> iz <strong>%{filename}</strong>."
bookmarks_html: "<strong>Med zaznamke</strong> boste dodali boste največ <strong>%{total_items} objav</strong> iz <strong>%{filename}</strong>."
domain_blocking_html: "<strong>Blokirali boste</strong> največ <strong>%{total_items} domen</strong> iz <strong>%{filename}</strong>."
following_html: "<strong>Začeli boste slediti</strong> največ <strong>%{total_items} računom</strong> iz <strong>%{filename}</strong>."
lists_html: Dodali boste največ <strong>%{total_items} računov</strong> iz <strong>%{filename}</strong> na svoje <strong>sezname</strong>. Po potrebi bodo ustvarjeni novi seznami.
muting_html: "<strong>Utišali boste</strong> največ <strong>%{total_items} računov</strong> iz <strong>%{filename}</strong>."
preface: Podatke, ki ste jih izvozili iz drugega strežnika, lahko uvozite. Na primer seznam oseb, ki jih spremljate ali blokirate.
recent_imports: Nedavni uvozi
states:
@ -1448,7 +1393,6 @@ sl:
unsubscribe:
action: Da, odjavi me
complete: Odjavljeni
confirmation_html: Ali se res želite odjaviti od prejemanja %{type} za Mastodon na %{domain} na svojo e-pošto %{email}? Kadarkoli se lahko znova prijavite iz svojih <a href="%{settings_path}">nastavitev e-poštnih obvestil</a>.
emails:
notification_emails:
favourite: e-sporočil z obvestili o priljubljenosti
@ -1456,7 +1400,6 @@ sl:
follow_request: e-sporočil o zahtevah za sledenje
mention: e-sporočil z obvestili o omembah
reblog: e-sporočil z obvestili o izpostavljanju
resubscribe_html: Če ste se odjavili po pomoti, se lahko znova prijavite iz svojih <a href="%{settings_path}">nastavitev e-poštnih obvestil</a>.
success_html: Nič več ne boste prejemali %{type} za Mastodon na %{domain} na svoj e-naslov %{email}.
title: Odjavi od naročnine
media_attachments:
@ -1583,13 +1526,9 @@ sl:
posting_defaults: Privzete nastavitev objavljanja
public_timelines: Javne časovnice
privacy:
hint_html: "<strong>Prilagodite, kako lahko drugi najdejo vaš profil in vaše objave.</strong> V Mastodonu obstaja več zmožnosti, ki vam pomagajo doseči širše občinstvo, če so omogočene. Vzemite si čas in preverite, ali te nastavitve ustrezajo vašemu namenu uporabe."
privacy: Zasebnost
privacy_hint_html: Nadzorujte, koliko informacij želite razkriti drugim. Ljudje lahko zanimive profile in aplikacije odkrijejo z brskanjem po seznamih sledenih in ko vidijo katere programe drugi uporabljajo za objavljanje. Morda pa bi to želeli skriti in varovati zasebnost.
reach: Dosegljivost
reach_hint_html: Nadzorujte, ali želite, da vas drugi ljudje najdejo in vam pričnejo slediti. Ali želite, da se vaše objave prikažejo na strani Razišči? Ali želite, da vas drugi ljudje vidijo med predlogi za sledenje? Ali želite nove sledilce odobriti samodejno, ali vsakega posebej odobriti ročno?
search: Iskanje
search_hint_html: Nadzorujte, kako želite, da vas najdejo. Ali želite, da vas ljudje najdejo po javnih objavah? Ali želite, da ljudje, ki niso na Mastodonu, lahko najdejo vaš profil med iskanjem po spletu? Vedite, da javnih objav in podatkov ni mogoče povsem izvzeti iz podatkovnih zbirk vseh spletnih iskalnikov.
title: Zasebnost in dosegljivost
privacy_policy:
title: Pravilnik o zasebnosti
@ -1632,9 +1571,6 @@ sl:
over_daily_limit: Za ta dan ste presegli omejitev %{limit} načrtovanih objav
over_total_limit: Presegli ste omejitev %{limit} načrtovanih objav
too_soon: Načrtovani datum mora biti v prihodnosti
self_destruct:
lead_html: Na žalost se <strong>%{domain}</strong> za vedno zapira. Če ste tu imeli svoj račun, ga v prihodnje ne boste mogli več uporabljati. Zahtevate lahko kopijo svojih podatkov.
title: Ta strežnik se zapira
sessions:
activity: Zadnja dejavnost
browser: Brskalnik
@ -1816,10 +1752,6 @@ sl:
month: "%b %Y"
time: "%H:%M"
with_time_zone: "%d. %b. %Y %H:%M %Z"
translation:
errors:
quota_exceeded: Kvota uporabe prevajalne storitve za ta strežnik je bila presežena.
too_many_requests: V zadnjem času je prevajalna storitev prejela preveč zahtevkov.
two_factor_authentication:
add: Dodaj
disable: Onemogoči
@ -1905,9 +1837,7 @@ sl:
seamless_external_login: Prijavljeni ste prek zunanje storitve, tako da nastavitve gesla in e-pošte niso na voljo.
signed_in_as: 'Vpisani kot:'
verification:
extra_instructions_html: <strong>Nasvet:</strong> Povezava na vaši spletni strani je lahko nevidna. Pomembni del je atribut <code>rel="me"</code>, ki preprečuje lažno predstavljanje na spletnih straneh z uporabniško ustvarjeno vsebino. Namesto oznake <code>a</code> lahko uporabite tudi oznako <code>link</code> znotraj glave (<code>head</code>) spletne strani, vendar mora biti HTML dosegljiv brez izvajanja skript JavaScript.
here_is_how: Kako to poteka
hint_html: "<strong>Vsakdo lahko potrdi svojo istovetnost na Mastodonu.</strong> To temelji na odprtih spletnih standardih in je sedaj in za vedno brezplačno. Potrebujete le osebno spletno stran, po kateri vas ljudje prepoznajo. Ko na svoj profil dodate povezavo na to osebno spletno stran, bo Mastodon preveril, ali na njej obstaja povezava nazaj na profil. Če ta obstaja, bo to vidno na profiu."
instructions_html: Spodnjo kodo kopirajte in prilepite v HTML svojega spletnega mesta. Nato dodajte naslov svoje spletne strani v eno od dodatnih polj v svojem profilu v zavihku »Uredi profil« in shranite spremembe.
verification: Potrditev
verified_links: Vaše preverjene povezave

View File

@ -533,7 +533,6 @@ sq:
total_reported: Raportime rreth tyre
total_storage: Bashkëngjitje media
totals_time_period_hint_html: Vlerat e shfaqura më poshtë përfshijnë të dhënat për krejt kohën.
unknown_instance: Aktualisht në këtë shërbyes ska gjurmë të kësaj përkatësie.
invites:
deactivate_all: Çaktivizoji krejt
filter:
@ -1035,14 +1034,6 @@ sq:
hint_html: Edhe një gjë tjetër! Na duhet të ripohoni se jeni qenie njerëzore (që të mbajmë larg mesazhe të padëshiruar!). Zgjidhni CAPTCHA-n më poshtë dhe klikoni mbi “Vazhdo”.
title: Kontroll sigurie
confirmations:
awaiting_review: Adresa juaj email u ripohua! Ekipi i %{domain} stani po bën regjistrimin tuaj. Nëse e miratojnë llogarinë tuaj, do të merrni një email!
awaiting_review_title: Regjistrimi juaj po merret në shqyrtim
clicking_this_link: duke klikuar këtë lidhje
login_link: hyni
proceed_to_login_html: Tani mund të vazhdoni të %{login_link}.
redirect_to_app_html: Duhet të ishit ridrejtuar te aplikacioni <strong>%{app_name}</strong>. Nëse sndodhi, provoni %{clicking_this_link}, ose të ktheheni dorazi te aplikacioni.
registration_complete: Tanimë është plotësuar regjistrimi juaj në %{domain}!
welcome_title: Mirë se vini, %{name}!
wrong_email_hint: Nëse ajo adresë email sështë e saktë, mund ta ndryshoni te rregullimet e llogarisë.
delete_account: Fshije llogarinë
delete_account_html: Nëse dëshironi të fshihni llogarinë tuaj, mund <a href="%{path}">ta bëni që këtu</a>. Do tju kërkohet ta ripohoni.
@ -1104,7 +1095,6 @@ sq:
functional: Llogaria juaj është tërësisht funksionale.
pending: Aplikimi juaj është në pritje të shqyrtimit nga stafi ynë. Kjo mund të dojë ca kohë. Nëse aplikimi juaj miratohet, do të merrni një email.
redirecting_to: Llogaria juaj është joaktive, ngaqë aktualisht ridrejton te %{acct}.
self_destruct: Ngaqë %{domain} po mbyllet, do të keni vetëm hyrje të kufizuar te llogaria juaj.
view_strikes: Shihni paralajmërime të dikurshme kundër llogarisë tuaj
too_fast: Formulari u parashtrua shumë shpejt, riprovoni.
use_security_key: Përdor kyç sigurie
@ -1574,9 +1564,6 @@ sq:
over_daily_limit: Keni tejkaluar kufirin e %{limit} mesazheve të planifikuara për atë ditë
over_total_limit: Keni tejkaluar kufirin prej %{limit} mesazhesh të planifikuara
too_soon: Data e planifikimit duhet të bjerë në të ardhmen
self_destruct:
lead_html: Mjerisht, <strong>%{domain}</strong> po mbyllet përgjithmonë. Nëse patët një llogari këtu, sdo të jeni në gjendje të vazhdoni ta përdorni, por mundeni ende të kërkoni një kopjeruajtje të të dhënave tuaja.
title: Ky shërbyes po mbyllet
sessions:
activity: Veprimtaria e fundit
browser: Shfletues

View File

@ -545,7 +545,6 @@ sr-Latn:
total_reported: Prijave vezane za njih
total_storage: Multimedijalni prilozi
totals_time_period_hint_html: Ukupne vrednosti prikazane ispod uključuju podatke za sva vremena.
unknown_instance: Trenutno ne postoji zapis o ovom domenu na ovom serveru.
invites:
deactivate_all: Deaktiviraj sve
filter:
@ -1059,14 +1058,6 @@ sr-Latn:
hint_html: Samo još jedna stvar! Moramo da potvrdimo da ste ljudsko biće (ovo je da bismo sprečili neželjenu poštu!). Rešite CAPTCHA ispod i kliknite na „Nastavi”.
title: Bezbedonosna provera
confirmations:
awaiting_review: Vaša adresa e-pošte je potvrđena! Osoblje %{domain} sada pregleda vašu registraciju. Dobićete e-poštu ako odobre vaš nalog!
awaiting_review_title: Vaša registracija se pregleda
clicking_this_link: klikom na ovu vezu
login_link: prijavi se
proceed_to_login_html: Sada možete da pređete na %{login_link}.
redirect_to_app_html: Trebalo je da budete preusmereni na aplikaciju <strong>%{app_name}</strong>. Ako se to nije desilo, pokušajte sa %{clicking_this_link} ili se ručno vratite u aplikaciju.
registration_complete: Vaša registracija na %{domain} je sada kompletirana!
welcome_title: Dobro došli, %{name}!
wrong_email_hint: Ako ta imejl adresa nije ispravna, možete je promeniti u podešavanjima naloga.
delete_account: Brisanje naloga
delete_account_html: Ako želite da izbrišete vaš nalog, možete <a href="%{path}">nastaviti ovde</a>. Od vas će se tražiti potvrda.
@ -1128,7 +1119,6 @@ sr-Latn:
functional: Vaš nalog je potpuno operativan.
pending: Vaš zahtev je na čekanju za pregled od strane našeg osoblja. Ovo može potrajati neko vreme. Primićete imejl poruku ukoliko Vam zahtev bude odobren.
redirecting_to: Vaš nalog je neaktivan jer preusmerava na %{acct}.
self_destruct: Pošto se %{domain} zatvara, dobićete samo ograničen pristup svom nalogu.
view_strikes: Pogledajte prethodne prestupe upisane na Vaše ime
too_fast: Formular je podnet prebrzo, pokušajte ponovo.
use_security_key: Koristite sigurnosni ključ
@ -1606,9 +1596,6 @@ sr-Latn:
over_daily_limit: Prekoračili ste granicu od %{limit} planiranih objava za danas
over_total_limit: Prekoračili ste granicu od %{limit} planiranih objava
too_soon: Planirani datum mora biti u budućnosti
self_destruct:
lead_html: Nažalost, <strong>%{domain}</strong> se trajno zatvara. Ako ste tamo imali nalog, nećete moći da nastavite da ga koristite, ali i dalje možete da zatražite rezervnu kopiju svojih podataka.
title: Ovaj server se zatvara
sessions:
activity: Poslednja aktivnost
browser: Veb čitač
@ -1863,8 +1850,8 @@ sr-Latn:
final_step: 'Počnite da objavljujete! Čak i bez pratilaca, Vaše javne objave su vidljive drugim ljudima, na primer na lokalnoj vremenskoj liniji ili u heš oznakama. Možda želite da se predstavite sa heš oznakom #introductions ili #predstavljanja.'
full_handle: Vaš pun nadimak
full_handle_hint: Ovo biste rekli svojim prijateljima kako bi vam oni poslali poruku, ili zapratili sa druge instance.
subject: Dobro došli na Mastodon
title: Dobro došli, %{name}!
subject: Dobrodošli na Mastodon
title: Dobrodošli, %{name}!
users:
follow_limit_reached: Ne možete pratiti više od %{limit} ljudi
go_to_sso_account_settings: Idite na podešavanja naloga svog dobavljača identiteta

View File

@ -545,7 +545,6 @@ sr:
total_reported: Пријаве везане за њих
total_storage: Мултимедијални прилози
totals_time_period_hint_html: Укупне вредности приказане испод укључују податке за сва времена.
unknown_instance: Тренутно не постоји запис о овом домену на овом серверу.
invites:
deactivate_all: Деактивирај све
filter:
@ -1059,14 +1058,6 @@ sr:
hint_html: Само још једна ствар! Морамо да потврдимо да сте људско биће (ово је да бисмо спречили нежељену пошту!). Решите CAPTCHA испод и кликните на „Настави”.
title: Безбедоносна провера
confirmations:
awaiting_review: Ваша адреса е-поште је потврђена! Особље %{domain} сада прегледа вашу регистрацију. Добићете е-пошту ако одобре ваш налог!
awaiting_review_title: Ваша регистрација се прегледа
clicking_this_link: кликом на ову везу
login_link: пријави се
proceed_to_login_html: Сада можете да пређете на %{login_link}.
redirect_to_app_html: Требало је да будете преусмерени на апликацију <strong>%{app_name}</strong>. Ако се то није десило, покушајте са %{clicking_this_link} или се ручно вратите у апликацију.
registration_complete: Ваша регистрација на %{domain} је сада комплетирана!
welcome_title: Добро дошли, %{name}!
wrong_email_hint: Ако та имејл адреса није исправна, можете је променити у подешавањима налога.
delete_account: Брисање налога
delete_account_html: Ако желите да избришете ваш налог, можете <a href="%{path}">наставити овде</a>. Од вас ће се тражити потврда.
@ -1128,7 +1119,6 @@ sr:
functional: Ваш налог је потпуно оперативан.
pending: Ваш захтев је на чекању за преглед од стране нашег особља. Ово може потрајати неко време. Примићете имејл поруку уколико Вам захтев буде одобрен.
redirecting_to: Ваш налог је неактиван јер преусмерава на %{acct}.
self_destruct: Пошто се %{domain} затвара, добићете само ограничен приступ свом налогу.
view_strikes: Погледајте претходне преступе уписане на Ваше име
too_fast: Формулар је поднет пребрзо, покушајте поново.
use_security_key: Користите сигурносни кључ
@ -1606,9 +1596,6 @@ sr:
over_daily_limit: Прекорачили сте границу од %{limit} планираних објава за данас
over_total_limit: Прекорачили сте границу од %{limit} планираних објава
too_soon: Планирани датум мора бити у будућности
self_destruct:
lead_html: Нажалост, <strong>%{domain}</strong> се трајно затвара. Ако сте тамо имали налог, нећете моћи да наставите да га користите, али и даље можете да затражите резервну копију својих података.
title: Овај сервер се затвара
sessions:
activity: Последња активност
browser: Веб читач
@ -1863,8 +1850,8 @@ sr:
final_step: 'Почните да објављујете! Чак и без пратилаца, Ваше јавне објаве су видљиве другим људима, на пример на локалној временској линији или у хеш ознакама. Можда желите да се представите са хеш ознаком #introductions или #представљања.'
full_handle: Ваш пун надимак
full_handle_hint: Ово бисте рекли својим пријатељима како би вам они послали поруку, или запратили са друге инстанце.
subject: Добро дошли на Mastodon
title: Добро дошли, %{name}!
subject: Добродошли на Mastodon
title: Добродошли, %{name}!
users:
follow_limit_reached: Не можете пратити више од %{limit} људи
go_to_sso_account_settings: Идите на подешавања налога свог добављача идентитета

View File

@ -534,7 +534,6 @@ sv:
total_reported: Rapporter om dem
total_storage: Media-bilagor
totals_time_period_hint_html: Totalsummorna som visas nedan inkluderar data för all tid.
unknown_instance: Det finns för närvarande inga uppgifter om denna domän på denna server.
invites:
deactivate_all: Inaktivera alla
filter:
@ -1041,13 +1040,6 @@ sv:
hint_html: En sista sak till! Vi måste bekräfta att du är en människa (för att hålla borta skräpinlägg!). Lös CAPTCHA nedan och klicka på "Fortsätt".
title: Säkerhetskontroll
confirmations:
awaiting_review_title: Din registrering är under granskning
clicking_this_link: klicka på denna länk
login_link: logga in
proceed_to_login_html: Du kan nu fortsätta med att %{login_link}.
redirect_to_app_html: Du borde ha omdirigerats till appen <strong>%{app_name}</strong>. Om det inte hände, försök att %{clicking_this_link} eller återgå manuellt till appen.
registration_complete: Din registrering på %{domain} är nu slutförd!
welcome_title: Välkommen %{name}!
wrong_email_hint: Om e-postadressen inte är rätt, kan du ändra den i kontoinställningarna.
delete_account: Radera konto
delete_account_html: Om du vill radera ditt konto kan du <a href="%{path}">fortsätta här</a>. Du kommer att bli ombedd att bekräfta.
@ -1109,7 +1101,6 @@ sv:
functional: Ditt konto fungerar som det ska.
pending: Din ansökan inväntar granskning. Detta kan ta tid. Du kommer att få ett e-postmeddelande om din ansökan godkänns.
redirecting_to: Ditt konto är inaktivt eftersom det för närvarande dirigeras om till %{acct}.
self_destruct: Eftersom %{domain} håller på att stängas ned, kommer du endast att ha begränsad tillgång till ditt konto.
view_strikes: Visa tidigare prickar på ditt konto
too_fast: Formuläret har skickats för snabbt, försök igen.
use_security_key: Använd säkerhetsnyckel
@ -1579,9 +1570,6 @@ sv:
over_daily_limit: Du har överskridit dygnsgränsen på %{limit} schemalagda inlägg
over_total_limit: Du har överskridit gränsen på %{limit} schemalagda inlägg
too_soon: Schemaläggningsdatumet måste vara i framtiden
self_destruct:
lead_html: Tyvärr stänger <strong>%{domain}</strong> för gott. Om du hade ett konto där kommer du inte längre kunna använda det, men du kan fortfarande begära en säkerhetskopia av din data.
title: Denna server stänger ned
sessions:
activity: Senaste aktivitet
browser: Webbläsare

View File

@ -523,7 +523,6 @@ th:
total_reported: รายงานเกี่ยวกับเขา
total_storage: ไฟล์แนบสื่อ
totals_time_period_hint_html: ยอดรวมที่แสดงด้านล่างรวมข้อมูลสำหรับเวลาทั้งหมด
unknown_instance: ไม่มีระเบียนของโดเมนนี้ในเซิร์ฟเวอร์นี้ในปัจจุบัน
invites:
deactivate_all: ปิดใช้งานทั้งหมด
filter:
@ -1023,14 +1022,6 @@ th:
hint_html: อีกเพียงหนึ่งสิ่งเพิ่มเติม! เราจำเป็นต้องยืนยันว่าคุณเป็นมนุษย์ (นี่ก็เพื่อให้เราสามารถกันสแปมออกไป!) แก้ CAPTCHA ด้านล่างและคลิก "ดำเนินการต่อ"
title: การตรวจสอบความปลอดภัย
confirmations:
awaiting_review: ยืนยันที่อยู่อีเมลของคุณแล้ว! ตอนนี้พนักงานของ %{domain} กำลังตรวจทานการลงทะเบียนของคุณ คุณจะได้รับอีเมลหากพนักงานอนุมัติบัญชีของคุณ!
awaiting_review_title: กำลังตรวจทานการลงทะเบียนของคุณ
clicking_this_link: คลิกลิงก์นี้
login_link: เข้าสู่ระบบ
proceed_to_login_html: ตอนนี้คุณสามารถดำเนินการต่อเพื่อ %{login_link}
redirect_to_app_html: คุณควรได้รับการเปลี่ยนเส้นทางไปยังแอป <strong>%{app_name}</strong> หากนั่นไม่เกิดขึ้น ลอง %{clicking_this_link} หรือกลับไปยังแอปด้วยตนเอง
registration_complete: ตอนนี้การลงทะเบียนของคุณใน %{domain} เสร็จสมบูรณ์แล้ว!
welcome_title: ยินดีต้อนรับ %{name}!
wrong_email_hint: หากที่อยู่อีเมลนั้นไม่ถูกต้อง คุณสามารถเปลี่ยนที่อยู่อีเมลได้ในการตั้งค่าบัญชี
delete_account: ลบบัญชี
delete_account_html: หากคุณต้องการลบบัญชีของคุณ คุณสามารถ <a href="%{path}">ดำเนินการต่อที่นี่</a> คุณจะได้รับการถามเพื่อการยืนยัน
@ -1092,7 +1083,6 @@ th:
functional: บัญชีของคุณทำงานได้อย่างเต็มที่
pending: ใบสมัครของคุณกำลังรอดำเนินการตรวจทานโดยพนักงานของเรา นี่อาจใช้เวลาสักครู่ คุณจะได้รับอีเมลหากมีการอนุมัติใบสมัครของคุณ
redirecting_to: บัญชีของคุณไม่ได้ใช้งานเนื่องจากบัญชีกำลังเปลี่ยนเส้นทางไปยัง %{acct} ในปัจจุบัน
self_destruct: เนื่องจาก %{domain} กำลังปิดตัวลง คุณจะได้รับการเข้าถึงบัญชีของคุณแบบจำกัดเท่านั้น
view_strikes: ดูการดำเนินการที่ผ่านมาต่อบัญชีของคุณ
too_fast: ส่งแบบฟอร์มเร็วเกินไป ลองอีกครั้ง
use_security_key: ใช้กุญแจความปลอดภัย
@ -1554,9 +1544,6 @@ th:
over_daily_limit: คุณมีโพสต์ที่จัดกำหนดการไว้เกินขีดจำกัดที่ %{limit} สำหรับวันนี้แล้ว
over_total_limit: คุณมีโพสต์ที่จัดกำหนดการไว้เกินขีดจำกัดที่ %{limit} แล้ว
too_soon: วันที่จัดกำหนดการต้องอยู่ในอนาคต
self_destruct:
lead_html: น่าเสียดาย <strong>%{domain}</strong> กำลังปิดตัวลงอย่างถาวร หากคุณมีบัญชีที่นั่น คุณจะไม่สามารถใช้บัญชีต่อไปได้ แต่คุณยังสามารถขอข้อมูลสำรองของข้อมูลของคุณ
title: เซิร์ฟเวอร์นี้กำลังปิดตัวลง
sessions:
activity: กิจกรรมล่าสุด
browser: เบราว์เซอร์

View File

@ -534,7 +534,6 @@ tr:
total_reported: Onlar hakkında şikayetler
total_storage: Medya ekleri
totals_time_period_hint_html: Aşağıdaki gösterilen toplamlar, gelmiş geçmiş tüm veriyi içeriyor.
unknown_instance: Bu sunucuda bu alan adının şu an bir kaydı yok.
invites:
deactivate_all: Tümünü devre dışı bırak
filter:
@ -1041,14 +1040,6 @@ tr:
hint_html: Sadece bir şey daha! Sizin bir insan olduğunuzu doğrulamamız gerekiyor (bu, spam'i dışarıda tutabilmemiz içindir!). Aşağıdaki CAPTCHA'yı çözün ve "Devam Et" düğmesini tıklayın.
title: Güvenlik denetimi
confirmations:
awaiting_review: E-posta adresiniz doğrulandı! %{domain} çalışanları şimdi kaydınızı inceliyorlar. Hesabınızı onayladıklarında bir e-posta alacaksınız!
awaiting_review_title: Kaydınız inceleniyor
clicking_this_link: bu bağlantıyı tıklamayı
login_link: oturum aç
proceed_to_login_html: Şimdi %{login_link} devam edebilirsiniz.
redirect_to_app_html: "<strong>%{app_name}</strong> uygulamasına yönlendirileceksiniz. Eğer yönlendirme olmazsa, %{clicking_this_link} veya uygulamaya geri dönmeyi deneyin."
registration_complete: "%{domain} sunucusunda kaydınız şimdi tamamlandı!"
welcome_title: Hoşgeldin %{name}!
wrong_email_hint: Eğer bu e-posta adresi doğru değilse, hesap ayarlarında değiştirebilirsiniz.
delete_account: Hesabı sil
delete_account_html: Hesabını silmek istersen, <a href="%{path}">buradan devam edebilirsin</a>. Onay istenir.
@ -1110,7 +1101,6 @@ tr:
functional: Hesabınız tamamen kullanıma hazır.
pending: Başvurunuz personelimiz tarafından gözden geçirilmeyi beklemektedir. Bu biraz zaman alabilir. Başvurunuz onaylanırsa bir e-posta alacaksınız.
redirecting_to: Hesabınız aktif değil çünkü şu anda %{acct} adresine yönlendirilmektedir.
self_destruct: "%{domain} kapandığı için, hesabınıza sadece kısıtlı erişiminiz olacak."
view_strikes: Hesabınıza yönelik eski eylemleri görüntüleyin
too_fast: Form çok hızlı gönderildi, tekrar deneyin.
use_security_key: Güvenlik anahtarını kullan
@ -1580,9 +1570,6 @@ tr:
over_daily_limit: Bugün için %{limit} zamanlanmış gönderi sınırını aştınız
over_total_limit: "%{limit} zamanlanmış gönderi sınırını aştınız"
too_soon: Programlanan tarih bugünden ileri bir tarihte olmalıdır
self_destruct:
lead_html: Maalesef <strong>%{domain}</strong> kalıcı olarak kapanıyor. Eğer orada hesabınız varsa, onu kullanmaya devam edemeyeceksiniz, ancak yine de verinizin bir yedeğini isteyebilirsiniz.
title: Bu sunucu kapanıyor
sessions:
activity: Son etkinlik
browser: Tarayıcı

View File

@ -556,7 +556,6 @@ uk:
total_reported: Звітів про них
total_storage: Мультимедійні вкладення
totals_time_period_hint_html: Нижче зображена статистика за все існування сервера.
unknown_instance: Наразі на цьому сервері немає записів цього домену.
invites:
deactivate_all: Деактивувати всі
filter:
@ -1077,14 +1076,6 @@ uk:
hint_html: Ще одне! Ми повинні пересвідчитись, що ви людина (щоб ми могли уникнути спаму!). Розв'яжіть CAPTCHA внизу і натисніть кнопку "Продовжити".
title: Перевірка безпеки
confirmations:
awaiting_review: Ваша електронна адреса підтверджена! Співробітники %{domain} тепер переглядають вашу реєстрацію. Ви отримаєте електронного листа, якщо вони затвердять ваш обліковий запис!
awaiting_review_title: Ваша реєстрація розглядається
clicking_this_link: натисніть це посилання
login_link: увійти
proceed_to_login_html: Тепер ви можете перейти до %{login_link}.
redirect_to_app_html: Ви мали бути перенаправлені до програми <strong>%{app_name}</strong>. Якщо цього не сталося, спробуйте %{clicking_this_link} або вручну поверніться до програми.
registration_complete: Ваша реєстрація на %{domain} завершена!
welcome_title: Ласкаво просимо, %{name}!
wrong_email_hint: Якщо ця адреса електронної пошти неправильна, можна змінити її в налаштуваннях облікового запису.
delete_account: Видалити обліковий запис
delete_account_html: Якщо ви хочете видалити свій обліковий запис, ви можете <a href="%{path}">перейти сюди</a>. Вас попросять підтвердити дію.
@ -1146,7 +1137,6 @@ uk:
functional: Ваш обліковий запис повністю робочий.
pending: Ваша заява очікує на розгляд нашим персоналом. Це може зайняти деякий час. Ви отримаєте електронний лист, якщо ваша заява буде схвалена.
redirecting_to: Ваш обліковий запис наразі неактивний, тому що він перенаправлений до %{acct}.
self_destruct: Оскільки %{domain} закривається, ви отримаєте тільки обмежений доступ до вашого облікового запису.
view_strikes: Переглянути попередні попередження вашому обліковому запису
too_fast: Форму подано занадто швидко, спробуйте ще раз.
use_security_key: Використовувати ключ безпеки
@ -1632,9 +1622,6 @@ uk:
over_daily_limit: Ви перевищили ліміт в %{limit} запланованих дописів на сьогодні
over_total_limit: Ви перевищили ліміт в %{limit} запланованих дописів
too_soon: Запланована дата має бути в майбутньому
self_destruct:
lead_html: На жаль, <strong>%{domain}</strong> остаточно закривається. Якщо у вас є обліковий запис там, ви не зможете продовжити його використання, але ви все ще можете надіслати запит на резервну копію даних.
title: Сервер закривається
sessions:
activity: Остання активність
browser: Браузер

View File

@ -523,7 +523,6 @@ vi:
total_reported: Toàn bộ báo cáo
total_storage: Media
totals_time_period_hint_html: Tổng số được hiển thị bên dưới bao gồm dữ liệu cho mọi thời điểm.
unknown_instance: Hiện tại không có bản ghi tên miền này trên máy chủ này.
invites:
deactivate_all: Vô hiệu hóa tất cả
filter:
@ -1023,14 +1022,6 @@ vi:
hint_html: Còn một xíu nữa! Chúng tôi cần xác minh bạn là con người (để chúng tôi có thể ngăn chặn thư rác!). Nhập CAPTCHA bên dưới và nhấn "Tiếp tục".
title: Kiểm tra an toàn
confirmations:
awaiting_review: Đã xác minh email của bạn! Kiểm duyệt viên %{domain} đang xem xét đăng ký của bạn. Bạn sẽ nhận được một email nếu tài khoản của bạn được duyệt!
awaiting_review_title: Đăng ký của bạn đang chờ duyệt
clicking_this_link: nhấn vào link này
login_link: đăng nhập
proceed_to_login_html: Bạn có thể tiếp tục %{login_link}.
redirect_to_app_html: Bạn đã có thể chuyển tiếp tới <strong>%{app_name}</strong>. Nếu không có gì xảy ra, thử %{clicking_this_link} hoặc tự quay lại app.
registration_complete: Hoàn tất đăng ký trên %{domain}!
welcome_title: Chào mừng, %{name}!
wrong_email_hint: Nếu địa chỉ email đó không chính xác, bạn có thể thay đổi nó trong cài đặt tài khoản.
delete_account: Xóa tài khoản
delete_account_html: Nếu bạn muốn xóa tài khoản của mình, hãy <a href="%{path}">yêu cầu tại đây</a>. Bạn sẽ được yêu cầu xác nhận.
@ -1092,7 +1083,6 @@ vi:
functional: Tài khoản của bạn đã được xác minh.
pending: Đơn đăng ký của bạn đang chờ phê duyệt. Điều này có thể mất một thời gian. Bạn sẽ nhận được email nếu đơn đăng ký của bạn được chấp thuận.
redirecting_to: Tài khoản của bạn không hoạt động vì hiện đang chuyển hướng đến %{acct}.
self_destruct: Vì %{domain} đang đóng cửa, bạn sẽ chỉ có quyền truy cập hạn chế vào tài khoản của mình.
view_strikes: Xem những lần cảnh cáo cũ
too_fast: Nghi vấn đăng ký spam, xin thử lại.
use_security_key: Dùng khóa bảo mật
@ -1554,9 +1544,6 @@ vi:
over_daily_limit: Bạn đã vượt qua giới hạn được lên lịch đăng tút %{limit} hôm nay
over_total_limit: Bạn đã vượt quá giới hạn %{limit} của các tút được lên lịch
too_soon: Ngày lên lịch phải trong tương lai
self_destruct:
lead_html: Rất tiếc, <strong>%{domain}</strong>đã đóng cửa vĩnh viễn. Nếu bạn có tài khoản ở đó, bạn sẽ không thể tiếp tục sử dụng tài khoản đó nhưng bạn vẫn có thể yêu cầu bản sao lưu dữ liệu của mình.
title: Máy chủ đang đóng cửa
sessions:
activity: Gần đây nhất
browser: Ứng dụng

View File

@ -523,7 +523,6 @@ zh-CN:
total_reported: 关于对方的举报
total_storage: 媒体文件
totals_time_period_hint_html: 下方显示的总数来自全部历史数据。
unknown_instance: 此服务器上目前没有此域名的记录。
invites:
deactivate_all: 撤销所有邀请链接
filter:
@ -1023,14 +1022,6 @@ zh-CN:
hint_html: 只剩最后一件事了!我们需要确认您是一个人类(这样我们才能阻止恶意访问!)。请输入下面的验证码,然后点击“继续”。
title: 安全检查
confirmations:
awaiting_review: 您的电子邮件地址已确认!%{domain} 的工作人员正在审核您的注册信息。如果他们批准了您的账户,您将收到一封邮件通知!
awaiting_review_title: 您的注册申请正在审核中
clicking_this_link: 点击此链接
login_link: 登录
proceed_to_login_html: 现在您可以继续前往 %{login_link} 。
redirect_to_app_html: 您应该已被重定向到 <strong>%{app_name}</strong> 应用程序。如果没有,请尝试 %{clicking_this_link} 或手动返回应用程序。
registration_complete: 您在 %{domain} 上的注册现已完成!
welcome_title: 欢迎您,%{name}
wrong_email_hint: 如果该电子邮件地址不正确,您可以在帐户设置中进行更改。
delete_account: 删除帐户
delete_account_html: 如果你想删除你的帐户,请<a href="%{path}">点击这里继续</a>。你需要确认你的操作。
@ -1092,7 +1083,6 @@ zh-CN:
functional: 你的账号可以正常使用了。
pending: 工作人员正在审核你的申请。这需要花点时间。在申请被批准后,你将收到一封电子邮件。
redirecting_to: 你的账户无效,因为它已被设置为跳转到 %{acct}
self_destruct: 由于 %{domain} 即将关闭,你只能获得对你本人账号的有限访问权限。
view_strikes: 查看针对你账号的记录
too_fast: 表单提交过快,请重试。
use_security_key: 使用安全密钥
@ -1554,9 +1544,6 @@ zh-CN:
over_daily_limit: 你已超出每日定时嘟文的上限(%{limit} 条)
over_total_limit: 你已超出定时嘟文的上限(%{limit} 条)
too_soon: 所定的时间必须在未来
self_destruct:
lead_html: 很遗憾,<strong>%{domain}</strong> 即将永久关闭。 如果你在其中设有账号,那么你将无法再继续使用,但你仍可以请求获得本人数据的备份。
title: 此服务器即将关闭
sessions:
activity: 最后一次活跃的时间
browser: 浏览器

View File

@ -523,7 +523,6 @@ zh-HK:
total_reported: 關於他們的舉報
total_storage: 媒體附件
totals_time_period_hint_html: 下面顯示的總數包括所有時間的數據。
unknown_instance: 此伺服器目前沒有這個網域的紀錄。
invites:
deactivate_all: 全部停用
filter:
@ -1084,7 +1083,6 @@ zh-HK:
functional: 你的帳號已完全投入使用。
pending: 管理員正在處理你的申請。可能會需要一點時間處理。我們將會在申請被批準的時候馬上寄電郵給你。
redirecting_to: 你的帳戶因為正在重新定向到 %{acct},所以暫時被停用。
self_destruct: 由於 %{domain} 即將停止服務,你只能有限存取你的帳號。
view_strikes: 查看針對你的帳戶的過往警告
too_fast: 你太快遞交了,請再試一次。
use_security_key: 使用安全密鑰裝置
@ -1546,9 +1544,6 @@ zh-HK:
over_daily_limit: 你已經超越了當天排定發文的限額 (%{limit})
over_total_limit: 你已經超越了排定發文的限額 (%{limit})
too_soon: 不可以改變過去哦,嘟文只可以排定在未來
self_destruct:
lead_html: 很遺憾,<strong>%{domain}</strong> 即將永久停止服務。如果你在該處擁有帳號,你將無法繼續使用它,但你仍然可以要求備份你的數據。
title: 這個伺服器即將停止服務
sessions:
activity: 最近活動
browser: 瀏覽器
@ -1711,7 +1706,6 @@ zh-HK:
default: "%Y年%-m月%d日 %H:%M"
month: "%b %Y"
time: "%H:%M"
with_time_zone: "%b %d, %Y, %H:%M %Z"
translation:
errors:
quota_exceeded: 已超出伺服器範圍的翻譯服務之使用配額。

View File

@ -523,7 +523,6 @@ zh-TW:
total_reported: 關於他們的檢舉報告
total_storage: 多媒體附加檔案
totals_time_period_hint_html: 以下顯示之總和包含所有時間的資料。
unknown_instance: 此伺服器目前沒有這個網域的紀錄。
invites:
deactivate_all: 全部停用
filter:
@ -989,7 +988,7 @@ zh-TW:
created_msg: 成功建立別名。您可以自舊帳號開始轉移。
deleted_msg: 成功移除別名。您將無法再由舊帳號轉移至目前的帳號。
empty: 您目前沒有任何別名。
hint_html: 如果想由其他帳號轉移至此帳號,您可以此處新增別名,稍後系統將容許您將跟隨者由舊帳號轉移至此。此項作業是<strong>無害且可復原的</strong>。 <strong>帳號的遷移程序需要在舊帳號啟動</strong>。
hint_html: 如果想由其他帳號轉移至此帳號,您可以此處新增別名,稍後系統將容許您將跟隨者由舊帳號轉移至此。此項作業是<strong>無害且可復原的</strong>。 <strong>帳號的遷移程序需要在舊帳號啟動</strong>。
remove: 取消連結別名
appearance:
advanced_web_interface: 進階網頁介面
@ -1025,14 +1024,6 @@ zh-TW:
hint_html: 僅再一步!我們必須確認您是位人類(這是防止垃圾訊息濫用)。請完成以下 CAPTCHA 挑戰並點擊「繼續」。
title: 安全性檢查
confirmations:
awaiting_review: 已驗證您的電子郵件!%{domain} 的管理員正在審核您的註冊申請。若您的帳號通過審核,您將收到電子郵件通知。
awaiting_review_title: 我們正在審核您的註冊申請
clicking_this_link: 點擊此連結
login_link: 登入
proceed_to_login_html: 您現在可以前往 %{login_link}。
redirect_to_app_html: 您應被重新導向至 <strong>%{app_name}</strong> 應用程式。如尚未重新導向,請嘗試 %{clicking_this_link} 或手動回到應用程式。
registration_complete: 您於 %{domain} 之註冊申請已完成!
welcome_title: 歡迎,%{name}
wrong_email_hint: 若電子郵件地址不正確,您可以於帳號設定中更改。
delete_account: 刪除帳號
delete_account_html: 如果您欲刪除您的帳號,請<a href="%{path}">點擊這裡繼續</a>。您需要再三確認您的操作。
@ -1082,7 +1073,7 @@ zh-TW:
new_confirmation_instructions_sent: 您將於幾分鐘之內收到新的包含確認連結的電子郵件!
title: 請檢查您的收件匣
sign_in:
preamble_html: 請使用您於 <strong>%{domain}</strong> 的帳號密碼登入。若您的帳號託管於其他伺服器,您將無法此登入。
preamble_html: 請使用您於 <strong>%{domain}</strong> 的帳號密碼登入。若您的帳號託管於其他伺服器,您將無法此登入。
title: 登入 %{domain}
sign_up:
manual_review: "%{domain} 上的註冊由我們的管理員進行人工審核。為協助我們處理您的註冊,請寫一些關於您自己的資訊以及您想要在 %{domain} 上註冊帳號的原因。"
@ -1094,7 +1085,6 @@ zh-TW:
functional: "您的帳號可以正常使用了。🎉"
pending: 管管們正在處理您的申請,這可能需要一點時間處理。我們將於申請通過後以電子郵件方式通知您。
redirecting_to: 您的帳號因目前重定向至 %{acct} 而被停用。
self_destruct: 由於 %{domain} 即將停止服務,您只能有限地存取您的帳號。
view_strikes: 檢視針對您帳號過去的警示
too_fast: 送出表單的速度太快跟不上,請稍後再試。
use_security_key: 使用安全金鑰
@ -1304,7 +1294,7 @@ zh-TW:
following_html: 您將要 <strong>跟隨</strong> 自 <strong>%{filename}</strong> 中之 <strong>%{total_items} 個帳號</strong>。
lists_html: 您將自 <strong>%{filename}</strong> 新增 <strong>%{total_items} 個帳號</strong>至您的<strong>列表</strong>。若不存在列表用以新增帳號,則會建立新列表。
muting_html: 您將要 <strong>靜音</strong> 自 <strong>%{filename}</strong> 中之 <strong>%{total_items} 個帳號</strong>。
preface: 能於此匯入您在其他伺服器所匯出的資料檔,包括跟隨的使用者、封鎖的使用者名單
preface: 可以在此匯入您在其他伺服器所匯出的資料檔,包括跟隨的使用者、封鎖的使用者名單。
recent_imports: 最近匯入的
states:
finished: 已完成
@ -1556,9 +1546,6 @@ zh-TW:
over_daily_limit: 您已經超過了本日排定發嘟的限額 (%{limit})
over_total_limit: 您已經超過排程發嘟的限額 (%{limit})
too_soon: 嘟文不可以改變過去哦,只能預定未來 (咦)
self_destruct:
lead_html: 很遺憾,<strong>%{domain}</strong> 即將永久停止服務。如果您於該伺服器擁有帳號,您將無法繼續使用它,但您仍然可以請求您的資料備份。
title: 這個伺服器即將停止服務
sessions:
activity: 最近活動
browser: 瀏覽器

View File

@ -1,46 +1,44 @@
# frozen_string_literal: true
SimpleNavigation::Configuration.run do |navigation|
self_destruct = SelfDestructHelper.self_destruct?
navigation.items do |n|
n.item :web, safe_join([fa_icon('chevron-left fw'), t('settings.back')]), root_path
n.item :software_updates, safe_join([fa_icon('exclamation-circle fw'), t('admin.critical_update_pending')]), admin_software_updates_path, if: -> { ENV['UPDATE_CHECK_URL'] != '' && current_user.can?(:view_devops) && SoftwareUpdate.urgent_pending? }, html: { class: 'warning' }
n.item :profile, safe_join([fa_icon('user fw'), t('settings.profile')]), settings_profile_path, if: -> { current_user.functional? && !self_destruct }, highlights_on: %r{/settings/profile|/settings/featured_tags|/settings/verification|/settings/privacy}
n.item :profile, safe_join([fa_icon('user fw'), t('settings.profile')]), settings_profile_path, if: -> { current_user.functional? }, highlights_on: %r{/settings/profile|/settings/featured_tags|/settings/verification|/settings/privacy}
n.item :preferences, safe_join([fa_icon('cog fw'), t('settings.preferences')]), settings_preferences_path, if: -> { current_user.functional? && !self_destruct } do |s|
n.item :preferences, safe_join([fa_icon('cog fw'), t('settings.preferences')]), settings_preferences_path, if: -> { current_user.functional? } do |s|
s.item :appearance, safe_join([fa_icon('desktop fw'), t('settings.appearance')]), settings_preferences_appearance_path
s.item :notifications, safe_join([fa_icon('bell fw'), t('settings.notifications')]), settings_preferences_notifications_path
s.item :other, safe_join([fa_icon('cog fw'), t('preferences.other')]), settings_preferences_other_path
end
n.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_path, if: -> { current_user.functional? && !self_destruct }
n.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? && !self_destruct }
n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_path, if: -> { current_user.functional_or_moved? && !self_destruct }
n.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_path, if: -> { current_user.functional? }
n.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? }
n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_path, if: -> { current_user.functional_or_moved? }
n.item :security, safe_join([fa_icon('lock fw'), t('settings.account')]), edit_user_registration_path do |s|
s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_path, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities|^/disputes}
s.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_methods_path, highlights_on: %r{/settings/two_factor_authentication|/settings/otp_authentication|/settings/security_keys}
s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_path, if: -> { !self_destruct }
s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_path
end
n.item :data, safe_join([fa_icon('cloud-download fw'), t('settings.import_and_export')]), settings_export_path do |s|
s.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_imports_path, if: -> { current_user.functional? && !self_destruct }
s.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_imports_path, if: -> { current_user.functional? }
s.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_path
end
n.item :invites, safe_join([fa_icon('user-plus fw'), t('invites.title')]), invites_path, if: -> { current_user.can?(:invite_users) && current_user.functional? && !self_destruct }
n.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_path, if: -> { current_user.functional? && !self_destruct }
n.item :invites, safe_join([fa_icon('user-plus fw'), t('invites.title')]), invites_path, if: -> { current_user.can?(:invite_users) && current_user.functional? }
n.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_path, if: -> { current_user.functional? }
n.item :trends, safe_join([fa_icon('fire fw'), t('admin.trends.title')]), admin_trends_statuses_path, if: -> { current_user.can?(:manage_taxonomies) && !self_destruct } do |s|
n.item :trends, safe_join([fa_icon('fire fw'), t('admin.trends.title')]), admin_trends_statuses_path, if: -> { current_user.can?(:manage_taxonomies) } do |s|
s.item :statuses, safe_join([fa_icon('comments-o fw'), t('admin.trends.statuses.title')]), admin_trends_statuses_path, highlights_on: %r{/admin/trends/statuses}
s.item :tags, safe_join([fa_icon('hashtag fw'), t('admin.trends.tags.title')]), admin_trends_tags_path, highlights_on: %r{/admin/tags|/admin/trends/tags}
s.item :links, safe_join([fa_icon('newspaper-o fw'), t('admin.trends.links.title')]), admin_trends_links_path, highlights_on: %r{/admin/trends/links}
end
n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), nil, if: -> { current_user.can?(:manage_reports, :view_audit_log, :manage_users, :manage_invites, :manage_taxonomies, :manage_federation, :manage_blocks) && !self_destruct } do |s|
n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), nil, if: -> { current_user.can?(:manage_reports, :view_audit_log, :manage_users, :manage_invites, :manage_taxonomies, :manage_federation, :manage_blocks) } do |s|
s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_path, highlights_on: %r{/admin/reports}, if: -> { current_user.can?(:manage_reports) }
s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_path(origin: 'local'), highlights_on: %r{/admin/accounts|/admin/pending_accounts|/admin/disputes|/admin/users}, if: -> { current_user.can?(:manage_users) }
s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) }
@ -51,7 +49,7 @@ SimpleNavigation::Configuration.run do |navigation|
s.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_path, if: -> { current_user.can?(:view_audit_log) }
end
n.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), nil, if: -> { current_user.can?(:view_dashboard, :manage_settings, :manage_rules, :manage_announcements, :manage_custom_emojis, :manage_webhooks, :manage_federation) && !self_destruct } do |s|
n.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), nil, if: -> { current_user.can?(:view_dashboard, :manage_settings, :manage_rules, :manage_announcements, :manage_custom_emojis, :manage_webhooks, :manage_federation) } do |s|
s.item :dashboard, safe_join([fa_icon('tachometer fw'), t('admin.dashboard.title')]), admin_dashboard_path, if: -> { current_user.can?(:view_dashboard) }
s.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), admin_settings_path, if: -> { current_user.can?(:manage_settings) }, highlights_on: %r{/admin/settings}
s.item :rules, safe_join([fa_icon('gavel fw'), t('admin.rules.title')]), admin_rules_path, highlights_on: %r{/admin/rules}, if: -> { current_user.can?(:manage_rules) }

View File

@ -134,7 +134,7 @@ Rails.application.routes.draw do
get '/@:account_username/:id/embed', to: 'statuses#embed', as: :embed_short_account_status
end
get '/@:username_with_domain/(*any)', to: 'home#index', constraints: { username_with_domain: %r{([^/])+?} }, as: :account_with_domain, format: false
get '/@:username_with_domain/(*any)', to: 'home#index', constraints: { username_with_domain: %r{([^/])+?} }, format: false
get '/settings', to: redirect('/settings/profile')
draw(:settings)

View File

@ -7,7 +7,6 @@
- [mailers, 2]
- [pull]
- [scheduler]
:scheduler:
:listened_queues_only: true
:schedule:

View File

@ -1,13 +1,12 @@
module.exports = {
test: /\.svg$/,
include: /node_modules\/@material-symbols/,
include: /node_modules\/@material-design-icons/,
issuer: /\.[jt]sx?$/,
use: [
{
loader: '@svgr/webpack',
options: {
svgo: false,
titleProp: true,
},
},
],

View File

@ -18,9 +18,6 @@ const config = {
],
coverageDirectory: '<rootDir>/coverage',
moduleDirectories: ['<rootDir>/node_modules', '<rootDir>/app/javascript'],
moduleNameMapper: {
'\\.svg$': '<rootDir>/app/javascript/__mocks__/svg.js',
},
};
module.exports = config;

View File

@ -13,7 +13,7 @@ module ActiveRecord
column_names.unshift(primary_key)
relation = relation.reorder(build_batch_orders(order).to_h).limit(batch_limit)
relation = relation.reorder(batch_order(order)).limit(batch_limit)
relation.skip_query_cache!
batch_relation = relation

View File

@ -65,6 +65,7 @@ module Mastodon::CLI
desc 'maintenance SUBCOMMAND ...ARGS', 'Various maintenance utilities'
subcommand 'maintenance', Maintenance
option :dry_run, type: :boolean
desc 'self-destruct', 'Erase the server from the federation'
long_desc <<~LONG_DESC
Erase the server from the federation by broadcasting account delete
@ -91,37 +92,55 @@ module Mastodon::CLI
prompt = TTY::Prompt.new
if SelfDestructHelper.self_destruct?
prompt.ok('Self-destruct mode is already enabled for this Mastodon server')
pending_accounts = Account.local.without_suspended.count + Account.local.suspended.joins(:deletion_request).count
sidekiq_stats = Sidekiq::Stats.new
if pending_accounts.positive?
prompt.warn("#{pending_accounts} accounts are still pending deletion.")
elsif sidekiq_stats.enqueued.positive?
prompt.warn('Deletion notices are still being processed')
elsif sidekiq_stats.retry_size.positive?
prompt.warn('At least one delivery attempt for each deletion notice has been made, but some have failed and are scheduled for retry')
else
prompt.ok('Every deletion notice has been sent! You can safely delete all data and decomission your servers!')
end
exit(0)
end
exit(1) unless prompt.ask('Type in the domain of the server to confirm:', required: true) == Rails.configuration.x.local_domain
prompt.warn('This operation WILL NOT be reversible.')
prompt.warn('While the data won\'t be erased locally, the server will be in a BROKEN STATE afterwards.')
prompt.warn('The deletion process itself may take a long time, and will be handled by Sidekiq, so do not shut it down until it has finished (you will be able to re-run this command to see the state of the self-destruct process).')
unless dry_run?
prompt.warn('This operation WILL NOT be reversible. It can also take a long time.')
prompt.warn('While the data won\'t be erased locally, the server will be in a BROKEN STATE afterwards.')
prompt.warn('A running Sidekiq process is required. Do not shut it down until queues clear.')
exit(1) if prompt.no?('Are you sure you want to proceed?')
exit(1) if prompt.no?('Are you sure you want to proceed?')
end
self_destruct_value = Rails.application.message_verifier('self-destruct').generate(Rails.configuration.x.local_domain)
prompt.ok('To switch Mastodon to self-destruct mode, add the following variable to your evironment (e.g. by adding a line to your `.env.production`) and restart all Mastodon processes:')
prompt.ok(" SELF_DESTRUCT=#{self_destruct_value}")
prompt.ok("\nYou can re-run this command to see the state of the self-destruct process.")
inboxes = Account.inboxes
processed = 0
Setting.registrations_mode = 'none' unless dry_run?
if inboxes.empty?
Account.local.without_suspended.in_batches.update_all(suspended_at: Time.now.utc, suspension_origin: :local) unless dry_run?
prompt.ok('It seems like your server has not federated with anything')
prompt.ok('You can shut it down and delete it any time')
return
end
prompt.warn('Do NOT interrupt this process...')
delete_account = lambda do |account|
payload = ActiveModelSerializers::SerializableResource.new(
account,
serializer: ActivityPub::DeleteActorSerializer,
adapter: ActivityPub::Adapter
).as_json
json = Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(account))
unless dry_run?
ActivityPub::DeliveryWorker.push_bulk(inboxes, limit: 1_000) do |inbox_url|
[json, account.id, inbox_url]
end
account.suspend!(block_email: false)
end
processed += 1
end
Account.local.without_suspended.find_each { |account| delete_account.call(account) }
Account.local.suspended.joins(:deletion_request).find_each { |account| delete_account.call(account) }
prompt.ok("Queued #{inboxes.size * processed} items into Sidekiq for #{processed} accounts#{dry_run_mode_suffix}")
prompt.ok('Wait until Sidekiq processes all items, then you can shut everything down and delete the data')
rescue TTY::Reader::InputInterrupt
exit(1)
end

View File

@ -158,8 +158,10 @@ module Mastodon
'in the body of your migration class'
end
options = options.merge({ algorithm: :concurrently })
disable_statement_timeout
if supports_drop_index_concurrently?
options = options.merge({ algorithm: :concurrently })
disable_statement_timeout
end
remove_index(table_name, **options.merge({ column: column_name }))
end
@ -180,12 +182,28 @@ module Mastodon
'in the body of your migration class'
end
options = options.merge({ algorithm: :concurrently })
disable_statement_timeout
if supports_drop_index_concurrently?
options = options.merge({ algorithm: :concurrently })
disable_statement_timeout
end
remove_index(table_name, **options.merge({ name: index_name }))
end
# Only available on Postgresql >= 9.2
def supports_drop_index_concurrently?
version = select_one("SELECT current_setting('server_version_num') AS v")['v'].to_i
version >= 90_200
end
# Only available on Postgresql >= 11
def supports_add_column_with_default?
version = select_one("SELECT current_setting('server_version_num') AS v")['v'].to_i
version >= 110_000
end
# Adds a foreign key with only minimal locking on the tables involved.
#
# This method only requires minimal locking when using PostgreSQL. When
@ -402,7 +420,42 @@ module Mastodon
# This method can also take a block which is passed directly to the
# `update_column_in_batches` method.
def add_column_with_default(table, column, type, default:, limit: nil, allow_null: false, &block)
add_column(table, column, type, default: default, limit: limit, null: allow_null)
if supports_add_column_with_default?
add_column(table, column, type, default: default, limit: limit, null: allow_null)
return
end
if transaction_open?
raise 'add_column_with_default can not be run inside a transaction, ' \
'you can disable transactions by calling disable_ddl_transaction! ' \
'in the body of your migration class'
end
disable_statement_timeout
transaction do
if limit
add_column(table, column, type, default: nil, limit: limit)
else
add_column(table, column, type, default: nil)
end
# Changing the default before the update ensures any newly inserted
# rows already use the proper default value.
change_column_default(table, column, default)
end
begin
update_column_in_batches(table, column, default, &block)
change_column_null(table, column, false) unless allow_null
# We want to rescue _all_ exceptions here, even those that don't inherit
# from StandardError.
rescue Exception => error # rubocop: disable all
remove_column(table, column)
raise error
end
end
# Renames a column without requiring downtime.

View File

@ -35,11 +35,9 @@ REDIS_CACHE_PARAMS = {
url: ENV['CACHE_REDIS_URL'],
expires_in: 10.minutes,
namespace: cache_namespace,
pool_size: Sidekiq.server? ? Sidekiq[:concurrency] : Integer(ENV['MAX_THREADS'] || 5),
pool_timeout: 5,
connect_timeout: 5,
pool: {
size: Sidekiq.server? ? Sidekiq[:concurrency] : Integer(ENV['MAX_THREADS'] || 5),
timeout: 5,
},
}.freeze
REDIS_SIDEKIQ_PARAMS = {

View File

@ -17,8 +17,6 @@ namespace :mastodon do
ENV.delete('SIDEKIQ_REDIS_URL')
begin
errors = false
prompt.say('Your instance is identified by its domain name. Changing it afterward will break things.')
env['LOCAL_DOMAIN'] = prompt.ask('Domain name:') do |q|
q.required true
@ -97,12 +95,7 @@ namespace :mastodon do
rescue => e
prompt.error 'Database connection could not be established with this configuration, try again.'
prompt.error e.message
unless prompt.yes?('Try again?')
return prompt.warn 'Nothing saved. Bye!' unless prompt.yes?('Continue anyway?')
errors = true
break
end
break unless prompt.yes?('Try again?')
end
end
@ -142,13 +135,7 @@ namespace :mastodon do
rescue => e
prompt.error 'Redis connection could not be established with this configuration, try again.'
prompt.error e.message
unless prompt.yes?('Try again?')
return prompt.warn 'Nothing saved. Bye!' unless prompt.yes?('Continue anyway?')
errors = true
break
end
break unless prompt.yes?('Try again?')
end
end
@ -433,13 +420,7 @@ namespace :mastodon do
rescue => e
prompt.error 'E-mail could not be sent with this configuration, try again.'
prompt.error e.message
unless prompt.yes?('Try again?')
return prompt.warn 'Nothing saved. Bye!' unless prompt.yes?('Continue anyway?')
errors = true
break
end
break unless prompt.yes?('Try again?')
end
end
@ -485,7 +466,6 @@ namespace :mastodon do
prompt.ok 'Done!'
else
prompt.error 'That failed! Perhaps your configuration is not right'
errors = true
end
end
@ -502,17 +482,12 @@ namespace :mastodon do
prompt.say 'Done!'
else
prompt.error 'That failed! Maybe you need swap space?'
errors = true
end
end
end
prompt.say "\n"
if errors
prompt.warn 'Your Mastodon server is set up, but there were some errors along the way, you may have to fix them.'
else
prompt.ok 'All done! You can now power on the Mastodon server 🐘'
end
prompt.ok 'All done! You can now power on the Mastodon server 🐘'
prompt.say "\n"
if db_connection_works && prompt.yes?('Do you want to create an admin user straight away?')

View File

@ -44,8 +44,8 @@
"@formatjs/intl-pluralrules": "^5.2.2",
"@gamestdio/websocket": "^0.3.2",
"@github/webauthn-json": "^2.1.1",
"@material-symbols/svg-600": "^0.13.1",
"@rails/ujs": "^7.1.1",
"@material-design-icons/svg": "^0.14.10",
"@rails/ujs": "^7.0.6",
"@reduxjs/toolkit": "^1.9.5",
"@renchap/compression-webpack-plugin": "^6.1.4",
"@svgr/webpack": "^5.5.0",
@ -97,7 +97,7 @@
"pg-connection-string": "^2.6.0",
"postcss": "^8.4.24",
"postcss-loader": "^4.3.0",
"prom-client": "^15.0.0",
"prom-client": "^14.2.0",
"prop-types": "^15.8.1",
"punycode": "^2.3.0",
"react": "^18.2.0",
@ -206,7 +206,7 @@
"husky": "^8.0.3",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
"lint-staged": "^13.2.2",
"lint-staged": "^15.0.0",
"prettier": "^3.0.0",
"react-test-renderer": "^18.2.0",
"stylelint": "^15.10.1",

View File

@ -33,6 +33,8 @@ RSpec.describe Admin::Disputes::AppealsController do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
before do
allow(UserMailer).to receive(:appeal_approved)
.and_return(instance_double(ActionMailer::MessageDelivery, deliver_later: nil))
post :approve, params: { id: appeal.id }
end
@ -45,9 +47,7 @@ RSpec.describe Admin::Disputes::AppealsController do
end
it 'notifies target account about approved appeal' do
expect(UserMailer.deliveries.size).to eq(1)
expect(UserMailer.deliveries.first.to.first).to eq(target_account.user.email)
expect(UserMailer.deliveries.first.subject).to eq(I18n.t('user_mailer.appeal_approved.subject', date: I18n.l(appeal.created_at)))
expect(UserMailer).to have_received(:appeal_approved).with(target_account.user, appeal)
end
end
@ -55,6 +55,8 @@ RSpec.describe Admin::Disputes::AppealsController do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
before do
allow(UserMailer).to receive(:appeal_rejected)
.and_return(instance_double(ActionMailer::MessageDelivery, deliver_later: nil))
post :reject, params: { id: appeal.id }
end
@ -63,9 +65,7 @@ RSpec.describe Admin::Disputes::AppealsController do
end
it 'notifies target account about rejected appeal' do
expect(UserMailer.deliveries.size).to eq(1)
expect(UserMailer.deliveries.first.to.first).to eq(target_account.user.email)
expect(UserMailer.deliveries.first.subject).to eq(I18n.t('user_mailer.appeal_rejected.subject', date: I18n.l(appeal.created_at)))
expect(UserMailer).to have_received(:appeal_rejected).with(target_account.user, appeal)
end
end
end

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
require 'rails_helper'
describe Api::V1::Accounts::FeaturedTagsController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
let(:account) { Fabricate(:account) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index' do
it 'returns http success' do
get :index, params: { account_id: account.id, limit: 2 }
expect(response).to have_http_status(200)
end
end
end

View File

@ -0,0 +1,107 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Api::V1::MediaController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:media') }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'POST #create' do
describe 'with paperclip errors' do
context 'when imagemagick cant identify the file type' do
it 'returns http 422' do
allow_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Errors::NotIdentifiedByImageMagickError)
post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') }
expect(response).to have_http_status(422)
end
end
context 'when there is a generic error' do
it 'returns http 422' do
allow_any_instance_of(Account).to receive_message_chain(:media_attachments, :create!).and_raise(Paperclip::Error)
post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') }
expect(response).to have_http_status(500)
end
end
end
context 'with image/jpeg' do
before do
post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') }
end
it 'creates a media attachment', :aggregate_failures do
expect(response).to have_http_status(200)
expect(MediaAttachment.first).to_not be_nil
expect(MediaAttachment.first).to have_attached_file(:file)
expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s
end
end
context 'with image/gif' do
before do
post :create, params: { file: fixture_file_upload('attachment.gif', 'image/gif') }
end
it 'creates a media attachment', :aggregate_failures do
expect(response).to have_http_status(200)
expect(MediaAttachment.first).to_not be_nil
expect(MediaAttachment.first).to have_attached_file(:file)
expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s
end
end
context 'with video/webm' do
before do
post :create, params: { file: fixture_file_upload('attachment.webm', 'video/webm') }
end
it 'creates a media attachment', :aggregate_failures do
expect(response).to have_http_status(200)
expect(MediaAttachment.first).to_not be_nil
expect(MediaAttachment.first).to have_attached_file(:file)
expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s
end
end
end
describe 'PUT #update' do
context 'when somebody else\'s' do
let(:media) { Fabricate(:media_attachment, status: nil) }
it 'returns http not found' do
put :update, params: { id: media.id, description: 'Lorem ipsum!!!' }
expect(response).to have_http_status(404)
end
end
context 'when the author \'s' do
let(:status) { nil }
let(:media) { Fabricate(:media_attachment, status: status, account: user.account) }
before do
put :update, params: { id: media.id, description: 'Lorem ipsum!!!' }
end
it 'updates the description' do
expect(media.reload.description).to eq 'Lorem ipsum!!!'
end
context 'when already attached to a status' do
let(:status) { Fabricate(:status, account: user.account) }
it 'returns http not found' do
expect(response).to have_http_status(404)
end
end
end
end
end

View File

@ -127,6 +127,8 @@ RSpec.describe Auth::SessionsController do
before do
allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return(current_ip)
allow(UserMailer).to receive(:suspicious_sign_in)
.and_return(instance_double(ActionMailer::MessageDelivery, deliver_later!: nil))
user.update(current_sign_in_at: 1.month.ago)
post :create, params: { user: { email: user.email, password: user.password } }
end
@ -140,9 +142,7 @@ RSpec.describe Auth::SessionsController do
end
it 'sends a suspicious sign-in mail' do
expect(UserMailer.deliveries.size).to eq(1)
expect(UserMailer.deliveries.first.to.first).to eq(user.email)
expect(UserMailer.deliveries.first.subject).to eq(I18n.t('user_mailer.suspicious_sign_in.subject'))
expect(UserMailer).to have_received(:suspicious_sign_in).with(user, current_ip, anything, anything)
end
end

View File

@ -30,14 +30,6 @@ describe 'email confirmation flow when captcha is enabled' do
click_button I18n.t('challenge.confirm')
expect(user.reload.confirmed?).to be true
expect(page).to have_current_path(/\A#{client_app.confirmation_redirect_uri}/, url: true)
# Browsers will generally reload the original page upon redirection
# to external handlers, so test this as well
visit "/auth/confirmation?confirmation_token=#{user.confirmation_token}&redirect_to_app=true"
# It presents a page with a link to the app callback
expect(page).to have_content(I18n.t('auth.confirmations.registration_complete', domain: 'cb6e6126.ngrok.io'))
expect(page).to have_link(I18n.t('auth.confirmations.clicking_this_link'), href: client_app.confirmation_redirect_uri)
end
end
end

View File

@ -1,13 +1,13 @@
# frozen_string_literal: true
require 'rails_helper'
require 'rails/generators/testing/behavior'
require 'rails/generators/testing/behaviour'
require 'rails/generators/testing/assertions'
require 'generators/post_deployment_migration/post_deployment_migration_generator'
describe PostDeploymentMigrationGenerator, type: :generator do
include Rails::Generators::Testing::Behavior
include Rails::Generators::Testing::Behaviour
include Rails::Generators::Testing::Assertions
include FileUtils

View File

@ -31,7 +31,7 @@ describe CacheBuster do
around do |example|
# Disables the CacheBuster.new deprecation warning about default arguments.
# Remove this `silence` block when default arg support is removed from CacheBuster
Rails.application.deprecators[:mastodon].silence do
ActiveSupport::Deprecation.silence do
example.run
end
end

View File

@ -1,129 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe ContentSecurityPolicy do
subject { described_class.new }
around do |example|
original_asset_host = Rails.configuration.action_controller.asset_host
original_web_domain = Rails.configuration.x.web_domain
original_use_https = Rails.configuration.x.use_https
example.run
Rails.configuration.action_controller.asset_host = original_asset_host
Rails.configuration.x.web_domain = original_web_domain
Rails.configuration.x.use_https = original_use_https
end
describe '#base_host' do
before { Rails.configuration.x.web_domain = 'host.example' }
it 'returns the configured value for the web domain' do
expect(subject.base_host).to eq 'host.example'
end
end
describe '#assets_host' do
context 'when asset_host is not configured' do
before { Rails.configuration.action_controller.asset_host = nil }
context 'with a configured web domain' do
before { Rails.configuration.x.web_domain = 'host.example' }
context 'when use_https is enabled' do
before { Rails.configuration.x.use_https = true }
it 'returns value from base host with https protocol' do
expect(subject.assets_host).to eq 'https://host.example'
end
end
context 'when use_https is disabled' do
before { Rails.configuration.x.use_https = false }
it 'returns value from base host with http protocol' do
expect(subject.assets_host).to eq 'http://host.example'
end
end
end
end
context 'when asset_host is configured' do
before do
Rails.configuration.action_controller.asset_host = 'https://assets.host.example'
end
it 'returns full value from configured host' do
expect(subject.assets_host).to eq 'https://assets.host.example'
end
end
end
describe '#media_host' do
context 'when there is no configured CDN' do
it 'defaults to using the assets_host value' do
expect(subject.media_host).to eq(subject.assets_host)
end
end
context 'when an S3 alias host is configured' do
around do |example|
ClimateControl.modify S3_ALIAS_HOST: 'asset-host.s3-alias.example' do
example.run
end
end
it 'uses the s3 alias host value' do
expect(subject.media_host).to eq 'https://asset-host.s3-alias.example'
end
end
context 'when an S3 alias host with a trailing path is configured' do
around do |example|
ClimateControl.modify S3_ALIAS_HOST: 'asset-host.s3-alias.example/pathname' do
example.run
end
end
it 'uses the s3 alias host value and preserves the path' do
expect(subject.media_host).to eq 'https://asset-host.s3-alias.example/pathname/'
end
end
context 'when an S3 cloudfront host is configured' do
around do |example|
ClimateControl.modify S3_CLOUDFRONT_HOST: 'asset-host.s3-cloudfront.example' do
example.run
end
end
it 'uses the s3 cloudfront host value' do
expect(subject.media_host).to eq 'https://asset-host.s3-cloudfront.example'
end
end
context 'when an azure alias host is configured' do
around do |example|
ClimateControl.modify AZURE_ALIAS_HOST: 'asset-host.azure-alias.example' do
example.run
end
end
it 'uses the azure alias host value' do
expect(subject.media_host).to eq 'https://asset-host.azure-alias.example'
end
end
context 'when s3_enabled is configured' do
around do |example|
ClimateControl.modify S3_ENABLED: 'true', S3_HOSTNAME: 'asset-host.s3.example' do
example.run
end
end
it 'uses the s3 hostname host value' do
expect(subject.media_host).to eq 'https://asset-host.s3.example'
end
end
end
end

View File

@ -5,7 +5,7 @@ require 'rails_helper'
describe UserMailer do
let(:receiver) { Fabricate(:user) }
describe '#confirmation_instructions' do
describe 'confirmation_instructions' do
let(:mail) { described_class.confirmation_instructions(receiver, 'spec') }
it 'renders confirmation instructions' do
@ -20,7 +20,7 @@ describe UserMailer do
instance: Rails.configuration.x.local_domain
end
describe '#reconfirmation_instructions' do
describe 'reconfirmation_instructions' do
let(:mail) { described_class.confirmation_instructions(receiver, 'spec') }
it 'renders reconfirmation instructions' do
@ -34,7 +34,7 @@ describe UserMailer do
end
end
describe '#reset_password_instructions' do
describe 'reset_password_instructions' do
let(:mail) { described_class.reset_password_instructions(receiver, 'spec') }
it 'renders reset password instructions' do
@ -47,7 +47,7 @@ describe UserMailer do
'devise.mailer.reset_password_instructions.subject'
end
describe '#password_change' do
describe 'password_change' do
let(:mail) { described_class.password_change(receiver) }
it 'renders password change notification' do
@ -59,7 +59,7 @@ describe UserMailer do
'devise.mailer.password_change.subject'
end
describe '#email_changed' do
describe 'email_changed' do
let(:mail) { described_class.email_changed(receiver) }
it 'renders email change notification' do
@ -71,7 +71,7 @@ describe UserMailer do
'devise.mailer.email_changed.subject'
end
describe '#warning' do
describe 'warning' do
let(:strike) { Fabricate(:account_warning, target_account: receiver.account, text: 'dont worry its just the testsuite', action: 'suspend') }
let(:mail) { described_class.warning(receiver, strike) }
@ -82,7 +82,7 @@ describe UserMailer do
end
end
describe '#webauthn_credential_deleted' do
describe 'webauthn_credential_deleted' do
let(:credential) { Fabricate(:webauthn_credential, user_id: receiver.id) }
let(:mail) { described_class.webauthn_credential_deleted(receiver, credential) }
@ -95,7 +95,7 @@ describe UserMailer do
'devise.mailer.webauthn_credential.deleted.subject'
end
describe '#suspicious_sign_in' do
describe 'suspicious_sign_in' do
let(:ip) { '192.168.0.1' }
let(:agent) { 'NCSA_Mosaic/2.0 (Windows 3.1)' }
let(:timestamp) { Time.now.utc }
@ -110,7 +110,7 @@ describe UserMailer do
'user_mailer.suspicious_sign_in.subject'
end
describe '#appeal_approved' do
describe 'appeal_approved' do
let(:appeal) { Fabricate(:appeal, account: receiver.account, approved_at: Time.now.utc) }
let(:mail) { described_class.appeal_approved(receiver, appeal) }
@ -120,7 +120,7 @@ describe UserMailer do
end
end
describe '#appeal_rejected' do
describe 'appeal_rejected' do
let(:appeal) { Fabricate(:appeal, account: receiver.account, rejected_at: Time.now.utc) }
let(:mail) { described_class.appeal_rejected(receiver, appeal) }
@ -130,7 +130,7 @@ describe UserMailer do
end
end
describe '#two_factor_enabled' do
describe 'two_factor_enabled' do
let(:mail) { described_class.two_factor_enabled(receiver) }
it 'renders two_factor_enabled mail' do
@ -139,7 +139,7 @@ describe UserMailer do
end
end
describe '#two_factor_disabled' do
describe 'two_factor_disabled' do
let(:mail) { described_class.two_factor_disabled(receiver) }
it 'renders two_factor_disabled mail' do
@ -148,7 +148,7 @@ describe UserMailer do
end
end
describe '#webauthn_enabled' do
describe 'webauthn_enabled' do
let(:mail) { described_class.webauthn_enabled(receiver) }
it 'renders webauthn_enabled mail' do
@ -157,7 +157,7 @@ describe UserMailer do
end
end
describe '#webauthn_disabled' do
describe 'webauthn_disabled' do
let(:mail) { described_class.webauthn_disabled(receiver) }
it 'renders webauthn_disabled mail' do
@ -166,7 +166,7 @@ describe UserMailer do
end
end
describe '#two_factor_recovery_codes_changed' do
describe 'two_factor_recovery_codes_changed' do
let(:mail) { described_class.two_factor_recovery_codes_changed(receiver) }
it 'renders two_factor_recovery_codes_changed mail' do
@ -175,7 +175,7 @@ describe UserMailer do
end
end
describe '#webauthn_credential_added' do
describe 'webauthn_credential_added' do
let(:credential) { Fabricate.build(:webauthn_credential) }
let(:mail) { described_class.webauthn_credential_added(receiver, credential) }
@ -184,23 +184,4 @@ describe UserMailer do
expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_credential.added.explanation')
end
end
describe '#welcome' do
let(:mail) { described_class.welcome(receiver) }
it 'renders welcome mail' do
expect(mail.subject).to eq I18n.t('user_mailer.welcome.subject')
expect(mail.body.encoded).to include I18n.t('user_mailer.welcome.explanation')
end
end
describe '#backup_ready' do
let(:backup) { Fabricate(:backup) }
let(:mail) { described_class.backup_ready(receiver, backup) }
it 'renders backup_ready mail' do
expect(mail.subject).to eq I18n.t('user_mailer.backup_ready.subject')
expect(mail.body.encoded).to include I18n.t('user_mailer.backup_ready.explanation')
end
end
end

View File

@ -32,52 +32,44 @@ RSpec.describe Tag do
expect(subject.match('https://en.wikipedia.org/wiki/Ghostbusters_(song)#Lawsuit')).to be_nil
end
it 'does not match URLs with hashtag-like anchors after a numeral' do
expect(subject.match('https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111895#c4')).to be_nil
end
it 'does not match URLs with hashtag-like anchors after an empty query parameter' do
expect(subject.match('https://en.wikipedia.org/wiki/Ghostbusters_(song)?foo=#Lawsuit')).to be_nil
end
it 'matches #' do
expect(subject.match('this is #').to_s).to eq '#'
expect(subject.match('this is #').to_s).to eq ' #'
end
it 'matches digits at the start' do
expect(subject.match('hello #3d').to_s).to eq '#3d'
expect(subject.match('hello #3d').to_s).to eq ' #3d'
end
it 'matches digits in the middle' do
expect(subject.match('hello #l33ts35k').to_s).to eq '#l33ts35k'
expect(subject.match('hello #l33ts35k').to_s).to eq ' #l33ts35k'
end
it 'matches digits at the end' do
expect(subject.match('hello #world2016').to_s).to eq '#world2016'
expect(subject.match('hello #world2016').to_s).to eq ' #world2016'
end
it 'matches underscores at the beginning' do
expect(subject.match('hello #_test').to_s).to eq '#_test'
expect(subject.match('hello #_test').to_s).to eq ' #_test'
end
it 'matches underscores at the end' do
expect(subject.match('hello #test_').to_s).to eq '#test_'
expect(subject.match('hello #test_').to_s).to eq ' #test_'
end
it 'matches underscores in the middle' do
expect(subject.match('hello #one_two_three').to_s).to eq '#one_two_three'
expect(subject.match('hello #one_two_three').to_s).to eq ' #one_two_three'
end
it 'matches middle dots' do
expect(subject.match('hello #one·two·three').to_s).to eq '#one·two·three'
expect(subject.match('hello #one·two·three').to_s).to eq ' #one·two·three'
end
it 'matches ・unicode in ぼっち・ざ・ろっく correctly' do
expect(subject.match('testing #ぼっち・ざ・ろっく').to_s).to eq '#ぼっち・ざ・ろっく'
expect(subject.match('testing #ぼっち・ざ・ろっく').to_s).to eq ' #ぼっち・ざ・ろっく'
end
it 'matches ZWNJ' do
expect(subject.match('just add #نرم‌افزار and').to_s).to eq '#نرم‌افزار'
expect(subject.match('just add #نرم‌افزار and').to_s).to eq ' #نرم‌افزار'
end
it 'does not match middle dots at the start' do
@ -85,7 +77,7 @@ RSpec.describe Tag do
end
it 'does not match middle dots at the end' do
expect(subject.match('hello #one·two·three·').to_s).to eq '#one·two·three'
expect(subject.match('hello #one·two·three·').to_s).to eq ' #one·two·three'
end
it 'does not match purely-numeric hashtags' do

View File

@ -1,50 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'account featured tags API' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'read:accounts' }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:account) { Fabricate(:account) }
describe 'GET /api/v1/accounts/:id/featured_tags' do
subject do
get "/api/v1/accounts/#{account.id}/featured_tags", headers: headers
end
before do
account.featured_tags.create!(name: 'foo')
account.featured_tags.create!(name: 'bar')
end
it 'returns the expected tags', :aggregate_failures do
subject
expect(response).to have_http_status(200)
expect(body_as_json).to contain_exactly(a_hash_including({
name: 'bar',
url: "https://cb6e6126.ngrok.io/@#{account.username}/tagged/bar",
}), a_hash_including({
name: 'foo',
url: "https://cb6e6126.ngrok.io/@#{account.username}/tagged/foo",
}))
end
context 'when the account is remote' do
it 'returns the expected tags', :aggregate_failures do
subject
expect(response).to have_http_status(200)
expect(body_as_json).to contain_exactly(a_hash_including({
name: 'bar',
url: "https://cb6e6126.ngrok.io/@#{account.pretty_acct}/tagged/bar",
}), a_hash_including({
name: 'foo',
url: "https://cb6e6126.ngrok.io/@#{account.pretty_acct}/tagged/foo",
}))
end
end
end
end

View File

@ -1,189 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Media' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'write:media' }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v1/media/:id' do
subject do
get "/api/v1/media/#{media.id}", headers: headers
end
let(:media) { Fabricate(:media_attachment, account: user.account) }
it_behaves_like 'forbidden for wrong scope', 'read'
it 'returns http success' do
subject
expect(response).to have_http_status(200)
end
it 'returns the media information' do
subject
expect(body_as_json).to match(
a_hash_including(
id: media.id.to_s,
description: media.description,
type: media.type
)
)
end
context 'when the media is still being processed' do
before do
media.update(processing: :in_progress)
end
it 'returns http partial content' do
subject
expect(response).to have_http_status(206)
end
end
context 'when the media belongs to somebody else' do
let(:media) { Fabricate(:media_attachment) }
it 'returns http not found' do
subject
expect(response).to have_http_status(404)
end
end
context 'when media is attached to a status' do
let(:media) { Fabricate(:media_attachment, account: user.account, status: Fabricate.build(:status)) }
it 'returns http not found' do
subject
expect(response).to have_http_status(404)
end
end
end
describe 'POST /api/v1/media' do
subject do
post '/api/v1/media', headers: headers, params: params
end
let(:params) { {} }
shared_examples 'a successful media upload' do |media_type|
it 'uploads the file successfully', :aggregate_failures do
subject
expect(response).to have_http_status(200)
expect(MediaAttachment.first).to be_present
expect(MediaAttachment.first).to have_attached_file(:file)
end
it 'returns the correct media content' do
subject
body = body_as_json
expect(body).to match(
a_hash_including(id: MediaAttachment.first.id.to_s, description: params[:description], type: media_type)
)
end
end
it_behaves_like 'forbidden for wrong scope', 'read read:media'
describe 'when paperclip errors occur' do
let(:media_attachments) { double }
let(:params) { { file: fixture_file_upload('attachment.jpg', 'image/jpeg') } }
before do
allow(User).to receive(:find).with(token.resource_owner_id).and_return(user)
allow(user.account).to receive(:media_attachments).and_return(media_attachments)
end
context 'when imagemagick cannot identify the file type' do
it 'returns http unprocessable entity' do
allow(media_attachments).to receive(:create!).and_raise(Paperclip::Errors::NotIdentifiedByImageMagickError)
subject
expect(response).to have_http_status(422)
end
end
context 'when there is a generic error' do
it 'returns http 500' do
allow(media_attachments).to receive(:create!).and_raise(Paperclip::Error)
subject
expect(response).to have_http_status(500)
end
end
end
context 'with image/jpeg', paperclip_processing: true do
let(:params) { { file: fixture_file_upload('attachment.jpg', 'image/jpeg'), description: 'jpeg image' } }
it_behaves_like 'a successful media upload', 'image'
end
context 'with image/gif', paperclip_processing: true do
let(:params) { { file: fixture_file_upload('attachment.gif', 'image/gif') } }
it_behaves_like 'a successful media upload', 'image'
end
context 'with video/webm', paperclip_processing: true do
let(:params) { { file: fixture_file_upload('attachment.webm', 'video/webm') } }
it_behaves_like 'a successful media upload', 'gifv'
end
end
describe 'PUT /api/v1/media/:id' do
subject do
put "/api/v1/media/#{media.id}", headers: headers, params: params
end
let(:params) { {} }
let(:media) { Fabricate(:media_attachment, status: status, account: user.account, description: 'old') }
it_behaves_like 'forbidden for wrong scope', 'read read:media'
context 'when the media belongs to somebody else' do
let(:media) { Fabricate(:media_attachment, status: nil) }
let(:params) { { description: 'Lorem ipsum!!!' } }
it 'returns http not found' do
subject
expect(response).to have_http_status(404)
end
end
context 'when the requesting user owns the media' do
let(:status) { nil }
let(:params) { { description: 'Lorem ipsum!!!' } }
it 'updates the description' do
expect { subject }.to change { media.reload.description }.from('old').to('Lorem ipsum!!!')
end
context 'when the media is attached to a status' do
let(:status) { Fabricate(:status, account: user.account) }
it 'returns http not found' do
subject
expect(response).to have_http_status(404)
end
end
end
end
end

View File

@ -42,22 +42,12 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
}
end
let(:featured_with_null) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: 'https://example.com/account/collections/featured',
totalItems: 0,
type: 'OrderedCollection',
}
end
let(:items) do
[
'https://example.com/account/pinned/known', # known
status_json_pinned_unknown_inlined, # unknown inlined
'https://example.com/account/pinned/unknown-unreachable', # unknown unreachable
'https://example.com/account/pinned/unknown-reachable', # unknown reachable
'https://example.com/account/collections/featured', # featured with null
]
end
@ -76,7 +66,6 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined))
stub_request(:get, 'https://example.com/account/pinned/unknown-unreachable').to_return(status: 404)
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_unreachable))
stub_request(:get, 'https://example.com/account/collections/featured').to_return(status: 200, body: Oj.dump(featured_with_null))
subject.call(actor, note: true, hashtag: false)
end

260
yarn.lock
View File

@ -1765,10 +1765,10 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
"@material-symbols/svg-600@^0.13.1":
version "0.13.2"
resolved "https://registry.yarnpkg.com/@material-symbols/svg-600/-/svg-600-0.13.2.tgz#a98361ed5a100492780e3301c9d9e4d79aefe0f1"
integrity sha512-4n/bbh6444ZfJ72VHYrWc2f2E8PCsC6ue/ou4Q4QqQFvSRbQSZjcSXuTb0lA4xkaIf2cJf4grvF8ZsskIBLbHg==
"@material-design-icons/svg@^0.14.10":
version "0.14.13"
resolved "https://registry.yarnpkg.com/@material-design-icons/svg/-/svg-0.14.13.tgz#de5a79038cf8b281f4b47d79c07399b2b92fcfb7"
integrity sha512-nCExGZOtoLoFeeqShEOM4XA9DkkLzLlQdk/ZxHxps0//dz6e1Lw3fvQbZ2X/+0Dz2O+udiEukfZ4Nd4KpHg8aA==
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
@ -1807,11 +1807,6 @@
mkdirp "^1.0.4"
rimraf "^3.0.2"
"@opentelemetry/api@^1.4.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.6.0.tgz#de2c6823203d6f319511898bb5de7e70f5267e19"
integrity sha512-OWlrQAnWn9577PhVgqjUvMr1pg57Bc4jv0iL4w0PRuOSRvq67rvHW9Ie/dZVMvCzhSCB+UxhcY/PmCmFj33Q+g==
"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
@ -1839,10 +1834,10 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
"@rails/ujs@^7.1.1":
version "7.1.1"
resolved "https://registry.yarnpkg.com/@rails/ujs/-/ujs-7.1.1.tgz#f8df96e406a2a824084b637880e57c257073cb05"
integrity sha512-ywGwWNiqXN3Bb1BifVQTrkWEWcAGLHW3D0JNQMQeu57LsoluRzvnenNLPsmdoDPkrmSIASDXNsJiCIpUzFj8CA==
"@rails/ujs@^7.0.6":
version "7.0.8"
resolved "https://registry.yarnpkg.com/@rails/ujs/-/ujs-7.0.8.tgz#59853367d0827b3955d2c4bedfd5eba4a79d3422"
integrity sha512-tOQQBVH8LsUpGXqDnk+kaOGVsgZ8maHAhEiw3Git3p88q+c0Slgu47HuDnL6sVxeCfz24zbq7dOjsVYDiTpDIA==
"@reduxjs/toolkit@^1.9.5":
version "1.9.7"
@ -2995,13 +2990,20 @@ ansi-colors@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
ansi-escapes@^4.2.1, ansi-escapes@^4.3.0:
ansi-escapes@^4.2.1:
version "4.3.2"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
dependencies:
type-fest "^0.21.3"
ansi-escapes@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-5.0.0.tgz#b6a0caf0eef0c41af190e9a749e0c00ec04bb2a6"
integrity sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==
dependencies:
type-fest "^1.0.2"
ansi-html-community@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41"
@ -4016,10 +4018,10 @@ caniuse-lite@^1.0.30001541:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001553.tgz#e64e7dc8fd4885cd246bb476471420beb5e474b5"
integrity sha512-N0ttd6TrFfuqKNi+pMgWJTb9qrdJu4JSpgPFLe/lrD19ugC6fZgF0pUewRowDwzdDnb9V41mFcdlYgl/PyKf4A==
chalk@5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3"
integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==
chalk@5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385"
integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==
chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
@ -4138,20 +4140,12 @@ clean-stack@^2.0.0:
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
cli-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
cli-cursor@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea"
integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==
dependencies:
restore-cursor "^3.1.0"
cli-truncate@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7"
integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==
dependencies:
slice-ansi "^3.0.0"
string-width "^4.2.0"
restore-cursor "^4.0.0"
cli-truncate@^3.1.0:
version "3.1.0"
@ -4264,7 +4258,7 @@ colord@^2.9.1, colord@^2.9.3:
resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==
colorette@^2.0.19:
colorette@^2.0.20:
version "2.0.20"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
@ -4281,10 +4275,10 @@ combined-stream@^1.0.8:
dependencies:
delayed-stream "~1.0.0"
commander@^10.0.0:
version "10.0.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
commander@11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906"
integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==
commander@^2.20.0:
version "2.20.3"
@ -4746,7 +4740,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
dependencies:
ms "2.0.0"
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -5749,6 +5743,11 @@ eventemitter3@^4.0.0:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
eventemitter3@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
events@^3.0.0, events@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
@ -5767,6 +5766,21 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
md5.js "^1.3.4"
safe-buffer "^5.1.1"
execa@8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c"
integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==
dependencies:
cross-spawn "^7.0.3"
get-stream "^8.0.1"
human-signals "^5.0.0"
is-stream "^3.0.0"
merge-stream "^2.0.0"
npm-run-path "^5.1.0"
onetime "^6.0.0"
signal-exit "^4.1.0"
strip-final-newline "^3.0.0"
execa@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
@ -5795,7 +5809,7 @@ execa@^5.0.0:
signal-exit "^3.0.3"
strip-final-newline "^2.0.0"
execa@^7.0.0, execa@^7.1.1:
execa@^7.1.1:
version "7.2.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9"
integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==
@ -6316,6 +6330,11 @@ get-stream@^6.0.0, get-stream@^6.0.1:
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
get-stream@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2"
integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==
get-symbol-description@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6"
@ -6763,6 +6782,11 @@ human-signals@^4.3.0:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2"
integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==
human-signals@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28"
integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==
husky@^8.0.3:
version "8.0.3"
resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184"
@ -8207,38 +8231,33 @@ lines-and-columns@^1.1.6:
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
lint-staged@^13.2.2:
version "13.2.3"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.2.3.tgz#f899aad6c093473467e9c9e316e3c2d8a28f87a7"
integrity sha512-zVVEXLuQIhr1Y7R7YAWx4TZLdvuzk7DnmrsTNL0fax6Z3jrpFcas+vKbzxhhvp6TA55m1SQuWkpzI1qbfDZbAg==
lint-staged@^15.0.0:
version "15.0.2"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.0.2.tgz#abef713182ec2770143e40a5d6d0130fe61ed442"
integrity sha512-vnEy7pFTHyVuDmCAIFKR5QDO8XLVlPFQQyujQ/STOxe40ICWqJ6knS2wSJ/ffX/Lw0rz83luRDh+ET7toN+rOw==
dependencies:
chalk "5.2.0"
cli-truncate "^3.1.0"
commander "^10.0.0"
debug "^4.3.4"
execa "^7.0.0"
chalk "5.3.0"
commander "11.1.0"
debug "4.3.4"
execa "8.0.1"
lilconfig "2.1.0"
listr2 "^5.0.7"
micromatch "^4.0.5"
normalize-path "^3.0.0"
object-inspect "^1.12.3"
pidtree "^0.6.0"
string-argv "^0.3.1"
yaml "^2.2.2"
listr2 "7.0.2"
micromatch "4.0.5"
pidtree "0.6.0"
string-argv "0.3.2"
yaml "2.3.3"
listr2@^5.0.7:
version "5.0.8"
resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.8.tgz#a9379ffeb4bd83a68931a65fb223a11510d6ba23"
integrity sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==
listr2@7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/listr2/-/listr2-7.0.2.tgz#3aa3e1549dfaf3c57ab5eeaba754da3b87f33063"
integrity sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==
dependencies:
cli-truncate "^2.1.0"
colorette "^2.0.19"
log-update "^4.0.0"
p-map "^4.0.0"
cli-truncate "^3.1.0"
colorette "^2.0.20"
eventemitter3 "^5.0.1"
log-update "^5.0.1"
rfdc "^1.3.0"
rxjs "^7.8.0"
through "^2.3.8"
wrap-ansi "^7.0.0"
wrap-ansi "^8.1.0"
loader-runner@^2.4.0:
version "2.4.0"
@ -8387,15 +8406,16 @@ lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-update@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1"
integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==
log-update@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/log-update/-/log-update-5.0.1.tgz#9e928bf70cb183c1f0c9e91d9e6b7115d597ce09"
integrity sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==
dependencies:
ansi-escapes "^4.3.0"
cli-cursor "^3.1.0"
slice-ansi "^4.0.0"
wrap-ansi "^6.2.0"
ansi-escapes "^5.0.0"
cli-cursor "^4.0.0"
slice-ansi "^5.0.0"
strip-ansi "^7.0.1"
wrap-ansi "^8.0.1"
loglevel@^1.6.8:
version "1.8.1"
@ -8598,6 +8618,14 @@ methods@~1.1.2:
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
micromatch@4.0.5, micromatch@^4.0.4, micromatch@^4.0.5:
version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
dependencies:
braces "^3.0.2"
picomatch "^2.3.1"
micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
@ -8617,14 +8645,6 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.2"
micromatch@^4.0.4, micromatch@^4.0.5:
version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
dependencies:
braces "^3.0.2"
picomatch "^2.3.1"
miller-rabin@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@ -9546,7 +9566,7 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatc
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pidtree@^0.6.0:
pidtree@0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c"
integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==
@ -9996,12 +10016,11 @@ process@^0.11.10:
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
prom-client@^15.0.0:
version "15.0.0"
resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-15.0.0.tgz#067da874a2aa5d2e21bd5cdba9f24a8178bdab6a"
integrity sha512-UocpgIrKyA2TKLVZDSfm8rGkL13C19YrQBAiG3xo3aDFWcHedxRxI3z+cIcucoxpSO0h5lff5iv/SXoxyeopeA==
prom-client@^14.2.0:
version "14.2.0"
resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-14.2.0.tgz#ca94504e64156f6506574c25fb1c34df7812cf11"
integrity sha512-sF308EhTenb/pDRPakm+WgiN+VdM/T1RaHj1x+MvAuT8UiQP8JmOEbxVqtkbfR4LrvOg5n7ic01kRBDGXjYikA==
dependencies:
"@opentelemetry/api" "^1.4.0"
tdigest "^0.1.1"
promise-inflight@^1.0.1:
@ -10782,10 +10801,10 @@ resolve@^2.0.0-next.4:
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
restore-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
restore-cursor@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9"
integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==
dependencies:
onetime "^5.1.0"
signal-exit "^3.0.2"
@ -10875,13 +10894,6 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
rxjs@^7.8.0:
version "7.8.1"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
dependencies:
tslib "^2.1.0"
safe-array-concat@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.0.tgz#2064223cba3c08d2ee05148eedbc563cd6d84060"
@ -10945,9 +10957,9 @@ sass-loader@^10.2.0:
semver "^7.3.2"
sass@^1.62.1:
version "1.69.5"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.5.tgz#23e18d1c757a35f2e52cc81871060b9ad653dfde"
integrity sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==
version "1.69.4"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.4.tgz#10c735f55e3ea0b7742c6efa940bce30e07fbca2"
integrity sha512-+qEreVhqAy8o++aQfCJwp0sklr2xyEzkm9Pp/Igu9wNPoe7EZEQ8X/MBvvXggI2ql607cxKg/RKOwDj6pp2XDA==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"
@ -11206,7 +11218,7 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
signal-exit@^4.0.1:
signal-exit@^4.0.1, signal-exit@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
@ -11230,15 +11242,6 @@ slash@^3.0.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
slice-ansi@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787"
integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==
dependencies:
ansi-styles "^4.0.0"
astral-regex "^2.0.0"
is-fullwidth-code-point "^3.0.0"
slice-ansi@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b"
@ -11543,7 +11546,7 @@ stream-http@^2.7.2:
to-arraybuffer "^1.0.0"
xtend "^4.0.0"
string-argv@^0.3.1:
string-argv@0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
@ -12091,11 +12094,6 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
through@^2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
thunky@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
@ -12246,11 +12244,6 @@ tslib@2.6.2, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
tslib@^2.1.0:
version "2.6.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410"
integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
@ -12298,7 +12291,7 @@ type-fest@^0.21.3:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
type-fest@^1.0.1, type-fest@^1.2.1, type-fest@^1.2.2:
type-fest@^1.0.1, type-fest@^1.0.2, type-fest@^1.2.1, type-fest@^1.2.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
@ -13206,16 +13199,7 @@ wrap-ansi@^5.1.0:
string-width "^3.0.0"
strip-ansi "^5.0.0"
wrap-ansi@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^8.1.0:
wrap-ansi@^8.0.1, wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
@ -13297,16 +13281,16 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.3.tgz#01f6d18ef036446340007db8e016810e5d64aad9"
integrity sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==
yaml@^1.10.0:
version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yaml@^2.2.2:
version "2.3.1"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b"
integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==
yargs-parser@^13.1.2:
version "13.1.2"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"