diff --git a/.bundler-audit.yml b/.bundler-audit.yml new file mode 100644 index 0000000000..0671df390f --- /dev/null +++ b/.bundler-audit.yml @@ -0,0 +1,6 @@ +--- +ignore: + # devise-two-factor advisory about brute-forcing TOTP + # We have rate-limits on authentication endpoints in place (including second + # factor verification) since Mastodon v3.2.0 + - CVE-2024-0227 diff --git a/.devcontainer/codespaces/devcontainer.json b/.devcontainer/codespaces/devcontainer.json index ca9156fdaa..b32e4026d2 100644 --- a/.devcontainer/codespaces/devcontainer.json +++ b/.devcontainer/codespaces/devcontainer.json @@ -5,7 +5,7 @@ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", "features": { - "ghcr.io/devcontainers/features/sshd:1": {} + "ghcr.io/devcontainers/features/sshd:1": {}, }, "runServices": ["app", "db", "redis"], @@ -15,16 +15,16 @@ "portsAttributes": { "3000": { "label": "web", - "onAutoForward": "notify" + "onAutoForward": "notify", }, "4000": { "label": "stream", - "onAutoForward": "silent" - } + "onAutoForward": "silent", + }, }, "otherPortsAttributes": { - "onAutoForward": "silent" + "onAutoForward": "silent", }, "remoteEnv": { @@ -33,7 +33,7 @@ "STREAMING_API_BASE_URL": "https://${localEnv:CODESPACE_NAME}-4000.app.github.dev", "DISABLE_FORGERY_REQUEST_PROTECTION": "true", "ES_ENABLED": "", - "LIBRE_TRANSLATE_ENDPOINT": "" + "LIBRE_TRANSLATE_ENDPOINT": "", }, "onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}", @@ -43,7 +43,7 @@ "customizations": { "vscode": { "settings": {}, - "extensions": ["EditorConfig.EditorConfig", "webben.browserslist"] - } - } + "extensions": ["EditorConfig.EditorConfig", "webben.browserslist"], + }, + }, } diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index fa8d6542c1..ed71235b3b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,7 +5,7 @@ "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", "features": { - "ghcr.io/devcontainers/features/sshd:1": {} + "ghcr.io/devcontainers/features/sshd:1": {}, }, "forwardPorts": [3000, 4000], @@ -14,17 +14,17 @@ "3000": { "label": "web", "onAutoForward": "notify", - "requireLocalPort": true + "requireLocalPort": true, }, "4000": { "label": "stream", "onAutoForward": "silent", - "requireLocalPort": true - } + "requireLocalPort": true, + }, }, "otherPortsAttributes": { - "onAutoForward": "silent" + "onAutoForward": "silent", }, "onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}", @@ -34,7 +34,7 @@ "customizations": { "vscode": { "settings": {}, - "extensions": ["EditorConfig.EditorConfig", "webben.browserslist"] - } - } + "extensions": ["EditorConfig.EditorConfig", "webben.browserslist"], + }, + }, } diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 21ee078d60..88979723c3 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -70,7 +70,7 @@ services: hard: -1 libretranslate: - image: libretranslate/libretranslate:v1.5.3 + image: libretranslate/libretranslate:v1.5.4 restart: unless-stopped volumes: - lt-data:/home/libretranslate/.local diff --git a/.rubocop.yml b/.rubocop.yml index d2bd2f4905..e5bce22eb9 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -103,9 +103,26 @@ Rails/Exit: - 'config/boot.rb' - 'lib/mastodon/cli/*.rb' -Rails/SkipsModelValidations: +# Reason: Conflicts with `Lint/UselessMethodDefinition` for inherited controller actions +# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railslexicallyscopedactionfilter +Rails/LexicallyScopedActionFilter: Exclude: - - 'db/*migrate/**/*' + - 'app/controllers/auth/*' + +# Reason: These tasks are doing local work which do not need full env loaded +# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsrakeenvironment +Rails/RakeEnvironment: + Exclude: + - 'lib/tasks/auto_annotate_models.rake' + - 'lib/tasks/emojis.rake' + - 'lib/tasks/mastodon.rake' + - 'lib/tasks/repo.rake' + - 'lib/tasks/statistics.rake' + +# Reason: There are appropriate times to use these features +# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsskipsmodelvalidations +Rails/SkipsModelValidations: + Enabled: false # Reason: We want to preserve the ability to migrate from arbitrary old versions, # and cannot guarantee that every installation has run every migration as they upgrade. diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 16ea33b64c..29161a3ee6 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -13,13 +13,6 @@ Bundler/OrderedGems: Exclude: - 'Gemfile' -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. -# URISchemes: http, https -Layout/LineLength: - Exclude: - - 'app/models/account.rb' - Lint/NonLocalExitFromIterator: Exclude: - 'app/helpers/jsonld_helper.rb' @@ -74,64 +67,10 @@ Rails/HasAndBelongsToMany: - 'app/models/status.rb' - 'app/models/tag.rb' -# Configuration parameters: Include. -# Include: app/controllers/**/*.rb, app/mailers/**/*.rb -Rails/LexicallyScopedActionFilter: - Exclude: - - 'app/controllers/auth/passwords_controller.rb' - - 'app/controllers/auth/registrations_controller.rb' - Rails/OutputSafety: Exclude: - 'config/initializers/simple_form.rb' -# This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: Include. -# Include: **/Rakefile, **/*.rake -Rails/RakeEnvironment: - Exclude: - - 'lib/tasks/auto_annotate_models.rake' - - 'lib/tasks/db.rake' - - 'lib/tasks/emojis.rake' - - 'lib/tasks/mastodon.rake' - - 'lib/tasks/repo.rake' - - 'lib/tasks/statistics.rake' - -# 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: - Exclude: - - 'app/controllers/admin/invites_controller.rb' - - 'app/controllers/concerns/session_tracking_concern.rb' - - 'app/models/concerns/account/merging.rb' - - 'app/models/concerns/expireable.rb' - - 'app/models/status.rb' - - 'app/models/trends/links.rb' - - 'app/models/trends/preview_card_batch.rb' - - 'app/models/trends/preview_card_provider_batch.rb' - - 'app/models/trends/status_batch.rb' - - 'app/models/trends/statuses.rb' - - 'app/models/trends/tag_batch.rb' - - 'app/models/trends/tags.rb' - - 'app/models/user.rb' - - 'app/services/activitypub/process_status_update_service.rb' - - 'app/services/approve_appeal_service.rb' - - 'app/services/block_domain_service.rb' - - 'app/services/delete_account_service.rb' - - 'app/services/process_mentions_service.rb' - - 'app/services/unallow_domain_service.rb' - - 'app/services/unblock_domain_service.rb' - - 'app/services/update_status_service.rb' - - 'app/workers/activitypub/post_upgrade_worker.rb' - - 'app/workers/move_worker.rb' - - 'app/workers/scheduler/ip_cleanup_scheduler.rb' - - 'app/workers/scheduler/scheduled_statuses_scheduler.rb' - - 'lib/mastodon/cli/accounts.rb' - - 'lib/mastodon/cli/maintenance.rb' - - 'spec/lib/activitypub/activity/follow_spec.rb' - - 'spec/services/follow_service_spec.rb' - - 'spec/services/update_account_service_spec.rb' - # Configuration parameters: Include. # Include: app/models/**/*.rb Rails/UniqueValidationWithoutIndex: @@ -151,23 +90,10 @@ Rails/WhereExists: - 'app/lib/activitypub/activity/create.rb' - 'app/lib/delivery_failure_tracker.rb' - 'app/lib/feed_manager.rb' - - 'app/lib/status_cache_hydrator.rb' - 'app/lib/suspicious_sign_in_detector.rb' - - 'app/models/concerns/account/interactions.rb' - - 'app/models/featured_tag.rb' - - 'app/models/poll.rb' - - 'app/models/session_activation.rb' - - 'app/models/status.rb' - - 'app/models/user.rb' - 'app/policies/status_policy.rb' - 'app/serializers/rest/announcement_serializer.rb' - - 'app/serializers/rest/tag_serializer.rb' - - 'app/services/activitypub/fetch_remote_status_service.rb' - - 'app/services/vote_service.rb' - - 'app/validators/reaction_validator.rb' - - 'app/validators/vote_validator.rb' - 'app/workers/move_worker.rb' - - 'lib/tasks/tests.rake' - 'spec/models/account_spec.rb' - 'spec/services/activitypub/process_collection_service_spec.rb' - 'spec/services/purge_domain_service_spec.rb' @@ -211,7 +137,6 @@ Style/FetchEnvVar: # AllowedMethods: redirect Style/FormatStringToken: Exclude: - - 'app/models/privacy_policy.rb' - 'config/initializers/devise.rb' - 'lib/paperclip/color_extractor.rb' diff --git a/.ruby-version b/.ruby-version index be94e6f53d..b347b11eac 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.2.2 +3.2.3 diff --git a/Dockerfile b/Dockerfile index 96f8b5cd27..119c266b89 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,15 +7,15 @@ ARG TARGETPLATFORM=${TARGETPLATFORM} ARG BUILDPLATFORM=${BUILDPLATFORM} -# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.2.2"] -ARG RUBY_VERSION="3.2.2" +# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.2.3"] +ARG RUBY_VERSION="3.2.3" # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] ARG NODE_MAJOR_VERSION="20" # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] ARG DEBIAN_VERSION="bookworm" # Node image to use for base image based on combined variables (ex: 20-bookworm-slim) FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node -# Ruby image to use for base image based on combined variables (ex: 3.2.2-slim-bookworm) +# Ruby image to use for base image based on combined variables (ex: 3.2.3-slim-bookworm) FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA diff --git a/FEDERATION.md b/FEDERATION.md index e3721d7241..2819fa935a 100644 --- a/FEDERATION.md +++ b/FEDERATION.md @@ -1,19 +1,35 @@ -## ActivityPub federation in Mastodon +# Federation + +## Supported federation protocols and standards + +- [ActivityPub](https://www.w3.org/TR/activitypub/) (Server-to-Server) +- [WebFinger](https://webfinger.net/) +- [Http Signatures](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures) +- [NodeInfo](https://nodeinfo.diaspora.software/) + +## Supported FEPs + +- [FEP-67ff: FEDERATION.md](https://codeberg.org/fediverse/fep/src/branch/main/fep/67ff/fep-67ff.md) +- [FEP-f1d5: NodeInfo in Fediverse Software](https://codeberg.org/fediverse/fep/src/branch/main/fep/f1d5/fep-f1d5.md) +- [FEP-8fcf: Followers collection synchronization across servers](https://codeberg.org/fediverse/fep/src/branch/main/fep/8fcf/fep-8fcf.md) +- [FEP-5feb: Search indexing consent for actors](https://codeberg.org/fediverse/fep/src/branch/main/fep/5feb/fep-5feb.md) + +## ActivityPub in Mastodon Mastodon largely follows the ActivityPub server-to-server specification but it makes uses of some non-standard extensions, some of which are required for interacting with Mastodon at all. -Supported vocabulary: https://docs.joinmastodon.org/spec/activitypub/ +- [Supported ActivityPub vocabulary](https://docs.joinmastodon.org/spec/activitypub/) ### Required extensions -#### Webfinger +#### WebFinger In Mastodon, users are identified by a `username` and `domain` pair (e.g., `Gargron@mastodon.social`). This is used both for discovery and for unambiguously mentioning users across the fediverse. Furthermore, this is part of Mastodon's database design from its very beginnings. As a result, Mastodon requires that each ActivityPub actor uniquely maps back to an `acct:` URI that can be resolved via WebFinger. -More information and examples are available at: https://docs.joinmastodon.org/spec/webfinger/ +- [WebFinger information and examples](https://docs.joinmastodon.org/spec/webfinger/) #### HTTP Signatures @@ -21,11 +37,13 @@ In order to authenticate activities, Mastodon relies on HTTP Signatures, signing Mastodon requires all `POST` requests to be signed, and MAY require `GET` requests to be signed, depending on the configuration of the Mastodon server. -More information on HTTP Signatures, as well as examples, can be found here: https://docs.joinmastodon.org/spec/security/#http +- [HTTP Signatures information and examples](https://docs.joinmastodon.org/spec/security/#http) ### Optional extensions -- Linked-Data Signatures: https://docs.joinmastodon.org/spec/security/#ld -- Bearcaps: https://docs.joinmastodon.org/spec/bearcaps/ -- Followers collection synchronization: https://codeberg.org/fediverse/fep/src/branch/main/fep/8fcf/fep-8fcf.md -- Search indexing consent for actors: https://codeberg.org/fediverse/fep/src/branch/main/fep/5feb/fep-5feb.md +- [Linked-Data Signatures](https://docs.joinmastodon.org/spec/security/#ld) +- [Bearcaps](https://docs.joinmastodon.org/spec/bearcaps/) + +### Additional documentation + +- [Mastodon documentation](https://docs.joinmastodon.org/) diff --git a/Gemfile b/Gemfile index 4176ddb8de..4dc200df24 100644 --- a/Gemfile +++ b/Gemfile @@ -39,8 +39,7 @@ end gem 'net-ldap', '~> 0.18' -# TODO: Point back at released omniauth-cas gem when new version is released -gem 'omniauth-cas', github: 'dlindahl/omniauth-cas', ref: '9d9d3a91b316c55d49ab6e621977f2067010c5bf' +gem 'omniauth-cas', '~> 3.0.0.beta.1' gem 'omniauth-saml', '~> 2.0' gem 'omniauth_openid_connect', '~> 0.6.1' gem 'omniauth', '~> 2.0' diff --git a/Gemfile.lock b/Gemfile.lock index ccb9f4b115..93931d8724 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,16 +7,6 @@ GIT hkdf (~> 0.2) jwt (~> 2.0) -GIT - remote: https://github.com/dlindahl/omniauth-cas.git - revision: 9d9d3a91b316c55d49ab6e621977f2067010c5bf - ref: 9d9d3a91b316c55d49ab6e621977f2067010c5bf - specs: - omniauth-cas (3.0.0) - addressable (~> 2.8) - nokogiri (~> 1.12) - omniauth (~> 2.1) - GIT remote: https://github.com/jhawthorn/nsa.git revision: e020fcc3a54d993ab45b7194d89ab720296c111b @@ -31,35 +21,35 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (7.1.2) - actionpack (= 7.1.2) - activesupport (= 7.1.2) + actioncable (7.1.3) + actionpack (= 7.1.3) + activesupport (= 7.1.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.2) - actionpack (= 7.1.2) - activejob (= 7.1.2) - activerecord (= 7.1.2) - activestorage (= 7.1.2) - activesupport (= 7.1.2) + actionmailbox (7.1.3) + actionpack (= 7.1.3) + activejob (= 7.1.3) + activerecord (= 7.1.3) + activestorage (= 7.1.3) + activesupport (= 7.1.3) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.1.2) - actionpack (= 7.1.2) - actionview (= 7.1.2) - activejob (= 7.1.2) - activesupport (= 7.1.2) + actionmailer (7.1.3) + actionpack (= 7.1.3) + actionview (= 7.1.3) + activejob (= 7.1.3) + activesupport (= 7.1.3) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.2) - actionpack (7.1.2) - actionview (= 7.1.2) - activesupport (= 7.1.2) + actionpack (7.1.3) + actionview (= 7.1.3) + activesupport (= 7.1.3) nokogiri (>= 1.8.5) racc rack (>= 2.2.4) @@ -67,15 +57,15 @@ GEM rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.2) - actionpack (= 7.1.2) - activerecord (= 7.1.2) - activestorage (= 7.1.2) - activesupport (= 7.1.2) + actiontext (7.1.3) + actionpack (= 7.1.3) + activerecord (= 7.1.3) + activestorage (= 7.1.3) + activesupport (= 7.1.3) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.2) - activesupport (= 7.1.2) + actionview (7.1.3) + activesupport (= 7.1.3) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) @@ -85,22 +75,22 @@ GEM activemodel (>= 4.1) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) - activejob (7.1.2) - activesupport (= 7.1.2) + activejob (7.1.3) + activesupport (= 7.1.3) globalid (>= 0.3.6) - activemodel (7.1.2) - activesupport (= 7.1.2) - activerecord (7.1.2) - activemodel (= 7.1.2) - activesupport (= 7.1.2) + activemodel (7.1.3) + activesupport (= 7.1.3) + activerecord (7.1.3) + activemodel (= 7.1.3) + activesupport (= 7.1.3) timeout (>= 0.4.0) - activestorage (7.1.2) - actionpack (= 7.1.2) - activejob (= 7.1.2) - activerecord (= 7.1.2) - activesupport (= 7.1.2) + activestorage (7.1.3) + actionpack (= 7.1.3) + activejob (= 7.1.3) + activerecord (= 7.1.3) + activesupport (= 7.1.3) marcel (~> 1.0) - activesupport (7.1.2) + activesupport (7.1.3) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -160,12 +150,12 @@ GEM erubi (~> 1.4) parser (>= 2.4) smart_properties - bigdecimal (3.1.5) + bigdecimal (3.1.6) bindata (2.4.15) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) blurhash (0.1.7) - bootsnap (1.17.0) + bootsnap (1.17.1) msgpack (~> 1.2) brakeman (6.1.1) racc @@ -198,7 +188,7 @@ GEM climate_control (0.2.0) cocoon (1.2.15) color_diff (0.1) - concurrent-ruby (1.2.2) + concurrent-ruby (1.2.3) connection_pool (2.4.1) cose (1.3.0) cbor (~> 0.5.9) @@ -267,7 +257,7 @@ GEM tzinfo excon (0.109.0) fabrication (2.31.0) - faker (3.2.2) + faker (3.2.3) i18n (>= 1.8.11, < 2) faraday (1.10.3) faraday-em_http (~> 1.0) @@ -408,12 +398,12 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) - kt-paperclip (7.2.1) + kt-paperclip (7.2.2) activemodel (>= 4.2.0) activesupport (>= 4.2.0) marcel (~> 1.0.1) mime-types - terrapin (~> 0.6.0) + terrapin (>= 0.6.0, < 2.0) language_server-protocol (3.17.0.3) launchy (2.5.2) addressable (~> 2.8) @@ -464,7 +454,7 @@ GEM uri net-http-persistent (4.0.2) connection_pool (~> 2.2) - net-imap (0.4.4) + net-imap (0.4.9.1) date net-protocol net-ldap (0.19.0) @@ -472,7 +462,7 @@ GEM net-protocol net-protocol (0.2.2) timeout - net-smtp (0.4.0) + net-smtp (0.4.0.1) net-protocol nio4r (2.5.9) nokogiri (1.16.0) @@ -484,6 +474,10 @@ GEM hashie (>= 3.4.6) rack (>= 2.2.3) rack-protection + omniauth-cas (3.0.0.beta.1) + addressable (~> 2.8) + nokogiri (~> 1.12) + omniauth (~> 2.1) omniauth-rails_csrf_protection (1.0.1) actionpack (>= 4.2) omniauth (~> 2.0) @@ -558,27 +552,27 @@ GEM rack rack-proxy (0.7.6) rack - rack-session (1.0.1) + rack-session (1.0.2) rack (< 3) rack-test (2.1.0) rack (>= 1.3) rackup (1.0.0) rack (< 3) webrick - rails (7.1.2) - actioncable (= 7.1.2) - actionmailbox (= 7.1.2) - actionmailer (= 7.1.2) - actionpack (= 7.1.2) - actiontext (= 7.1.2) - actionview (= 7.1.2) - activejob (= 7.1.2) - activemodel (= 7.1.2) - activerecord (= 7.1.2) - activestorage (= 7.1.2) - activesupport (= 7.1.2) + rails (7.1.3) + actioncable (= 7.1.3) + actionmailbox (= 7.1.3) + actionmailer (= 7.1.3) + actionpack (= 7.1.3) + actiontext (= 7.1.3) + actionview (= 7.1.3) + activejob (= 7.1.3) + activemodel (= 7.1.3) + activerecord (= 7.1.3) + activestorage (= 7.1.3) + activesupport (= 7.1.3) bundler (>= 1.15.0) - railties (= 7.1.2) + railties (= 7.1.3) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -593,9 +587,9 @@ GEM rails-i18n (7.0.8) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - railties (7.1.2) - actionpack (= 7.1.2) - activesupport (= 7.1.2) + railties (7.1.3) + actionpack (= 7.1.3) + activesupport (= 7.1.3) irb rackup (>= 1.0.0) rake (>= 12.2) @@ -606,8 +600,8 @@ GEM rdf (3.3.1) bcp47_spec (~> 0.2) link_header (~> 0.0, >= 0.0.8) - rdf-normalize (0.6.1) - rdf (~> 3.2) + rdf-normalize (0.7.0) + rdf (~> 3.3) rdoc (6.6.2) psych (>= 4.0.0) redcarpet (3.6.0) @@ -736,7 +730,7 @@ GEM simplecov-lcov (0.8.0) simplecov_json_formatter (0.1.4) smart_properties (1.17.0) - stackprof (0.2.25) + stackprof (0.2.26) statsd-ruby (1.5.0) stoplight (3.0.2) redlock (~> 1.0) @@ -894,7 +888,7 @@ DEPENDENCIES nsa! oj (~> 3.14) omniauth (~> 2.0) - omniauth-cas! + omniauth-cas (~> 3.0.0.beta.1) omniauth-rails_csrf_protection (~> 1.0) omniauth-saml (~> 2.0) omniauth_openid_connect (~> 0.6.1) @@ -961,4 +955,4 @@ RUBY VERSION ruby 3.2.2p53 BUNDLED WITH - 2.4.20 + 2.5.4 diff --git a/app/controllers/activitypub/followers_synchronizations_controller.rb b/app/controllers/activitypub/followers_synchronizations_controller.rb index 976caa3445..d2942104e5 100644 --- a/app/controllers/activitypub/followers_synchronizations_controller.rb +++ b/app/controllers/activitypub/followers_synchronizations_controller.rb @@ -24,7 +24,7 @@ class ActivityPub::FollowersSynchronizationsController < ActivityPub::BaseContro end def set_items - @items = @account.followers.where(Account.arel_table[:uri].matches("#{Account.sanitize_sql_like(uri_prefix)}/%", false, true)).or(@account.followers.where(uri: uri_prefix)).pluck(:uri) + @items = @account.followers.matches_uri_prefix(uri_prefix).pluck(:uri) end def collection_presenter diff --git a/app/controllers/admin/action_logs_controller.rb b/app/controllers/admin/action_logs_controller.rb index 37a00ad225..8b8e83fde7 100644 --- a/app/controllers/admin/action_logs_controller.rb +++ b/app/controllers/admin/action_logs_controller.rb @@ -6,7 +6,7 @@ module Admin def index authorize :audit_log, :index? - @auditable_accounts = Account.where(id: Admin::ActionLog.select('distinct account_id')).select(:id, :username) + @auditable_accounts = Account.auditable.select(:id, :username) end private diff --git a/app/controllers/admin/confirmations_controller.rb b/app/controllers/admin/confirmations_controller.rb index 6f4e426797..7ccf5c9012 100644 --- a/app/controllers/admin/confirmations_controller.rb +++ b/app/controllers/admin/confirmations_controller.rb @@ -7,7 +7,7 @@ module Admin def create authorize @user, :confirm? - @user.confirm! + @user.mark_email_as_confirmed! log_action :confirm, @user redirect_to admin_accounts_path end diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb index 21b1095f18..f60181f1eb 100644 --- a/app/controllers/api/v1/accounts/follower_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/follower_accounts_controller.rb @@ -21,7 +21,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController return [] if hide_results? scope = default_accounts - scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil? || current_account.id == @account.id + scope = scope.not_excluded_by_account(current_account) unless current_account.nil? || current_account.id == @account.id scope.merge(paginated_follows).to_a end @@ -30,7 +30,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController end def default_accounts - Account.includes(:active_relationships, :account_stat).references(:active_relationships) + Account.includes(:active_relationships, :account_stat, :user).references(:active_relationships) end def paginated_follows diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb index 1db521f79c..3ab8c1efd6 100644 --- a/app/controllers/api/v1/accounts/following_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/following_accounts_controller.rb @@ -21,7 +21,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController return [] if hide_results? scope = default_accounts - scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil? || current_account.id == @account.id + scope = scope.not_excluded_by_account(current_account) unless current_account.nil? || current_account.id == @account.id scope.merge(paginated_follows).to_a end @@ -30,7 +30,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController end def default_accounts - Account.includes(:passive_relationships, :account_stat).references(:passive_relationships) + Account.includes(:passive_relationships, :account_stat, :user).references(:passive_relationships) end def paginated_follows diff --git a/app/controllers/api/v1/annual_reports_controller.rb b/app/controllers/api/v1/annual_reports_controller.rb new file mode 100644 index 0000000000..9bc8e68ac2 --- /dev/null +++ b/app/controllers/api/v1/annual_reports_controller.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class Api::V1::AnnualReportsController < Api::BaseController + before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, only: :index + before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, except: :index + before_action :require_user! + before_action :set_annual_report, except: :index + + def index + with_read_replica do + @presenter = AnnualReportsPresenter.new(GeneratedAnnualReport.where(account_id: current_account.id).pending) + @relationships = StatusRelationshipsPresenter.new(@presenter.statuses, current_account.id) + end + + render json: @presenter, + serializer: REST::AnnualReportsSerializer, + relationships: @relationships + end + + def read + @annual_report.view! + render_empty + end + + private + + def set_annual_report + @annual_report = GeneratedAnnualReport.find_by!(account_id: current_account.id, year: params[:id]) + end +end diff --git a/app/controllers/api/v1/blocks_controller.rb b/app/controllers/api/v1/blocks_controller.rb index 06a8bfa891..0934622f88 100644 --- a/app/controllers/api/v1/blocks_controller.rb +++ b/app/controllers/api/v1/blocks_controller.rb @@ -17,7 +17,7 @@ class Api::V1::BlocksController < Api::BaseController end def paginated_blocks - @paginated_blocks ||= Block.eager_load(target_account: :account_stat) + @paginated_blocks ||= Block.eager_load(target_account: [:account_stat, :user]) .joins(:target_account) .merge(Account.without_suspended) .where(account: current_account) diff --git a/app/controllers/api/v1/directories_controller.rb b/app/controllers/api/v1/directories_controller.rb index e79b20ce42..6c540404ea 100644 --- a/app/controllers/api/v1/directories_controller.rb +++ b/app/controllers/api/v1/directories_controller.rb @@ -27,7 +27,7 @@ class Api::V1::DirectoriesController < Api::BaseController scope.merge!(local_account_scope) if local_accounts? scope.merge!(account_exclusion_scope) if current_account scope.merge!(account_domain_block_scope) if current_account && !local_accounts? - end + end.includes(:account_stat, user: :role) end def local_accounts? diff --git a/app/controllers/api/v1/endorsements_controller.rb b/app/controllers/api/v1/endorsements_controller.rb index 46e3fcd647..2216a9860d 100644 --- a/app/controllers/api/v1/endorsements_controller.rb +++ b/app/controllers/api/v1/endorsements_controller.rb @@ -25,7 +25,7 @@ class Api::V1::EndorsementsController < Api::BaseController end def endorsed_accounts - current_account.endorsed_accounts.includes(:account_stat).without_suspended + current_account.endorsed_accounts.includes(:account_stat, :user).without_suspended end def insert_pagination_headers diff --git a/app/controllers/api/v1/follow_requests_controller.rb b/app/controllers/api/v1/follow_requests_controller.rb index ee717ebbcc..87f6df5f94 100644 --- a/app/controllers/api/v1/follow_requests_controller.rb +++ b/app/controllers/api/v1/follow_requests_controller.rb @@ -37,7 +37,7 @@ class Api::V1::FollowRequestsController < Api::BaseController end def default_accounts - Account.without_suspended.includes(:follow_requests, :account_stat).references(:follow_requests) + Account.without_suspended.includes(:follow_requests, :account_stat, :user).references(:follow_requests) end def paginated_follow_requests diff --git a/app/controllers/api/v1/lists/accounts_controller.rb b/app/controllers/api/v1/lists/accounts_controller.rb index 8e12cb7b65..0604ad60fc 100644 --- a/app/controllers/api/v1/lists/accounts_controller.rb +++ b/app/controllers/api/v1/lists/accounts_controller.rb @@ -37,9 +37,9 @@ class Api::V1::Lists::AccountsController < Api::BaseController def load_accounts if unlimited? - @list.accounts.without_suspended.includes(:account_stat).all + @list.accounts.without_suspended.includes(:account_stat, :user).all else - @list.accounts.without_suspended.includes(:account_stat).paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id]) + @list.accounts.without_suspended.includes(:account_stat, :user).paginate_by_max_id(limit_param(DEFAULT_ACCOUNTS_LIMIT), params[:max_id], params[:since_id]) end end diff --git a/app/controllers/api/v1/markers_controller.rb b/app/controllers/api/v1/markers_controller.rb index f8dfba8a94..8eaf7767df 100644 --- a/app/controllers/api/v1/markers_controller.rb +++ b/app/controllers/api/v1/markers_controller.rb @@ -19,7 +19,7 @@ class Api::V1::MarkersController < Api::BaseController @markers = {} resource_params.each_pair do |timeline, timeline_params| - @markers[timeline] = current_user.markers.find_or_initialize_by(timeline: timeline) + @markers[timeline] = current_user.markers.find_or_create_by(timeline: timeline) @markers[timeline].update!(timeline_params) end end diff --git a/app/controllers/api/v1/mutes_controller.rb b/app/controllers/api/v1/mutes_controller.rb index 555485823c..2fb685ac39 100644 --- a/app/controllers/api/v1/mutes_controller.rb +++ b/app/controllers/api/v1/mutes_controller.rb @@ -17,7 +17,7 @@ class Api::V1::MutesController < Api::BaseController end def paginated_mutes - @paginated_mutes ||= Mute.eager_load(:target_account) + @paginated_mutes ||= Mute.eager_load(target_account: [:account_stat, :user]) .joins(:target_account) .merge(Account.without_suspended) .where(account: current_account) diff --git a/app/controllers/api/v1/peers/search_controller.rb b/app/controllers/api/v1/peers/search_controller.rb index 0c503d9bc5..1780554c5d 100644 --- a/app/controllers/api/v1/peers/search_controller.rb +++ b/app/controllers/api/v1/peers/search_controller.rb @@ -27,7 +27,7 @@ class Api::V1::Peers::SearchController < Api::BaseController @domains = InstancesIndex.query(function_score: { query: { prefix: { - domain: TagManager.instance.normalize_domain(params[:q].strip), + domain: normalized_domain, }, }, @@ -37,11 +37,18 @@ class Api::V1::Peers::SearchController < Api::BaseController }, }).limit(10).pluck(:domain) else - domain = params[:q].strip - domain = TagManager.instance.normalize_domain(domain) - @domains = Instance.searchable.where(Instance.arel_table[:domain].matches("#{Instance.sanitize_sql_like(domain)}%", false, true)).limit(10).pluck(:domain) + domain = normalized_domain + @domains = Instance.searchable.domain_starts_with(domain).limit(10).pluck(:domain) end rescue Addressable::URI::InvalidURIError @domains = [] end + + def normalized_domain + TagManager.instance.normalize_domain(query_value) + end + + def query_value + params[:q].strip + end end diff --git a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb index 3cca246ce8..069ad37cb2 100644 --- a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb +++ b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb @@ -14,14 +14,14 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::V1::Statuses::Bas def load_accounts scope = default_accounts - scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil? + scope = scope.not_excluded_by_account(current_account) unless current_account.nil? scope.merge(paginated_favourites).to_a end def default_accounts Account .without_suspended - .includes(:favourites, :account_stat) + .includes(:favourites, :account_stat, :user) .references(:favourites) .where(favourites: { status_id: @status.id }) end diff --git a/app/controllers/api/v1/statuses/reactions_controller.rb b/app/controllers/api/v1/statuses/reactions_controller.rb index 1d8382f833..c4b0fa307f 100644 --- a/app/controllers/api/v1/statuses/reactions_controller.rb +++ b/app/controllers/api/v1/statuses/reactions_controller.rb @@ -1,38 +1,19 @@ # frozen_string_literal: true -class Api::V1::Statuses::ReactionsController < Api::BaseController - include Authorization - +class Api::V1::Statuses::ReactionsController < Api::V1::Statuses::BaseController before_action -> { doorkeeper_authorize! :write, :'write:favourites' } before_action :require_user! - before_action :set_status def create - ReactService.new.call(current_account, @status, normalize(params[:id])) + ReactService.new.call(current_account, @status, params[:id]) render json: @status, serializer: REST::StatusSerializer end def destroy - UnreactWorker.perform_async(current_account.id, @status.id, normalize(params[:id])) + UnreactWorker.perform_async(current_account.id, @status.id, params[:id]) render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, reactions_map: { @status.id => false }) rescue Mastodon::NotPermittedError not_found end - - private - - def normalize(name) - normalized = "#{name}\uFE0F" - return normalized if StatusReactionValidator::SUPPORTED_EMOJIS.include?(normalized) - - name - end - - def set_status - @status = Status.find(params[:status_id]) - authorize @status, :show? - rescue Mastodon::NotPermittedError - not_found - end end diff --git a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb index dd3e60846b..b8a997518d 100644 --- a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb +++ b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb @@ -14,12 +14,12 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::V1::Statuses::Base def load_accounts scope = default_accounts - scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil? + scope = scope.not_excluded_by_account(current_account) unless current_account.nil? scope.merge(paginated_statuses).to_a end def default_accounts - Account.without_suspended.includes(:statuses, :account_stat).references(:statuses) + Account.without_suspended.includes(:statuses, :account_stat, :user).references(:statuses) end def paginated_statuses diff --git a/app/controllers/api/v2/filters_controller.rb b/app/controllers/api/v2/filters_controller.rb index 2fcdeeae45..09d4813f34 100644 --- a/app/controllers/api/v2/filters_controller.rb +++ b/app/controllers/api/v2/filters_controller.rb @@ -35,7 +35,7 @@ class Api::V2::FiltersController < Api::BaseController private def set_filters - @filters = current_account.custom_filters.includes(:keywords) + @filters = current_account.custom_filters.includes(:keywords, :statuses) end def set_filter diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb index 1c773511b4..41c8562363 100644 --- a/app/controllers/auth/sessions_controller.rb +++ b/app/controllers/auth/sessions_controller.rb @@ -1,6 +1,10 @@ # frozen_string_literal: true class Auth::SessionsController < Devise::SessionsController + include Redisable + + MAX_2FA_ATTEMPTS_PER_HOUR = 10 + layout 'auth' skip_before_action :check_self_destruct! @@ -135,9 +139,23 @@ class Auth::SessionsController < Devise::SessionsController session.delete(:attempt_user_updated_at) end + def clear_2fa_attempt_from_user(user) + redis.del(second_factor_attempts_key(user)) + end + + def check_second_factor_rate_limits(user) + attempts, = redis.multi do |multi| + multi.incr(second_factor_attempts_key(user)) + multi.expire(second_factor_attempts_key(user), 1.hour) + end + + attempts >= MAX_2FA_ATTEMPTS_PER_HOUR + end + def on_authentication_success(user, security_measure) @on_authentication_success_called = true + clear_2fa_attempt_from_user(user) clear_attempt_from_session user.update_sign_in!(new_sign_in: true) @@ -168,5 +186,14 @@ class Auth::SessionsController < Devise::SessionsController ip: request.remote_ip, user_agent: request.user_agent ) + + # Only send a notification email every hour at most + return if redis.set("2fa_failure_notification:#{user.id}", '1', ex: 1.hour, get: true).present? + + UserMailer.failed_2fa(user, request.remote_ip, request.user_agent, Time.now.utc).deliver_later! + end + + def second_factor_attempts_key(user) + "2fa_auth_attempts:#{user.id}:#{Time.now.utc.hour}" end end diff --git a/app/controllers/concerns/auth/two_factor_authentication_concern.rb b/app/controllers/concerns/auth/two_factor_authentication_concern.rb index ebd6a93441..edcdd2990f 100644 --- a/app/controllers/concerns/auth/two_factor_authentication_concern.rb +++ b/app/controllers/concerns/auth/two_factor_authentication_concern.rb @@ -66,6 +66,11 @@ module Auth::TwoFactorAuthenticationConcern end def authenticate_with_two_factor_via_otp(user) + if check_second_factor_rate_limits(user) + flash.now[:alert] = I18n.t('users.rate_limited') + return prompt_for_two_factor(user) + end + if valid_otp_attempt?(user) on_authentication_success(user, :otp) else diff --git a/app/controllers/custom_css_controller.rb b/app/controllers/custom_css_controller.rb index e7a02ea89c..62f8e0d772 100644 --- a/app/controllers/custom_css_controller.rb +++ b/app/controllers/custom_css_controller.rb @@ -1,8 +1,21 @@ # frozen_string_literal: true class CustomCssController < ActionController::Base # rubocop:disable Rails/ApplicationController + before_action :set_user_roles + def show expires_in 3.minutes, public: true render content_type: 'text/css' end + + private + + def custom_css_styles + Setting.custom_css + end + helper_method :custom_css_styles + + def set_user_roles + @user_roles = UserRole.where(highlighted: true).where.not(color: [nil, '']) + end end diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb index b8277ee17e..110a53e4e1 100644 --- a/app/helpers/accounts_helper.rb +++ b/app/helpers/accounts_helper.rb @@ -31,22 +31,26 @@ module AccountsHelper Setting.hide_followers_count || account.user&.settings&.[]('hide_followers_count') end + def account_formatted_stat(value) + number_to_human(value, precision: 3, strip_insignificant_zeros: true) + end + def account_description(account) prepend_stats = [ [ - number_to_human(account.statuses_count, precision: 3, strip_insignificant_zeros: true), + account_formatted_stat(account.statuses_count), I18n.t('accounts.posts', count: account.statuses_count), ].join(' '), [ - number_to_human(account.following_count, precision: 3, strip_insignificant_zeros: true), + account_formatted_stat(account.following_count), I18n.t('accounts.following', count: account.following_count), ].join(' '), ] unless hide_followers_count?(account) prepend_stats << [ - number_to_human(account.followers_count, precision: 3, strip_insignificant_zeros: true), + account_formatted_stat(account.followers_count), I18n.t('accounts.followers', count: account.followers_count), ].join(' ') end diff --git a/app/helpers/jsonld_helper.rb b/app/helpers/jsonld_helper.rb index ce3ff094f6..b3d0d032c4 100644 --- a/app/helpers/jsonld_helper.rb +++ b/app/helpers/jsonld_helper.rb @@ -155,7 +155,7 @@ module JsonLdHelper end end - def fetch_resource(uri, id, on_behalf_of = nil) + def fetch_resource(uri, id, on_behalf_of = nil, request_options: {}) unless id json = fetch_resource_without_id_validation(uri, on_behalf_of) @@ -164,14 +164,14 @@ module JsonLdHelper uri = json['id'] end - json = fetch_resource_without_id_validation(uri, on_behalf_of) + json = fetch_resource_without_id_validation(uri, on_behalf_of, request_options: request_options) json.present? && json['id'] == uri ? json : nil end - def fetch_resource_without_id_validation(uri, on_behalf_of = nil, raise_on_temporary_error = false) + def fetch_resource_without_id_validation(uri, on_behalf_of = nil, raise_on_temporary_error = false, request_options: {}) on_behalf_of ||= Account.representative - build_request(uri, on_behalf_of).perform do |response| + build_request(uri, on_behalf_of, options: request_options).perform do |response| raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) || !raise_on_temporary_error body_to_json(response.body_with_limit) if response.code == 200 @@ -204,8 +204,8 @@ module JsonLdHelper response.code == 501 || ((400...500).cover?(response.code) && ![401, 408, 429].include?(response.code)) end - def build_request(uri, on_behalf_of = nil) - Request.new(:get, uri).tap do |request| + def build_request(uri, on_behalf_of = nil, options: {}) + Request.new(:get, uri, **options).tap do |request| request.on_behalf_of(on_behalf_of) if on_behalf_of request.add_headers('Accept' => 'application/activity+json, application/ld+json') end diff --git a/app/helpers/mascot_helper.rb b/app/helpers/mascot_helper.rb index 8ee04383ec..34b656411e 100644 --- a/app/helpers/mascot_helper.rb +++ b/app/helpers/mascot_helper.rb @@ -2,7 +2,7 @@ module MascotHelper def mascot_url - full_asset_url(instance_presenter.mascot&.file&.url || asset_pack_path('media/images/elephant_ui_plane.svg')) + full_asset_url(instance_presenter.mascot&.file&.url || frontend_asset_path('images/elephant_ui_plane.svg')) end def instance_presenter diff --git a/app/helpers/routing_helper.rb b/app/helpers/routing_helper.rb index 2fb9ce72cb..15d988f64d 100644 --- a/app/helpers/routing_helper.rb +++ b/app/helpers/routing_helper.rb @@ -24,8 +24,12 @@ module RoutingHelper Rails.configuration.action_controller.asset_host || root_url end - def full_pack_url(source, **options) - full_asset_url(asset_pack_path(source, **options)) + def frontend_asset_path(source, **options) + asset_pack_path("media/#{source}", **options) + end + + def frontend_asset_url(source, **options) + full_asset_url(frontend_asset_path(source, **options)) end def use_storage? diff --git a/app/javascript/__mocks__/svg.js b/app/javascript/__mocks__/svg.js index e725dc2da6..762bc165d0 100644 --- a/app/javascript/__mocks__/svg.js +++ b/app/javascript/__mocks__/svg.js @@ -1,3 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export -export default 'SvgrURL'; -export const ReactComponent = 'div'; +const ReactComponent = 'div'; + +export default ReactComponent; diff --git a/app/javascript/core/inert.js b/app/javascript/core/inert.js new file mode 100644 index 0000000000..7c04a97faf --- /dev/null +++ b/app/javascript/core/inert.js @@ -0,0 +1,4 @@ +/* Placeholder file to have `inert.scss` compiled by Webpack + This is used by the `wicg-inert` polyfill */ + +import '../styles/inert.scss'; diff --git a/app/javascript/core/theme.yml b/app/javascript/core/theme.yml index 1b2bfb98f1..f6f653c0a9 100644 --- a/app/javascript/core/theme.yml +++ b/app/javascript/core/theme.yml @@ -10,6 +10,9 @@ pack: embed: embed.js error: home: + inert: + filename: inert.js + stylesheet: true mailer: filename: mailer.js stylesheet: true diff --git a/app/javascript/flavours/glitch/actions/search.js b/app/javascript/flavours/glitch/actions/search.js index 5bb3aa3a79..7e54740d52 100644 --- a/app/javascript/flavours/glitch/actions/search.js +++ b/app/javascript/flavours/glitch/actions/search.js @@ -170,6 +170,11 @@ export const openURL = routerHistory => (dispatch, getState) => { export const clickSearchResult = (q, type) => (dispatch, getState) => { const previous = getState().getIn(['search', 'recent']); + + if (previous.some(x => x.get('q') === q && x.get('type') === type)) { + return; + } + const me = getState().getIn(['meta', 'me']); const current = previous.add(fromJS({ type, q })).takeLast(4); @@ -198,4 +203,4 @@ export const hydrateSearch = () => (dispatch, getState) => { if (history !== null) { dispatch(updateSearchHistory(history)); } -}; \ No newline at end of file +}; diff --git a/app/javascript/flavours/glitch/components/attachment_list.jsx b/app/javascript/flavours/glitch/components/attachment_list.jsx index e7b259b200..44b8bf78ee 100644 --- a/app/javascript/flavours/glitch/components/attachment_list.jsx +++ b/app/javascript/flavours/glitch/components/attachment_list.jsx @@ -7,10 +7,10 @@ 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 LinkIcon from '@/material-icons/400-24px/link.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + const filename = url => url.split('/').pop().split('#')[0].split('?')[0]; export default class AttachmentList extends ImmutablePureComponent { diff --git a/app/javascript/flavours/glitch/components/badge.jsx b/app/javascript/flavours/glitch/components/badge.jsx index cf225a6a0c..646655c249 100644 --- a/app/javascript/flavours/glitch/components/badge.jsx +++ b/app/javascript/flavours/glitch/components/badge.jsx @@ -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 GroupsIcon from '@/material-icons/400-24px/group.svg?react'; +import PersonIcon from '@/material-icons/400-24px/person.svg?react'; +import SmartToyIcon from '@/material-icons/400-24px/smart_toy.svg?react'; export const Badge = ({ icon, label, domain }) => ( diff --git a/app/javascript/flavours/glitch/components/column_back_button.tsx b/app/javascript/flavours/glitch/components/column_back_button.tsx index 9f90f1dddc..75c594c20a 100644 --- a/app/javascript/flavours/glitch/components/column_back_button.tsx +++ b/app/javascript/flavours/glitch/components/column_back_button.tsx @@ -2,8 +2,7 @@ import { useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; -import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg'; - +import ArrowBackIcon from '@/material-icons/400-24px/arrow_back.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { ButtonInTabsBar } from 'flavours/glitch/features/ui/util/columns_context'; diff --git a/app/javascript/flavours/glitch/components/column_header.jsx b/app/javascript/flavours/glitch/components/column_header.jsx index 8cc9fde9d3..ec99698d0c 100644 --- a/app/javascript/flavours/glitch/components/column_header.jsx +++ b/app/javascript/flavours/glitch/components/column_header.jsx @@ -6,17 +6,17 @@ 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 AddIcon from '@/material-icons/400-24px/add.svg?react'; +import ArrowBackIcon from '@/material-icons/400-24px/arrow_back.svg?react'; +import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react'; +import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import TuneIcon from '@/material-icons/400-24px/tune.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { ButtonInTabsBar, useColumnsContext } from 'flavours/glitch/features/ui/util/columns_context'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; + import { useAppHistory } from './router'; const messages = defineMessages({ diff --git a/app/javascript/flavours/glitch/components/dismissable_banner.tsx b/app/javascript/flavours/glitch/components/dismissable_banner.tsx index 2edc4e8e66..650befb349 100644 --- a/app/javascript/flavours/glitch/components/dismissable_banner.tsx +++ b/app/javascript/flavours/glitch/components/dismissable_banner.tsx @@ -8,8 +8,7 @@ import { useCallback, useState, useEffect } from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg'; - +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { changeSetting } from 'flavours/glitch/actions/settings'; import { bannerSettings } from 'flavours/glitch/settings'; import { useAppSelector, useAppDispatch } from 'flavours/glitch/store'; diff --git a/app/javascript/flavours/glitch/components/domain.tsx b/app/javascript/flavours/glitch/components/domain.tsx index 34c376f530..ed5e8e7e4c 100644 --- a/app/javascript/flavours/glitch/components/domain.tsx +++ b/app/javascript/flavours/glitch/components/domain.tsx @@ -2,7 +2,7 @@ import { useCallback } from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { ReactComponent as LockOpenIcon } from '@material-symbols/svg-600/outlined/lock_open.svg'; +import LockOpenIcon from '@/material-icons/400-24px/lock_open.svg?react'; import { IconButton } from './icon_button'; diff --git a/app/javascript/flavours/glitch/components/dropdown_menu.jsx b/app/javascript/flavours/glitch/components/dropdown_menu.jsx index f00961dcad..bfaa53f6e5 100644 --- a/app/javascript/flavours/glitch/components/dropdown_menu.jsx +++ b/app/javascript/flavours/glitch/components/dropdown_menu.jsx @@ -6,10 +6,10 @@ 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'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { CircularProgress } from 'flavours/glitch/components/circular_progress'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; diff --git a/app/javascript/flavours/glitch/components/edited_timestamp/index.jsx b/app/javascript/flavours/glitch/components/edited_timestamp/index.jsx index f7186e1325..29a418dfb1 100644 --- a/app/javascript/flavours/glitch/components/edited_timestamp/index.jsx +++ b/app/javascript/flavours/glitch/components/edited_timestamp/index.jsx @@ -5,8 +5,8 @@ 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 ArrowDropDownIcon from '@/material-icons/400-24px/arrow_drop_down.svg?react'; import { openModal } from 'flavours/glitch/actions/modal'; import { Icon } from 'flavours/glitch/components/icon'; import InlineAccount from 'flavours/glitch/components/inline_account'; diff --git a/app/javascript/flavours/glitch/components/icon.tsx b/app/javascript/flavours/glitch/components/icon.tsx index 1784eaf38f..052833fedd 100644 --- a/app/javascript/flavours/glitch/components/icon.tsx +++ b/app/javascript/flavours/glitch/components/icon.tsx @@ -1,7 +1,6 @@ import classNames from 'classnames'; -import { ReactComponent as CheckBoxOutlineBlankIcon } from '@material-symbols/svg-600/outlined/check_box_outline_blank.svg'; - +import CheckBoxOutlineBlankIcon from '@/material-icons/400-24px/check_box_outline_blank.svg?react'; import { isProduction } from 'flavours/glitch/utils/environment'; interface SVGPropsWithTitle extends React.SVGProps { diff --git a/app/javascript/flavours/glitch/components/load_gap.tsx b/app/javascript/flavours/glitch/components/load_gap.tsx index 14ad26f8c7..f0d15d3776 100644 --- a/app/javascript/flavours/glitch/components/load_gap.tsx +++ b/app/javascript/flavours/glitch/components/load_gap.tsx @@ -2,8 +2,7 @@ import { useCallback } from 'react'; import { useIntl, defineMessages } from 'react-intl'; -import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg'; - +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; const messages = defineMessages({ diff --git a/app/javascript/flavours/glitch/components/logo.jsx b/app/javascript/flavours/glitch/components/logo.jsx index 16ca9f80fd..73a94af9ed 100644 --- a/app/javascript/flavours/glitch/components/logo.jsx +++ b/app/javascript/flavours/glitch/components/logo.jsx @@ -1,4 +1,4 @@ -import logo from 'mastodon/../images/logo.svg'; +import logo from '@/images/logo.svg'; export const WordmarkLogo = () => ( diff --git a/app/javascript/flavours/glitch/components/media_gallery.jsx b/app/javascript/flavours/glitch/components/media_gallery.jsx index 575851543a..9db2a43009 100644 --- a/app/javascript/flavours/glitch/components/media_gallery.jsx +++ b/app/javascript/flavours/glitch/components/media_gallery.jsx @@ -8,9 +8,9 @@ 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 VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; import { Blurhash } from 'flavours/glitch/components/blurhash'; import { autoPlayGif, displayMedia, useBlurhash } from '../initial_state'; @@ -123,7 +123,7 @@ class Item extends PureComponent { } if (attachment.get('description')?.length > 0) { - badges.push(ALT); + badges.push(ALT); } const description = attachment.getIn(['translation', 'description']) || attachment.get('description'); diff --git a/app/javascript/flavours/glitch/components/notification_purge_buttons.jsx b/app/javascript/flavours/glitch/components/notification_purge_buttons.jsx index ddbfb1d44a..b171738322 100644 --- a/app/javascript/flavours/glitch/components/notification_purge_buttons.jsx +++ b/app/javascript/flavours/glitch/components/notification_purge_buttons.jsx @@ -12,10 +12,10 @@ import classNames from 'classnames'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { ReactComponent as DeleteIcon } from '@material-symbols/svg-600/outlined/delete.svg'; - +import DeleteIcon from '@/material-icons/400-24px/delete.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + const messages = defineMessages({ btnAll : { id: 'notification_purge.btn_all', defaultMessage: 'Select\nall' }, btnNone : { id: 'notification_purge.btn_none', defaultMessage: 'Select\nnone' }, diff --git a/app/javascript/flavours/glitch/components/picture_in_picture_placeholder.jsx b/app/javascript/flavours/glitch/components/picture_in_picture_placeholder.jsx index 685f3c2738..10a0a7f5bb 100644 --- a/app/javascript/flavours/glitch/components/picture_in_picture_placeholder.jsx +++ b/app/javascript/flavours/glitch/components/picture_in_picture_placeholder.jsx @@ -5,8 +5,8 @@ import { FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; -import { ReactComponent as CancelPresentationIcon } from '@material-symbols/svg-600/outlined/cancel_presentation.svg'; +import CancelPresentationIcon from '@/material-icons/400-24px/cancel_presentation.svg?react'; import { removePictureInPicture } from 'flavours/glitch/actions/picture_in_picture'; import { Icon } from 'flavours/glitch/components/icon'; diff --git a/app/javascript/flavours/glitch/components/poll.jsx b/app/javascript/flavours/glitch/components/poll.jsx index 4fcd56a0f3..f9e008bd72 100644 --- a/app/javascript/flavours/glitch/components/poll.jsx +++ b/app/javascript/flavours/glitch/components/poll.jsx @@ -7,10 +7,10 @@ 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'; +import CheckIcon from '@/material-icons/400-24px/check.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import emojify from 'flavours/glitch/features/emoji/emoji'; import Motion from 'flavours/glitch/features/ui/util/optional_motion'; diff --git a/app/javascript/flavours/glitch/components/status_action_bar.jsx b/app/javascript/flavours/glitch/components/status_action_bar.jsx index 7fe62c79f1..9860b7c7a2 100644 --- a/app/javascript/flavours/glitch/components/status_action_bar.jsx +++ b/app/javascript/flavours/glitch/components/status_action_bar.jsx @@ -8,22 +8,21 @@ import { withRouter } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { ReactComponent as AddReactionIcon } from '@material-symbols/svg-600/outlined/add_reaction.svg'; -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 AddReactionIcon from '@/material-icons/400-24px/add_reaction.svg?react'; +import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg?react'; +import BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; +import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; +import StarBorderIcon from '@/material-icons/400-24px/star.svg?react'; +import VisibilityIcon from '@/material-icons/400-24px/visibility.svg?react'; +import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg'; +import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions'; import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; -import { ReactComponent as RepeatDisabledIcon } from 'mastodon/../svg-icons/repeat_disabled.svg'; -import { ReactComponent as RepeatPrivateIcon } from 'mastodon/../svg-icons/repeat_private.svg'; import DropdownMenuContainer from '../containers/dropdown_menu_container'; import EmojiPickerDropdown from '../features/compose/containers/emoji_picker_dropdown_container'; diff --git a/app/javascript/flavours/glitch/components/status_content.jsx b/app/javascript/flavours/glitch/components/status_content.jsx index ee6c33d713..b351ea657d 100644 --- a/app/javascript/flavours/glitch/components/status_content.jsx +++ b/app/javascript/flavours/glitch/components/status_content.jsx @@ -9,16 +9,16 @@ import { withRouter } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { connect } from 'react-redux'; -import { ReactComponent as ImageIcon } from '@material-symbols/svg-600/outlined/image.svg'; -import { ReactComponent as InsertChartIcon } from '@material-symbols/svg-600/outlined/insert_chart.svg'; -import { ReactComponent as LinkIcon } from '@material-symbols/svg-600/outlined/link.svg'; -import { ReactComponent as MovieIcon } from '@material-symbols/svg-600/outlined/movie.svg'; -import { ReactComponent as MusicNoteIcon } from '@material-symbols/svg-600/outlined/music_note.svg'; - +import ImageIcon from '@/material-icons/400-24px/image.svg?react'; +import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react'; +import LinkIcon from '@/material-icons/400-24px/link.svg?react'; +import MovieIcon from '@/material-icons/400-24px/movie.svg?react'; +import MusicNoteIcon from '@/material-icons/400-24px/music_note.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { autoPlayGif, languages as preloadedLanguages } from 'flavours/glitch/initial_state'; import { decode as decodeIDNA } from 'flavours/glitch/utils/idna'; + import { Permalink } from './permalink'; const textMatchesTarget = (text, origin, host) => { diff --git a/app/javascript/flavours/glitch/components/status_icons.jsx b/app/javascript/flavours/glitch/components/status_icons.jsx index 5e7aa6e638..2727d3410a 100644 --- a/app/javascript/flavours/glitch/components/status_icons.jsx +++ b/app/javascript/flavours/glitch/components/status_icons.jsx @@ -6,18 +6,18 @@ import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { ReactComponent as ExpandLessIcon } from '@material-symbols/svg-600/outlined/expand_less.svg'; -import { ReactComponent as ForumIcon } from '@material-symbols/svg-600/outlined/forum.svg'; -import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home.svg'; -import { ReactComponent as ImageIcon } from '@material-symbols/svg-600/outlined/image.svg'; -import { ReactComponent as InsertChartIcon } from '@material-symbols/svg-600/outlined/insert_chart.svg'; -import { ReactComponent as LinkIcon } from '@material-symbols/svg-600/outlined/link.svg'; -import { ReactComponent as MovieIcon } from '@material-symbols/svg-600/outlined/movie.svg'; -import { ReactComponent as MusicNoteIcon } from '@material-symbols/svg-600/outlined/music_note.svg'; - +import ExpandLessIcon from '@/material-icons/400-24px/expand_less.svg?react'; +import ForumIcon from '@/material-icons/400-24px/forum.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home.svg?react'; +import ImageIcon from '@/material-icons/400-24px/image.svg?react'; +import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react'; +import LinkIcon from '@/material-icons/400-24px/link.svg?react'; +import MovieIcon from '@/material-icons/400-24px/movie.svg?react'; +import MusicNoteIcon from '@/material-icons/400-24px/music_note.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { languages } from 'flavours/glitch/initial_state'; + import { IconButton } from './icon_button'; import { VisibilityIcon } from './visibility_icon'; diff --git a/app/javascript/flavours/glitch/components/status_prepend.jsx b/app/javascript/flavours/glitch/components/status_prepend.jsx index 8362b6ead7..ee5454ef7c 100644 --- a/app/javascript/flavours/glitch/components/status_prepend.jsx +++ b/app/javascript/flavours/glitch/components/status_prepend.jsx @@ -6,14 +6,13 @@ import { FormattedMessage } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { ReactComponent as AddReactionIcon } from '@material-symbols/svg-600/outlined/add_reaction.svg'; -import { ReactComponent as EditIcon } from '@material-symbols/svg-600/outlined/edit.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 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 StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg'; - +import AddReactionIcon from '@/material-icons/400-24px/add_reaction.svg?react'; +import EditIcon from '@/material-icons/400-24px/edit.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; +import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react'; +import PushPinIcon from '@/material-icons/400-24px/push_pin.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { me } from 'flavours/glitch/initial_state'; diff --git a/app/javascript/flavours/glitch/components/verified_badge.tsx b/app/javascript/flavours/glitch/components/verified_badge.tsx index e96bf82563..626cc500d6 100644 --- a/app/javascript/flavours/glitch/components/verified_badge.tsx +++ b/app/javascript/flavours/glitch/components/verified_badge.tsx @@ -1,4 +1,4 @@ -import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg'; +import CheckIcon from '@/material-icons/400-24px/check.svg?react'; import { Icon } from './icon'; diff --git a/app/javascript/flavours/glitch/components/visibility_icon.tsx b/app/javascript/flavours/glitch/components/visibility_icon.tsx index 3a8a54d173..baf134c0ae 100644 --- a/app/javascript/flavours/glitch/components/visibility_icon.tsx +++ b/app/javascript/flavours/glitch/components/visibility_icon.tsx @@ -1,9 +1,9 @@ import { defineMessages, useIntl } from 'react-intl'; -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 MailIcon } from '@material-symbols/svg-600/outlined/mail.svg'; -import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg'; +import LockIcon from '@/material-icons/400-24px/lock.svg?react'; +import LockOpenIcon from '@/material-icons/400-24px/lock_open.svg?react'; +import MailIcon from '@/material-icons/400-24px/mail.svg?react'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { Icon } from './icon'; diff --git a/app/javascript/flavours/glitch/features/about/index.jsx b/app/javascript/flavours/glitch/features/about/index.jsx index 9510f46f55..e5544c8a74 100644 --- a/app/javascript/flavours/glitch/features/about/index.jsx +++ b/app/javascript/flavours/glitch/features/about/index.jsx @@ -10,9 +10,9 @@ 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 ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; +import ExpandMoreIcon from '@/material-icons/400-24px/expand_more.svg?react'; import { fetchServer, fetchExtendedDescription, fetchDomainBlocks } from 'flavours/glitch/actions/server'; import Column from 'flavours/glitch/components/column'; import { Icon } from 'flavours/glitch/components/icon'; diff --git a/app/javascript/flavours/glitch/features/account/components/action_bar.jsx b/app/javascript/flavours/glitch/features/account/components/action_bar.jsx index 96a5ec2712..3fcf0440c0 100644 --- a/app/javascript/flavours/glitch/features/account/components/action_bar.jsx +++ b/app/javascript/flavours/glitch/features/account/components/action_bar.jsx @@ -6,10 +6,10 @@ import { NavLink } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { ReactComponent as InfoIcon } from '@material-symbols/svg-600/outlined/info.svg'; - +import InfoIcon from '@/material-icons/400-24px/info.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + class ActionBar extends PureComponent { static propTypes = { @@ -30,7 +30,8 @@ class ActionBar extends PureComponent { return (
- + @@ -44,14 +45,17 @@ class ActionBar extends PureComponent { if (account.get('acct') !== account.get('username')) { extraInfo = (
- - {' '} - - - + +
+ + {' '} + + + +
); } diff --git a/app/javascript/flavours/glitch/features/account/components/follow_request_note.jsx b/app/javascript/flavours/glitch/features/account/components/follow_request_note.jsx index da150ff8fb..37d1508528 100644 --- a/app/javascript/flavours/glitch/features/account/components/follow_request_note.jsx +++ b/app/javascript/flavours/glitch/features/account/components/follow_request_note.jsx @@ -3,11 +3,11 @@ 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 CheckIcon from '@/material-icons/400-24px/check.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + export default class FollowRequestNote extends ImmutablePureComponent { static propTypes = { diff --git a/app/javascript/flavours/glitch/features/account/components/header.jsx b/app/javascript/flavours/glitch/features/account/components/header.jsx index 8e96e84ba3..81ce989e99 100644 --- a/app/javascript/flavours/glitch/features/account/components/header.jsx +++ b/app/javascript/flavours/glitch/features/account/components/header.jsx @@ -9,12 +9,12 @@ import { 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 CheckIcon from '@/material-icons/400-24px/check.svg?react'; +import LockIcon from '@/material-icons/400-24px/lock.svg?react'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import NotificationsIcon from '@/material-icons/400-24px/notifications.svg?react'; +import NotificationsActiveIcon from '@/material-icons/400-24px/notifications_active-fill.svg?react'; import { Avatar } from 'flavours/glitch/components/avatar'; import { Badge, AutomatedBadge, GroupBadge } from 'flavours/glitch/components/badge'; import { Button } from 'flavours/glitch/components/button'; diff --git a/app/javascript/flavours/glitch/features/account/components/profile_column_header.jsx b/app/javascript/flavours/glitch/features/account/components/profile_column_header.jsx index b3b07f273f..0628773497 100644 --- a/app/javascript/flavours/glitch/features/account/components/profile_column_header.jsx +++ b/app/javascript/flavours/glitch/features/account/components/profile_column_header.jsx @@ -3,7 +3,7 @@ import { PureComponent } from 'react'; import { injectIntl, defineMessages } from 'react-intl'; -import { ReactComponent as PersonIcon } from '@material-symbols/svg-600/outlined/person.svg'; +import PersonIcon from '@/material-icons/400-24px/person.svg?react'; import ColumnHeader from '../../../components/column_header'; diff --git a/app/javascript/flavours/glitch/features/account_gallery/components/media_item.jsx b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.jsx index c16cd8ddd0..ebd156a4f9 100644 --- a/app/javascript/flavours/glitch/features/account_gallery/components/media_item.jsx +++ b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.jsx @@ -5,14 +5,14 @@ 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 AudiotrackIcon from '@/material-icons/400-24px/music_note.svg?react'; +import PlayArrowIcon from '@/material-icons/400-24px/play_arrow.svg?react'; +import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; import { Blurhash } from 'flavours/glitch/components/blurhash'; import { Icon } from 'flavours/glitch/components/icon'; import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/initial_state'; + export default class MediaItem extends ImmutablePureComponent { static propTypes = { diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.jsx b/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.jsx index 90048472a1..9ccf5bd17a 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.jsx +++ b/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.jsx @@ -5,8 +5,8 @@ import { withRouter } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { ReactComponent as TripIcon } from '@material-symbols/svg-600/outlined/trip.svg'; +import TripIcon from '@/material-icons/400-24px/trip.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; diff --git a/app/javascript/flavours/glitch/features/audio/index.jsx b/app/javascript/flavours/glitch/features/audio/index.jsx index 3e949dca42..dc9d76222d 100644 --- a/app/javascript/flavours/glitch/features/audio/index.jsx +++ b/app/javascript/flavours/glitch/features/audio/index.jsx @@ -7,17 +7,18 @@ 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 DownloadIcon from '@/material-icons/400-24px/download.svg?react'; +import PauseIcon from '@/material-icons/400-24px/pause.svg?react'; +import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react'; +import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; +import VolumeOffIcon from '@/material-icons/400-24px/volume_off-fill.svg?react'; +import VolumeUpIcon from '@/material-icons/400-24px/volume_up-fill.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { formatTime, getPointerPosition, fileNameFromURL } from 'flavours/glitch/features/video'; + import { Blurhash } from '../../components/blurhash'; import { displayMedia, useBlurhash } from '../../initial_state'; diff --git a/app/javascript/flavours/glitch/features/blocks/index.jsx b/app/javascript/flavours/glitch/features/blocks/index.jsx index 615e4c8be2..1a631d3d07 100644 --- a/app/javascript/flavours/glitch/features/blocks/index.jsx +++ b/app/javascript/flavours/glitch/features/blocks/index.jsx @@ -6,9 +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 BlockIcon from '@/material-icons/400-24px/block-fill.svg?react'; + import { fetchBlocks, expandBlocks } from '../../actions/blocks'; import { LoadingIndicator } from '../../components/loading_indicator'; import ScrollableList from '../../components/scrollable_list'; diff --git a/app/javascript/flavours/glitch/features/bookmarked_statuses/index.jsx b/app/javascript/flavours/glitch/features/bookmarked_statuses/index.jsx index 2dc0a3b9c9..81d2e79a12 100644 --- a/app/javascript/flavours/glitch/features/bookmarked_statuses/index.jsx +++ b/app/javascript/flavours/glitch/features/bookmarked_statuses/index.jsx @@ -8,9 +8,9 @@ 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 BookmarksIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react'; import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'flavours/glitch/actions/bookmarks'; import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import ColumnHeader from 'flavours/glitch/components/column_header'; diff --git a/app/javascript/flavours/glitch/features/community_timeline/index.jsx b/app/javascript/flavours/glitch/features/community_timeline/index.jsx index 8667f7d53d..e2b982aaf8 100644 --- a/app/javascript/flavours/glitch/features/community_timeline/index.jsx +++ b/app/javascript/flavours/glitch/features/community_timeline/index.jsx @@ -7,8 +7,8 @@ import { Helmet } from 'react-helmet'; import { connect } from 'react-redux'; -import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg'; +import PeopleIcon from '@/material-icons/400-24px/group.svg?react'; import { DismissableBanner } from 'flavours/glitch/components/dismissable_banner'; import { domain } from 'flavours/glitch/initial_state'; diff --git a/app/javascript/flavours/glitch/features/compose/components/action_bar.jsx b/app/javascript/flavours/glitch/features/compose/components/action_bar.jsx index 737bb6c622..de5d2369c3 100644 --- a/app/javascript/flavours/glitch/features/compose/components/action_bar.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/action_bar.jsx @@ -5,10 +5,10 @@ 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 MenuIcon from '@/material-icons/400-24px/menu.svg?react'; import { preferencesLink, profileLink } from 'flavours/glitch/utils/backend_links'; + import DropdownMenuContainer from '../../../containers/dropdown_menu_container'; const messages = defineMessages({ diff --git a/app/javascript/flavours/glitch/features/compose/components/header.jsx b/app/javascript/flavours/glitch/features/compose/components/header.jsx index 021fcb3bb2..bdcb51cd92 100644 --- a/app/javascript/flavours/glitch/features/compose/components/header.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/header.jsx @@ -7,18 +7,18 @@ import { Link } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -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 ManufacturingIcon } from '@material-symbols/svg-600/outlined/manufacturing.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 PeopleIcon from '@/material-icons/400-24px/group.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; +import LogoutIcon from '@/material-icons/400-24px/logout.svg?react'; +import ManufacturingIcon from '@/material-icons/400-24px/manufacturing.svg?react'; +import MenuIcon from '@/material-icons/400-24px/menu.svg?react'; +import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg?react'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { signOutLink } from 'flavours/glitch/utils/backend_links'; import { conditionalRender } from 'flavours/glitch/utils/react_helpers'; + const messages = defineMessages({ community: { defaultMessage: 'Local timeline', diff --git a/app/javascript/flavours/glitch/features/compose/components/options.jsx b/app/javascript/flavours/glitch/features/compose/components/options.jsx index cdcc0dc1e7..314b6e638f 100644 --- a/app/javascript/flavours/glitch/features/compose/components/options.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/options.jsx @@ -6,19 +6,20 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { ReactComponent as AttachFileIcon } from '@material-symbols/svg-600/outlined/attach_file.svg'; -import { ReactComponent as BrushIcon } from '@material-symbols/svg-600/outlined/brush.svg'; -import { ReactComponent as CodeIcon } from '@material-symbols/svg-600/outlined/code.svg'; -import { ReactComponent as DescriptionIcon } from '@material-symbols/svg-600/outlined/description.svg'; -import { ReactComponent as InsertChartIcon } from '@material-symbols/svg-600/outlined/insert_chart.svg'; -import { ReactComponent as MarkdownIcon } from '@material-symbols/svg-600/outlined/markdown.svg'; -import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg'; -import { ReactComponent as UploadFileIcon } from '@material-symbols/svg-600/outlined/upload_file.svg'; import Toggle from 'react-toggle'; +import AttachFileIcon from '@/material-icons/400-24px/attach_file.svg?react'; +import BrushIcon from '@/material-icons/400-24px/brush.svg?react'; +import CodeIcon from '@/material-icons/400-24px/code.svg?react'; +import DescriptionIcon from '@/material-icons/400-24px/description.svg?react'; +import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react'; +import MarkdownIcon from '@/material-icons/400-24px/markdown.svg?react'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import UploadFileIcon from '@/material-icons/400-24px/upload_file.svg?react'; import { IconButton } from 'flavours/glitch/components/icon_button'; import { pollLimits } from 'flavours/glitch/initial_state'; + import DropdownContainer from '../containers/dropdown_container'; import LanguageDropdown from '../containers/language_dropdown_container'; import PrivacyDropdownContainer from '../containers/privacy_dropdown_container'; diff --git a/app/javascript/flavours/glitch/features/compose/components/poll_form.jsx b/app/javascript/flavours/glitch/features/compose/components/poll_form.jsx index e8c22fbd0e..053b02673d 100644 --- a/app/javascript/flavours/glitch/features/compose/components/poll_form.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/poll_form.jsx @@ -8,9 +8,9 @@ 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 AddIcon from '@/material-icons/400-24px/add.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import AutosuggestInput from 'flavours/glitch/components/autosuggest_input'; import { Icon } from 'flavours/glitch/components/icon'; import { IconButton } from 'flavours/glitch/components/icon_button'; diff --git a/app/javascript/flavours/glitch/features/compose/components/privacy_dropdown.jsx b/app/javascript/flavours/glitch/features/compose/components/privacy_dropdown.jsx index c0bc4bf85e..7980c1007e 100644 --- a/app/javascript/flavours/glitch/features/compose/components/privacy_dropdown.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/privacy_dropdown.jsx @@ -3,10 +3,10 @@ import { PureComponent } from 'react'; import { injectIntl, defineMessages } from 'react-intl'; -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 MailIcon } from '@material-symbols/svg-600/outlined/mail.svg'; -import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg'; +import LockIcon from '@/material-icons/400-24px/lock.svg?react'; +import LockOpenIcon from '@/material-icons/400-24px/lock_open.svg?react'; +import MailIcon from '@/material-icons/400-24px/mail.svg?react'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import Dropdown from './dropdown'; diff --git a/app/javascript/flavours/glitch/features/compose/components/publisher.jsx b/app/javascript/flavours/glitch/features/compose/components/publisher.jsx index b8d81b7f96..ff825ca0c9 100644 --- a/app/javascript/flavours/glitch/features/compose/components/publisher.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/publisher.jsx @@ -4,14 +4,14 @@ import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; -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 MailIcon } from '@material-symbols/svg-600/outlined/mail.svg'; -import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg'; - +import LockIcon from '@/material-icons/400-24px/lock.svg?react'; +import LockOpenIcon from '@/material-icons/400-24px/lock_open.svg?react'; +import MailIcon from '@/material-icons/400-24px/mail.svg?react'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { Button } from 'flavours/glitch/components/button'; import { Icon } from 'flavours/glitch/components/icon'; + const messages = defineMessages({ publish: { defaultMessage: 'Publish', diff --git a/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx b/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx index 48ded3dcd4..8af8cd441a 100644 --- a/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx @@ -5,8 +5,8 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import AttachmentList from 'flavours/glitch/components/attachment_list'; import { WithOptionalRouterPropTypes, withOptionalRouter } from 'flavours/glitch/utils/react_router'; diff --git a/app/javascript/flavours/glitch/features/compose/components/search.jsx b/app/javascript/flavours/glitch/features/compose/components/search.jsx index ccd56af365..fa995663f0 100644 --- a/app/javascript/flavours/glitch/features/compose/components/search.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/search.jsx @@ -8,10 +8,10 @@ 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 CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import SearchIcon from '@/material-icons/400-24px/search.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { domain, searchEnabled } from 'flavours/glitch/initial_state'; import { HASHTAG_REGEX } from 'flavours/glitch/utils/hashtags'; @@ -63,14 +63,14 @@ class Search extends PureComponent { }; defaultOptions = [ - { label: <>has: , action: e => { e.preventDefault(); this._insertText('has:'); } }, - { label: <>is: , action: e => { e.preventDefault(); this._insertText('is:'); } }, - { label: <>language: , action: e => { e.preventDefault(); this._insertText('language:'); } }, - { label: <>from: , action: e => { e.preventDefault(); this._insertText('from:'); } }, - { label: <>before: , action: e => { e.preventDefault(); this._insertText('before:'); } }, - { label: <>during: , action: e => { e.preventDefault(); this._insertText('during:'); } }, - { label: <>after: , action: e => { e.preventDefault(); this._insertText('after:'); } }, - { label: <>in: , action: e => { e.preventDefault(); this._insertText('in:'); } } + { key: 'prompt-has', label: <>has: , action: e => { e.preventDefault(); this._insertText('has:'); } }, + { key: 'prompt-is', label: <>is: , action: e => { e.preventDefault(); this._insertText('is:'); } }, + { key: 'prompt-language', label: <>language: , action: e => { e.preventDefault(); this._insertText('language:'); } }, + { key: 'prompt-from', label: <>from: , action: e => { e.preventDefault(); this._insertText('from:'); } }, + { key: 'prompt-before', label: <>before: , action: e => { e.preventDefault(); this._insertText('before:'); } }, + { key: 'prompt-during', label: <>during: , action: e => { e.preventDefault(); this._insertText('during:'); } }, + { key: 'prompt-after', label: <>after: , action: e => { e.preventDefault(); this._insertText('after:'); } }, + { key: 'prompt-in', label: <>in: , action: e => { e.preventDefault(); this._insertText('in:'); } } ]; setRef = c => { @@ -263,6 +263,8 @@ class Search extends PureComponent { const { recent } = this.props; return recent.toArray().map(search => ({ + key: `${search.get('type')}/${search.get('q')}`, + label: labelForRecentSearch(search), action: () => this.handleRecentSearchClick(search), @@ -347,8 +349,8 @@ class Search extends PureComponent {

- {recent.size > 0 ? this._getOptions().map(({ label, action, forget }, i) => ( - diff --git a/app/javascript/flavours/glitch/features/compose/components/search_results.jsx b/app/javascript/flavours/glitch/features/compose/components/search_results.jsx index 503afd432a..3c0aec1956 100644 --- a/app/javascript/flavours/glitch/features/compose/components/search_results.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/search_results.jsx @@ -5,15 +5,15 @@ 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 FindInPageIcon from '@/material-icons/400-24px/find_in_page.svg?react'; +import PeopleIcon from '@/material-icons/400-24px/group.svg?react'; +import SearchIcon from '@/material-icons/400-24px/search.svg?react'; +import TagIcon from '@/material-icons/400-24px/tag.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { LoadMore } from 'flavours/glitch/components/load_more'; import { SearchSection } from 'flavours/glitch/features/explore/components/search_section'; + import { ImmutableHashtag as Hashtag } from '../../../components/hashtag'; import AccountContainer from '../../../containers/account_container'; import StatusContainer from '../../../containers/status_container'; diff --git a/app/javascript/flavours/glitch/features/compose/components/textarea_icons.jsx b/app/javascript/flavours/glitch/features/compose/components/textarea_icons.jsx index 334efdac87..74706833d9 100644 --- a/app/javascript/flavours/glitch/features/compose/components/textarea_icons.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/textarea_icons.jsx @@ -5,11 +5,11 @@ import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { ReactComponent as ForumIcon } from '@material-symbols/svg-600/outlined/forum.svg'; -import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg'; - +import ForumIcon from '@/material-icons/400-24px/forum.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + const messages = defineMessages({ localOnly: { defaultMessage: 'This post is local-only', diff --git a/app/javascript/flavours/glitch/features/compose/components/upload.jsx b/app/javascript/flavours/glitch/features/compose/components/upload.jsx index ac26fb1c6a..c317fc4fc1 100644 --- a/app/javascript/flavours/glitch/features/compose/components/upload.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/upload.jsx @@ -5,13 +5,14 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import EditIcon from '@/material-icons/400-24px/edit.svg?react'; +import InfoIcon from '@/material-icons/400-24px/info.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + import Motion from '../../ui/util/optional_motion'; export default class Upload extends ImmutablePureComponent { diff --git a/app/javascript/flavours/glitch/features/compose/components/upload_progress.jsx b/app/javascript/flavours/glitch/features/compose/components/upload_progress.jsx index 5169fbf783..f4408b5460 100644 --- a/app/javascript/flavours/glitch/features/compose/components/upload_progress.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/upload_progress.jsx @@ -3,9 +3,9 @@ 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 UploadFileIcon from '@/material-icons/400-24px/upload_file.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import Motion from '../../ui/util/optional_motion'; diff --git a/app/javascript/flavours/glitch/features/compose/containers/search_container.js b/app/javascript/flavours/glitch/features/compose/containers/search_container.js index 17be30edcc..93b8645ac6 100644 --- a/app/javascript/flavours/glitch/features/compose/containers/search_container.js +++ b/app/javascript/flavours/glitch/features/compose/containers/search_container.js @@ -1,3 +1,4 @@ +import { createSelector } from '@reduxjs/toolkit'; import { connect } from 'react-redux'; import { @@ -12,10 +13,15 @@ import { import Search from '../components/search'; +const getRecentSearches = createSelector( + state => state.getIn(['search', 'recent']), + recent => recent.reverse(), +); + const mapStateToProps = state => ({ value: state.getIn(['search', 'value']), submitted: state.getIn(['search', 'submitted']), - recent: state.getIn(['search', 'recent']).reverse(), + recent: getRecentSearches(state), }); const mapDispatchToProps = dispatch => ({ diff --git a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.jsx b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.jsx index 8c576b4d16..4b82a0f2d9 100644 --- a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.jsx +++ b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.jsx @@ -8,10 +8,10 @@ import { 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 MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; import AttachmentList from 'flavours/glitch/components/attachment_list'; import AvatarComposite from 'flavours/glitch/components/avatar_composite'; import { IconButton } from 'flavours/glitch/components/icon_button'; diff --git a/app/javascript/flavours/glitch/features/direct_timeline/index.jsx b/app/javascript/flavours/glitch/features/direct_timeline/index.jsx index edb5b5aa45..9de5751ffb 100644 --- a/app/javascript/flavours/glitch/features/direct_timeline/index.jsx +++ b/app/javascript/flavours/glitch/features/direct_timeline/index.jsx @@ -7,8 +7,8 @@ import { Helmet } from 'react-helmet'; import { connect } from 'react-redux'; -import { ReactComponent as MailIcon } from '@material-symbols/svg-600/outlined/mail.svg'; +import MailIcon from '@/material-icons/400-24px/mail.svg?react'; import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import { mountConversations, unmountConversations, expandConversations } from 'flavours/glitch/actions/conversations'; import { connectDirectStream } from 'flavours/glitch/actions/streaming'; diff --git a/app/javascript/flavours/glitch/features/directory/index.jsx b/app/javascript/flavours/glitch/features/directory/index.jsx index a3c97506cf..0d8742b255 100644 --- a/app/javascript/flavours/glitch/features/directory/index.jsx +++ b/app/javascript/flavours/glitch/features/directory/index.jsx @@ -9,8 +9,8 @@ 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 PeopleIcon from '@/material-icons/400-24px/group.svg?react'; import { addColumn, removeColumn, moveColumn, changeColumnParams } from 'flavours/glitch/actions/columns'; import { fetchDirectory, expandDirectory } from 'flavours/glitch/actions/directory'; import Column from 'flavours/glitch/components/column'; diff --git a/app/javascript/flavours/glitch/features/domain_blocks/index.jsx b/app/javascript/flavours/glitch/features/domain_blocks/index.jsx index 142f14bf71..964eada9c1 100644 --- a/app/javascript/flavours/glitch/features/domain_blocks/index.jsx +++ b/app/javascript/flavours/glitch/features/domain_blocks/index.jsx @@ -8,9 +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 BlockIcon from '@/material-icons/400-24px/block-fill.svg?react'; + import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks'; import { LoadingIndicator } from '../../components/loading_indicator'; import ScrollableList from '../../components/scrollable_list'; diff --git a/app/javascript/flavours/glitch/features/explore/index.jsx b/app/javascript/flavours/glitch/features/explore/index.jsx index 8e0d8f71b1..9a18ccb72c 100644 --- a/app/javascript/flavours/glitch/features/explore/index.jsx +++ b/app/javascript/flavours/glitch/features/explore/index.jsx @@ -8,9 +8,9 @@ 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 SearchIcon from '@/material-icons/400-24px/search.svg?react'; +import TagIcon from '@/material-icons/400-24px/tag.svg?react'; import Column from 'flavours/glitch/components/column'; import ColumnHeader from 'flavours/glitch/components/column_header'; import Search from 'flavours/glitch/features/compose/containers/search_container'; diff --git a/app/javascript/flavours/glitch/features/explore/results.jsx b/app/javascript/flavours/glitch/features/explore/results.jsx index d2b84f801d..53285988c3 100644 --- a/app/javascript/flavours/glitch/features/explore/results.jsx +++ b/app/javascript/flavours/glitch/features/explore/results.jsx @@ -9,10 +9,10 @@ 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 FindInPageIcon from '@/material-icons/400-24px/find_in_page.svg?react'; +import PeopleIcon from '@/material-icons/400-24px/group.svg?react'; +import TagIcon from '@/material-icons/400-24px/tag.svg?react'; import { submitSearch, expandSearch } from 'flavours/glitch/actions/search'; import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag'; import { Icon } from 'flavours/glitch/components/icon'; diff --git a/app/javascript/flavours/glitch/features/favourited_statuses/index.jsx b/app/javascript/flavours/glitch/features/favourited_statuses/index.jsx index 61f2faa2da..119fd247b6 100644 --- a/app/javascript/flavours/glitch/features/favourited_statuses/index.jsx +++ b/app/javascript/flavours/glitch/features/favourited_statuses/index.jsx @@ -8,9 +8,9 @@ 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 StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import { fetchFavouritedStatuses, expandFavouritedStatuses } from 'flavours/glitch/actions/favourites'; import ColumnHeader from 'flavours/glitch/components/column_header'; diff --git a/app/javascript/flavours/glitch/features/favourites/index.jsx b/app/javascript/flavours/glitch/features/favourites/index.jsx index b6aa0f42e7..c21166a16e 100644 --- a/app/javascript/flavours/glitch/features/favourites/index.jsx +++ b/app/javascript/flavours/glitch/features/favourites/index.jsx @@ -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 RefreshIcon } from '@material-symbols/svg-600/outlined/refresh.svg'; -import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg'; import { debounce } from 'lodash'; +import RefreshIcon from '@/material-icons/400-24px/refresh.svg?react'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; import { fetchFavourites, expandFavourites } from 'flavours/glitch/actions/interactions'; import ColumnHeader from 'flavours/glitch/components/column_header'; import { Icon } from 'flavours/glitch/components/icon'; diff --git a/app/javascript/flavours/glitch/features/filters/select_filter.jsx b/app/javascript/flavours/glitch/features/filters/select_filter.jsx index 2cda219e48..f409cc2d70 100644 --- a/app/javascript/flavours/glitch/features/filters/select_filter.jsx +++ b/app/javascript/flavours/glitch/features/filters/select_filter.jsx @@ -5,9 +5,9 @@ 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 AddIcon from '@/material-icons/400-24px/add.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { toServerSideType } from 'flavours/glitch/utils/filters'; import { loupeIcon, deleteIcon } from 'flavours/glitch/utils/icons'; diff --git a/app/javascript/flavours/glitch/features/firehose/index.jsx b/app/javascript/flavours/glitch/features/firehose/index.jsx index 45e17939d2..29219974a9 100644 --- a/app/javascript/flavours/glitch/features/firehose/index.jsx +++ b/app/javascript/flavours/glitch/features/firehose/index.jsx @@ -6,8 +6,8 @@ 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 PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { addColumn } from 'flavours/glitch/actions/columns'; import { changeSetting } from 'flavours/glitch/actions/settings'; import { connectPublicStream, connectCommunityStream } from 'flavours/glitch/actions/streaming'; diff --git a/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.jsx b/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.jsx index 225045c4c8..877d84c632 100644 --- a/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.jsx +++ b/app/javascript/flavours/glitch/features/follow_requests/components/account_authorize.jsx @@ -5,8 +5,8 @@ import { defineMessages, injectIntl } 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 CheckIcon from '@/material-icons/400-24px/check.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { Avatar } from '../../../components/avatar'; import { DisplayName } from '../../../components/display_name'; diff --git a/app/javascript/flavours/glitch/features/follow_requests/index.jsx b/app/javascript/flavours/glitch/features/follow_requests/index.jsx index 3b98791926..7d651f2ca6 100644 --- a/app/javascript/flavours/glitch/features/follow_requests/index.jsx +++ b/app/javascript/flavours/glitch/features/follow_requests/index.jsx @@ -8,9 +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 PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; + import { fetchFollowRequests, expandFollowRequests } from '../../actions/accounts'; import ScrollableList from '../../components/scrollable_list'; import { me } from '../../initial_state'; diff --git a/app/javascript/flavours/glitch/features/followed_tags/index.jsx b/app/javascript/flavours/glitch/features/followed_tags/index.jsx index 4ac7dddb99..5809d848bc 100644 --- a/app/javascript/flavours/glitch/features/followed_tags/index.jsx +++ b/app/javascript/flavours/glitch/features/followed_tags/index.jsx @@ -8,9 +8,9 @@ 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 TagIcon from '@/material-icons/400-24px/tag.svg?react'; import { expandFollowedHashtags, fetchFollowedHashtags } from 'flavours/glitch/actions/tags'; import ColumnHeader from 'flavours/glitch/components/column_header'; import { Hashtag } from 'flavours/glitch/components/hashtag'; diff --git a/app/javascript/flavours/glitch/features/getting_started/components/announcements.jsx b/app/javascript/flavours/glitch/features/getting_started/components/announcements.jsx index 43063e7bb3..90d1f9a9aa 100644 --- a/app/javascript/flavours/glitch/features/getting_started/components/announcements.jsx +++ b/app/javascript/flavours/glitch/features/getting_started/components/announcements.jsx @@ -9,13 +9,14 @@ 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'; +import elephantUIPlane from '@/images/elephant_ui_plane.svg'; +import AddIcon from '@/material-icons/400-24px/add.svg?react'; +import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react'; +import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; import { AnimatedNumber } from 'flavours/glitch/components/animated_number'; import { Icon } from 'flavours/glitch/components/icon'; import { IconButton } from 'flavours/glitch/components/icon_button'; diff --git a/app/javascript/flavours/glitch/features/getting_started/index.jsx b/app/javascript/flavours/glitch/features/getting_started/index.jsx index 7abf26594e..866904eafb 100644 --- a/app/javascript/flavours/glitch/features/getting_started/index.jsx +++ b/app/javascript/flavours/glitch/features/getting_started/index.jsx @@ -10,20 +10,19 @@ 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 { 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 MailIcon } from '@material-symbols/svg-600/outlined/mail.svg'; -import { ReactComponent as ManufacturingIcon } from '@material-symbols/svg-600/outlined/manufacturing.svg'; -import { ReactComponent as MenuIcon } from '@material-symbols/svg-600/outlined/menu.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 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 TagIcon } from '@material-symbols/svg-600/outlined/tag.svg'; - +import BookmarksIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react'; +import PeopleIcon from '@/material-icons/400-24px/group.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; +import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; +import MailIcon from '@/material-icons/400-24px/mail.svg?react'; +import ManufacturingIcon from '@/material-icons/400-24px/manufacturing.svg?react'; +import MenuIcon from '@/material-icons/400-24px/menu.svg?react'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import NotificationsIcon from '@/material-icons/400-24px/notifications.svg?react'; +import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; +import SettingsIcon from '@/material-icons/400-24px/settings-fill.svg?react'; +import TagIcon from '@/material-icons/400-24px/tag.svg?react'; import { fetchFollowRequests } from 'flavours/glitch/actions/accounts'; import { fetchLists } from 'flavours/glitch/actions/lists'; import { openModal } from 'flavours/glitch/actions/modal'; @@ -31,6 +30,7 @@ import Column from 'flavours/glitch/features/ui/components/column'; import LinkFooter from 'flavours/glitch/features/ui/components/link_footer'; import { preferencesLink } from 'flavours/glitch/utils/backend_links'; + import { me, showTrends } from '../../initial_state'; import NavigationBar from '../compose/components/navigation_bar'; import ColumnLink from '../ui/components/column_link'; diff --git a/app/javascript/flavours/glitch/features/getting_started_misc/index.jsx b/app/javascript/flavours/glitch/features/getting_started_misc/index.jsx index aa07b64c90..7c4979bd63 100644 --- a/app/javascript/flavours/glitch/features/getting_started_misc/index.jsx +++ b/app/javascript/flavours/glitch/features/getting_started_misc/index.jsx @@ -5,18 +5,19 @@ import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { ReactComponent as BlockIcon } from '@material-symbols/svg-600/outlined/block.svg'; -import { ReactComponent as InfoIcon } from '@material-symbols/svg-600/outlined/info.svg'; -import { ReactComponent as PersonCheckIcon } from '@material-symbols/svg-600/outlined/person_check.svg'; -import { ReactComponent as PushPinIcon } from '@material-symbols/svg-600/outlined/push_pin.svg'; -import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg'; -import { ReactComponent as VolumeOffIcon } from '@material-symbols/svg-600/outlined/volume_off.svg'; - +import BlockIcon from '@/material-icons/400-24px/block.svg?react'; +import InfoIcon from '@/material-icons/400-24px/info.svg?react'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import PersonCheckIcon from '@/material-icons/400-24px/person_check.svg?react'; +import PushPinIcon from '@/material-icons/400-24px/push_pin.svg?react'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; +import VolumeOffIcon from '@/material-icons/400-24px/volume_off.svg?react'; import { openModal } from 'flavours/glitch/actions/modal'; import Column from 'flavours/glitch/features/ui/components/column'; import ColumnLink from 'flavours/glitch/features/ui/components/column_link'; import ColumnSubheading from 'flavours/glitch/features/ui/components/column_subheading'; + const messages = defineMessages({ heading: { id: 'column.heading', defaultMessage: 'Misc' }, subheading: { id: 'column.subheading', defaultMessage: 'Miscellaneous options' }, @@ -51,7 +52,7 @@ class GettingStartedMisc extends ImmutablePureComponent { const { signedIn } = this.context.identity; return ( - +
{signedIn && ()} diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.jsx b/app/javascript/flavours/glitch/features/hashtag_timeline/index.jsx index 11f09ffdb2..c2a7574307 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.jsx +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.jsx @@ -8,9 +8,9 @@ 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 TagIcon from '@/material-icons/400-24px/tag.svg?react'; import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import { connectHashtagStream } from 'flavours/glitch/actions/streaming'; import { fetchHashtag, followHashtag, unfollowHashtag } from 'flavours/glitch/actions/tags'; diff --git a/app/javascript/flavours/glitch/features/home_timeline/components/explore_prompt.tsx b/app/javascript/flavours/glitch/features/home_timeline/components/explore_prompt.tsx index f33135621a..73ef8a5fe1 100644 --- a/app/javascript/flavours/glitch/features/home_timeline/components/explore_prompt.tsx +++ b/app/javascript/flavours/glitch/features/home_timeline/components/explore_prompt.tsx @@ -2,8 +2,8 @@ import { FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; +import background from '@/images/friends-cropped.png'; import { DismissableBanner } from 'flavours/glitch/components/dismissable_banner'; -import background from 'mastodon/../images/friends-cropped.png'; export const ExplorePrompt = () => ( diff --git a/app/javascript/flavours/glitch/features/home_timeline/index.jsx b/app/javascript/flavours/glitch/features/home_timeline/index.jsx index ee23c65276..093d8a7602 100644 --- a/app/javascript/flavours/glitch/features/home_timeline/index.jsx +++ b/app/javascript/flavours/glitch/features/home_timeline/index.jsx @@ -10,9 +10,9 @@ import { createSelector } from '@reduxjs/toolkit'; import { List as ImmutableList } from 'immutable'; import { connect } from 'react-redux'; -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 CampaignIcon from '@/material-icons/400-24px/campaign.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; import { fetchAnnouncements, toggleShowAnnouncements } from 'flavours/glitch/actions/announcements'; import { IconWithBadge } from 'flavours/glitch/components/icon_with_badge'; import { NotSignedInIndicator } from 'flavours/glitch/components/not_signed_in_indicator'; diff --git a/app/javascript/flavours/glitch/features/interaction_modal/index.jsx b/app/javascript/flavours/glitch/features/interaction_modal/index.jsx index 627fbef970..71cdf8409c 100644 --- a/app/javascript/flavours/glitch/features/interaction_modal/index.jsx +++ b/app/javascript/flavours/glitch/features/interaction_modal/index.jsx @@ -7,12 +7,12 @@ 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 PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; +import StarIcon from '@/material-icons/400-24px/star.svg?react'; import { openModal, closeModal } from 'flavours/glitch/actions/modal'; import api from 'flavours/glitch/api'; import { Button } from 'flavours/glitch/components/button'; diff --git a/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.jsx b/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.jsx index 466f2cb561..98f65d9b50 100644 --- a/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.jsx +++ b/app/javascript/flavours/glitch/features/keyboard_shortcuts/index.jsx @@ -7,8 +7,8 @@ import { Helmet } from 'react-helmet'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { ReactComponent as InfoIcon } from '@material-symbols/svg-600/outlined/info.svg'; +import InfoIcon from '@/material-icons/400-24px/info.svg?react'; import Column from 'flavours/glitch/components/column'; import ColumnHeader from 'flavours/glitch/components/column_header'; diff --git a/app/javascript/flavours/glitch/features/list_adder/components/list.jsx b/app/javascript/flavours/glitch/features/list_adder/components/list.jsx index 8c0333b5ad..adbb16fcd6 100644 --- a/app/javascript/flavours/glitch/features/list_adder/components/list.jsx +++ b/app/javascript/flavours/glitch/features/list_adder/components/list.jsx @@ -6,12 +6,12 @@ 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 AddIcon from '@/material-icons/400-24px/add.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + import { removeFromListAdder, addToListAdder } from '../../../actions/lists'; import { IconButton } from '../../../components/icon_button'; diff --git a/app/javascript/flavours/glitch/features/list_editor/components/account.jsx b/app/javascript/flavours/glitch/features/list_editor/components/account.jsx index 18d5e905cb..77d32af80a 100644 --- a/app/javascript/flavours/glitch/features/list_editor/components/account.jsx +++ b/app/javascript/flavours/glitch/features/list_editor/components/account.jsx @@ -6,8 +6,8 @@ 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 AddIcon from '@/material-icons/400-24px/add.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { removeFromListEditor, addToListEditor } from '../../../actions/lists'; import { Avatar } from '../../../components/avatar'; diff --git a/app/javascript/flavours/glitch/features/list_editor/components/edit_list_form.jsx b/app/javascript/flavours/glitch/features/list_editor/components/edit_list_form.jsx index 1e2446f92b..89f596636e 100644 --- a/app/javascript/flavours/glitch/features/list_editor/components/edit_list_form.jsx +++ b/app/javascript/flavours/glitch/features/list_editor/components/edit_list_form.jsx @@ -5,7 +5,7 @@ import { defineMessages, injectIntl } from 'react-intl'; import { connect } from 'react-redux'; -import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg'; +import CheckIcon from '@/material-icons/400-24px/check.svg?react'; import { changeListEditorTitle, submitListEditor } from '../../../actions/lists'; import { IconButton } from '../../../components/icon_button'; diff --git a/app/javascript/flavours/glitch/features/list_editor/components/search.jsx b/app/javascript/flavours/glitch/features/list_editor/components/search.jsx index 58fb6566d6..6e9cd44835 100644 --- a/app/javascript/flavours/glitch/features/list_editor/components/search.jsx +++ b/app/javascript/flavours/glitch/features/list_editor/components/search.jsx @@ -7,11 +7,11 @@ 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 CancelIcon from '@/material-icons/400-24px/cancel.svg?react'; +import SearchIcon from '@/material-icons/400-24px/search.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from '../../../actions/lists'; const messages = defineMessages({ diff --git a/app/javascript/flavours/glitch/features/list_timeline/index.jsx b/app/javascript/flavours/glitch/features/list_timeline/index.jsx index 48100a0a4c..ae9f75318f 100644 --- a/app/javascript/flavours/glitch/features/list_timeline/index.jsx +++ b/app/javascript/flavours/glitch/features/list_timeline/index.jsx @@ -9,11 +9,11 @@ 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 DeleteIcon from '@/material-icons/400-24px/delete.svg?react'; +import EditIcon from '@/material-icons/400-24px/edit.svg?react'; +import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import { fetchList, deleteList, updateList } from 'flavours/glitch/actions/lists'; import { openModal } from 'flavours/glitch/actions/modal'; diff --git a/app/javascript/flavours/glitch/features/lists/index.jsx b/app/javascript/flavours/glitch/features/lists/index.jsx index 89aea03321..9c24d82f03 100644 --- a/app/javascript/flavours/glitch/features/lists/index.jsx +++ b/app/javascript/flavours/glitch/features/lists/index.jsx @@ -9,8 +9,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg'; +import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; import { fetchLists } from 'flavours/glitch/actions/lists'; import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; diff --git a/app/javascript/flavours/glitch/features/local_settings/navigation/index.jsx b/app/javascript/flavours/glitch/features/local_settings/navigation/index.jsx index 32b25e0c07..00744fa2ae 100644 --- a/app/javascript/flavours/glitch/features/local_settings/navigation/index.jsx +++ b/app/javascript/flavours/glitch/features/local_settings/navigation/index.jsx @@ -4,15 +4,15 @@ import { PureComponent } from 'react'; import { injectIntl, defineMessages } from 'react-intl'; -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 ExpandLessIcon } from '@material-symbols/svg-600/outlined/expand_less.svg'; -import { ReactComponent as ImageIcon } from '@material-symbols/svg-600/outlined/image.svg'; -import { ReactComponent as ManufacturingIcon } from '@material-symbols/svg-600/outlined/manufacturing.svg'; -import { ReactComponent as SettingsIcon } from '@material-symbols/svg-600/outlined/settings-fill.svg'; - +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import EditIcon from '@/material-icons/400-24px/edit.svg?react'; +import ExpandLessIcon from '@/material-icons/400-24px/expand_less.svg?react'; +import ImageIcon from '@/material-icons/400-24px/image.svg?react'; +import ManufacturingIcon from '@/material-icons/400-24px/manufacturing.svg?react'; +import SettingsIcon from '@/material-icons/400-24px/settings-fill.svg?react'; import { preferencesLink } from 'flavours/glitch/utils/backend_links'; + import LocalSettingsNavigationItem from './item'; const messages = defineMessages({ diff --git a/app/javascript/flavours/glitch/features/mutes/index.jsx b/app/javascript/flavours/glitch/features/mutes/index.jsx index 7f66edc03d..3b50244ea4 100644 --- a/app/javascript/flavours/glitch/features/mutes/index.jsx +++ b/app/javascript/flavours/glitch/features/mutes/index.jsx @@ -8,9 +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 VolumeOffIcon from '@/material-icons/400-24px/volume_off.svg?react'; + import { fetchMutes, expandMutes } from '../../actions/mutes'; import { LoadingIndicator } from '../../components/loading_indicator'; import ScrollableList from '../../components/scrollable_list'; diff --git a/app/javascript/flavours/glitch/features/notifications/components/admin_report.jsx b/app/javascript/flavours/glitch/features/notifications/components/admin_report.jsx index 01273f959b..d16a775ea5 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/admin_report.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/admin_report.jsx @@ -8,9 +8,9 @@ import { withRouter } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { ReactComponent as FlagIcon } from '@material-symbols/svg-600/outlined/flag-fill.svg'; import { HotKeys } from 'react-hotkeys'; +import FlagIcon from '@/material-icons/400-24px/flag-fill.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { Permalink } from 'flavours/glitch/components/permalink'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; diff --git a/app/javascript/flavours/glitch/features/notifications/components/admin_signup.jsx b/app/javascript/flavours/glitch/features/notifications/components/admin_signup.jsx index a99d90e0f5..60affd444b 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/admin_signup.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/admin_signup.jsx @@ -8,9 +8,9 @@ import { withRouter } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add-fill.svg'; import { HotKeys } from 'react-hotkeys'; +import PersonAddIcon from '@/material-icons/400-24px/person_add-fill.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { Permalink } from 'flavours/glitch/components/permalink'; import AccountContainer from 'flavours/glitch/containers/account_container'; diff --git a/app/javascript/flavours/glitch/features/notifications/components/clear_column_button.jsx b/app/javascript/flavours/glitch/features/notifications/components/clear_column_button.jsx index 373f20e51d..6e29709b59 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/clear_column_button.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/clear_column_button.jsx @@ -3,10 +3,10 @@ import { PureComponent } from 'react'; import { FormattedMessage } from 'react-intl'; -import { ReactComponent as DeleteForeverIcon } from '@material-symbols/svg-600/outlined/delete_forever.svg'; - +import DeleteForeverIcon from '@/material-icons/400-24px/delete_forever.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + export default class ClearColumnButton extends PureComponent { static propTypes = { diff --git a/app/javascript/flavours/glitch/features/notifications/components/filter_bar.jsx b/app/javascript/flavours/glitch/features/notifications/components/filter_bar.jsx index e5f28c7c18..13aba0d0ef 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/filter_bar.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/filter_bar.jsx @@ -3,16 +3,16 @@ import { PureComponent } from 'react'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import { ReactComponent as AddReactionIcon } from '@material-symbols/svg-600/outlined/add_reaction.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 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 AddReactionIcon from '@/material-icons/400-24px/add_reaction.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; +import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react'; +import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react'; +import StarIcon from '@/material-icons/400-24px/star.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + const tooltips = defineMessages({ mentions: { id: 'notifications.filter.mentions', defaultMessage: 'Mentions' }, favourites: { id: 'notifications.filter.favourites', defaultMessage: 'Favorites' }, diff --git a/app/javascript/flavours/glitch/features/notifications/components/follow.jsx b/app/javascript/flavours/glitch/features/notifications/components/follow.jsx index 6aff0dfede..85ccde094b 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/follow.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/follow.jsx @@ -8,9 +8,9 @@ import { withRouter } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add-fill.svg'; import { HotKeys } from 'react-hotkeys'; +import PersonAddIcon from '@/material-icons/400-24px/person_add-fill.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { Permalink } from 'flavours/glitch/components/permalink'; import AccountContainer from 'flavours/glitch/containers/account_container'; diff --git a/app/javascript/flavours/glitch/features/notifications/components/follow_request.jsx b/app/javascript/flavours/glitch/features/notifications/components/follow_request.jsx index 8462cc16b1..6607279983 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/follow_request.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/follow_request.jsx @@ -8,11 +8,11 @@ import { 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 CloseIcon } from '@material-symbols/svg-600/outlined/close.svg'; -import { ReactComponent as PersonIcon } from '@material-symbols/svg-600/outlined/person-fill.svg'; import { HotKeys } from 'react-hotkeys'; +import CheckIcon from '@/material-icons/400-24px/check.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import PersonIcon from '@/material-icons/400-24px/person-fill.svg?react'; import { Avatar } from 'flavours/glitch/components/avatar'; import { DisplayName } from 'flavours/glitch/components/display_name'; import { Icon } from 'flavours/glitch/components/icon'; diff --git a/app/javascript/flavours/glitch/features/notifications/components/notifications_permission_banner.jsx b/app/javascript/flavours/glitch/features/notifications/components/notifications_permission_banner.jsx index 4dc8ca9f5c..82c08ea175 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/notifications_permission_banner.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/notifications_permission_banner.jsx @@ -5,9 +5,9 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import TuneIcon from '@/material-icons/400-24px/tune.svg?react'; import { requestBrowserPermission } from 'flavours/glitch/actions/notifications'; import { changeSetting } from 'flavours/glitch/actions/settings'; import { Button } from 'flavours/glitch/components/button'; diff --git a/app/javascript/flavours/glitch/features/notifications/components/overlay.jsx b/app/javascript/flavours/glitch/features/notifications/components/overlay.jsx index 1ed052f83e..faf7e42e71 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/overlay.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/overlay.jsx @@ -9,10 +9,10 @@ import { defineMessages, injectIntl } 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 CheckIcon from '@/material-icons/400-24px/check.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + const messages = defineMessages({ markForDeletion: { id: 'notification.markForDeletion', defaultMessage: 'Mark for deletion' }, }); diff --git a/app/javascript/flavours/glitch/features/notifications/index.jsx b/app/javascript/flavours/glitch/features/notifications/index.jsx index a4b14f011e..4e3d61f25a 100644 --- a/app/javascript/flavours/glitch/features/notifications/index.jsx +++ b/app/javascript/flavours/glitch/features/notifications/index.jsx @@ -11,11 +11,11 @@ import { List as ImmutableList } from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { connect } from 'react-redux'; -import { ReactComponent as DeleteForeverIcon } from '@material-symbols/svg-600/outlined/delete_forever.svg'; -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 DeleteForeverIcon from '@/material-icons/400-24px/delete_forever.svg?react'; +import DoneAllIcon from '@/material-icons/400-24px/done_all.svg?react'; +import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg?react'; import { compareId } from 'flavours/glitch/compare_id'; import { Icon } from 'flavours/glitch/components/icon'; import { NotSignedInIndicator } from 'flavours/glitch/components/not_signed_in_indicator'; diff --git a/app/javascript/flavours/glitch/features/onboarding/components/step.jsx b/app/javascript/flavours/glitch/features/onboarding/components/step.jsx index 179e688b9c..4dcd3c9ce5 100644 --- a/app/javascript/flavours/glitch/features/onboarding/components/step.jsx +++ b/app/javascript/flavours/glitch/features/onboarding/components/step.jsx @@ -2,11 +2,11 @@ import PropTypes from 'prop-types'; import { Link } from 'react-router-dom'; -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 ArrowRightAltIcon from '@/material-icons/400-24px/arrow_right_alt.svg?react'; +import CheckIcon from '@/material-icons/400-24px/done.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + export const Step = ({ label, description, icon, iconComponent, completed, onClick, href, to }) => { const content = ( <> diff --git a/app/javascript/flavours/glitch/features/onboarding/index.jsx b/app/javascript/flavours/glitch/features/onboarding/index.jsx index dbf1ba1f61..fb9df29aeb 100644 --- a/app/javascript/flavours/glitch/features/onboarding/index.jsx +++ b/app/javascript/flavours/glitch/features/onboarding/index.jsx @@ -8,19 +8,19 @@ import { Link, Switch, Route, useHistory } from 'react-router-dom'; import { useDispatch } 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 illustration from '@/images/elephant_ui_conversation.svg'; +import AccountCircleIcon from '@/material-icons/400-24px/account_circle.svg?react'; +import ArrowRightAltIcon from '@/material-icons/400-24px/arrow_right_alt.svg?react'; +import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react'; +import EditNoteIcon from '@/material-icons/400-24px/edit_note.svg?react'; +import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; import { focusCompose } from 'flavours/glitch/actions/compose'; import { Icon } from 'flavours/glitch/components/icon'; import Column from 'flavours/glitch/features/ui/components/column'; import { me } from 'flavours/glitch/initial_state'; import { useAppSelector } from 'flavours/glitch/store'; import { assetHost } from 'flavours/glitch/utils/config'; -import illustration from 'mastodon/../images/elephant_ui_conversation.svg'; import { Step } from './components/step'; import { Follows } from './follows'; diff --git a/app/javascript/flavours/glitch/features/onboarding/profile.jsx b/app/javascript/flavours/glitch/features/onboarding/profile.jsx index fb7c515f00..75e179ee1e 100644 --- a/app/javascript/flavours/glitch/features/onboarding/profile.jsx +++ b/app/javascript/flavours/glitch/features/onboarding/profile.jsx @@ -8,10 +8,10 @@ import { useHistory } from 'react-router-dom'; import { useDispatch } from 'react-redux'; -import { ReactComponent as AddPhotoAlternateIcon } from '@material-symbols/svg-600/outlined/add_photo_alternate.svg'; -import { ReactComponent as EditIcon } from '@material-symbols/svg-600/outlined/edit.svg'; import Toggle from 'react-toggle'; +import AddPhotoAlternateIcon from '@/material-icons/400-24px/add_photo_alternate.svg?react'; +import EditIcon from '@/material-icons/400-24px/edit.svg?react'; import { updateAccount } from 'flavours/glitch/actions/accounts'; import { Button } from 'flavours/glitch/components/button'; import { ColumnBackButton } from 'flavours/glitch/components/column_back_button'; diff --git a/app/javascript/flavours/glitch/features/onboarding/share.jsx b/app/javascript/flavours/glitch/features/onboarding/share.jsx index b5732c0abc..0c7d579c10 100644 --- a/app/javascript/flavours/glitch/features/onboarding/share.jsx +++ b/app/javascript/flavours/glitch/features/onboarding/share.jsx @@ -7,10 +7,10 @@ import classNames from 'classnames'; import { Link } from 'react-router-dom'; -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 ArrowRightAltIcon from '@/material-icons/400-24px/arrow_right_alt.svg?react'; +import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react'; import { ColumnBackButton } from 'flavours/glitch/components/column_back_button'; import { Icon } from 'flavours/glitch/components/icon'; import { me, domain } from 'flavours/glitch/initial_state'; diff --git a/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx b/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx index ee8179fc3b..83e53d9263 100644 --- a/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx +++ b/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx @@ -9,12 +9,12 @@ 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 OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; +import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react'; +import StarIcon from '@/material-icons/400-24px/star.svg?react'; import { initBoostModal } from 'flavours/glitch/actions/boosts'; import { replyCompose } from 'flavours/glitch/actions/compose'; import { reblog, favourite, unreblog, unfavourite } from 'flavours/glitch/actions/interactions'; diff --git a/app/javascript/flavours/glitch/features/picture_in_picture/components/header.jsx b/app/javascript/flavours/glitch/features/picture_in_picture/components/header.jsx index 6ed1f4fbdd..dd90cd3522 100644 --- a/app/javascript/flavours/glitch/features/picture_in_picture/components/header.jsx +++ b/app/javascript/flavours/glitch/features/picture_in_picture/components/header.jsx @@ -8,8 +8,8 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { Avatar } from 'flavours/glitch/components/avatar'; import { DisplayName } from 'flavours/glitch/components/display_name'; import { IconButton } from 'flavours/glitch/components/icon_button'; diff --git a/app/javascript/flavours/glitch/features/pinned_statuses/index.jsx b/app/javascript/flavours/glitch/features/pinned_statuses/index.jsx index b888ab6850..94d5f6cb4c 100644 --- a/app/javascript/flavours/glitch/features/pinned_statuses/index.jsx +++ b/app/javascript/flavours/glitch/features/pinned_statuses/index.jsx @@ -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 PushPinIcon } from '@material-symbols/svg-600/outlined/push_pin.svg'; - +import PushPinIcon from '@/material-icons/400-24px/push_pin.svg?react'; import { getStatusList } from 'flavours/glitch/selectors'; + import { fetchPinnedStatuses } from '../../actions/pin_statuses'; import StatusList from '../../components/status_list'; import Column from '../ui/components/column'; diff --git a/app/javascript/flavours/glitch/features/public_timeline/index.jsx b/app/javascript/flavours/glitch/features/public_timeline/index.jsx index 00e023eaac..0062a9f719 100644 --- a/app/javascript/flavours/glitch/features/public_timeline/index.jsx +++ b/app/javascript/flavours/glitch/features/public_timeline/index.jsx @@ -7,8 +7,8 @@ import { Helmet } from 'react-helmet'; import { connect } from 'react-redux'; -import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { DismissableBanner } from 'flavours/glitch/components/dismissable_banner'; import { domain } from 'flavours/glitch/initial_state'; diff --git a/app/javascript/flavours/glitch/features/reblogs/index.jsx b/app/javascript/flavours/glitch/features/reblogs/index.jsx index 57ccf9cfb1..52e9a35833 100644 --- a/app/javascript/flavours/glitch/features/reblogs/index.jsx +++ b/app/javascript/flavours/glitch/features/reblogs/index.jsx @@ -8,12 +8,13 @@ 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 { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg'; import { debounce } from 'lodash'; +import RefreshIcon from '@/material-icons/400-24px/refresh.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + import { fetchReblogs, expandReblogs } from '../../actions/interactions'; import ColumnHeader from '../../components/column_header'; import { LoadingIndicator } from '../../components/loading_indicator'; diff --git a/app/javascript/flavours/glitch/features/report/components/option.jsx b/app/javascript/flavours/glitch/features/report/components/option.jsx index af296528b3..3b40de8cba 100644 --- a/app/javascript/flavours/glitch/features/report/components/option.jsx +++ b/app/javascript/flavours/glitch/features/report/components/option.jsx @@ -3,10 +3,10 @@ import { PureComponent } from 'react'; import classNames from 'classnames'; -import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/done.svg'; - +import CheckIcon from '@/material-icons/400-24px/done.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; + export default class Option extends PureComponent { static propTypes = { diff --git a/app/javascript/flavours/glitch/features/status/components/action_bar.jsx b/app/javascript/flavours/glitch/features/status/components/action_bar.jsx index 66830b7af8..1725203976 100644 --- a/app/javascript/flavours/glitch/features/status/components/action_bar.jsx +++ b/app/javascript/flavours/glitch/features/status/components/action_bar.jsx @@ -8,21 +8,20 @@ import { withRouter } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { ReactComponent as AddReactionIcon } from '@material-symbols/svg-600/outlined/add_reaction.svg'; -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 AddReactionIcon from '@/material-icons/400-24px/add_reaction.svg?react'; +import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg?react'; +import BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; +import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; +import StarBorderIcon from '@/material-icons/400-24px/star.svg?react'; +import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg'; +import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions'; import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; -import { ReactComponent as RepeatDisabledIcon } from 'mastodon/../svg-icons/repeat_disabled.svg'; -import { ReactComponent as RepeatPrivateIcon } from 'mastodon/../svg-icons/repeat_private.svg'; import { IconButton } from '../../../components/icon_button'; import DropdownMenuContainer from '../../../containers/dropdown_menu_container'; diff --git a/app/javascript/flavours/glitch/features/status/components/card.jsx b/app/javascript/flavours/glitch/features/status/components/card.jsx index 722c6acd86..3d5522ab61 100644 --- a/app/javascript/flavours/glitch/features/status/components/card.jsx +++ b/app/javascript/flavours/glitch/features/status/components/card.jsx @@ -8,10 +8,10 @@ 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 DescriptionIcon from '@/material-icons/400-24px/description-fill.svg?react'; +import OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react'; +import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react'; import { Blurhash } from 'flavours/glitch/components/blurhash'; import { Icon } from 'flavours/glitch/components/icon'; import { useBlurhash } from 'flavours/glitch/initial_state'; diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.jsx b/app/javascript/flavours/glitch/features/status/components/detailed_status.jsx index c2b81cdad7..2e368cf58a 100644 --- a/app/javascript/flavours/glitch/features/status/components/detailed_status.jsx +++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.jsx @@ -8,16 +8,15 @@ import { Link, withRouter } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -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 RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; import { AnimatedNumber } from 'flavours/glitch/components/animated_number'; import AttachmentList from 'flavours/glitch/components/attachment_list'; import EditedTimestamp from 'flavours/glitch/components/edited_timestamp'; import { getHashtagBarForStatus } from 'flavours/glitch/components/hashtag_bar'; import { Icon } from 'flavours/glitch/components/icon'; import PictureInPicturePlaceholder from 'flavours/glitch/components/picture_in_picture_placeholder'; -import StatusReactions from 'flavours/glitch/components/status_reactions'; import { VisibilityIcon } from 'flavours/glitch/components/visibility_icon'; import PollContainer from 'flavours/glitch/containers/poll_container'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; @@ -26,6 +25,7 @@ import { Avatar } from '../../../components/avatar'; import { DisplayName } from '../../../components/display_name'; import MediaGallery from '../../../components/media_gallery'; import StatusContent from '../../../components/status_content'; +import StatusReactions from '../../../components/status_reactions'; import Audio from '../../audio'; import scheduleIdleTask from '../../ui/util/schedule_idle_task'; import Video from '../../video'; diff --git a/app/javascript/flavours/glitch/features/status/index.jsx b/app/javascript/flavours/glitch/features/status/index.jsx index 55c6e1a0f2..7a85c1d619 100644 --- a/app/javascript/flavours/glitch/features/status/index.jsx +++ b/app/javascript/flavours/glitch/features/status/index.jsx @@ -12,11 +12,11 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { ReactComponent as ChatIcon } from '@material-symbols/svg-600/outlined/chat.svg'; -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 ChatIcon from '@/material-icons/400-24px/chat.svg?react'; +import VisibilityIcon from '@/material-icons/400-24px/visibility.svg?react'; +import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; import ScrollContainer from 'flavours/glitch/containers/scroll_container'; diff --git a/app/javascript/flavours/glitch/features/subscribed_languages_modal/index.jsx b/app/javascript/flavours/glitch/features/subscribed_languages_modal/index.jsx index 86c2ede894..1edfe700fe 100644 --- a/app/javascript/flavours/glitch/features/subscribed_languages_modal/index.jsx +++ b/app/javascript/flavours/glitch/features/subscribed_languages_modal/index.jsx @@ -8,8 +8,8 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { followAccount } from 'flavours/glitch/actions/accounts'; import { Button } from 'flavours/glitch/components/button'; import { IconButton } from 'flavours/glitch/components/icon_button'; diff --git a/app/javascript/flavours/glitch/features/ui/components/boost_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/boost_modal.jsx index a3d9423f91..f44fd5ebf4 100644 --- a/app/javascript/flavours/glitch/features/ui/components/boost_modal.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/boost_modal.jsx @@ -9,8 +9,8 @@ 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 RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; import { changeBoostPrivacy } from 'flavours/glitch/actions/boosts'; import AttachmentList from 'flavours/glitch/components/attachment_list'; import { Icon } from 'flavours/glitch/components/icon'; diff --git a/app/javascript/flavours/glitch/features/ui/components/bundle_modal_error.jsx b/app/javascript/flavours/glitch/features/ui/components/bundle_modal_error.jsx index 44165f1417..d1c9e36883 100644 --- a/app/javascript/flavours/glitch/features/ui/components/bundle_modal_error.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/bundle_modal_error.jsx @@ -3,7 +3,7 @@ import { PureComponent } from 'react'; import { defineMessages, injectIntl } from 'react-intl'; -import { ReactComponent as RefreshIcon } from '@material-symbols/svg-600/outlined/refresh.svg'; +import RefreshIcon from '@/material-icons/400-24px/refresh.svg?react'; import { IconButton } from '../../../components/icon_button'; diff --git a/app/javascript/flavours/glitch/features/ui/components/compare_history_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/compare_history_modal.jsx index 10cd32d168..7e84a578c2 100644 --- a/app/javascript/flavours/glitch/features/ui/components/compare_history_modal.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/compare_history_modal.jsx @@ -6,9 +6,9 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { closeModal } from 'flavours/glitch/actions/modal'; import { IconButton } from 'flavours/glitch/components/icon_button'; import InlineAccount from 'flavours/glitch/components/inline_account'; diff --git a/app/javascript/flavours/glitch/features/ui/components/deprecated_settings_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/deprecated_settings_modal.jsx index 61750a20dd..2f0c07e78b 100644 --- a/app/javascript/flavours/glitch/features/ui/components/deprecated_settings_modal.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/deprecated_settings_modal.jsx @@ -5,9 +5,9 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import { ReactComponent as ManufacturingIcon } from '@material-symbols/svg-600/outlined/manufacturing.svg'; -import { ReactComponent as SettingsIcon } from '@material-symbols/svg-600/outlined/settings-fill.svg'; +import ManufacturingIcon from '@/material-icons/400-24px/manufacturing.svg?react'; +import SettingsIcon from '@/material-icons/400-24px/settings-fill.svg?react'; import { Button } from 'flavours/glitch/components/button'; import { Icon } from 'flavours/glitch/components/icon'; import illustration from 'flavours/glitch/images/logo_warn_glitch.svg'; diff --git a/app/javascript/flavours/glitch/features/ui/components/embed_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/embed_modal.jsx index 7caef5fccf..edd2fb8940 100644 --- a/app/javascript/flavours/glitch/features/ui/components/embed_modal.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/embed_modal.jsx @@ -4,8 +4,8 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import api from 'flavours/glitch/api'; import { IconButton } from 'flavours/glitch/components/icon_button'; diff --git a/app/javascript/flavours/glitch/features/ui/components/favourite_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/favourite_modal.jsx index da9c74111e..388bc5762c 100644 --- a/app/javascript/flavours/glitch/features/ui/components/favourite_modal.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/favourite_modal.jsx @@ -8,8 +8,8 @@ import { withRouter } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; import AttachmentList from 'flavours/glitch/components/attachment_list'; import { Avatar } from 'flavours/glitch/components/avatar'; import { Button } from 'flavours/glitch/components/button'; diff --git a/app/javascript/flavours/glitch/features/ui/components/filter_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/filter_modal.jsx index 6c347f8f6b..9ce5eec874 100644 --- a/app/javascript/flavours/glitch/features/ui/components/filter_modal.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/filter_modal.jsx @@ -5,8 +5,8 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { fetchFilters, createFilter, createFilterStatus } from 'flavours/glitch/actions/filters'; import { fetchStatus } from 'flavours/glitch/actions/statuses'; import { IconButton } from 'flavours/glitch/components/icon_button'; diff --git a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx index 29784c89e2..caed29c252 100644 --- a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx @@ -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 @@ -17,6 +16,7 @@ import tesseractWorkerPath from 'tesseract.js/dist/worker.min.js'; // eslint-disable-next-line import/no-extraneous-dependencies import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { Button } from 'flavours/glitch/components/button'; import { GIFV } from 'flavours/glitch/components/gifv'; import { IconButton } from 'flavours/glitch/components/icon_button'; diff --git a/app/javascript/flavours/glitch/features/ui/components/follow_requests_column_link.jsx b/app/javascript/flavours/glitch/features/ui/components/follow_requests_column_link.jsx index 612d5eace4..24fd5b6442 100644 --- a/app/javascript/flavours/glitch/features/ui/components/follow_requests_column_link.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/follow_requests_column_link.jsx @@ -6,8 +6,7 @@ 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 PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; import { fetchFollowRequests } from 'flavours/glitch/actions/accounts'; import { IconWithBadge } from 'flavours/glitch/components/icon_with_badge'; import ColumnLink from 'flavours/glitch/features/ui/components/column_link'; diff --git a/app/javascript/flavours/glitch/features/ui/components/header.jsx b/app/javascript/flavours/glitch/features/ui/components/header.jsx index ed2d6ba7f3..618a6b63d4 100644 --- a/app/javascript/flavours/glitch/features/ui/components/header.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/header.jsx @@ -7,8 +7,7 @@ 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 SearchIcon from '@/material-icons/400-24px/search.svg?react'; import { openModal } from 'flavours/glitch/actions/modal'; import { fetchServer } from 'flavours/glitch/actions/server'; import { Avatar } from 'flavours/glitch/components/avatar'; diff --git a/app/javascript/flavours/glitch/features/ui/components/image_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/image_modal.jsx index bc650802b0..0e7a3d3121 100644 --- a/app/javascript/flavours/glitch/features/ui/components/image_modal.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/image_modal.jsx @@ -5,8 +5,7 @@ import { defineMessages, injectIntl } from 'react-intl'; import classNames from 'classnames'; -import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg'; - +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { IconButton } from 'flavours/glitch/components/icon_button'; import ImageLoader from './image_loader'; diff --git a/app/javascript/flavours/glitch/features/ui/components/list_panel.jsx b/app/javascript/flavours/glitch/features/ui/components/list_panel.jsx index 6284988fa2..1baedfb8b0 100644 --- a/app/javascript/flavours/glitch/features/ui/components/list_panel.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/list_panel.jsx @@ -5,8 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg'; - +import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; import { fetchLists } from 'flavours/glitch/actions/lists'; import ColumnLink from './column_link'; diff --git a/app/javascript/flavours/glitch/features/ui/components/media_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/media_modal.jsx index 19591fc1c8..d16b274170 100644 --- a/app/javascript/flavours/glitch/features/ui/components/media_modal.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/media_modal.jsx @@ -7,11 +7,11 @@ 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 ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react'; +import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { getAverageFromBlurhash } from 'flavours/glitch/blurhash'; import { GIFV } from 'flavours/glitch/components/gifv'; import { Icon } from 'flavours/glitch/components/icon'; diff --git a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx index e868055f0d..0bde497c63 100644 --- a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx @@ -3,18 +3,17 @@ import { Component } from 'react'; import { defineMessages, injectIntl } from 'react-intl'; -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 MailIcon } from '@material-symbols/svg-600/outlined/mail.svg'; -import { ReactComponent as ManufacturingIcon } from '@material-symbols/svg-600/outlined/manufacturing.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 BookmarksIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; +import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; +import MailIcon from '@/material-icons/400-24px/mail.svg?react'; +import ManufacturingIcon from '@/material-icons/400-24px/manufacturing.svg?react'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; +import SearchIcon from '@/material-icons/400-24px/search.svg?react'; +import SettingsIcon from '@/material-icons/400-24px/settings-fill.svg?react'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; +import TagIcon from '@/material-icons/400-24px/tag.svg?react'; import { NavigationPortal } from 'flavours/glitch/components/navigation_portal'; import { timelinePreview, trendsEnabled } from 'flavours/glitch/initial_state'; import { transientSingleColumn } from 'flavours/glitch/is_mobile'; diff --git a/app/javascript/flavours/glitch/features/ui/components/notifications_counter_icon.js b/app/javascript/flavours/glitch/features/ui/components/notifications_counter_icon.js index 78e62fbf3a..8e38acfe80 100644 --- a/app/javascript/flavours/glitch/features/ui/components/notifications_counter_icon.js +++ b/app/javascript/flavours/glitch/features/ui/components/notifications_counter_icon.js @@ -1,7 +1,6 @@ import { connect } from 'react-redux'; -import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications-fill.svg'; - +import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg?react'; import { IconWithBadge } from 'flavours/glitch/components/icon_with_badge'; const mapStateToProps = state => ({ diff --git a/app/javascript/flavours/glitch/features/ui/components/report_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/report_modal.jsx index f4f8f70194..98ff00bcbf 100644 --- a/app/javascript/flavours/glitch/features/ui/components/report_modal.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/report_modal.jsx @@ -7,8 +7,7 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { fetchRelationships } from 'flavours/glitch/actions/accounts'; import { submitReport } from 'flavours/glitch/actions/reports'; import { fetchServer } from 'flavours/glitch/actions/server'; diff --git a/app/javascript/flavours/glitch/features/ui/components/zoomable_image.jsx b/app/javascript/flavours/glitch/features/ui/components/zoomable_image.jsx index 7271e40db8..31a25159ea 100644 --- a/app/javascript/flavours/glitch/features/ui/components/zoomable_image.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/zoomable_image.jsx @@ -3,9 +3,8 @@ 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 FullscreenExitIcon from '@/material-icons/400-24px/fullscreen_exit.svg?react'; +import RectangleIcon from '@/material-icons/400-24px/rectangle.svg?react'; import { IconButton } from 'flavours/glitch/components/icon_button'; const messages = defineMessages({ diff --git a/app/javascript/flavours/glitch/features/video/index.jsx b/app/javascript/flavours/glitch/features/video/index.jsx index d98a29a757..d6b93dcdbc 100644 --- a/app/javascript/flavours/glitch/features/video/index.jsx +++ b/app/javascript/flavours/glitch/features/video/index.jsx @@ -7,16 +7,16 @@ 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 FullscreenIcon from '@/material-icons/400-24px/fullscreen.svg?react'; +import FullscreenExitIcon from '@/material-icons/400-24px/fullscreen_exit.svg?react'; +import PauseIcon from '@/material-icons/400-24px/pause.svg?react'; +import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react'; +import RectangleIcon from '@/material-icons/400-24px/rectangle.svg?react'; +import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; +import VolumeOffIcon from '@/material-icons/400-24px/volume_off-fill.svg?react'; +import VolumeUpIcon from '@/material-icons/400-24px/volume_up-fill.svg?react'; import { Blurhash } from 'flavours/glitch/components/blurhash'; import { Icon } from 'flavours/glitch/components/icon'; import { playerSettings } from 'flavours/glitch/settings'; diff --git a/app/javascript/flavours/glitch/locales/ar.json b/app/javascript/flavours/glitch/locales/ar.json index 20ca870f7c..a259146328 100644 --- a/app/javascript/flavours/glitch/locales/ar.json +++ b/app/javascript/flavours/glitch/locales/ar.json @@ -32,11 +32,13 @@ "compose_form.spoiler": "إخفاء النص خلف تحذير", "confirmation_modal.do_not_ask_again": "لا تطلب التأكيد مرة أخرى", "confirmations.deprecated_settings.confirm": "استخدام تفضيلات ماستدون", + "confirmations.deprecated_settings.message": "تم استبدال بعض من الجهاز الخاص بالماستدون {preferences} الذي تستخدمه {app_settings} الخاص بجهاز ماستدون سيتم تجاوزه:", "confirmations.missing_media_description.confirm": "أرسل على أيّة حال", "confirmations.missing_media_description.edit": "تعديل الوسائط", "confirmations.unfilter.author": "المؤلف", "confirmations.unfilter.confirm": "عرض", "confirmations.unfilter.edit_filter": "تعديل عامل التصفية", + "confirmations.unfilter.filters": "مطابقة {count, plural, zero {}one {فلتر} two {فلاتر} few {فلاتر} many {فلاتر} other {فلاتر}}", "content-type.change": "نوع المحتوى", "direct.group_by_conversations": "تجميع حسب المحادثة", "endorsed_accounts_editor.endorsed_accounts": "الحسابات المميزة", @@ -61,6 +63,10 @@ "notification_purge.start": "أدخل وضع تنظيف الإشعارات", "notifications.marked_clear": "مسح الإشعارات المحددة", "notifications.marked_clear_confirmation": "هل أنت متأكد من أنك تريد مسح جميع الإشعارات المحددة نهائياً؟", + "settings.always_show_spoilers_field": "تمكين دائما حقل تحذير المحتوى", + "settings.auto_collapse_height": "الارتفاع (بالبكسل) لاعتبار التبويق طويل", + "settings.auto_collapse_reblogs": "دفع", + "settings.auto_collapse_replies": "ردود {{count}}", "settings.close": "إغلاق", "settings.content_warnings": "Content warnings", "settings.preferences": "Preferences" diff --git a/app/javascript/flavours/glitch/locales/de.json b/app/javascript/flavours/glitch/locales/de.json index a83c4df787..96650a5efa 100644 --- a/app/javascript/flavours/glitch/locales/de.json +++ b/app/javascript/flavours/glitch/locales/de.json @@ -2,6 +2,7 @@ "about.fork_disclaimer": "Glitch-soc ist freie, quelloffene Software geforkt von Mastodon.", "account.disclaimer_full": "Die folgenden Informationen könnten das Profil des Nutzers unvollständig wiedergeben.", "account.follows": "Folgt", + "account.follows_you": "Folgt dir", "account.joined": "Beigetreten am {date}", "account.suspended_disclaimer_full": "Dieser Nutzer wurde durch einen Moderator gesperrt.", "account.view_full_profile": "Vollständiges Profil anzeigen", diff --git a/app/javascript/flavours/glitch/locales/es-AR.json b/app/javascript/flavours/glitch/locales/es-AR.json index 860c2c0beb..48ae0f0683 100644 --- a/app/javascript/flavours/glitch/locales/es-AR.json +++ b/app/javascript/flavours/glitch/locales/es-AR.json @@ -2,6 +2,7 @@ "about.fork_disclaimer": "Glitch-soc es software gratuito, de código abierto, bifurcado de Mastodon.", "account.disclaimer_full": "La información aquí presentada puede reflejar de manera incompleta el perfil del usuario.", "account.follows": "Sigue", + "account.follows_you": "Te sigue", "account.joined": "Unido el {date}", "account.suspended_disclaimer_full": "Este usuario ha sido suspendido por un moderador.", "account.view_full_profile": "Ver perfil completo", diff --git a/app/javascript/flavours/glitch/locales/es-MX.json b/app/javascript/flavours/glitch/locales/es-MX.json index 00b87e9c12..bb0a5ab74f 100644 --- a/app/javascript/flavours/glitch/locales/es-MX.json +++ b/app/javascript/flavours/glitch/locales/es-MX.json @@ -2,6 +2,7 @@ "about.fork_disclaimer": "Glitch-soc es software gratuito, de código abierto, bifurcado de Mastodon.", "account.disclaimer_full": "La información aquí presentada puede reflejar de manera incompleta el perfil del usuario.", "account.follows": "Seguir", + "account.follows_you": "Te sigue", "account.joined": "Unido {date}", "account.suspended_disclaimer_full": "Este usuario ha sido suspendido por un moderador.", "account.view_full_profile": "Ver perfil completo", diff --git a/app/javascript/flavours/glitch/locales/es.json b/app/javascript/flavours/glitch/locales/es.json index b7f266aa3e..35f0fa8deb 100644 --- a/app/javascript/flavours/glitch/locales/es.json +++ b/app/javascript/flavours/glitch/locales/es.json @@ -2,6 +2,7 @@ "about.fork_disclaimer": "Glitch-soc es software gratuito, de código abierto, bifurcado de Mastodon.", "account.disclaimer_full": "La información que figura a continuación puede reflejar el perfil de la cuenta de forma incompleta.", "account.follows": "Sigue", + "account.follows_you": "Te sigue", "account.joined": "Se unió el {date}", "account.suspended_disclaimer_full": "Este usuario ha sido suspendido por un moderador.", "account.view_full_profile": "Ver perfil completo", diff --git a/app/javascript/flavours/glitch/locales/fr-CA.json b/app/javascript/flavours/glitch/locales/fr-CA.json new file mode 100644 index 0000000000..6015f4097d --- /dev/null +++ b/app/javascript/flavours/glitch/locales/fr-CA.json @@ -0,0 +1,159 @@ +{ + "about.fork_disclaimer": "Glitch-soc est un logiciel gratuit et open source, fork de Mastodon.", + "account.disclaimer_full": "Les informations ci-dessous peuvent être incomplètes.", + "account.follows": "Abonnements", + "account.follows_you": "Vous suit", + "account.joined": "Ici depuis {date}", + "account.suspended_disclaimer_full": "Cet utilisateur a été suspendu par un modérateur.", + "account.view_full_profile": "Voir le profil complet", + "advanced_options.icon_title": "Options avancées", + "advanced_options.local-only.long": "Ne pas envoyer aux autres instances", + "advanced_options.local-only.short": "Uniquement en local", + "advanced_options.local-only.tooltip": "Ce post est uniquement local", + "advanced_options.threaded_mode.long": "Ouvre automatiquement une réponse lors de la publication", + "advanced_options.threaded_mode.short": "Mode thread", + "advanced_options.threaded_mode.tooltip": "Mode thread activé", + "boost_modal.missing_description": "Ce post contient des médias sans description", + "column.favourited_by": "Ajouté en favori par", + "column.heading": "Divers", + "column.reblogged_by": "Partagé par", + "column.subheading": "Autres options", + "column_header.profile": "Profil", + "column_subheading.lists": "Listes", + "column_subheading.navigation": "Navigation", + "community.column_settings.allow_local_only": "Afficher seulement les posts locaux", + "compose.attach": "Joindre…", + "compose.attach.doodle": "Dessiner quelque chose", + "compose.attach.upload": "Téléverser un fichier", + "compose.content-type.html": "HTML", + "compose.content-type.markdown": "Markdown", + "compose.content-type.plain": "Text brut", + "compose_form.poll.multiple_choices": "Choix multiples", + "compose_form.poll.single_choice": "Choix unique", + "compose_form.spoiler": "Cacher le texte derrière un avertissement", + "confirmation_modal.do_not_ask_again": "Ne plus demander confirmation", + "confirmations.deprecated_settings.confirm": "Utiliser les préférences de Mastodon", + "confirmations.deprecated_settings.message": "Certaines {app_settings} de glitch-soc que vous utilisez ont été remplacées par les {preferences} de Mastodon et seront remplacées :", + "confirmations.missing_media_description.confirm": "Envoyer quand même", + "confirmations.missing_media_description.edit": "Modifier le média", + "confirmations.missing_media_description.message": "Au moins un média joint manque d'une description. Pensez à décrire tous les médias attachés pour les malvoyant·e·s avant de publier votre post.", + "confirmations.unfilter.author": "Auteur", + "confirmations.unfilter.confirm": "Afficher", + "confirmations.unfilter.edit_filter": "Modifier le filtre", + "confirmations.unfilter.filters": "Correspondance avec {count, plural, one {un filtre} other {plusieurs filtres}}", + "content-type.change": "Type de contenu", + "direct.group_by_conversations": "Grouper par conversation", + "endorsed_accounts_editor.endorsed_accounts": "Comptes mis en avant", + "favourite_modal.combo": "Vous pouvez appuyer sur {combo} pour passer ceci la prochaine fois", + "firehose.column_settings.allow_local_only": "Afficher les messages locaux dans \"Tous\"", + "home.column_settings.advanced": "Avancé", + "home.column_settings.filter_regex": "Filtrer par expression régulière", + "home.column_settings.show_direct": "Afficher les MPs", + "home.settings": "Paramètres de la colonne", + "keyboard_shortcuts.bookmark": "ajouter aux marque-pages", + "keyboard_shortcuts.secondary_toot": "Envoyer le post en utilisant les paramètres secondaires de confidentialité", + "keyboard_shortcuts.toggle_collapse": "Plier/déplier les posts", + "media_gallery.sensitive": "Sensible", + "moved_to_warning": "Ce compte a déménagé vers {moved_to_link} et ne peut donc plus accepter de nouveaux abonné·e·s.", + "navigation_bar.app_settings": "Paramètres de l'application", + "navigation_bar.featured_users": "Utilisateurs mis en avant", + "navigation_bar.keyboard_shortcuts": "Raccourcis clavier", + "navigation_bar.misc": "Autres", + "notification.markForDeletion": "Ajouter aux éléments à supprimer", + "notification_purge.btn_all": "Sélectionner\ntout", + "notification_purge.btn_apply": "Effacer\nla sélection", + "notification_purge.btn_invert": "Inverser\nla sélection", + "notification_purge.btn_none": "Annuler\nla sélection", + "notification_purge.start": "Activer le mode de nettoyage des notifications", + "notifications.marked_clear": "Effacer les notifications sélectionnées", + "notifications.marked_clear_confirmation": "Voulez-vous vraiment effacer de manière permanente toutes les notifications sélectionnées ?", + "settings.always_show_spoilers_field": "Toujours activer le champ de rédaction de l'avertissement de contenu", + "settings.auto_collapse": "Repliage automatique", + "settings.auto_collapse_all": "Tout", + "settings.auto_collapse_height": "Hauteur (en pixels) pour qu'un pouet soit considéré comme long", + "settings.auto_collapse_lengthy": "Posts longs", + "settings.auto_collapse_media": "Posts avec média", + "settings.auto_collapse_notifications": "Notifications", + "settings.auto_collapse_reblogs": "Boosts", + "settings.auto_collapse_replies": "Réponses", + "settings.close": "Fermer", + "settings.collapsed_statuses": "Posts repliés", + "settings.compose_box_opts": "Zone de rédaction", + "settings.confirm_before_clearing_draft": "Afficher une fenêtre de confirmation avant d'écraser le message en cours de rédaction", + "settings.confirm_boost_missing_media_description": "Afficher une fenêtre de confirmation avant de partager des posts manquant de description des médias", + "settings.confirm_missing_media_description": "Afficher une fenêtre de confirmation avant de publier des posts manquant de description de média", + "settings.content_warnings": "Content warnings", + "settings.content_warnings.regexp": "Expression rationnelle", + "settings.content_warnings_filter": "Avertissement de contenu à ne pas automatiquement déplier :", + "settings.content_warnings_media_outside": "Afficher les médias en dehors des avertissements de contenu", + "settings.content_warnings_media_outside_hint": "Reproduit le comportement par défaut de Mastodon, les médias attachés ne sont plus affectés par le bouton d'affichage d'un post avec avertissement", + "settings.content_warnings_shared_state": "Affiche/cache le contenu de toutes les copies à la fois", + "settings.content_warnings_shared_state_hint": "Reproduit le comportement par défaut de Mastodon, le bouton d'avertissement de contenu affecte toutes les copies d'un post à la fois. Cela empêchera le repliement automatique de n'importe quelle copie d'un post avec un avertissement déplié", + "settings.content_warnings_unfold_opts": "Options de dépliement automatique", + "settings.deprecated_setting": "Cette option est maintenant définie par les {settings_page_link} de Mastodon", + "settings.enable_collapsed": "Activer le repliement des posts", + "settings.enable_collapsed_hint": "Les posts repliés ont une partie de leur contenu caché pour libérer de l'espace sur l'écran. C'est une option différente de l'avertissement de contenu", + "settings.enable_content_warnings_auto_unfold": "Déplier automatiquement les avertissements de contenu", + "settings.general": "Général", + "settings.hicolor_privacy_icons": "Indicateurs de confidentialité en couleurs", + "settings.hicolor_privacy_icons.hint": "Affiche les indicateurs de confidentialité dans des couleurs facilement distinguables", + "settings.image_backgrounds": "Images en arrière-plan", + "settings.image_backgrounds_media": "Prévisualiser les médias d'un post replié", + "settings.image_backgrounds_media_hint": "Si le post a un média attaché, utiliser le premier comme arrière-plan du post", + "settings.image_backgrounds_users": "Donner aux posts repliés une image en arrière-plan", + "settings.inline_preview_cards": "Cartes d'aperçu pour les liens externes", + "settings.layout_opts": "Mise en page", + "settings.media": "Média", + "settings.media_fullwidth": "Utiliser toute la largeur pour les aperçus", + "settings.media_letterbox": "Afficher les médias en Letterbox", + "settings.media_letterbox_hint": "Réduit le média et utilise une letterbox pour afficher l'image entière plutôt que de l'étirer et de la rogner", + "settings.media_reveal_behind_cw": "Toujours afficher les médias sensibles avec avertissement", + "settings.notifications.favicon_badge": "Badge de notifications non lues dans la favicon", + "settings.notifications.favicon_badge.hint": "Ajoute un badge dans la favicon pour alerter d'une notification non lue", + "settings.notifications.tab_badge": "Badge de notifications non lues", + "settings.notifications.tab_badge.hint": "Affiche un badge de notifications non lues dans les icônes des colonnes quand la colonne n'est pas ouverte", + "settings.notifications_opts": "Options des notifications", + "settings.pop_in_left": "Gauche", + "settings.pop_in_player": "Activer le lecteur pop-in", + "settings.pop_in_position": "Position du lecteur pop-in :", + "settings.pop_in_right": "Droite", + "settings.preferences": "Preferences", + "settings.prepend_cw_re": "Préfixer les avertissements avec \"re: \" lors d'une réponse", + "settings.preselect_on_reply": "Présélectionner les noms d’utilisateur·rices lors de la réponse", + "settings.preselect_on_reply_hint": "Présélectionner les noms d'utilisateurs après le premier lors d'une réponse à une conversation à plusieurs participants", + "settings.rewrite_mentions": "Réécrire les mentions dans les posts affichés", + "settings.rewrite_mentions_acct": "Réécrire avec le nom d'utilisateur·rice et le domaine (lorsque le compte est distant)", + "settings.rewrite_mentions_no": "Ne pas réécrire les mentions", + "settings.rewrite_mentions_username": "Réécrire avec le nom d’utilisateur·rice", + "settings.shared_settings_link": "préférences de l'utilisateur", + "settings.show_action_bar": "Afficher les boutons d'action dans les posts repliés", + "settings.show_content_type_choice": "Afficher le choix du type de contenu lors de la création des posts", + "settings.show_reply_counter": "Afficher une estimation du nombre de réponses", + "settings.side_arm": "Bouton secondaire de publication :", + "settings.side_arm.none": "Aucun", + "settings.side_arm_reply_mode": "Quand vous répondez à un post, le bouton secondaire de publication devrait :", + "settings.side_arm_reply_mode.copy": "Copier la confidentialité du post auquel vous répondez", + "settings.side_arm_reply_mode.keep": "Garder la confidentialité établie", + "settings.side_arm_reply_mode.restrict": "Restreindre la confidentialité de la réponse à celle du post auquel vous répondez", + "settings.status_icons": "Icônes des posts", + "settings.status_icons_language": "Indicateur de langue", + "settings.status_icons_local_only": "Indicateur de post local", + "settings.status_icons_media": "Indicateur de médias et sondage", + "settings.status_icons_reply": "Indicateur de réponses", + "settings.status_icons_visibility": "Indicateur de la confidentialité du post", + "settings.swipe_to_change_columns": "Glissement latéral pour changer de colonne (mobile uniquement)", + "settings.tag_misleading_links": "Étiqueter les liens trompeurs", + "settings.tag_misleading_links.hint": "Ajouter une indication visuelle avec l'hôte cible du lien à chaque lien ne le mentionnant pas explicitement", + "settings.wide_view": "Vue élargie (mode ordinateur uniquement)", + "settings.wide_view_hint": "Étire les colonnes pour mieux remplir l'espace disponible.", + "status.collapse": "Replier", + "status.has_audio": "Contient des fichiers audio attachés", + "status.has_pictures": "Contient des images attachées", + "status.has_preview_card": "Contient une carte de prévisualisation attachée", + "status.has_video": "Contient des vidéos attachées", + "status.in_reply_to": "Ce post est une réponse", + "status.is_poll": "Ce post est un sondage", + "status.local_only": "Visible uniquement depuis votre instance", + "status.sensitive_toggle": "Cliquer pour voir", + "status.uncollapse": "Déplier" +} diff --git a/app/javascript/flavours/glitch/locales/fr.json b/app/javascript/flavours/glitch/locales/fr.json index a9d0108ce4..6015f4097d 100644 --- a/app/javascript/flavours/glitch/locales/fr.json +++ b/app/javascript/flavours/glitch/locales/fr.json @@ -2,6 +2,7 @@ "about.fork_disclaimer": "Glitch-soc est un logiciel gratuit et open source, fork de Mastodon.", "account.disclaimer_full": "Les informations ci-dessous peuvent être incomplètes.", "account.follows": "Abonnements", + "account.follows_you": "Vous suit", "account.joined": "Ici depuis {date}", "account.suspended_disclaimer_full": "Cet utilisateur a été suspendu par un modérateur.", "account.view_full_profile": "Voir le profil complet", diff --git a/app/javascript/flavours/glitch/locales/ko.json b/app/javascript/flavours/glitch/locales/ko.json index 96f0b7aa97..49fcb0b46a 100644 --- a/app/javascript/flavours/glitch/locales/ko.json +++ b/app/javascript/flavours/glitch/locales/ko.json @@ -2,6 +2,7 @@ "about.fork_disclaimer": "글리치는 마스토돈에서 포크한 자유 오픈소스 소프트웨어입니다.", "account.disclaimer_full": "아래에 있는 정보들은 사용자의 프로필을 완벽하게 나타내지 못하고 있을 수도 있습니다.", "account.follows": "팔로우", + "account.follows_you": "날 팔로우합니다", "account.joined": "{date}에 가입함", "account.suspended_disclaimer_full": "이 사용자는 중재자에 의해 정지되었습니다.", "account.view_full_profile": "전체 프로필 보기", @@ -44,6 +45,7 @@ "direct.group_by_conversations": "대화별로 묶기", "endorsed_accounts_editor.endorsed_accounts": "추천하는 계정들", "favourite_modal.combo": "다음엔 {combo}를 눌러 건너뛸 수 있습니다", + "firehose.column_settings.allow_local_only": "\"모두\" 탭에서 로컬 전용 글 보여주기", "home.column_settings.advanced": "고급", "home.column_settings.filter_regex": "정규표현식으로 필터", "home.column_settings.show_direct": "DM 보여주기", diff --git a/app/javascript/flavours/glitch/locales/vi.json b/app/javascript/flavours/glitch/locales/vi.json index d360fed722..0967ef424b 100644 --- a/app/javascript/flavours/glitch/locales/vi.json +++ b/app/javascript/flavours/glitch/locales/vi.json @@ -1,4 +1 @@ -{ - "settings.content_warnings": "Content warnings", - "settings.preferences": "Preferences" -} +{} diff --git a/app/javascript/flavours/glitch/locales/zh-CN.json b/app/javascript/flavours/glitch/locales/zh-CN.json index 5a620c9346..742624108c 100644 --- a/app/javascript/flavours/glitch/locales/zh-CN.json +++ b/app/javascript/flavours/glitch/locales/zh-CN.json @@ -1,7 +1,8 @@ { - "about.fork_disclaimer": "Glitch-soc是从Mastodon派生的自由开源软件。", - "account.disclaimer_full": "以下信息可能无法完整代表你的个人资料。", + "about.fork_disclaimer": "Glitch-soc是从Mastodon生成的免费开源软件。", + "account.disclaimer_full": "下面的信息可能不完全反映用户的个人资料。", "account.follows": "正在关注", + "account.follows_you": "关注了你", "account.joined": "加入于 {date}", "account.suspended_disclaimer_full": "该用户已被管理员封禁。", "account.view_full_profile": "查看完整资料", diff --git a/app/javascript/flavours/glitch/locales/zh-TW.json b/app/javascript/flavours/glitch/locales/zh-TW.json index fcd4f4a3a6..414bd44f78 100644 --- a/app/javascript/flavours/glitch/locales/zh-TW.json +++ b/app/javascript/flavours/glitch/locales/zh-TW.json @@ -2,6 +2,7 @@ "about.fork_disclaimer": "Glitch-soc 是從 Mastodon 分支出來的自由開源軟體。", "account.disclaimer_full": "下面的資訊可能不完全反映使用者的個人資料。", "account.follows": "跟隨", + "account.follows_you": "跟隨了您", "account.joined": "加入於 {date}", "account.suspended_disclaimer_full": "使用者已被管理者停權。", "account.view_full_profile": "查看完整個人資料", diff --git a/app/javascript/flavours/glitch/reducers/accounts.ts b/app/javascript/flavours/glitch/reducers/accounts.ts index 345bff06ce..c9d7b5fe12 100644 --- a/app/javascript/flavours/glitch/reducers/accounts.ts +++ b/app/javascript/flavours/glitch/reducers/accounts.ts @@ -59,25 +59,19 @@ export const accountsReducer: Reducer = ( return normalizeAccounts(state, action.payload.accounts); else if (followAccountSuccess.match(action)) { return state - .update( - action.payload.relationship.id, - (account) => account?.update('followers_count', (n) => n + 1), + .update(action.payload.relationship.id, (account) => + account?.update('followers_count', (n) => n + 1), ) - .update( - getCurrentUser(), - (account) => account?.update('following_count', (n) => n + 1), + .update(getCurrentUser(), (account) => + account?.update('following_count', (n) => n + 1), ); } else if (unfollowAccountSuccess.match(action)) return state - .update( - action.payload.relationship.id, - (account) => - account?.update('followers_count', (n) => Math.max(0, n - 1)), + .update(action.payload.relationship.id, (account) => + account?.update('followers_count', (n) => Math.max(0, n - 1)), ) - .update( - getCurrentUser(), - (account) => - account?.update('following_count', (n) => Math.max(0, n - 1)), + .update(getCurrentUser(), (account) => + account?.update('following_count', (n) => Math.max(0, n - 1)), ); else return state; }; diff --git a/app/javascript/flavours/glitch/reducers/statuses.js b/app/javascript/flavours/glitch/reducers/statuses.js index e9048bb3c0..1d881b2a85 100644 --- a/app/javascript/flavours/glitch/reducers/statuses.js +++ b/app/javascript/flavours/glitch/reducers/statuses.js @@ -137,6 +137,14 @@ export default function statuses(state = initialState, action) { return state.setIn([action.status.get('id'), 'reblogged'], true); case REBLOG_FAIL: return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], false); + case REACTION_UPDATE: + return updateReactionCount(state, action.reaction); + case REACTION_ADD_REQUEST: + case REACTION_REMOVE_FAIL: + return addReaction(state, action.id, action.name, action.url); + case REACTION_REMOVE_REQUEST: + case REACTION_ADD_FAIL: + return removeReaction(state, action.id, action.name); case UNREBLOG_REQUEST: return state.setIn([action.status.get('id'), 'reblogged'], false); case UNREBLOG_FAIL: diff --git a/app/javascript/flavours/glitch/store/typed_functions.ts b/app/javascript/flavours/glitch/store/typed_functions.ts index 46a10b8b47..4859b82651 100644 --- a/app/javascript/flavours/glitch/store/typed_functions.ts +++ b/app/javascript/flavours/glitch/store/typed_functions.ts @@ -1,12 +1,11 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; -import type { TypedUseSelectorHook } from 'react-redux'; // eslint-disable-next-line @typescript-eslint/no-restricted-imports import { useDispatch, useSelector } from 'react-redux'; import type { AppDispatch, RootState } from './store'; -export const useAppDispatch: () => AppDispatch = useDispatch; -export const useAppSelector: TypedUseSelectorHook = useSelector; +export const useAppDispatch = useDispatch.withTypes(); +export const useAppSelector = useSelector.withTypes(); export const createAppAsyncThunk = createAsyncThunk.withTypes<{ state: RootState; diff --git a/app/javascript/flavours/glitch/styles/components/accounts.scss b/app/javascript/flavours/glitch/styles/components/accounts.scss index aef9580ecc..c698e63d14 100644 --- a/app/javascript/flavours/glitch/styles/components/accounts.scss +++ b/app/javascript/flavours/glitch/styles/components/accounts.scss @@ -161,6 +161,7 @@ padding: 10px; gap: 5px; color: $dark-text-color; + align-items: center; strong { font-weight: 500; @@ -624,6 +625,13 @@ span { user-select: all; } + + .icon-lock { + height: 16px; + width: 16px; + position: relative; + top: 3px; + } } } } @@ -669,16 +677,13 @@ .icon { width: 18px; height: 18px; + vertical-align: middle; } dd { display: flex; align-items: center; gap: 4px; - - span { - display: flex; - } } .verified a { diff --git a/app/javascript/flavours/glitch/styles/components/columns.scss b/app/javascript/flavours/glitch/styles/components/columns.scss index ee8fe614ae..4e13278715 100644 --- a/app/javascript/flavours/glitch/styles/components/columns.scss +++ b/app/javascript/flavours/glitch/styles/components/columns.scss @@ -241,7 +241,7 @@ $ui-header-height: 55px; align-items: center; gap: 5px; font-size: 16px; - padding: 15px; + padding: 13px; text-decoration: none; overflow: hidden; white-space: nowrap; @@ -359,7 +359,7 @@ $ui-header-height: 55px; gap: 5px; margin: 0; border: 0; - padding: 15px; + padding: 13px; color: inherit; background: transparent; font: inherit; diff --git a/app/javascript/flavours/glitch/styles/components/drawer.scss b/app/javascript/flavours/glitch/styles/components/drawer.scss index 0669eb245c..2b777f89f9 100644 --- a/app/javascript/flavours/glitch/styles/components/drawer.scss +++ b/app/javascript/flavours/glitch/styles/components/drawer.scss @@ -52,7 +52,7 @@ .drawer__tab { display: flex; flex: 1 1 auto; - padding: 15px 5px 13px; + padding: 13px 3px 11px; color: $darker-text-color; text-decoration: none; text-align: center; diff --git a/app/javascript/flavours/glitch/styles/components/media.scss b/app/javascript/flavours/glitch/styles/components/media.scss index e0c054aae8..ac05e7742a 100644 --- a/app/javascript/flavours/glitch/styles/components/media.scss +++ b/app/javascript/flavours/glitch/styles/components/media.scss @@ -51,6 +51,7 @@ gap: 2px; } +.media-gallery__alt__label, .media-gallery__gifv__label { display: flex; align-items: center; diff --git a/app/javascript/flavours/glitch/styles/components/misc.scss b/app/javascript/flavours/glitch/styles/components/misc.scss index b72a0a1fa2..abb59d73be 100644 --- a/app/javascript/flavours/glitch/styles/components/misc.scss +++ b/app/javascript/flavours/glitch/styles/components/misc.scss @@ -171,8 +171,8 @@ .icon { flex: 0 0 auto; - width: 20px; - height: 20px; + width: 24px; + height: 24px; aspect-ratio: 1; path { @@ -184,7 +184,7 @@ display: inline-flex; color: $action-button-color; border: 0; - padding: 2px; + padding: 0; border-radius: 4px; background: transparent; cursor: pointer; diff --git a/app/javascript/flavours/glitch/styles/components/modal.scss b/app/javascript/flavours/glitch/styles/components/modal.scss index 9d1930ff0b..8f008a3c58 100644 --- a/app/javascript/flavours/glitch/styles/components/modal.scss +++ b/app/javascript/flavours/glitch/styles/components/modal.scss @@ -492,6 +492,10 @@ padding-inline-end: 10px; } + .icon { + vertical-align: middle; + } + .button { flex: 0 0 auto; } diff --git a/app/javascript/flavours/glitch/styles/components/status.scss b/app/javascript/flavours/glitch/styles/components/status.scss index cfcbce7af6..51c302c33b 100644 --- a/app/javascript/flavours/glitch/styles/components/status.scss +++ b/app/javascript/flavours/glitch/styles/components/status.scss @@ -242,6 +242,7 @@ line-height: inherit; cursor: pointer; vertical-align: top; + align-items: center; &:hover { background: lighten($ui-base-color, 33%); @@ -254,6 +255,8 @@ border-inline-start: 1px solid currentColor; padding: 0; padding-inline-start: 4px; + width: 16px; + height: 16px; } } @@ -739,8 +742,7 @@ .icon { width: 15px; height: 15px; - position: relative; - top: 0.145em; + vertical-align: middle; } } @@ -1153,6 +1155,7 @@ a.status-card.compact:hover { .icon { color: $dark-text-color; + vertical-align: middle; } } } diff --git a/app/javascript/fonts/inter/inter-variable-font-slnt-wght.woff2 b/app/javascript/fonts/inter/inter-variable-font-slnt-wght.woff2 new file mode 100644 index 0000000000..e6345f2e3d Binary files /dev/null and b/app/javascript/fonts/inter/inter-variable-font-slnt-wght.woff2 differ diff --git a/app/javascript/images/mailer-new/common/header-bg-end.png b/app/javascript/images/mailer-new/common/header-bg-end.png new file mode 100644 index 0000000000..900196678a Binary files /dev/null and b/app/javascript/images/mailer-new/common/header-bg-end.png differ diff --git a/app/javascript/images/mailer-new/common/header-bg-start.png b/app/javascript/images/mailer-new/common/header-bg-start.png new file mode 100644 index 0000000000..0037c1ad93 Binary files /dev/null and b/app/javascript/images/mailer-new/common/header-bg-start.png differ diff --git a/app/javascript/images/mailer-new/common/logo-footer.png b/app/javascript/images/mailer-new/common/logo-footer.png new file mode 100644 index 0000000000..2baafd8d7f Binary files /dev/null and b/app/javascript/images/mailer-new/common/logo-footer.png differ diff --git a/app/javascript/images/mailer-new/common/logo-header.png b/app/javascript/images/mailer-new/common/logo-header.png new file mode 100644 index 0000000000..46a6bddaa1 Binary files /dev/null and b/app/javascript/images/mailer-new/common/logo-header.png differ diff --git a/app/javascript/images/mailer-new/heading/2fa-disabled.png b/app/javascript/images/mailer-new/heading/2fa-disabled.png new file mode 100644 index 0000000000..b1e342a87c Binary files /dev/null and b/app/javascript/images/mailer-new/heading/2fa-disabled.png differ diff --git a/app/javascript/images/mailer-new/heading/2fa-enabled.png b/app/javascript/images/mailer-new/heading/2fa-enabled.png new file mode 100644 index 0000000000..3ce3e04f84 Binary files /dev/null and b/app/javascript/images/mailer-new/heading/2fa-enabled.png differ diff --git a/app/javascript/images/mailer-new/heading/2fa-recovery.png b/app/javascript/images/mailer-new/heading/2fa-recovery.png new file mode 100644 index 0000000000..cefb21e1eb Binary files /dev/null and b/app/javascript/images/mailer-new/heading/2fa-recovery.png differ diff --git a/app/javascript/images/mailer-new/heading/appeal-approved.png b/app/javascript/images/mailer-new/heading/appeal-approved.png new file mode 100755 index 0000000000..b2476ec346 Binary files /dev/null and b/app/javascript/images/mailer-new/heading/appeal-approved.png differ diff --git a/app/javascript/images/mailer-new/heading/appeal-rejected.png b/app/javascript/images/mailer-new/heading/appeal-rejected.png new file mode 100644 index 0000000000..7ae38ad0c1 Binary files /dev/null and b/app/javascript/images/mailer-new/heading/appeal-rejected.png differ diff --git a/app/javascript/images/mailer-new/heading/archive.png b/app/javascript/images/mailer-new/heading/archive.png new file mode 100644 index 0000000000..b0c7fad84d Binary files /dev/null and b/app/javascript/images/mailer-new/heading/archive.png differ diff --git a/app/javascript/images/mailer-new/heading/boost.png b/app/javascript/images/mailer-new/heading/boost.png new file mode 100644 index 0000000000..e33b759976 Binary files /dev/null and b/app/javascript/images/mailer-new/heading/boost.png differ diff --git a/app/javascript/images/mailer-new/heading/email.png b/app/javascript/images/mailer-new/heading/email.png new file mode 100644 index 0000000000..c922c5239e Binary files /dev/null and b/app/javascript/images/mailer-new/heading/email.png differ diff --git a/app/javascript/images/mailer-new/heading/favorite.png b/app/javascript/images/mailer-new/heading/favorite.png new file mode 100644 index 0000000000..0e483ee9b2 Binary files /dev/null and b/app/javascript/images/mailer-new/heading/favorite.png differ diff --git a/app/javascript/images/mailer-new/heading/follow.png b/app/javascript/images/mailer-new/heading/follow.png new file mode 100644 index 0000000000..ff5b7e0042 Binary files /dev/null and b/app/javascript/images/mailer-new/heading/follow.png differ diff --git a/app/javascript/images/mailer-new/heading/key-added.png b/app/javascript/images/mailer-new/heading/key-added.png new file mode 100755 index 0000000000..82dcd464bf Binary files /dev/null and b/app/javascript/images/mailer-new/heading/key-added.png differ diff --git a/app/javascript/images/mailer-new/heading/key-deleted.png b/app/javascript/images/mailer-new/heading/key-deleted.png new file mode 100755 index 0000000000..2930f591a0 Binary files /dev/null and b/app/javascript/images/mailer-new/heading/key-deleted.png differ diff --git a/app/javascript/images/mailer-new/heading/key-disabled.png b/app/javascript/images/mailer-new/heading/key-disabled.png new file mode 100755 index 0000000000..e0f259359a Binary files /dev/null and b/app/javascript/images/mailer-new/heading/key-disabled.png differ diff --git a/app/javascript/images/mailer-new/heading/key-enabled.png b/app/javascript/images/mailer-new/heading/key-enabled.png new file mode 100644 index 0000000000..b2476ec346 Binary files /dev/null and b/app/javascript/images/mailer-new/heading/key-enabled.png differ diff --git a/app/javascript/images/mailer-new/heading/login.png b/app/javascript/images/mailer-new/heading/login.png new file mode 100644 index 0000000000..89a6e9ee33 Binary files /dev/null and b/app/javascript/images/mailer-new/heading/login.png differ diff --git a/app/javascript/images/mailer-new/heading/mention.png b/app/javascript/images/mailer-new/heading/mention.png new file mode 100644 index 0000000000..c4dccff8ef Binary files /dev/null and b/app/javascript/images/mailer-new/heading/mention.png differ diff --git a/app/javascript/images/mailer-new/heading/password.png b/app/javascript/images/mailer-new/heading/password.png new file mode 100755 index 0000000000..552c7c0687 Binary files /dev/null and b/app/javascript/images/mailer-new/heading/password.png differ diff --git a/app/javascript/images/mailer-new/heading/reaction.png b/app/javascript/images/mailer-new/heading/reaction.png new file mode 100644 index 0000000000..2e2969953e Binary files /dev/null and b/app/javascript/images/mailer-new/heading/reaction.png differ diff --git a/app/javascript/images/mailer-new/heading/user.png b/app/javascript/images/mailer-new/heading/user.png new file mode 100644 index 0000000000..f1dd58a18d Binary files /dev/null and b/app/javascript/images/mailer-new/heading/user.png differ diff --git a/app/javascript/images/mailer-new/heading/warning.png b/app/javascript/images/mailer-new/heading/warning.png new file mode 100755 index 0000000000..7764837abe Binary files /dev/null and b/app/javascript/images/mailer-new/heading/warning.png differ diff --git a/app/javascript/images/mailer-new/welcome/checkbox-off.png b/app/javascript/images/mailer-new/welcome/checkbox-off.png new file mode 100644 index 0000000000..51c190efe6 Binary files /dev/null and b/app/javascript/images/mailer-new/welcome/checkbox-off.png differ diff --git a/app/javascript/images/mailer-new/welcome/checkbox-on.png b/app/javascript/images/mailer-new/welcome/checkbox-on.png new file mode 100644 index 0000000000..162095e7df Binary files /dev/null and b/app/javascript/images/mailer-new/welcome/checkbox-on.png differ diff --git a/app/javascript/images/mailer-new/welcome/step1-on.png b/app/javascript/images/mailer-new/welcome/step1-on.png new file mode 100644 index 0000000000..c3776d17df Binary files /dev/null and b/app/javascript/images/mailer-new/welcome/step1-on.png differ diff --git a/app/javascript/images/mailer-new/welcome/step2-off.png b/app/javascript/images/mailer-new/welcome/step2-off.png new file mode 100755 index 0000000000..a262454d2d Binary files /dev/null and b/app/javascript/images/mailer-new/welcome/step2-off.png differ diff --git a/app/javascript/images/mailer-new/welcome/step3-off.png b/app/javascript/images/mailer-new/welcome/step3-off.png new file mode 100755 index 0000000000..972de65a56 Binary files /dev/null and b/app/javascript/images/mailer-new/welcome/step3-off.png differ diff --git a/app/javascript/images/mailer-new/welcome/step4-off.png b/app/javascript/images/mailer-new/welcome/step4-off.png new file mode 100755 index 0000000000..f45e9a2c9a Binary files /dev/null and b/app/javascript/images/mailer-new/welcome/step4-off.png differ diff --git a/app/javascript/images/mailer-new/welcome/step5-off.png b/app/javascript/images/mailer-new/welcome/step5-off.png new file mode 100755 index 0000000000..ca270f5478 Binary files /dev/null and b/app/javascript/images/mailer-new/welcome/step5-off.png differ diff --git a/app/javascript/mastodon/actions/search.js b/app/javascript/mastodon/actions/search.js index 38a089b486..a34a490e76 100644 --- a/app/javascript/mastodon/actions/search.js +++ b/app/javascript/mastodon/actions/search.js @@ -179,6 +179,11 @@ export const openURL = (value, history, onFailure) => (dispatch, getState) => { export const clickSearchResult = (q, type) => (dispatch, getState) => { const previous = getState().getIn(['search', 'recent']); + + if (previous.some(x => x.get('q') === q && x.get('type') === type)) { + return; + } + const me = getState().getIn(['meta', 'me']); const current = previous.add(fromJS({ type, q })).takeLast(4); @@ -207,4 +212,4 @@ export const hydrateSearch = () => (dispatch, getState) => { if (history !== null) { dispatch(updateSearchHistory(history)); } -}; \ No newline at end of file +}; diff --git a/app/javascript/mastodon/components/attachment_list.jsx b/app/javascript/mastodon/components/attachment_list.jsx index ebf092b83d..c5ac046751 100644 --- a/app/javascript/mastodon/components/attachment_list.jsx +++ b/app/javascript/mastodon/components/attachment_list.jsx @@ -7,8 +7,7 @@ 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 LinkIcon from '@/material-icons/400-24px/link.svg?react'; import { Icon } from 'mastodon/components/icon'; const filename = url => url.split('/').pop().split('#')[0].split('?')[0]; diff --git a/app/javascript/mastodon/components/badge.jsx b/app/javascript/mastodon/components/badge.jsx index 2f762fed5f..646655c249 100644 --- a/app/javascript/mastodon/components/badge.jsx +++ b/app/javascript/mastodon/components/badge.jsx @@ -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 GroupsIcon from '@/material-icons/400-24px/group.svg?react'; +import PersonIcon from '@/material-icons/400-24px/person.svg?react'; +import SmartToyIcon from '@/material-icons/400-24px/smart_toy.svg?react'; export const Badge = ({ icon, label, domain }) => ( @@ -31,4 +31,4 @@ export const GroupBadge = () => ( export const AutomatedBadge = () => ( } label={} /> -); \ No newline at end of file +); diff --git a/app/javascript/mastodon/components/column_back_button.tsx b/app/javascript/mastodon/components/column_back_button.tsx index b835e9e6ad..af38c1e110 100644 --- a/app/javascript/mastodon/components/column_back_button.tsx +++ b/app/javascript/mastodon/components/column_back_button.tsx @@ -2,8 +2,7 @@ import { useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; -import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg'; - +import ArrowBackIcon from '@/material-icons/400-24px/arrow_back.svg?react'; import { Icon } from 'mastodon/components/icon'; import { ButtonInTabsBar } from 'mastodon/features/ui/util/columns_context'; diff --git a/app/javascript/mastodon/components/column_header.jsx b/app/javascript/mastodon/components/column_header.jsx index b78bd9a8ef..901888e750 100644 --- a/app/javascript/mastodon/components/column_header.jsx +++ b/app/javascript/mastodon/components/column_header.jsx @@ -6,13 +6,12 @@ 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 AddIcon from '@/material-icons/400-24px/add.svg?react'; +import ArrowBackIcon from '@/material-icons/400-24px/arrow_back.svg?react'; +import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react'; +import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import TuneIcon from '@/material-icons/400-24px/tune.svg?react'; import { Icon } from 'mastodon/components/icon'; import { ButtonInTabsBar, useColumnsContext } from 'mastodon/features/ui/util/columns_context'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; diff --git a/app/javascript/mastodon/components/copy_icon_button.jsx b/app/javascript/mastodon/components/copy_icon_button.jsx index 9b1a36d83a..0c3c6c290b 100644 --- a/app/javascript/mastodon/components/copy_icon_button.jsx +++ b/app/javascript/mastodon/components/copy_icon_button.jsx @@ -7,8 +7,7 @@ import classNames from 'classnames'; import { useDispatch } from 'react-redux'; -import { ReactComponent as ContentCopyIcon } from '@material-symbols/svg-600/outlined/content_copy.svg'; - +import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react'; import { showAlert } from 'mastodon/actions/alerts'; import { IconButton } from 'mastodon/components/icon_button'; diff --git a/app/javascript/mastodon/components/dismissable_banner.tsx b/app/javascript/mastodon/components/dismissable_banner.tsx index 4e6d3bb9a7..bc40e46f8d 100644 --- a/app/javascript/mastodon/components/dismissable_banner.tsx +++ b/app/javascript/mastodon/components/dismissable_banner.tsx @@ -8,8 +8,7 @@ import { useCallback, useState, useEffect } from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg'; - +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { changeSetting } from 'mastodon/actions/settings'; import { bannerSettings } from 'mastodon/settings'; import { useAppSelector, useAppDispatch } from 'mastodon/store'; diff --git a/app/javascript/mastodon/components/domain.tsx b/app/javascript/mastodon/components/domain.tsx index 34c376f530..ed5e8e7e4c 100644 --- a/app/javascript/mastodon/components/domain.tsx +++ b/app/javascript/mastodon/components/domain.tsx @@ -2,7 +2,7 @@ import { useCallback } from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { ReactComponent as LockOpenIcon } from '@material-symbols/svg-600/outlined/lock_open.svg'; +import LockOpenIcon from '@/material-icons/400-24px/lock_open.svg?react'; import { IconButton } from './icon_button'; diff --git a/app/javascript/mastodon/components/dropdown_menu.jsx b/app/javascript/mastodon/components/dropdown_menu.jsx index d9cbcc32e5..04c8bb0980 100644 --- a/app/javascript/mastodon/components/dropdown_menu.jsx +++ b/app/javascript/mastodon/components/dropdown_menu.jsx @@ -6,10 +6,10 @@ 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'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { CircularProgress } from 'mastodon/components/circular_progress'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; diff --git a/app/javascript/mastodon/components/edited_timestamp/index.jsx b/app/javascript/mastodon/components/edited_timestamp/index.jsx index 4375166bcd..4ca00f8dda 100644 --- a/app/javascript/mastodon/components/edited_timestamp/index.jsx +++ b/app/javascript/mastodon/components/edited_timestamp/index.jsx @@ -5,8 +5,7 @@ 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 ArrowDropDownIcon from '@/material-icons/400-24px/arrow_drop_down.svg?react'; import { openModal } from 'mastodon/actions/modal'; import { Icon } from 'mastodon/components/icon'; import InlineAccount from 'mastodon/components/inline_account'; diff --git a/app/javascript/mastodon/components/icon.tsx b/app/javascript/mastodon/components/icon.tsx index f0af11f7f6..f388380c44 100644 --- a/app/javascript/mastodon/components/icon.tsx +++ b/app/javascript/mastodon/components/icon.tsx @@ -1,7 +1,6 @@ import classNames from 'classnames'; -import { ReactComponent as CheckBoxOutlineBlankIcon } from '@material-symbols/svg-600/outlined/check_box_outline_blank.svg'; - +import CheckBoxOutlineBlankIcon from '@/material-icons/400-24px/check_box_outline_blank.svg?react'; import { isProduction } from 'mastodon/utils/environment'; interface SVGPropsWithTitle extends React.SVGProps { diff --git a/app/javascript/mastodon/components/load_gap.tsx b/app/javascript/mastodon/components/load_gap.tsx index 27ca6648c3..1d4193a359 100644 --- a/app/javascript/mastodon/components/load_gap.tsx +++ b/app/javascript/mastodon/components/load_gap.tsx @@ -2,8 +2,7 @@ import { useCallback } from 'react'; import { useIntl, defineMessages } from 'react-intl'; -import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg'; - +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; import { Icon } from 'mastodon/components/icon'; const messages = defineMessages({ diff --git a/app/javascript/mastodon/components/logo.tsx b/app/javascript/mastodon/components/logo.tsx index 928aa29a7c..b7f8bd6695 100644 --- a/app/javascript/mastodon/components/logo.tsx +++ b/app/javascript/mastodon/components/logo.tsx @@ -1,4 +1,4 @@ -import logo from 'mastodon/../images/logo.svg'; +import logo from '@/images/logo.svg'; export const WordmarkLogo: React.FC = () => ( diff --git a/app/javascript/mastodon/components/media_gallery.jsx b/app/javascript/mastodon/components/media_gallery.jsx index 668c2a2a8a..91459a1285 100644 --- a/app/javascript/mastodon/components/media_gallery.jsx +++ b/app/javascript/mastodon/components/media_gallery.jsx @@ -8,9 +8,9 @@ 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 VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; import { Blurhash } from 'mastodon/components/blurhash'; import { autoPlayGif, displayMedia, useBlurhash } from '../initial_state'; @@ -103,7 +103,7 @@ class Item extends PureComponent { } if (attachment.get('description')?.length > 0) { - badges.push(ALT); + badges.push(ALT); } const description = attachment.getIn(['translation', 'description']) || attachment.get('description'); diff --git a/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx b/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx index 08a599cd42..50f91a9275 100644 --- a/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx +++ b/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx @@ -5,8 +5,7 @@ import { FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; -import { ReactComponent as CancelPresentationIcon } from '@material-symbols/svg-600/outlined/cancel_presentation.svg'; - +import CancelPresentationIcon from '@/material-icons/400-24px/cancel_presentation.svg?react'; import { removePictureInPicture } from 'mastodon/actions/picture_in_picture'; import { Icon } from 'mastodon/components/icon'; diff --git a/app/javascript/mastodon/components/poll.jsx b/app/javascript/mastodon/components/poll.jsx index 7cf2c57b78..c7036d111b 100644 --- a/app/javascript/mastodon/components/poll.jsx +++ b/app/javascript/mastodon/components/poll.jsx @@ -7,10 +7,10 @@ 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'; +import CheckIcon from '@/material-icons/400-24px/check.svg?react'; import { Icon } from 'mastodon/components/icon'; import emojify from 'mastodon/features/emoji/emoji'; import Motion from 'mastodon/features/ui/util/optional_motion'; diff --git a/app/javascript/mastodon/components/regeneration_indicator.jsx b/app/javascript/mastodon/components/regeneration_indicator.jsx index 052e25f25f..d42a7d7c72 100644 --- a/app/javascript/mastodon/components/regeneration_indicator.jsx +++ b/app/javascript/mastodon/components/regeneration_indicator.jsx @@ -1,6 +1,6 @@ import { FormattedMessage } from 'react-intl'; -import illustration from 'mastodon/../images/elephant_ui_working.svg'; +import illustration from '@/images/elephant_ui_working.svg'; const RegenerationIndicator = () => (
diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index 7925b706af..8333448da8 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -7,12 +7,12 @@ 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 AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react'; +import PushPinIcon from '@/material-icons/400-24px/push_pin.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; import { Icon } from 'mastodon/components/icon'; import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder'; import { withOptionalRouter, WithOptionalRouterPropTypes } from 'mastodon/utils/react_router'; diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx index 0869e1ff1a..9de65f63b4 100644 --- a/app/javascript/mastodon/components/status_action_bar.jsx +++ b/app/javascript/mastodon/components/status_action_bar.jsx @@ -9,19 +9,17 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { ReactComponent as ReactIcon } from '@material-symbols/svg-600/outlined/add.svg'; -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 { ReactComponent as RepeatDisabledIcon } from 'mastodon/../svg-icons/repeat_disabled.svg'; -import { ReactComponent as RepeatPrivateIcon } from 'mastodon/../svg-icons/repeat_private.svg'; +import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg'; +import BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; +import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; +import StarBorderIcon from '@/material-icons/400-24px/star.svg?react'; +import VisibilityIcon from '@/material-icons/400-24px/visibility.svg?react'; +import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react'; +import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; diff --git a/app/javascript/mastodon/components/status_content.jsx b/app/javascript/mastodon/components/status_content.jsx index d1f50fc8d7..4a7ba941eb 100644 --- a/app/javascript/mastodon/components/status_content.jsx +++ b/app/javascript/mastodon/components/status_content.jsx @@ -9,8 +9,7 @@ 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 ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; import { Icon } from 'mastodon/components/icon'; import PollContainer from 'mastodon/containers/poll_container'; import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state'; diff --git a/app/javascript/mastodon/components/verified_badge.tsx b/app/javascript/mastodon/components/verified_badge.tsx index e96bf82563..626cc500d6 100644 --- a/app/javascript/mastodon/components/verified_badge.tsx +++ b/app/javascript/mastodon/components/verified_badge.tsx @@ -1,4 +1,4 @@ -import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg'; +import CheckIcon from '@/material-icons/400-24px/check.svg?react'; import { Icon } from './icon'; diff --git a/app/javascript/mastodon/components/visibility_icon.tsx b/app/javascript/mastodon/components/visibility_icon.tsx index 3e9f36dc70..d6ad4095eb 100644 --- a/app/javascript/mastodon/components/visibility_icon.tsx +++ b/app/javascript/mastodon/components/visibility_icon.tsx @@ -1,9 +1,9 @@ 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 AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react'; +import LockIcon from '@/material-icons/400-24px/lock.svg?react'; +import LockOpenIcon from '@/material-icons/400-24px/lock_open.svg?react'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { Icon } from './icon'; diff --git a/app/javascript/mastodon/features/about/index.jsx b/app/javascript/mastodon/features/about/index.jsx index 380942b8ee..3287631ed1 100644 --- a/app/javascript/mastodon/features/about/index.jsx +++ b/app/javascript/mastodon/features/about/index.jsx @@ -10,9 +10,8 @@ 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 ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; +import ExpandMoreIcon from '@/material-icons/400-24px/expand_more.svg?react'; import { fetchServer, fetchExtendedDescription, fetchDomainBlocks } from 'mastodon/actions/server'; import Column from 'mastodon/components/column'; import { Icon } from 'mastodon/components/icon'; diff --git a/app/javascript/mastodon/features/account/components/follow_request_note.jsx b/app/javascript/mastodon/features/account/components/follow_request_note.jsx index 685c282df2..d57fd030b2 100644 --- a/app/javascript/mastodon/features/account/components/follow_request_note.jsx +++ b/app/javascript/mastodon/features/account/components/follow_request_note.jsx @@ -3,9 +3,8 @@ 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 CheckIcon from '@/material-icons/400-24px/check.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { Icon } from 'mastodon/components/icon'; export default class FollowRequestNote extends ImmutablePureComponent { diff --git a/app/javascript/mastodon/features/account/components/header.jsx b/app/javascript/mastodon/features/account/components/header.jsx index 97f68c2217..233d208c64 100644 --- a/app/javascript/mastodon/features/account/components/header.jsx +++ b/app/javascript/mastodon/features/account/components/header.jsx @@ -9,13 +9,12 @@ 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 { ReactComponent as ShareIcon } from '@material-symbols/svg-600/outlined/share.svg'; - +import CheckIcon from '@/material-icons/400-24px/check.svg?react'; +import LockIcon from '@/material-icons/400-24px/lock.svg?react'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import NotificationsIcon from '@/material-icons/400-24px/notifications.svg?react'; +import NotificationsActiveIcon from '@/material-icons/400-24px/notifications_active-fill.svg?react'; +import ShareIcon from '@/material-icons/400-24px/share.svg?react'; import { Avatar } from 'mastodon/components/avatar'; import { Badge, AutomatedBadge, GroupBadge } from 'mastodon/components/badge'; import { Button } from 'mastodon/components/button'; diff --git a/app/javascript/mastodon/features/account_gallery/components/media_item.jsx b/app/javascript/mastodon/features/account_gallery/components/media_item.jsx index 657b17d43d..087e775753 100644 --- a/app/javascript/mastodon/features/account_gallery/components/media_item.jsx +++ b/app/javascript/mastodon/features/account_gallery/components/media_item.jsx @@ -5,10 +5,9 @@ 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 AudiotrackIcon from '@/material-icons/400-24px/music_note.svg?react'; +import PlayArrowIcon from '@/material-icons/400-24px/play_arrow.svg?react'; +import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; import { Blurhash } from 'mastodon/components/blurhash'; import { Icon } from 'mastodon/components/icon'; import { autoPlayGif, displayMedia, useBlurhash } from 'mastodon/initial_state'; diff --git a/app/javascript/mastodon/features/audio/index.jsx b/app/javascript/mastodon/features/audio/index.jsx index 7a7d0910fa..fdc1b0be0f 100644 --- a/app/javascript/mastodon/features/audio/index.jsx +++ b/app/javascript/mastodon/features/audio/index.jsx @@ -7,14 +7,14 @@ 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 DownloadIcon from '@/material-icons/400-24px/download.svg?react'; +import PauseIcon from '@/material-icons/400-24px/pause.svg?react'; +import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react'; +import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; +import VolumeOffIcon from '@/material-icons/400-24px/volume_off-fill.svg?react'; +import VolumeUpIcon from '@/material-icons/400-24px/volume_up-fill.svg?react'; import { Icon } from 'mastodon/components/icon'; import { formatTime, getPointerPosition, fileNameFromURL } from 'mastodon/features/video'; diff --git a/app/javascript/mastodon/features/blocks/index.jsx b/app/javascript/mastodon/features/blocks/index.jsx index 615e4c8be2..1a631d3d07 100644 --- a/app/javascript/mastodon/features/blocks/index.jsx +++ b/app/javascript/mastodon/features/blocks/index.jsx @@ -6,9 +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 BlockIcon from '@/material-icons/400-24px/block-fill.svg?react'; + import { fetchBlocks, expandBlocks } from '../../actions/blocks'; import { LoadingIndicator } from '../../components/loading_indicator'; import ScrollableList from '../../components/scrollable_list'; diff --git a/app/javascript/mastodon/features/bookmarked_statuses/index.jsx b/app/javascript/mastodon/features/bookmarked_statuses/index.jsx index be6110b0da..5494ad44b0 100644 --- a/app/javascript/mastodon/features/bookmarked_statuses/index.jsx +++ b/app/javascript/mastodon/features/bookmarked_statuses/index.jsx @@ -8,9 +8,9 @@ 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 BookmarksIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react'; import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'mastodon/actions/bookmarks'; import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; import ColumnHeader from 'mastodon/components/column_header'; diff --git a/app/javascript/mastodon/features/community_timeline/index.jsx b/app/javascript/mastodon/features/community_timeline/index.jsx index 60f036a628..0aa1f9aa23 100644 --- a/app/javascript/mastodon/features/community_timeline/index.jsx +++ b/app/javascript/mastodon/features/community_timeline/index.jsx @@ -7,8 +7,7 @@ import { Helmet } from 'react-helmet'; import { connect } from 'react-redux'; -import { ReactComponent as PeopleIcon } from '@material-symbols/svg-600/outlined/group.svg'; - +import PeopleIcon from '@/material-icons/400-24px/group.svg?react'; import { DismissableBanner } from 'mastodon/components/dismissable_banner'; import { domain } from 'mastodon/initial_state'; diff --git a/app/javascript/mastodon/features/compose/components/action_bar.jsx b/app/javascript/mastodon/features/compose/components/action_bar.jsx index 3e21090925..411ad77c79 100644 --- a/app/javascript/mastodon/features/compose/components/action_bar.jsx +++ b/app/javascript/mastodon/features/compose/components/action_bar.jsx @@ -5,7 +5,7 @@ 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 MenuIcon from '@/material-icons/400-24px/menu.svg?react'; import DropdownMenuContainer from '../../../containers/dropdown_menu_container'; diff --git a/app/javascript/mastodon/features/compose/components/compose_form.jsx b/app/javascript/mastodon/features/compose/components/compose_form.jsx index 3b752f252d..a70c774c37 100644 --- a/app/javascript/mastodon/features/compose/components/compose_form.jsx +++ b/app/javascript/mastodon/features/compose/components/compose_form.jsx @@ -8,9 +8,9 @@ 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 LockIcon from '@/material-icons/400-24px/lock.svg?react'; import { Icon } from 'mastodon/components/icon'; import { WithOptionalRouterPropTypes, withOptionalRouter } from 'mastodon/utils/react_router'; diff --git a/app/javascript/mastodon/features/compose/components/poll_button.jsx b/app/javascript/mastodon/features/compose/components/poll_button.jsx index f722815b51..4900d38119 100644 --- a/app/javascript/mastodon/features/compose/components/poll_button.jsx +++ b/app/javascript/mastodon/features/compose/components/poll_button.jsx @@ -3,7 +3,7 @@ import { PureComponent } from 'react'; import { defineMessages, injectIntl } from 'react-intl'; -import { ReactComponent as InsertChartIcon } from '@material-symbols/svg-600/outlined/insert_chart.svg'; +import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react'; import { IconButton } from '../../../components/icon_button'; diff --git a/app/javascript/mastodon/features/compose/components/poll_form.jsx b/app/javascript/mastodon/features/compose/components/poll_form.jsx index a7f933ff7c..e242f1bb3d 100644 --- a/app/javascript/mastodon/features/compose/components/poll_form.jsx +++ b/app/javascript/mastodon/features/compose/components/poll_form.jsx @@ -8,9 +8,8 @@ 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 AddIcon from '@/material-icons/400-24px/add.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import AutosuggestInput from 'mastodon/components/autosuggest_input'; import { Icon } from 'mastodon/components/icon'; import { IconButton } from 'mastodon/components/icon_button'; diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx b/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx index 060eb6767c..c3446b8d60 100644 --- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx +++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx @@ -6,14 +6,13 @@ 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 AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react'; +import LockIcon from '@/material-icons/400-24px/lock.svg?react'; +import LockOpenIcon from '@/material-icons/400-24px/lock_open.svg?react'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { Icon } from 'mastodon/components/icon'; import { IconButton } from '../../../components/icon_button'; diff --git a/app/javascript/mastodon/features/compose/components/reply_indicator.jsx b/app/javascript/mastodon/features/compose/components/reply_indicator.jsx index af7a9b6be5..8051e01db4 100644 --- a/app/javascript/mastodon/features/compose/components/reply_indicator.jsx +++ b/app/javascript/mastodon/features/compose/components/reply_indicator.jsx @@ -5,8 +5,7 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import AttachmentList from 'mastodon/components/attachment_list'; import { WithOptionalRouterPropTypes, withOptionalRouter } from 'mastodon/utils/react_router'; diff --git a/app/javascript/mastodon/features/compose/components/search.jsx b/app/javascript/mastodon/features/compose/components/search.jsx index 5d55330dcb..ca02c23fc4 100644 --- a/app/javascript/mastodon/features/compose/components/search.jsx +++ b/app/javascript/mastodon/features/compose/components/search.jsx @@ -8,10 +8,9 @@ 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 CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import SearchIcon from '@/material-icons/400-24px/search.svg?react'; import { Icon } from 'mastodon/components/icon'; import { domain, searchEnabled } from 'mastodon/initial_state'; import { HASHTAG_REGEX } from 'mastodon/utils/hashtags'; @@ -63,14 +62,14 @@ class Search extends PureComponent { }; defaultOptions = [ - { label: <>has: , action: e => { e.preventDefault(); this._insertText('has:'); } }, - { label: <>is: , action: e => { e.preventDefault(); this._insertText('is:'); } }, - { label: <>language: , action: e => { e.preventDefault(); this._insertText('language:'); } }, - { label: <>from: , action: e => { e.preventDefault(); this._insertText('from:'); } }, - { label: <>before: , action: e => { e.preventDefault(); this._insertText('before:'); } }, - { label: <>during: , action: e => { e.preventDefault(); this._insertText('during:'); } }, - { label: <>after: , action: e => { e.preventDefault(); this._insertText('after:'); } }, - { label: <>in: , action: e => { e.preventDefault(); this._insertText('in:'); } } + { key: 'prompt-has', label: <>has: , action: e => { e.preventDefault(); this._insertText('has:'); } }, + { key: 'prompt-is', label: <>is: , action: e => { e.preventDefault(); this._insertText('is:'); } }, + { key: 'prompt-language', label: <>language: , action: e => { e.preventDefault(); this._insertText('language:'); } }, + { key: 'prompt-from', label: <>from: , action: e => { e.preventDefault(); this._insertText('from:'); } }, + { key: 'prompt-before', label: <>before: , action: e => { e.preventDefault(); this._insertText('before:'); } }, + { key: 'prompt-during', label: <>during: , action: e => { e.preventDefault(); this._insertText('during:'); } }, + { key: 'prompt-after', label: <>after: , action: e => { e.preventDefault(); this._insertText('after:'); } }, + { key: 'prompt-in', label: <>in: , action: e => { e.preventDefault(); this._insertText('in:'); } } ]; setRef = c => { @@ -263,6 +262,8 @@ class Search extends PureComponent { const { recent } = this.props; return recent.toArray().map(search => ({ + key: `${search.get('type')}/${search.get('q')}`, + label: labelForRecentSearch(search), action: () => this.handleRecentSearchClick(search), @@ -347,8 +348,8 @@ class Search extends PureComponent {

- {recent.size > 0 ? this._getOptions().map(({ label, action, forget }, i) => ( - diff --git a/app/javascript/mastodon/features/compose/components/search_results.jsx b/app/javascript/mastodon/features/compose/components/search_results.jsx index 2667ed5437..694deea04e 100644 --- a/app/javascript/mastodon/features/compose/components/search_results.jsx +++ b/app/javascript/mastodon/features/compose/components/search_results.jsx @@ -5,11 +5,10 @@ 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 FindInPageIcon from '@/material-icons/400-24px/find_in_page.svg?react'; +import PeopleIcon from '@/material-icons/400-24px/group.svg?react'; +import SearchIcon from '@/material-icons/400-24px/search.svg?react'; +import TagIcon from '@/material-icons/400-24px/tag.svg?react'; import { Icon } from 'mastodon/components/icon'; import { LoadMore } from 'mastodon/components/load_more'; import { SearchSection } from 'mastodon/features/explore/components/search_section'; diff --git a/app/javascript/mastodon/features/compose/components/upload.jsx b/app/javascript/mastodon/features/compose/components/upload.jsx index a443741d5c..76d394af7a 100644 --- a/app/javascript/mastodon/features/compose/components/upload.jsx +++ b/app/javascript/mastodon/features/compose/components/upload.jsx @@ -5,11 +5,11 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import EditIcon from '@/material-icons/400-24px/edit.svg?react'; +import InfoIcon from '@/material-icons/400-24px/info.svg?react'; import { Icon } from 'mastodon/components/icon'; import Motion from '../../ui/util/optional_motion'; diff --git a/app/javascript/mastodon/features/compose/components/upload_button.jsx b/app/javascript/mastodon/features/compose/components/upload_button.jsx index dda8a42ab0..923d6a3c47 100644 --- a/app/javascript/mastodon/features/compose/components/upload_button.jsx +++ b/app/javascript/mastodon/features/compose/components/upload_button.jsx @@ -6,7 +6,7 @@ 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 AddPhotoAlternateIcon from '@/material-icons/400-24px/add_photo_alternate.svg?react'; import { IconButton } from '../../../components/icon_button'; diff --git a/app/javascript/mastodon/features/compose/components/upload_progress.jsx b/app/javascript/mastodon/features/compose/components/upload_progress.jsx index 90c5142e24..e4973b24fd 100644 --- a/app/javascript/mastodon/features/compose/components/upload_progress.jsx +++ b/app/javascript/mastodon/features/compose/components/upload_progress.jsx @@ -3,9 +3,9 @@ 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 UploadFileIcon from '@/material-icons/400-24px/upload_file.svg?react'; import { Icon } from 'mastodon/components/icon'; import Motion from '../../ui/util/optional_motion'; diff --git a/app/javascript/mastodon/features/compose/containers/search_container.js b/app/javascript/mastodon/features/compose/containers/search_container.js index 758b6b07db..616b91369c 100644 --- a/app/javascript/mastodon/features/compose/containers/search_container.js +++ b/app/javascript/mastodon/features/compose/containers/search_container.js @@ -1,3 +1,4 @@ +import { createSelector } from '@reduxjs/toolkit'; import { connect } from 'react-redux'; import { @@ -12,10 +13,15 @@ import { import Search from '../components/search'; +const getRecentSearches = createSelector( + state => state.getIn(['search', 'recent']), + recent => recent.reverse(), +); + const mapStateToProps = state => ({ value: state.getIn(['search', 'value']), submitted: state.getIn(['search', 'submitted']), - recent: state.getIn(['search', 'recent']).reverse(), + recent: getRecentSearches(state), }); const mapDispatchToProps = dispatch => ({ diff --git a/app/javascript/mastodon/features/compose/index.jsx b/app/javascript/mastodon/features/compose/index.jsx index 65650ffe02..ea3a149501 100644 --- a/app/javascript/mastodon/features/compose/index.jsx +++ b/app/javascript/mastodon/features/compose/index.jsx @@ -9,15 +9,15 @@ 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 PeopleIcon from '@/material-icons/400-24px/group.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; +import LogoutIcon from '@/material-icons/400-24px/logout.svg?react'; +import MenuIcon from '@/material-icons/400-24px/menu.svg?react'; +import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg?react'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; +import SettingsIcon from '@/material-icons/400-24px/settings-fill.svg?react'; import { openModal } from 'mastodon/actions/modal'; import Column from 'mastodon/components/column'; import { Icon } from 'mastodon/components/icon'; diff --git a/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx b/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx index 005edc5c2b..274cfa69f5 100644 --- a/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx +++ b/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx @@ -8,10 +8,10 @@ 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 MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; import AttachmentList from 'mastodon/components/attachment_list'; import AvatarComposite from 'mastodon/components/avatar_composite'; import { IconButton } from 'mastodon/components/icon_button'; diff --git a/app/javascript/mastodon/features/direct_timeline/index.jsx b/app/javascript/mastodon/features/direct_timeline/index.jsx index 4e6d0c3e72..af29d7a5b8 100644 --- a/app/javascript/mastodon/features/direct_timeline/index.jsx +++ b/app/javascript/mastodon/features/direct_timeline/index.jsx @@ -7,8 +7,7 @@ import { Helmet } from 'react-helmet'; import { connect } from 'react-redux'; -import { ReactComponent as AlternateEmailIcon } from '@material-symbols/svg-600/outlined/alternate_email.svg'; - +import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react'; import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; import { mountConversations, unmountConversations, expandConversations } from 'mastodon/actions/conversations'; import { connectDirectStream } from 'mastodon/actions/streaming'; diff --git a/app/javascript/mastodon/features/directory/index.jsx b/app/javascript/mastodon/features/directory/index.jsx index 20c84d4df0..0d3408146e 100644 --- a/app/javascript/mastodon/features/directory/index.jsx +++ b/app/javascript/mastodon/features/directory/index.jsx @@ -9,8 +9,7 @@ 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 PeopleIcon from '@/material-icons/400-24px/group.svg?react'; import { addColumn, removeColumn, moveColumn, changeColumnParams } from 'mastodon/actions/columns'; import { fetchDirectory, expandDirectory } from 'mastodon/actions/directory'; import Column from 'mastodon/components/column'; diff --git a/app/javascript/mastodon/features/domain_blocks/index.jsx b/app/javascript/mastodon/features/domain_blocks/index.jsx index 142f14bf71..964eada9c1 100644 --- a/app/javascript/mastodon/features/domain_blocks/index.jsx +++ b/app/javascript/mastodon/features/domain_blocks/index.jsx @@ -8,9 +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 BlockIcon from '@/material-icons/400-24px/block-fill.svg?react'; + import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks'; import { LoadingIndicator } from '../../components/loading_indicator'; import ScrollableList from '../../components/scrollable_list'; diff --git a/app/javascript/mastodon/features/explore/index.jsx b/app/javascript/mastodon/features/explore/index.jsx index 80825e4563..8ebaccd013 100644 --- a/app/javascript/mastodon/features/explore/index.jsx +++ b/app/javascript/mastodon/features/explore/index.jsx @@ -8,9 +8,8 @@ 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 SearchIcon from '@/material-icons/400-24px/search.svg?react'; +import TagIcon from '@/material-icons/400-24px/tag.svg?react'; import Column from 'mastodon/components/column'; import ColumnHeader from 'mastodon/components/column_header'; import Search from 'mastodon/features/compose/containers/search_container'; diff --git a/app/javascript/mastodon/features/explore/results.jsx b/app/javascript/mastodon/features/explore/results.jsx index 8c172c134a..355c0f1c4c 100644 --- a/app/javascript/mastodon/features/explore/results.jsx +++ b/app/javascript/mastodon/features/explore/results.jsx @@ -9,10 +9,9 @@ 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 FindInPageIcon from '@/material-icons/400-24px/find_in_page.svg?react'; +import PeopleIcon from '@/material-icons/400-24px/group.svg?react'; +import TagIcon from '@/material-icons/400-24px/tag.svg?react'; import { submitSearch, expandSearch } from 'mastodon/actions/search'; import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag'; import { Icon } from 'mastodon/components/icon'; diff --git a/app/javascript/mastodon/features/favourited_statuses/index.jsx b/app/javascript/mastodon/features/favourited_statuses/index.jsx index d3c3cc9f09..8e65ff5b68 100644 --- a/app/javascript/mastodon/features/favourited_statuses/index.jsx +++ b/app/javascript/mastodon/features/favourited_statuses/index.jsx @@ -8,9 +8,9 @@ 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 StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; import { fetchFavouritedStatuses, expandFavouritedStatuses } from 'mastodon/actions/favourites'; import ColumnHeader from 'mastodon/components/column_header'; diff --git a/app/javascript/mastodon/features/favourites/index.jsx b/app/javascript/mastodon/features/favourites/index.jsx index 637a9d6994..27ca169409 100644 --- a/app/javascript/mastodon/features/favourites/index.jsx +++ b/app/javascript/mastodon/features/favourites/index.jsx @@ -8,9 +8,9 @@ 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 RefreshIcon from '@/material-icons/400-24px/refresh.svg?react'; import { fetchFavourites, expandFavourites } from 'mastodon/actions/interactions'; import ColumnHeader from 'mastodon/components/column_header'; import { Icon } from 'mastodon/components/icon'; diff --git a/app/javascript/mastodon/features/filters/select_filter.jsx b/app/javascript/mastodon/features/filters/select_filter.jsx index 9e8f87e005..5b2eb64952 100644 --- a/app/javascript/mastodon/features/filters/select_filter.jsx +++ b/app/javascript/mastodon/features/filters/select_filter.jsx @@ -5,9 +5,9 @@ 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 AddIcon from '@/material-icons/400-24px/add.svg?react'; import { Icon } from 'mastodon/components/icon'; import { toServerSideType } from 'mastodon/utils/filters'; import { loupeIcon, deleteIcon } from 'mastodon/utils/icons'; diff --git a/app/javascript/mastodon/features/firehose/index.jsx b/app/javascript/mastodon/features/firehose/index.jsx index 0ed8aa11aa..6355efbfe0 100644 --- a/app/javascript/mastodon/features/firehose/index.jsx +++ b/app/javascript/mastodon/features/firehose/index.jsx @@ -6,8 +6,7 @@ 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 PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { addColumn } from 'mastodon/actions/columns'; import { changeSetting } from 'mastodon/actions/settings'; import { connectPublicStream, connectCommunityStream } from 'mastodon/actions/streaming'; diff --git a/app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx b/app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx index ca2b454143..dd308c87cb 100644 --- a/app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx +++ b/app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx @@ -7,8 +7,8 @@ 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 CheckIcon from '@/material-icons/400-24px/check.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { Avatar } from '../../../components/avatar'; import { DisplayName } from '../../../components/display_name'; diff --git a/app/javascript/mastodon/features/follow_requests/index.jsx b/app/javascript/mastodon/features/follow_requests/index.jsx index 3b98791926..7d651f2ca6 100644 --- a/app/javascript/mastodon/features/follow_requests/index.jsx +++ b/app/javascript/mastodon/features/follow_requests/index.jsx @@ -8,9 +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 PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; + import { fetchFollowRequests, expandFollowRequests } from '../../actions/accounts'; import ScrollableList from '../../components/scrollable_list'; import { me } from '../../initial_state'; diff --git a/app/javascript/mastodon/features/followed_tags/index.jsx b/app/javascript/mastodon/features/followed_tags/index.jsx index dec53f0121..21248e6de9 100644 --- a/app/javascript/mastodon/features/followed_tags/index.jsx +++ b/app/javascript/mastodon/features/followed_tags/index.jsx @@ -8,9 +8,9 @@ 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 TagIcon from '@/material-icons/400-24px/tag.svg?react'; import { expandFollowedHashtags, fetchFollowedHashtags } from 'mastodon/actions/tags'; import ColumnHeader from 'mastodon/components/column_header'; import { Hashtag } from 'mastodon/components/hashtag'; diff --git a/app/javascript/mastodon/features/getting_started/components/announcements.jsx b/app/javascript/mastodon/features/getting_started/components/announcements.jsx index 026698b716..a5a3040609 100644 --- a/app/javascript/mastodon/features/getting_started/components/announcements.jsx +++ b/app/javascript/mastodon/features/getting_started/components/announcements.jsx @@ -9,13 +9,14 @@ 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'; +import elephantUIPlane from '@/images/elephant_ui_plane.svg'; +import AddIcon from '@/material-icons/400-24px/add.svg?react'; +import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react'; +import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; import { AnimatedNumber } from 'mastodon/components/animated_number'; import { Icon } from 'mastodon/components/icon'; import { IconButton } from 'mastodon/components/icon_button'; diff --git a/app/javascript/mastodon/features/getting_started/index.jsx b/app/javascript/mastodon/features/getting_started/index.jsx index 5994e88edf..53bb22ddb2 100644 --- a/app/javascript/mastodon/features/getting_started/index.jsx +++ b/app/javascript/mastodon/features/getting_started/index.jsx @@ -9,18 +9,17 @@ 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 AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react'; +import BookmarksIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react'; +import PeopleIcon from '@/material-icons/400-24px/group.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; +import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; +import MenuIcon from '@/material-icons/400-24px/menu.svg?react'; +import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; +import SettingsIcon from '@/material-icons/400-24px/settings-fill.svg?react'; +import StarIcon from '@/material-icons/400-24px/star.svg?react'; +import TagIcon from '@/material-icons/400-24px/tag.svg?react'; import { fetchFollowRequests } from 'mastodon/actions/accounts'; import Column from 'mastodon/components/column'; import ColumnHeader from 'mastodon/components/column_header'; diff --git a/app/javascript/mastodon/features/hashtag_timeline/index.jsx b/app/javascript/mastodon/features/hashtag_timeline/index.jsx index d39d550a1b..f431a7e9b7 100644 --- a/app/javascript/mastodon/features/hashtag_timeline/index.jsx +++ b/app/javascript/mastodon/features/hashtag_timeline/index.jsx @@ -8,9 +8,9 @@ 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 TagIcon from '@/material-icons/400-24px/tag.svg?react'; import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; import { connectHashtagStream } from 'mastodon/actions/streaming'; import { fetchHashtag, followHashtag, unfollowHashtag } from 'mastodon/actions/tags'; diff --git a/app/javascript/mastodon/features/home_timeline/components/explore_prompt.tsx b/app/javascript/mastodon/features/home_timeline/components/explore_prompt.tsx index 9eeec00e34..960d30e2ca 100644 --- a/app/javascript/mastodon/features/home_timeline/components/explore_prompt.tsx +++ b/app/javascript/mastodon/features/home_timeline/components/explore_prompt.tsx @@ -2,7 +2,7 @@ import { FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; -import background from 'mastodon/../images/friends-cropped.png'; +import background from '@/images/friends-cropped.png'; import { DismissableBanner } from 'mastodon/components/dismissable_banner'; export const ExplorePrompt = () => ( diff --git a/app/javascript/mastodon/features/home_timeline/index.jsx b/app/javascript/mastodon/features/home_timeline/index.jsx index 613eb4b896..069f52b0be 100644 --- a/app/javascript/mastodon/features/home_timeline/index.jsx +++ b/app/javascript/mastodon/features/home_timeline/index.jsx @@ -10,9 +10,8 @@ import { createSelector } from '@reduxjs/toolkit'; import { List as ImmutableList } from 'immutable'; import { connect } from 'react-redux'; -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 CampaignIcon from '@/material-icons/400-24px/campaign.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; import { fetchAnnouncements, toggleShowAnnouncements } from 'mastodon/actions/announcements'; import { IconWithBadge } from 'mastodon/components/icon_with_badge'; import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator'; diff --git a/app/javascript/mastodon/features/interaction_modal/index.jsx b/app/javascript/mastodon/features/interaction_modal/index.jsx index 216c63a7e6..07f1e6fe5a 100644 --- a/app/javascript/mastodon/features/interaction_modal/index.jsx +++ b/app/javascript/mastodon/features/interaction_modal/index.jsx @@ -7,12 +7,12 @@ 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 PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; +import StarIcon from '@/material-icons/400-24px/star.svg?react'; import { openModal, closeModal } from 'mastodon/actions/modal'; import api from 'mastodon/api'; import { Button } from 'mastodon/components/button'; diff --git a/app/javascript/mastodon/features/keyboard_shortcuts/index.jsx b/app/javascript/mastodon/features/keyboard_shortcuts/index.jsx index 7552e1799b..622ca525c1 100644 --- a/app/javascript/mastodon/features/keyboard_shortcuts/index.jsx +++ b/app/javascript/mastodon/features/keyboard_shortcuts/index.jsx @@ -6,8 +6,7 @@ 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 InfoIcon from '@/material-icons/400-24px/info.svg?react'; import Column from 'mastodon/components/column'; import ColumnHeader from 'mastodon/components/column_header'; diff --git a/app/javascript/mastodon/features/list_adder/components/list.jsx b/app/javascript/mastodon/features/list_adder/components/list.jsx index 6c5aab85da..a7cfd60bf3 100644 --- a/app/javascript/mastodon/features/list_adder/components/list.jsx +++ b/app/javascript/mastodon/features/list_adder/components/list.jsx @@ -6,10 +6,9 @@ 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 AddIcon from '@/material-icons/400-24px/add.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; import { Icon } from 'mastodon/components/icon'; import { removeFromListAdder, addToListAdder } from '../../../actions/lists'; diff --git a/app/javascript/mastodon/features/list_editor/components/account.jsx b/app/javascript/mastodon/features/list_editor/components/account.jsx index 18d5e905cb..77d32af80a 100644 --- a/app/javascript/mastodon/features/list_editor/components/account.jsx +++ b/app/javascript/mastodon/features/list_editor/components/account.jsx @@ -6,8 +6,8 @@ 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 AddIcon from '@/material-icons/400-24px/add.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { removeFromListEditor, addToListEditor } from '../../../actions/lists'; import { Avatar } from '../../../components/avatar'; diff --git a/app/javascript/mastodon/features/list_editor/components/edit_list_form.jsx b/app/javascript/mastodon/features/list_editor/components/edit_list_form.jsx index 1e2446f92b..89f596636e 100644 --- a/app/javascript/mastodon/features/list_editor/components/edit_list_form.jsx +++ b/app/javascript/mastodon/features/list_editor/components/edit_list_form.jsx @@ -5,7 +5,7 @@ import { defineMessages, injectIntl } from 'react-intl'; import { connect } from 'react-redux'; -import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg'; +import CheckIcon from '@/material-icons/400-24px/check.svg?react'; import { changeListEditorTitle, submitListEditor } from '../../../actions/lists'; import { IconButton } from '../../../components/icon_button'; diff --git a/app/javascript/mastodon/features/list_editor/components/search.jsx b/app/javascript/mastodon/features/list_editor/components/search.jsx index 093af5cd4e..097d4f3f41 100644 --- a/app/javascript/mastodon/features/list_editor/components/search.jsx +++ b/app/javascript/mastodon/features/list_editor/components/search.jsx @@ -7,9 +7,8 @@ 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 CancelIcon from '@/material-icons/400-24px/cancel.svg?react'; +import SearchIcon from '@/material-icons/400-24px/search.svg?react'; import { Icon } from 'mastodon/components/icon'; import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from '../../../actions/lists'; diff --git a/app/javascript/mastodon/features/list_timeline/index.jsx b/app/javascript/mastodon/features/list_timeline/index.jsx index 55579c2fd1..24bf122fac 100644 --- a/app/javascript/mastodon/features/list_timeline/index.jsx +++ b/app/javascript/mastodon/features/list_timeline/index.jsx @@ -9,11 +9,11 @@ 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 DeleteIcon from '@/material-icons/400-24px/delete.svg?react'; +import EditIcon from '@/material-icons/400-24px/edit.svg?react'; +import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; import { fetchList, deleteList, updateList } from 'mastodon/actions/lists'; import { openModal } from 'mastodon/actions/modal'; diff --git a/app/javascript/mastodon/features/lists/index.jsx b/app/javascript/mastodon/features/lists/index.jsx index 9014394351..a7648f55b2 100644 --- a/app/javascript/mastodon/features/lists/index.jsx +++ b/app/javascript/mastodon/features/lists/index.jsx @@ -9,8 +9,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg'; - +import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; import { fetchLists } from 'mastodon/actions/lists'; import Column from 'mastodon/components/column'; import ColumnHeader from 'mastodon/components/column_header'; diff --git a/app/javascript/mastodon/features/mutes/index.jsx b/app/javascript/mastodon/features/mutes/index.jsx index 7f66edc03d..3b50244ea4 100644 --- a/app/javascript/mastodon/features/mutes/index.jsx +++ b/app/javascript/mastodon/features/mutes/index.jsx @@ -8,9 +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 VolumeOffIcon from '@/material-icons/400-24px/volume_off.svg?react'; + import { fetchMutes, expandMutes } from '../../actions/mutes'; import { LoadingIndicator } from '../../components/loading_indicator'; import ScrollableList from '../../components/scrollable_list'; diff --git a/app/javascript/mastodon/features/notifications/components/clear_column_button.jsx b/app/javascript/mastodon/features/notifications/components/clear_column_button.jsx index 54fa16fb67..73eaecba59 100644 --- a/app/javascript/mastodon/features/notifications/components/clear_column_button.jsx +++ b/app/javascript/mastodon/features/notifications/components/clear_column_button.jsx @@ -3,8 +3,7 @@ import { PureComponent } from 'react'; import { FormattedMessage } from 'react-intl'; -import { ReactComponent as DeleteForeverIcon } from '@material-symbols/svg-600/outlined/delete_forever.svg'; - +import DeleteForeverIcon from '@/material-icons/400-24px/delete_forever.svg?react'; import { Icon } from 'mastodon/components/icon'; export default class ClearColumnButton extends PureComponent { diff --git a/app/javascript/mastodon/features/notifications/components/filter_bar.jsx b/app/javascript/mastodon/features/notifications/components/filter_bar.jsx index f6b68c34dc..20597f8938 100644 --- a/app/javascript/mastodon/features/notifications/components/filter_bar.jsx +++ b/app/javascript/mastodon/features/notifications/components/filter_bar.jsx @@ -3,13 +3,12 @@ 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 HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; +import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react'; +import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react'; +import StarIcon from '@/material-icons/400-24px/star.svg?react'; import { Icon } from 'mastodon/components/icon'; const tooltips = defineMessages({ diff --git a/app/javascript/mastodon/features/notifications/components/follow_request.jsx b/app/javascript/mastodon/features/notifications/components/follow_request.jsx index 03420b6c01..4024455cbd 100644 --- a/app/javascript/mastodon/features/notifications/components/follow_request.jsx +++ b/app/javascript/mastodon/features/notifications/components/follow_request.jsx @@ -7,9 +7,8 @@ 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 CheckIcon from '@/material-icons/400-24px/check.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { Avatar } from 'mastodon/components/avatar'; import { DisplayName } from 'mastodon/components/display_name'; import { IconButton } from 'mastodon/components/icon_button'; diff --git a/app/javascript/mastodon/features/notifications/components/notification.jsx b/app/javascript/mastodon/features/notifications/components/notification.jsx index 8c0783292c..efa769fe1f 100644 --- a/app/javascript/mastodon/features/notifications/components/notification.jsx +++ b/app/javascript/mastodon/features/notifications/components/notification.jsx @@ -8,16 +8,16 @@ 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 EditIcon from '@/material-icons/400-24px/edit.svg?react'; +import FlagIcon from '@/material-icons/400-24px/flag-fill.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; +import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react'; +import PersonIcon from '@/material-icons/400-24px/person-fill.svg?react'; +import PersonAddIcon from '@/material-icons/400-24px/person_add-fill.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; import { Icon } from 'mastodon/components/icon'; import AccountContainer from 'mastodon/containers/account_container'; import StatusContainer from 'mastodon/containers/status_container'; diff --git a/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.jsx b/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.jsx index b7ebb4c467..1cdf5b5dfe 100644 --- a/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.jsx +++ b/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.jsx @@ -5,9 +5,8 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import TuneIcon from '@/material-icons/400-24px/tune.svg?react'; import { requestBrowserPermission } from 'mastodon/actions/notifications'; import { changeSetting } from 'mastodon/actions/settings'; import { Button } from 'mastodon/components/button'; diff --git a/app/javascript/mastodon/features/notifications/index.jsx b/app/javascript/mastodon/features/notifications/index.jsx index 762c96ccca..30c63ed32a 100644 --- a/app/javascript/mastodon/features/notifications/index.jsx +++ b/app/javascript/mastodon/features/notifications/index.jsx @@ -10,10 +10,10 @@ import { List as ImmutableList } from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { connect } from 'react-redux'; -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 DoneAllIcon from '@/material-icons/400-24px/done_all.svg?react'; +import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg?react'; import { compareId } from 'mastodon/compare_id'; import { Icon } from 'mastodon/components/icon'; import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator'; diff --git a/app/javascript/mastodon/features/onboarding/components/step.jsx b/app/javascript/mastodon/features/onboarding/components/step.jsx index 1f83f20801..a2a1653b8a 100644 --- a/app/javascript/mastodon/features/onboarding/components/step.jsx +++ b/app/javascript/mastodon/features/onboarding/components/step.jsx @@ -2,9 +2,8 @@ import PropTypes from 'prop-types'; import { Link } from 'react-router-dom'; -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 ArrowRightAltIcon from '@/material-icons/400-24px/arrow_right_alt.svg?react'; +import CheckIcon from '@/material-icons/400-24px/done.svg?react'; import { Icon } from 'mastodon/components/icon'; export const Step = ({ label, description, icon, iconComponent, completed, onClick, href, to }) => { diff --git a/app/javascript/mastodon/features/onboarding/index.jsx b/app/javascript/mastodon/features/onboarding/index.jsx index 51677fbc7a..5900b9ec76 100644 --- a/app/javascript/mastodon/features/onboarding/index.jsx +++ b/app/javascript/mastodon/features/onboarding/index.jsx @@ -8,13 +8,12 @@ import { Link, Switch, Route, useHistory } from 'react-router-dom'; import { useDispatch } 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 illustration from 'mastodon/../images/elephant_ui_conversation.svg'; +import illustration from '@/images/elephant_ui_conversation.svg'; +import AccountCircleIcon from '@/material-icons/400-24px/account_circle.svg?react'; +import ArrowRightAltIcon from '@/material-icons/400-24px/arrow_right_alt.svg?react'; +import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react'; +import EditNoteIcon from '@/material-icons/400-24px/edit_note.svg?react'; +import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; import { focusCompose } from 'mastodon/actions/compose'; import { Icon } from 'mastodon/components/icon'; import Column from 'mastodon/features/ui/components/column'; diff --git a/app/javascript/mastodon/features/onboarding/profile.jsx b/app/javascript/mastodon/features/onboarding/profile.jsx index daaef6065c..14250ae39b 100644 --- a/app/javascript/mastodon/features/onboarding/profile.jsx +++ b/app/javascript/mastodon/features/onboarding/profile.jsx @@ -8,10 +8,10 @@ import { useHistory } from 'react-router-dom'; import { useDispatch } from 'react-redux'; -import { ReactComponent as AddPhotoAlternateIcon } from '@material-symbols/svg-600/outlined/add_photo_alternate.svg'; -import { ReactComponent as EditIcon } from '@material-symbols/svg-600/outlined/edit.svg'; import Toggle from 'react-toggle'; +import AddPhotoAlternateIcon from '@/material-icons/400-24px/add_photo_alternate.svg?react'; +import EditIcon from '@/material-icons/400-24px/edit.svg?react'; import { updateAccount } from 'mastodon/actions/accounts'; import { Button } from 'mastodon/components/button'; import { ColumnBackButton } from 'mastodon/components/column_back_button'; diff --git a/app/javascript/mastodon/features/onboarding/share.jsx b/app/javascript/mastodon/features/onboarding/share.jsx index adc0f9cba3..32a86ab6cc 100644 --- a/app/javascript/mastodon/features/onboarding/share.jsx +++ b/app/javascript/mastodon/features/onboarding/share.jsx @@ -7,10 +7,10 @@ import classNames from 'classnames'; import { Link } from 'react-router-dom'; -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 ArrowRightAltIcon from '@/material-icons/400-24px/arrow_right_alt.svg?react'; +import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react'; import { ColumnBackButton } from 'mastodon/components/column_back_button'; import { Icon } from 'mastodon/components/icon'; import { me, domain } from 'mastodon/initial_state'; diff --git a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx index ed86d19f5c..8dfbf54cb6 100644 --- a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx +++ b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx @@ -9,12 +9,11 @@ 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 OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; +import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react'; +import StarIcon from '@/material-icons/400-24px/star.svg?react'; import { initBoostModal } from 'mastodon/actions/boosts'; import { replyCompose } from 'mastodon/actions/compose'; import { reblog, favourite, unreblog, unfavourite } from 'mastodon/actions/interactions'; diff --git a/app/javascript/mastodon/features/picture_in_picture/components/header.jsx b/app/javascript/mastodon/features/picture_in_picture/components/header.jsx index 80a13bd2e3..31073d7387 100644 --- a/app/javascript/mastodon/features/picture_in_picture/components/header.jsx +++ b/app/javascript/mastodon/features/picture_in_picture/components/header.jsx @@ -8,8 +8,7 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { Avatar } from 'mastodon/components/avatar'; import { DisplayName } from 'mastodon/components/display_name'; import { IconButton } from 'mastodon/components/icon_button'; diff --git a/app/javascript/mastodon/features/pinned_statuses/index.jsx b/app/javascript/mastodon/features/pinned_statuses/index.jsx index 82398ccda9..921e9a6072 100644 --- a/app/javascript/mastodon/features/pinned_statuses/index.jsx +++ b/app/javascript/mastodon/features/pinned_statuses/index.jsx @@ -8,8 +8,7 @@ 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 PushPinIcon from '@/material-icons/400-24px/push_pin.svg?react'; import { getStatusList } from 'mastodon/selectors'; import { fetchPinnedStatuses } from '../../actions/pin_statuses'; diff --git a/app/javascript/mastodon/features/public_timeline/index.jsx b/app/javascript/mastodon/features/public_timeline/index.jsx index 09a9f6821f..3601dfeae8 100644 --- a/app/javascript/mastodon/features/public_timeline/index.jsx +++ b/app/javascript/mastodon/features/public_timeline/index.jsx @@ -7,8 +7,7 @@ import { Helmet } from 'react-helmet'; import { connect } from 'react-redux'; -import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg'; - +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { DismissableBanner } from 'mastodon/components/dismissable_banner'; import { domain } from 'mastodon/initial_state'; diff --git a/app/javascript/mastodon/features/reblogs/index.jsx b/app/javascript/mastodon/features/reblogs/index.jsx index be17668418..3d1fc94cb7 100644 --- a/app/javascript/mastodon/features/reblogs/index.jsx +++ b/app/javascript/mastodon/features/reblogs/index.jsx @@ -8,9 +8,9 @@ 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 RefreshIcon from '@/material-icons/400-24px/refresh.svg?react'; import { Icon } from 'mastodon/components/icon'; import { fetchReblogs, expandReblogs } from '../../actions/interactions'; diff --git a/app/javascript/mastodon/features/report/components/option.jsx b/app/javascript/mastodon/features/report/components/option.jsx index b3602219f5..7aa0dd1379 100644 --- a/app/javascript/mastodon/features/report/components/option.jsx +++ b/app/javascript/mastodon/features/report/components/option.jsx @@ -3,8 +3,7 @@ import { PureComponent } from 'react'; import classNames from 'classnames'; -import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/done.svg'; - +import CheckIcon from '@/material-icons/400-24px/done.svg?react'; import { Icon } from 'mastodon/components/icon'; export default class Option extends PureComponent { diff --git a/app/javascript/mastodon/features/status/components/action_bar.jsx b/app/javascript/mastodon/features/status/components/action_bar.jsx index c083ac9252..1efd3dab20 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.jsx +++ b/app/javascript/mastodon/features/status/components/action_bar.jsx @@ -9,18 +9,16 @@ import { withRouter } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { connect } from 'react-redux'; -import { ReactComponent as ReactIcon } from '@material-symbols/svg-600/outlined/add.svg'; -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 RepeatDisabledIcon } from 'mastodon/../svg-icons/repeat_disabled.svg'; -import { ReactComponent as RepeatPrivateIcon } from 'mastodon/../svg-icons/repeat_private.svg'; +import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg?react'; +import BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; +import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; +import StarBorderIcon from '@/material-icons/400-24px/star.svg?react'; +import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react'; +import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; diff --git a/app/javascript/mastodon/features/status/components/card.jsx b/app/javascript/mastodon/features/status/components/card.jsx index d7d688952d..f37b558c4c 100644 --- a/app/javascript/mastodon/features/status/components/card.jsx +++ b/app/javascript/mastodon/features/status/components/card.jsx @@ -10,10 +10,9 @@ 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 DescriptionIcon from '@/material-icons/400-24px/description-fill.svg?react'; +import OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react'; +import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react'; import { Blurhash } from 'mastodon/components/blurhash'; import { Icon } from 'mastodon/components/icon'; import { RelativeTimestamp } from 'mastodon/components/relative_timestamp'; diff --git a/app/javascript/mastodon/features/status/components/detailed_status.jsx b/app/javascript/mastodon/features/status/components/detailed_status.jsx index 887ba32a30..9dab7f5d35 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.jsx +++ b/app/javascript/mastodon/features/status/components/detailed_status.jsx @@ -8,10 +8,9 @@ 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 AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react'; +import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; import { AnimatedNumber } from 'mastodon/components/animated_number'; import EditedTimestamp from 'mastodon/components/edited_timestamp'; import { getHashtagBarForStatus } from 'mastodon/components/hashtag_bar'; diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index e787691909..837c8a49d5 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -12,10 +12,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -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 VisibilityIcon from '@/material-icons/400-24px/visibility.svg?react'; +import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; import { Icon } from 'mastodon/components/icon'; import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import ScrollContainer from 'mastodon/containers/scroll_container'; diff --git a/app/javascript/mastodon/features/subscribed_languages_modal/index.jsx b/app/javascript/mastodon/features/subscribed_languages_modal/index.jsx index ac34f7986c..0531346f91 100644 --- a/app/javascript/mastodon/features/subscribed_languages_modal/index.jsx +++ b/app/javascript/mastodon/features/subscribed_languages_modal/index.jsx @@ -8,8 +8,7 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { followAccount } from 'mastodon/actions/accounts'; import { Button } from 'mastodon/components/button'; import { IconButton } from 'mastodon/components/icon_button'; diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.jsx b/app/javascript/mastodon/features/ui/components/boost_modal.jsx index c6fa8ce363..3b3e1e3f97 100644 --- a/app/javascript/mastodon/features/ui/components/boost_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/boost_modal.jsx @@ -9,8 +9,7 @@ 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 RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; import { changeBoostPrivacy } from 'mastodon/actions/boosts'; import AttachmentList from 'mastodon/components/attachment_list'; import { Icon } from 'mastodon/components/icon'; diff --git a/app/javascript/mastodon/features/ui/components/bundle_modal_error.jsx b/app/javascript/mastodon/features/ui/components/bundle_modal_error.jsx index 44165f1417..d1c9e36883 100644 --- a/app/javascript/mastodon/features/ui/components/bundle_modal_error.jsx +++ b/app/javascript/mastodon/features/ui/components/bundle_modal_error.jsx @@ -3,7 +3,7 @@ import { PureComponent } from 'react'; import { defineMessages, injectIntl } from 'react-intl'; -import { ReactComponent as RefreshIcon } from '@material-symbols/svg-600/outlined/refresh.svg'; +import RefreshIcon from '@/material-icons/400-24px/refresh.svg?react'; import { IconButton } from '../../../components/icon_button'; diff --git a/app/javascript/mastodon/features/ui/components/compare_history_modal.jsx b/app/javascript/mastodon/features/ui/components/compare_history_modal.jsx index 413c5069f1..4227c74131 100644 --- a/app/javascript/mastodon/features/ui/components/compare_history_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/compare_history_modal.jsx @@ -6,9 +6,9 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { closeModal } from 'mastodon/actions/modal'; import { IconButton } from 'mastodon/components/icon_button'; import InlineAccount from 'mastodon/components/inline_account'; diff --git a/app/javascript/mastodon/features/ui/components/embed_modal.jsx b/app/javascript/mastodon/features/ui/components/embed_modal.jsx index e5c0b5cae9..a4e5fc9dfb 100644 --- a/app/javascript/mastodon/features/ui/components/embed_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/embed_modal.jsx @@ -4,8 +4,7 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import api from 'mastodon/api'; import { IconButton } from 'mastodon/components/icon_button'; diff --git a/app/javascript/mastodon/features/ui/components/filter_modal.jsx b/app/javascript/mastodon/features/ui/components/filter_modal.jsx index d90edddec4..477575bd7b 100644 --- a/app/javascript/mastodon/features/ui/components/filter_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/filter_modal.jsx @@ -5,8 +5,7 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { fetchFilters, createFilter, createFilterStatus } from 'mastodon/actions/filters'; import { fetchStatus } from 'mastodon/actions/statuses'; import { IconButton } from 'mastodon/components/icon_button'; diff --git a/app/javascript/mastodon/features/ui/components/focal_point_modal.jsx b/app/javascript/mastodon/features/ui/components/focal_point_modal.jsx index 91dca26718..25ad1e2e9f 100644 --- a/app/javascript/mastodon/features/ui/components/focal_point_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/focal_point_modal.jsx @@ -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 @@ -17,6 +16,7 @@ import tesseractWorkerPath from 'tesseract.js/dist/worker.min.js'; // eslint-disable-next-line import/no-extraneous-dependencies import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { Button } from 'mastodon/components/button'; import { GIFV } from 'mastodon/components/gifv'; import { IconButton } from 'mastodon/components/icon_button'; diff --git a/app/javascript/mastodon/features/ui/components/follow_requests_column_link.jsx b/app/javascript/mastodon/features/ui/components/follow_requests_column_link.jsx index 314b2a2652..4aa0092631 100644 --- a/app/javascript/mastodon/features/ui/components/follow_requests_column_link.jsx +++ b/app/javascript/mastodon/features/ui/components/follow_requests_column_link.jsx @@ -6,8 +6,7 @@ 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 PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; import { fetchFollowRequests } from 'mastodon/actions/accounts'; import { IconWithBadge } from 'mastodon/components/icon_with_badge'; import ColumnLink from 'mastodon/features/ui/components/column_link'; diff --git a/app/javascript/mastodon/features/ui/components/header.jsx b/app/javascript/mastodon/features/ui/components/header.jsx index 150647ffb3..2f8636b12a 100644 --- a/app/javascript/mastodon/features/ui/components/header.jsx +++ b/app/javascript/mastodon/features/ui/components/header.jsx @@ -7,8 +7,7 @@ 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 SearchIcon from '@/material-icons/400-24px/search.svg?react'; import { openModal } from 'mastodon/actions/modal'; import { fetchServer } from 'mastodon/actions/server'; import { Avatar } from 'mastodon/components/avatar'; diff --git a/app/javascript/mastodon/features/ui/components/image_modal.jsx b/app/javascript/mastodon/features/ui/components/image_modal.jsx index c534bf1636..f08ce15342 100644 --- a/app/javascript/mastodon/features/ui/components/image_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/image_modal.jsx @@ -5,8 +5,7 @@ import { defineMessages, injectIntl } from 'react-intl'; import classNames from 'classnames'; -import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg'; - +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { IconButton } from 'mastodon/components/icon_button'; import ImageLoader from './image_loader'; diff --git a/app/javascript/mastodon/features/ui/components/list_panel.jsx b/app/javascript/mastodon/features/ui/components/list_panel.jsx index ff600730a0..fec21f14ca 100644 --- a/app/javascript/mastodon/features/ui/components/list_panel.jsx +++ b/app/javascript/mastodon/features/ui/components/list_panel.jsx @@ -5,8 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { ReactComponent as ListAltIcon } from '@material-symbols/svg-600/outlined/list_alt.svg'; - +import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; import { fetchLists } from 'mastodon/actions/lists'; import ColumnLink from './column_link'; diff --git a/app/javascript/mastodon/features/ui/components/media_modal.jsx b/app/javascript/mastodon/features/ui/components/media_modal.jsx index 8c06a96531..0f6e8a727b 100644 --- a/app/javascript/mastodon/features/ui/components/media_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/media_modal.jsx @@ -7,11 +7,11 @@ 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 ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react'; +import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { getAverageFromBlurhash } from 'mastodon/blurhash'; import { GIFV } from 'mastodon/components/gifv'; import { Icon } from 'mastodon/components/icon'; diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx index d1b2a0910b..d3f46c6d46 100644 --- a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx +++ b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx @@ -5,17 +5,16 @@ 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 AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react'; +import BookmarksIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react'; +import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; +import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; +import PublicIcon from '@/material-icons/400-24px/public.svg?react'; +import SearchIcon from '@/material-icons/400-24px/search.svg?react'; +import SettingsIcon from '@/material-icons/400-24px/settings-fill.svg?react'; +import StarIcon from '@/material-icons/400-24px/star-fill.svg?react'; +import TagIcon from '@/material-icons/400-24px/tag.svg?react'; import { WordmarkLogo } from 'mastodon/components/logo'; import { NavigationPortal } from 'mastodon/components/navigation_portal'; import { timelinePreview, trendsEnabled } from 'mastodon/initial_state'; diff --git a/app/javascript/mastodon/features/ui/components/notifications_counter_icon.js b/app/javascript/mastodon/features/ui/components/notifications_counter_icon.js index b3e9950e93..7d59d616d8 100644 --- a/app/javascript/mastodon/features/ui/components/notifications_counter_icon.js +++ b/app/javascript/mastodon/features/ui/components/notifications_counter_icon.js @@ -1,7 +1,6 @@ import { connect } from 'react-redux'; -import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications-fill.svg'; - +import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg?react'; import { IconWithBadge } from 'mastodon/components/icon_with_badge'; diff --git a/app/javascript/mastodon/features/ui/components/report_modal.jsx b/app/javascript/mastodon/features/ui/components/report_modal.jsx index 3fd8ff127d..6584364609 100644 --- a/app/javascript/mastodon/features/ui/components/report_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/report_modal.jsx @@ -7,8 +7,7 @@ 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 CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { submitReport } from 'mastodon/actions/reports'; import { fetchServer } from 'mastodon/actions/server'; import { expandAccountTimeline } from 'mastodon/actions/timelines'; diff --git a/app/javascript/mastodon/features/ui/components/zoomable_image.jsx b/app/javascript/mastodon/features/ui/components/zoomable_image.jsx index 5e71da9d96..272a3cff00 100644 --- a/app/javascript/mastodon/features/ui/components/zoomable_image.jsx +++ b/app/javascript/mastodon/features/ui/components/zoomable_image.jsx @@ -3,9 +3,8 @@ 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 FullscreenExitIcon from '@/material-icons/400-24px/fullscreen_exit.svg?react'; +import RectangleIcon from '@/material-icons/400-24px/rectangle.svg?react'; import { IconButton } from 'mastodon/components/icon_button'; const messages = defineMessages({ diff --git a/app/javascript/mastodon/features/video/index.jsx b/app/javascript/mastodon/features/video/index.jsx index e908715e91..89a8ba560a 100644 --- a/app/javascript/mastodon/features/video/index.jsx +++ b/app/javascript/mastodon/features/video/index.jsx @@ -7,16 +7,16 @@ 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 FullscreenIcon from '@/material-icons/400-24px/fullscreen.svg?react'; +import FullscreenExitIcon from '@/material-icons/400-24px/fullscreen_exit.svg?react'; +import PauseIcon from '@/material-icons/400-24px/pause.svg?react'; +import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react'; +import RectangleIcon from '@/material-icons/400-24px/rectangle.svg?react'; +import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; +import VolumeOffIcon from '@/material-icons/400-24px/volume_off-fill.svg?react'; +import VolumeUpIcon from '@/material-icons/400-24px/volume_up-fill.svg?react'; import { Blurhash } from 'mastodon/components/blurhash'; import { Icon } from 'mastodon/components/icon'; import { playerSettings } from 'mastodon/settings'; diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json index c4238edcd4..1467f8891e 100644 --- a/app/javascript/mastodon/locales/ast.json +++ b/app/javascript/mastodon/locales/ast.json @@ -13,14 +13,12 @@ "about.rules": "Normes del sirvidor", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Amestar o quitar de les llistes", - "account.badges.bot": "Automatizáu", "account.badges.group": "Grupu", "account.block": "Bloquiar a @{name}", "account.block_domain": "Bloquiar el dominiu {domain}", "account.block_short": "Bloquiar", "account.blocked": "Perfil bloquiáu", "account.browse_more_on_origin_server": "Restolar más nel perfil orixinal", - "account.cancel_follow_request": "Atayar siguimientu", "account.copy": "Copiar I'enllaz al perfil", "account.direct": "Mentar a @{name} per privao", "account.disable_notifications": "Dexar d'avisame cuando @{name} espublice artículos", @@ -28,13 +26,11 @@ "account.edit_profile": "Editar el perfil", "account.enable_notifications": "Avisame cuando @{name} espublice artículos", "account.endorse": "Destacar nel perfil", - "account.featured_tags.last_status_at": "Últimu estáu en {date}", - "account.featured_tags.last_status_never": "Sin estaos", + "account.featured_tags.last_status_never": "Nun hai nengún artículu", "account.featured_tags.title": "Etiquetes destacaes de: {name}", "account.follow": "Siguir", "account.followers": "Siguidores", "account.followers.empty": "Naide sigue a esti perfil.", - "account.followers_counter": "{count, plural, one {{counter} Siguíu} other {{counter} Siguíos}}", "account.following": "Siguiendo", "account.following_counter": "{count, plural,one {Sigue a {counter}} other {Sigue a {counter}}}", "account.follows.empty": "Esti perfil nun sigue a naide.", @@ -42,7 +38,6 @@ "account.hide_reblogs": "Anubrir los artículos compartíos de @{name}", "account.in_memoriam": "N'alcordanza.", "account.joined_short": "Data de xunión", - "account.languages": "Camudar llingües suscrites", "account.link_verified_on": "La propiedá d'esti enllaz foi comprobada'l {date}", "account.media": "Multimedia", "account.mention": "Mentar a @{name}", @@ -108,6 +103,7 @@ "community.column_settings.remote_only": "Namás lo remoto", "compose.language.change": "Camudar la llingua", "compose.language.search": "Buscar llingües…", + "compose.published.body": "Espublizóse l'artículu.", "compose_form.direct_message_warning_learn_more": "Saber más", "compose_form.encryption_warning": "Los artículos de Mastodon nun tán cifraos de puntu a puntu. Nun compartas nengún tipu d'información sensible per Mastodon.", "compose_form.lock_disclaimer": "La to cuenta nun ye {locked}. Cualesquier perfil pue siguite pa ver los artículos que son namás pa siguidores.", @@ -120,7 +116,6 @@ "compose_form.publish_form": "Artículu nuevu", "compose_form.publish_loud": "¡{publish}!", "compose_form.save_changes": "Guardar los cambeos", - "compose_form.spoiler.unmarked": "Text is not hidden", "confirmation_modal.cancel": "Encaboxar", "confirmations.block.block_and_report": "Bloquiar ya informar", "confirmations.block.confirm": "Bloquiar", @@ -150,6 +145,7 @@ "dismissable_banner.community_timeline": "Esta seición contién los artículos públicos más actuales de los perfiles agospiaos nel dominiu {domain}.", "dismissable_banner.dismiss": "Escartar", "dismissable_banner.explore_tags": "Esta seición contién les etiquetes del fediversu que tán ganando popularidá güei. Les etiquetes más usaes polos perfiles apaecen no cimero.", + "dismissable_banner.public_timeline": "Esta seición contién los artículos más nuevos de les persones na web social que les persones de {domain} siguen.", "embed.instructions": "Empotra esti artículu nel to sitiu web pente la copia del códigu d'abaxo.", "embed.preview": "Va apaecer asina:", "emoji_button.activity": "Actividá", @@ -159,6 +155,7 @@ "emoji_button.not_found": "Nun s'atoparon fustaxes que concasen", "emoji_button.objects": "Oxetos", "emoji_button.people": "Persones", + "emoji_button.recent": "D'usu frecuente", "emoji_button.search": "Buscar…", "emoji_button.search_results": "Resultaos de la busca", "emoji_button.symbols": "Símbolos", @@ -221,7 +218,6 @@ "hashtag.column_header.tag_mode.any": "o {additional}", "hashtag.column_header.tag_mode.none": "ensin {additional}", "hashtag.column_settings.select.no_options_message": "Nun s'atopó nenguna suxerencia", - "hashtag.column_settings.tag_toggle": "Include additional tags in this column", "hashtag.counter_by_accounts": "{count, plural, one {{counter} participante} other {{counter} participantes}}", "hashtag.follow": "Siguir a la etiqueta", "hashtag.unfollow": "Dexar de siguir a la etiqueta", @@ -263,7 +259,6 @@ "keyboard_shortcuts.reply": "Responder a un artículu", "keyboard_shortcuts.requests": "Abrir la llista de solicitúes de siguimientu", "keyboard_shortcuts.search": "Enfocar la barra de busca", - "keyboard_shortcuts.spoilers": "to show/hide CW field", "keyboard_shortcuts.start": "Abrir la columna «Entamar»", "keyboard_shortcuts.toggle_sensitivity": "Amosar/anubrir el conteníu multimedia", "keyboard_shortcuts.toot": "Comenzar un artículu nuevu", @@ -299,6 +294,7 @@ "navigation_bar.lists": "Llistes", "navigation_bar.logout": "Zarrar la sesión", "navigation_bar.mutes": "Perfiles colos avisos desactivaos", + "navigation_bar.opened_in_classic_interface": "Los artículos, les cuentes ya otres páxines específiques ábrense por defeutu na interfaz web clásica.", "navigation_bar.pins": "Artículos fixaos", "navigation_bar.preferences": "Preferencies", "navigation_bar.public_timeline": "Llinia de tiempu federada", @@ -334,7 +330,7 @@ "notifications.group": "{count} avisos", "notifications.mark_as_read": "Marcar tolos avisos como lleíos", "notifications.permission_required": "Los avisos d'escritoriu nun tán disponibles porque nun se concedió'l permisu riquíu.", - "onboarding.actions.go_to_explore": "See what's trending", + "onboarding.profile.note_hint": "Pues @mentar a otros perfiles o poner #etiquetes…", "onboarding.start.lead": "Xá yes parte de Mastodon, una plataforma social multimedia descentralizada onde tu ya non un algoritmu, personalices la to esperiencia. Vamos presentate esti llugar social nuevu:", "onboarding.start.skip": "¿Nun precises ayuda pa comenzar?", "onboarding.steps.follow_people.body": "Mastodon trata namás de siguir a cuentes interesantes.", @@ -415,12 +411,16 @@ "search.quick_action.go_to_hashtag": "Dir a la etiqueta {x}", "search.quick_action.status_search": "Artículos que concasen con {x}", "search.search_or_paste": "Busca o apiega una URL", + "search_popout.language_code": "códigu de llingua ISO", "search_popout.quick_actions": "Aiciones rápides", "search_popout.recent": "Busques de recién", + "search_popout.specific_date": "data específica", + "search_popout.user": "perfil", "search_results.accounts": "Perfiles", "search_results.all": "Too", "search_results.hashtags": "Etiquetes", "search_results.nothing_found": "Nun se pudo atopar nada con esos términos de busca", + "search_results.see_all": "Ver too", "search_results.statuses": "Artículos", "search_results.title": "Busca de: {q}", "server_banner.introduction": "{domain} ye parte de la rede social descentralizada que tien la teunoloxía de {mastodon}.", @@ -463,6 +463,7 @@ "status.replied_to": "En rempuesta a {name}", "status.reply": "Responder", "status.replyAll": "Responder al filu", + "status.report": "Informar de @{name}", "status.sensitive_warning": "Conteníu sensible", "status.show_filter_reason": "Amosar de toes toes", "status.show_less": "Amosar menos", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 290b364a52..7d1049a30f 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -150,7 +150,7 @@ "compose_form.poll.duration": "Durada de l'enquesta", "compose_form.poll.option_placeholder": "Opció {number}", "compose_form.poll.remove_option": "Elimina aquesta opció", - "compose_form.poll.switch_to_multiple": "Canvia l’enquesta per a permetre diverses opcions", + "compose_form.poll.switch_to_multiple": "Canvia l’enquesta per a permetre múltiples opcions", "compose_form.poll.switch_to_single": "Canvia l’enquesta per a permetre una única opció", "compose_form.publish": "Tut", "compose_form.publish_form": "Nou tut", @@ -607,7 +607,7 @@ "search.quick_action.status_search": "Tuts coincidint amb {x}", "search.search_or_paste": "Cerca o escriu l'URL", "search_popout.full_text_search_disabled_message": "No disponible a {domain}.", - "search_popout.full_text_search_logged_out_message": "Només disponible en iniciar la sessió.", + "search_popout.full_text_search_logged_out_message": "Només disponible amb la sessió iniciada.", "search_popout.language_code": "Codi de llengua ISO", "search_popout.options": "Opcions de cerca", "search_popout.quick_actions": "Accions ràpides", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 2608b91563..462352750c 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -489,7 +489,7 @@ "onboarding.profile.lead": "Du kannst das später in den Einstellungen vervollständigen, wo noch mehr Anpassungsmöglichkeiten zur Verfügung stehen.", "onboarding.profile.note": "Über mich", "onboarding.profile.note_hint": "Du kannst andere @Profile erwähnen oder #Hashtags verwenden …", - "onboarding.profile.save_and_continue": "Speichern und fortsetzen", + "onboarding.profile.save_and_continue": "Speichern und fortfahren", "onboarding.profile.title": "Profil einrichten", "onboarding.profile.upload_avatar": "Profilbild hochladen", "onboarding.profile.upload_header": "Titelbild hochladen", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index 9259f20154..94d13e8d91 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -393,6 +393,7 @@ "lists.search": "Leita millum fólk, sum tú fylgir", "lists.subheading": "Tínir listar", "load_pending": "{count, plural, one {# nýtt evni} other {# nýggj evni}}", + "loading_indicator.label": "Innlesur…", "media_gallery.toggle_visible": "{number, plural, one {Fjal mynd} other {Fjal myndir}}", "moved_to_account_banner.text": "Konta tín {disabledAccount} er í løtuni óvirkin, tí tú flutti til {movedToAccount}.", "mute_modal.duration": "Tíðarbil", @@ -483,6 +484,15 @@ "onboarding.follows.title": "Vælumtókt á Mastodon", "onboarding.profile.discoverable": "Ger tað møguligt hjá øðrum at finna vangan hjá mær", "onboarding.profile.discoverable_hint": "Tá tú játtar at onnur skulu kunna finna teg á Mastodon, so kann henda, at postar tínir síggjast í leitiúrslitum og rákum, og vangin hjá tær kann vera skotin upp fyri fólki við áhugamálum sum minna um tíni.", + "onboarding.profile.display_name": "Navn, sum skal vísast", + "onboarding.profile.display_name_hint": "Títt fulla navn ella títt stuttliga navn…", + "onboarding.profile.lead": "Tú kanst altíð gera hetta liðugt seinni í stillingunum, har enn fleiri tillagingarmøguleikar eru tøkir.", + "onboarding.profile.note": "Ævilýsing", + "onboarding.profile.note_hint": "Tú kanst @umrøða onnur fólk ella #frámerki…", + "onboarding.profile.save_and_continue": "Goym og halt fram", + "onboarding.profile.title": "Vangauppsetan", + "onboarding.profile.upload_avatar": "Legg vangamynd upp", + "onboarding.profile.upload_header": "Legg vangahøvd upp", "onboarding.share.lead": "Lat fólk vita, hvussu tey kunnu finna teg á Mastodon!", "onboarding.share.message": "Eg eri {username} á #Mastodon! Kom og fylg mær á {url}", "onboarding.share.next_steps": "Møgulig næstu stig:", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 48bbb6b307..e857b69554 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -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": "Desbotar a solicitude de seguimento", "account.copy": "Copiar ligazón ao perfil", "account.direct": "Mencionar de xeito privado a @{name}", "account.disable_notifications": "Deixar de notificarme cando @{name} publica", @@ -184,7 +184,7 @@ "confirmations.mute.explanation": "Isto agochará as súas publicacións ou as que a mencionen, mais poderá ler as túas publicacións e ser seguidora túa.", "confirmations.mute.message": "Tes a certeza de querer acalar a {name}?", "confirmations.redraft.confirm": "Eliminar e reescribir", - "confirmations.redraft.message": "Tes a certeza de querer eliminar esta publicación e reescribila? Perderás as comparticións e favoritas, e as respostas á publicación orixinal ficarán orfas.", + "confirmations.redraft.message": "Tes a certeza de querer eliminar esta publicación e reescribila? Perderás as promocións e favorecementos, e as respostas á publicación orixinal ficarán orfas.", "confirmations.reply.confirm": "Responder", "confirmations.reply.message": "Ao responder sobrescribirás a mensaxe que estás a compor. Tes a certeza de que queres continuar?", "confirmations.unfollow.confirm": "Deixar de seguir", @@ -204,7 +204,7 @@ "disabled_account_banner.text": "Actualmente a túa conta {disabledAccount} está desactivada.", "dismissable_banner.community_timeline": "Estas son as publicacións máis recentes das persoas que teñen a súa conta en {domain}.", "dismissable_banner.dismiss": "Desbotar", - "dismissable_banner.explore_links": "As persoas deste servidor e da rede descentralizada están a falar destas historias agora mesmo.", + "dismissable_banner.explore_links": "Estas son as novas historias más compartidas hoxe na web social. Aparecen primeiro as novas compartidas por máis persoas diferentes.", "dismissable_banner.explore_statuses": "Estas son as publicacións da web social que hoxe están gañando popularidade. As publicacións con máis promocións e favorecemento teñen puntuación máis alta.", "dismissable_banner.explore_tags": "Estes cancelos están gañando popularidade entre as persoas deste servidor e noutros servidores da rede descentralizada.", "dismissable_banner.public_timeline": "Estas son as publicacións públicas máis recentes das persoas que as usuarias de {domain} están a seguir.", @@ -240,7 +240,7 @@ "empty_column.follow_requests": "Non tes peticións de seguimento. Cando recibas unha, amosarase aquí.", "empty_column.followed_tags": "Aínda non seguiches ningún cancelo. Cando o fagas aparecerán aquí.", "empty_column.hashtag": "Aínda non hai nada con este cancelo.", - "empty_column.home": "A túa cronoloxía inicial está baleira! Segue a outras usuarias para enchela. {suggestions}", + "empty_column.home": "A túa cronoloxía inicial está baleira! Sigue a outras usuarias para enchela.", "empty_column.list": "Aínda non hai nada nesta listaxe. Cando as usuarias incluídas na listaxe publiquen mensaxes, amosaranse aquí.", "empty_column.lists": "Aínda non tes listaxes. Cando crees unha, amosarase aquí.", "empty_column.mutes": "Aínda non silenciaches a ningúnha usuaria.", @@ -346,7 +346,7 @@ "keyboard_shortcuts.down": "Para mover cara abaixo na listaxe", "keyboard_shortcuts.enter": "Para abrir publicación", "keyboard_shortcuts.favourite": "Marcar como favorita", - "keyboard_shortcuts.favourites": "Para abrir a listaxe das favoritas", + "keyboard_shortcuts.favourites": "Para abrir a lista das favoritas", "keyboard_shortcuts.federated": "Para abrir a cronoloxía federada", "keyboard_shortcuts.heading": "Atallos do teclado", "keyboard_shortcuts.home": "Para abrir a cronoloxía inicial", @@ -383,7 +383,7 @@ "lists.delete": "Eliminar listaxe", "lists.edit": "Editar listaxe", "lists.edit.submit": "Mudar o título", - "lists.exclusive": "Agocha estas publicacións no inicio", + "lists.exclusive": "Agocha estas publicacións no Inicio", "lists.new.create": "Engadir listaxe", "lists.new.title_placeholder": "Título da nova listaxe", "lists.replies_policy.followed": "Toda usuaria seguida", @@ -480,8 +480,8 @@ "onboarding.actions.go_to_home": "Vai á cronoloxía de inicio", "onboarding.compose.template": "Ola #Mastodon!", "onboarding.follows.empty": "Desgraciadamente agora mesmo non hai nada que mostrar. Podes intentalo coa busca ou na páxina descubrir para atopar persoas ás que seguir, ou intentalo máis tarde.", - "onboarding.follows.lead": "Podes facer que a túa cronoloxía de inicio sexa como ti a queres. Canta máis xente sigas máis interesante será. Estes perfís poderían axudarche a comezar —sempre poderás deixar de seguilos despois!", - "onboarding.follows.title": "Popular en Mastodon", + "onboarding.follows.lead": "A cronoloxía de Inicio é o principal xeito de desfrutar Mastodon. Cantas máis persoas sigas mais interesante e activa será. Para comezar, aquí tes algunhas suxestións:", + "onboarding.follows.title": "Personaliza a cronoloxía de inicio", "onboarding.profile.discoverable": "Que o meu perfil se poida atopar", "onboarding.profile.discoverable_hint": "Cando elixes que poidan atoparte en Mastodon as túas publicacións aparecerán nos resultados das buscas e nos temas en voga, e o teu perfil podería ser suxerido para seguimento a persoas con intereses semellantes aos teus.", "onboarding.profile.display_name": "Nome público", @@ -494,20 +494,20 @@ "onboarding.profile.upload_avatar": "Subir imaxe do perfil", "onboarding.profile.upload_header": "Subir cabeceira para o perfil", "onboarding.share.lead": "Fai que as persoas saiban como atoparte en Mastodon!", - "onboarding.share.message": "Son {username} en #Mastodon! Ségueme en {url}", + "onboarding.share.message": "Son {username} en #Mastodon! Sígueme en {url}", "onboarding.share.next_steps": "Seguintes pasos:", "onboarding.share.title": "Comparte o teu perfil", - "onboarding.start.lead": "A túa nova conta en Mastodon está preparada. Mira de que xeito lle podes sacar proveito:", + "onboarding.start.lead": "Xa formas parte de Mastodon, unha plataforma de relacións sociais descentralizada, única, onde ti —e non un algoritmo— elixes o que les. Axudámosche cos primeiros pasos:", "onboarding.start.skip": "Queres omitir todo isto?", "onboarding.start.title": "Pois xa está!", - "onboarding.steps.follow_people.body": "Constrúes a túa cronoloxía. Énchea con persoas interesantes.", - "onboarding.steps.follow_people.title": "Segue a {count, plural, one {unha persoa} other {# persoas}}", - "onboarding.steps.publish_status.body": "Saúda a todo o mundo.", + "onboarding.steps.follow_people.body": "Mastodon consiste en seguir a persoas interesantes.", + "onboarding.steps.follow_people.title": "Personaliza a túa cronoloxía", + "onboarding.steps.publish_status.body": "Exprésate con texto, fotos, vídeos ou enquisas {emoji}", "onboarding.steps.publish_status.title": "Escribe a túa primeira publicación", "onboarding.steps.setup_profile.body": "Ao engadir información ao teu perfil é máis probable que teñas máis interaccións.", "onboarding.steps.setup_profile.title": "Personaliza o perfil", "onboarding.steps.share_profile.body": "Dille ás amizades como poden atoparte en Mastodon!", - "onboarding.steps.share_profile.title": "Comparte o teu perfil", + "onboarding.steps.share_profile.title": "Comparte o teu perfil en Mastodon", "onboarding.tips.2fa": "Sabes que? Podes protexer a túa conta configurando un segundo factor de autenticación nos axustes. Funciona con calquera app TOTP, non precisas un número de teléfono!", "onboarding.tips.accounts_from_other_servers": "Sabes que? Como Mastodon é descentralizado, algúns perfís que atopes estarán en servidores diferentes ao teu. Pero podes interactuar igualmente con eles! O seu servidor é o que ven despois da @ no seu identificador!", "onboarding.tips.migration": "Sabes que? Se cres que {domain} non é o servidor axeitado para ti, podes mover a conta a outro servidor Mastodon sen perder as túas seguidoras. Incluso podes hospedar o teu propio servidor!", @@ -573,7 +573,7 @@ "report.reasons.dislike": "Non me gusta", "report.reasons.dislike_description": "Non é algo que queiras ver", "report.reasons.legal": "É ilegal", - "report.reasons.legal_description": "Cres que atenta contra as leis do país do teu servidor", + "report.reasons.legal_description": "Cres que atenta contra as leis do país do teu pais ou servidor", "report.reasons.other": "É outra cousa", "report.reasons.other_description": "O problema non cae dentro de outras categorías", "report.reasons.spam": "É spam", diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json index 76d7c1d381..412159bef9 100644 --- a/app/javascript/mastodon/locales/hi.json +++ b/app/javascript/mastodon/locales/hi.json @@ -386,6 +386,7 @@ "navigation_bar.security": "सुरक्षा", "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.reblog": "{name} boosted your status", + "notification.status": "{name} ने अभी पोस्ट किया", "notifications.clear": "सूचनाएं हटाए", "notifications.column_settings.admin.report": "नई रिपोर्ट:", "notifications.column_settings.favourite": "पसंदीदा:", @@ -399,9 +400,12 @@ "notifications.column_settings.show": "कॉलम में दिखाएँ", "notifications.column_settings.sound": "ध्वनि चलाएँ", "notifications.column_settings.status": "New toots:", + "notifications.column_settings.unread_notifications.category": "अपठित सूचनाएं", + "notifications.column_settings.unread_notifications.highlight": "अपठित सूचनाओं को हाइलाइट करें", "notifications.column_settings.update": "संपादन:", "notifications.filter.all": "सभी", "notifications.filter.boosts": "बूस्ट", + "notifications.filter.favourites": "पसंदीदा", "notifications.filter.follows": "फॉलो", "notifications.filter.mentions": "उल्लेख", "notifications.filter.polls": "चुनाव परिणाम", @@ -416,6 +420,7 @@ "onboarding.follows.title": "Popular on Mastodon", "onboarding.profile.discoverable": "अपना प्रोफाइल खोजने योग्य बनाएं", "onboarding.profile.discoverable_hint": "जब आप मॅस्टोडॉन पर डिस्कवरेबिलिटी चुनते हैं तो आपके पोस्ट ट्रेंडिंग और सर्च में दिख सकते हैं और आपका प्रोफाइल आपके ही जैसे अकाउंट्स को सुझाया जा सकता है।", + "onboarding.profile.display_name": "प्रदर्शित नाम", "onboarding.share.message": "मैं {username} मॅस्टोडॉन पर हूं! मुझे यहां {url} फॉलो करें", "onboarding.share.next_steps": "आगे कि संभवित विधि", "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", @@ -445,6 +450,9 @@ "recommended": "अनुशंसित", "refresh": "रीफ्रेश करें", "regeneration_indicator.label": "लोड हो रहा है...", + "relative_time.days": "{number}दिन", + "relative_time.full.days": "{number, plural, one {# दिन} other {# दिन}} पहले", + "relative_time.full.hours": "{number, plural,one {# घंटा} other {# घंटे}} पहले", "relative_time.full.just_now": "अभी-अभी", "relative_time.full.minutes": "{number, plural, one {# मिनट} other {# मिनट}} पहले", "relative_time.full.seconds": "{number, plural, one {# सेकंड} other {# सेकंड}} पहले", @@ -454,15 +462,23 @@ "relative_time.seconds": "{number} सेकंड", "relative_time.today": "आज", "reply_indicator.cancel": "रद्द करें", + "report.block": "ब्लॉक", "report.block_explanation": "आपको उनकी पोस्टें नहीं दिखेंगे। वे आपकी पोस्टें को देख नहीं पाएंगे और आपको फ़ॉलो नहीं कर पाएंगे। उन्हे पता लगेगा कि वे blocked हैं।", "report.categories.other": "अन्य", "report.categories.spam": "अवांछित", "report.category.title_account": "रूपरेखा", "report.close": "स्वीकार करें", "report.comment.title": "क्या और कुछ है जिसके बारे में आपको लगता है कि हमें सूचित होना चाहिए?", + "report.next": "आगे", "report.placeholder": "Type or paste additional comments", "report.reasons.dislike": "मुझे यह पसंद नहीं है", + "report.reasons.legal": "यह अवैध है", + "report.reasons.legal_description": "आप मानते हैं कि यह आपके या सर्वर के देश के कानून का उल्लंघन करता है", "report.reasons.other": "कुछ और है।", + "report.reasons.violation": "यह सर्वर नियमों का उल्लंघन करता है", + "report.rules.title": "किन नियमों का उल्लंघन हो रहा है?", + "report.statuses.subtitle": "लागू होने वाले सभी का चयन करें", + "report.statuses.title": "क्या ऐसे कोई पोस्ट हैं जो इस रिपोर्ट का समर्थन करते हों?", "report.submit": "सबमिट करें", "report.target": "Report {target}", "report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached", @@ -480,11 +496,24 @@ "search_results.statuses": "Toots", "sign_in_banner.sign_in": "Sign in", "status.admin_status": "Open this status in the moderation interface", + "status.block": "@{name} को ब्लॉक करें", + "status.bookmark": "बुकमार्क", + "status.cannot_reblog": "रिपोस्ट को बूस्ट नहीं किया जा सकता", "status.copy": "Copy link to status", + "status.delete": "हटाएं", + "status.detailed_status": "विस्तृत वार्ता दृश्य", "status.direct": "निजी संदेश @{name} से", "status.edited_x_times": "Edited {count, plural, one {# time} other {# times}}", + "status.media.open": "खोलने के लिए क्लिक करें", + "status.media.show": "दिखाने के लिए क्लिक करें", + "status.mention": "@{name} का उल्लेख करें", + "status.more": "अतिरिक्त", + "status.mute": "@{name} म्यूट करें", + "status.mute_conversation": "इस वार्तालाप को म्यूट करें", "status.open": "Expand this status", + "status.pin": "प्रोफ़ाइल पर पिन करें", "status.pinned": "Pinned toot", + "status.read_more": "और पढ़ें", "status.reblog": "बूस्ट", "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.replied_to": "{name} का उत्तर दें", diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index e790306e9c..a660eb77ff 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -9,14 +9,20 @@ "account.block": "Blocar @{name}", "account.block_short": "Blocar", "account.blocked": "Blocate", + "account.browse_more_on_origin_server": "Navigar plus sur le profilo original", "account.copy": "Copiar ligamine a profilo", + "account.domain_blocked": "Dominio blocate", "account.edit_profile": "Modificar profilo", + "account.enable_notifications": "Notifica me quando @{name} publica", "account.endorse": "Evidentiar sur le profilo", "account.featured_tags.last_status_at": "Ultime message in {date}", "account.featured_tags.last_status_never": "Necun messages", + "account.featured_tags.title": "Hashtags eminente de {name}", "account.follow": "Sequer", "account.follow_back": "Sequer etiam", "account.followers": "Sequitores", + "account.followers.empty": "Iste usator ancora non ha sequitores.", + "account.followers_counter": "{count, plural, one {{counter} sequitor} other {{counter} sequitores}}", "account.following": "Sequente", "account.go_to_profile": "Vader al profilo", "account.hide_reblogs": "Celar boosts de @{name}", @@ -30,6 +36,7 @@ "account.mute_short": "Silentiar", "account.muted": "Silentiate", "account.no_bio": "Nulle description fornite.", + "account.open_original_page": "Aperir le pagina original", "account.posts": "Messages", "account.posts_with_replies": "Messages e responsas", "account.share": "Compartir profilo de @{name}", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 264781baa3..70ce6611d6 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -683,7 +683,7 @@ "status.show_more": "펼치기", "status.show_more_all": "모두 펼치기", "status.show_original": "원본 보기", - "status.title.with_attachments": "{user} 님이 {attachmentCount, plural, one {첨부} other {{attachmentCount}개 첨부}}하여 게시", + "status.title.with_attachments": "{user} 님이 {attachmentCount, plural, one {첨부파일} other {{attachmentCount}개의 첨부파일}}과 함께 게시함", "status.translate": "번역", "status.translated_from_with": "{provider}에 의해 {lang}에서 번역됨", "status.uncached_media_warning": "마리보기 허용되지 않음", diff --git a/app/javascript/mastodon/locales/lad.json b/app/javascript/mastodon/locales/lad.json index 2a911483de..8fde687427 100644 --- a/app/javascript/mastodon/locales/lad.json +++ b/app/javascript/mastodon/locales/lad.json @@ -328,6 +328,7 @@ "interaction_modal.on_another_server": "En otro sirvidor", "interaction_modal.on_this_server": "En este sirvidor", "interaction_modal.sign_in": "No estas konektado kon este sirvidor. Ande tyenes tu kuento?", + "interaction_modal.sign_in_hint": "Konsejo: Akel es el sitio adonde te enrejistrates. Si no lo akodras, bushka el mesaj de posta elektronika de bienvenida en tu kuti de arivo. Tambien puedes eskrivir tu nombre de utilizador kompleto (por enshemplo @Mastodon@mastodon.social)", "interaction_modal.title.favourite": "Endika ke te plaze publikasyon de {name}", "interaction_modal.title.follow": "Sige a {name}", "interaction_modal.title.reblog": "Repartaja publikasyon de {name}", @@ -478,6 +479,7 @@ "onboarding.actions.go_to_explore": "Va a los trendes", "onboarding.actions.go_to_home": "Va a tu linya prinsipala", "onboarding.compose.template": "Ke haber, #Mastodon?", + "onboarding.follows.empty": "Malorozamente, no se pueden amostrar rezultados en este momento. Puedes aprovar uzar la bushkeda o navigar por la pajina de eksplorasyon para topar personas a las que segir, o aprovarlo de muevo mas tadre.", "onboarding.follows.title": "Personaliza tu linya prinsipala", "onboarding.profile.discoverable": "Faz ke mi profil apareska en bushkedas", "onboarding.profile.display_name": "Nombre amostrado", @@ -497,7 +499,9 @@ "onboarding.start.title": "Lo logrates!", "onboarding.steps.follow_people.body": "El buto de Mastodon es segir a djente interesante.", "onboarding.steps.follow_people.title": "Personaliza tu linya prinsipala", + "onboarding.steps.publish_status.body": "Puedes introdusirte al mundo con teksto, fotos, videos o anketas {emoji}", "onboarding.steps.publish_status.title": "Eskrive tu primera publikasyon", + "onboarding.steps.setup_profile.body": "Kompleta tu profil para aumentar tus enteraksyones.", "onboarding.steps.setup_profile.title": "Personaliza tu profil", "onboarding.steps.share_profile.body": "Informe a tus amigos komo toparte en Mastodon", "onboarding.steps.share_profile.title": "Partaja tu profil de Mastodon", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index ec0d30363c..623ff2248f 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -9,7 +9,7 @@ "about.domain_blocks.suspended.explanation": "Jokie duomenys iš šio serverio nebus apdorojami, saugomi ar keičiami, todėl bet kokia sąveika ar bendravimas su šio serverio naudotojais bus neįmanomas.", "about.domain_blocks.suspended.title": "Uždrausta", "about.not_available": "Ši informacija nebuvo pateikta šiame serveryje.", - "about.powered_by": "Decentralizuota socialinė žiniasklaida, kurią valdo {mastodon}", + "about.powered_by": "Decentralizuota socialinė medija, kurią valdo {mastodon}", "about.rules": "Serverio taisyklės", "account.account_note_header": "Pastaba", "account.add_or_remove_from_list": "Pridėti arba ištrinti iš sąrašų", @@ -27,24 +27,24 @@ "account.domain_blocked": "Užblokuotas domenas", "account.edit_profile": "Redaguoti profilį", "account.enable_notifications": "Pranešti man, kai @{name} paskelbia", - "account.endorse": "Savybė profilyje", + "account.endorse": "Rekomenduoti profilyje", "account.featured_tags.last_status_at": "Paskutinį kartą paskelbta {date}", "account.featured_tags.last_status_never": "Nėra įrašų", - "account.featured_tags.title": "{name} rekomenduojamos grotažymės", + "account.featured_tags.title": "{name} rekomenduojami saitažodžiai", "account.follow": "Sekti", "account.follow_back": "Sekti atgal", "account.followers": "Sekėjai", "account.followers.empty": "Šio naudotojo dar niekas neseka.", "account.followers_counter": "{count, plural, one {{counter} sekėjas} few {{counter} sekėjai} many {{counter} sekėjo} other {{counter} sekėjų}}", - "account.following": "Seka", - "account.following_counter": "{count, plural, one {{counter} Seka} few {{counter} Seka} many {{counter} Seka} other {{counter} Seka}}", + "account.following": "Sekama", + "account.following_counter": "{count, plural, one {{counter} sekimas} few {{counter} sekimai} many {{counter} sekimo} other {{counter} sekimų}}", "account.follows.empty": "Šis (-i) naudotojas (-a) dar nieko neseka.", "account.go_to_profile": "Eiti į profilį", "account.hide_reblogs": "Slėpti pakėlimus iš @{name}", "account.in_memoriam": "Atminimui.", "account.joined_short": "Prisijungė", "account.languages": "Keisti prenumeruojamas kalbas", - "account.link_verified_on": "Šios nuorodos nuosavybė buvo patikrinta {date}", + "account.link_verified_on": "Šios nuorodos nuosavybė buvo patikrinta {date}.", "account.locked_info": "Šios paskyros privatumo būsena nustatyta kaip užrakinta. Savininkas (-ė) rankiniu būdu peržiūri, kas gali sekti.", "account.media": "Medija", "account.mention": "Paminėti @{name}", @@ -58,8 +58,8 @@ "account.open_original_page": "Atidaryti originalinį puslapį", "account.posts": "Įrašai", "account.posts_with_replies": "Įrašai ir atsakymai", - "account.report": "Pranešti @{name}", - "account.requested": "Laukiama patvirtinimo. Spausk, kad atšaukti sekimo užklausą", + "account.report": "Pranešti apie @{name}", + "account.requested": "Laukiama patvirtinimo. Spustelėk, jei nori atšaukti sekimo prašymą.", "account.requested_follow": "{name} paprašė tave sekti", "account.share": "Bendrinti @{name} profilį", "account.show_reblogs": "Rodyti pakėlimus iš @{name}", @@ -69,28 +69,28 @@ "account.unblock_short": "Atblokuoti", "account.unendorse": "Nerodyti profilyje", "account.unfollow": "Nebesekti", - "account.unmute": "Atitildyti @{name}", - "account.unmute_notifications_short": "Atitildyti pranešimus", - "account.unmute_short": "Atitildyti", - "account_note.placeholder": "Spausk norėdamas (-a) pridėti pastabą", - "admin.dashboard.daily_retention": "Vartotojų išbuvimo rodiklis pagal dieną po registracijos", - "admin.dashboard.monthly_retention": "Naudotojų išlaikymo rodiklis pagal mėnesį po registracijos", + "account.unmute": "Atšaukti nutildymą @{name}", + "account.unmute_notifications_short": "Atšaukti nutildymą pranešimams", + "account.unmute_short": "Atšaukti nutildymą", + "account_note.placeholder": "Spustelėk norėdamas (-a) pridėti pastabą", + "admin.dashboard.daily_retention": "Naudotojų pasilikimo rodiklis pagal dieną po registracijos", + "admin.dashboard.monthly_retention": "Naudotojų pasilikimo rodiklis pagal mėnesį po registracijos", "admin.dashboard.retention.average": "Vidurkis", - "admin.dashboard.retention.cohort": "Registravimo mėnuo", + "admin.dashboard.retention.cohort": "Registracijos mėnuo", "admin.dashboard.retention.cohort_size": "Nauji naudotojai", "admin.impact_report.instance_accounts": "Paskyrų profiliai, kuriuos tai ištrintų", "admin.impact_report.instance_followers": "Sekėjai, kuriuos prarastų mūsų naudotojai", "admin.impact_report.instance_follows": "Sekėjai, kuriuos prarastų jų naudotojai", "admin.impact_report.title": "Poveikio apibendrinimas", "alert.rate_limited.message": "Pabandyk vėliau po {retry_time, time, medium}.", - "alert.rate_limited.title": "Spartos ribojimas", + "alert.rate_limited.title": "Sparta ribota", "alert.unexpected.message": "Įvyko netikėta klaida.", "alert.unexpected.title": "Ups!", "announcement.announcement": "Skelbimas", "attachments_list.unprocessed": "(neapdorotas)", "audio.hide": "Slėpti garsą", "autosuggest_hashtag.per_week": "{count} per savaitę", - "boost_modal.combo": "Gali spausti {combo}, kad praleisti kitą kartą", + "boost_modal.combo": "Gali paspausti {combo}, kad praleisti kitą kartą", "bundle_column_error.copy_stacktrace": "Kopijuoti klaidos ataskaitą", "bundle_column_error.error.body": "Užklausos puslapio nepavyko atvaizduoti. Tai gali būti dėl mūsų kodo klaidos arba naršyklės suderinamumo problemos.", "bundle_column_error.error.title": "O, ne!", @@ -104,10 +104,10 @@ "bundle_modal_error.message": "Kraunant šį komponentą kažkas nepavyko.", "bundle_modal_error.retry": "Bandyti dar kartą", "closed_registrations.other_server_instructions": "Kadangi Mastodon yra decentralizuotas, gali susikurti paskyrą kitame serveryje ir vis tiek bendrauti su šiuo serveriu.", - "closed_registrations_modal.description": "Sukurti paskyrą {domain} šiuo metu neįmanoma, tačiau nepamiršk, kad norint naudotis Mastodon nebūtina turėti paskyrą {domain}.", + "closed_registrations_modal.description": "Sukurti paskyrą {domain} šiuo metu neįmanoma, tačiau nepamiršk, kad norint naudotis Mastodon nebūtina turėti paskyrą domene {domain}.", "closed_registrations_modal.find_another_server": "Rasti kitą serverį", "closed_registrations_modal.preamble": "Mastodon yra decentralizuotas, todėl nesvarbu, kur susikursi paskyrą, galėsi sekti ir bendrauti su bet kuriuo šiame serveryje esančiu asmeniu. Jį gali net savarankiškai talpinti!", - "closed_registrations_modal.title": "Užsiregistravimas į Mastodon", + "closed_registrations_modal.title": "Užsiregistruoti Mastodon", "column.about": "Apie", "column.blocks": "Užblokuoti naudotojai", "column.bookmarks": "Žymės", @@ -116,15 +116,15 @@ "column.directory": "Naršyti profilius", "column.domain_blocks": "Užblokuoti domenai", "column.favourites": "Mėgstamiausi", - "column.firehose": "Tiesioginiai padavimai", - "column.follow_requests": "Sekti prašymus", + "column.firehose": "Tiesioginiai srautai", + "column.follow_requests": "Sekimo prašymus", "column.home": "Pagrindinis", "column.lists": "Sąrašai", "column.mutes": "Nutildyti naudotojai", "column.notifications": "Pranešimai", "column.pins": "Prisegti įrašai", "column.public": "Federacinė laiko skalė", - "column_back_button.label": "Atgal", + "column_back_button.label": "Grįžti", "column_header.hide_settings": "Slėpti nustatymus", "column_header.moveLeft_settings": "Judinti stulpelį į kairę", "column_header.moveRight_settings": "Judinti stulpelį į dešinę", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 482cc8ee73..b8e18e1229 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -32,6 +32,7 @@ "account.featured_tags.last_status_never": "Sem publicações", "account.featured_tags.title": "Hashtags em destaque de {name}", "account.follow": "Seguir", + "account.follow_back": "Seguir de volta", "account.followers": "Seguidores", "account.followers.empty": "Nada aqui.", "account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidores}}", @@ -52,6 +53,7 @@ "account.mute_notifications_short": "Silenciar notificações", "account.mute_short": "Silenciar", "account.muted": "Silenciado", + "account.mutual": "Mútuo", "account.no_bio": "Nenhuma descrição fornecida.", "account.open_original_page": "Abrir a página original", "account.posts": "Toots", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index b108e581a4..65f27ef061 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -314,7 +314,7 @@ "home.explore_prompt.body": "ฟีดหน้าแรกของคุณจะมีการผสมผสานของโพสต์จากแฮชแท็กที่คุณได้เลือกติดตาม, ผู้คนที่คุณได้เลือกติดตาม และโพสต์ที่เขาดัน หากนั่นรู้สึกเงียบเกินไป คุณอาจต้องการ:", "home.explore_prompt.title": "นี่คือฐานหน้าแรกของคุณภายใน Mastodon", "home.hide_announcements": "ซ่อนประกาศ", - "home.pending_critical_update.body": "โปรดอัปเดตเซิร์ฟเวอร์ Mastodon ของคุณโดยเร็วที่สุดเท่าที่จะทำได้!", + "home.pending_critical_update.body": "โปรดอัปเดตเซิร์ฟเวอร์ Mastodon ของคุณโดยเร็วที่สุดเท่าที่จะเป็นไปได้!", "home.pending_critical_update.link": "ดูการอัปเดต", "home.pending_critical_update.title": "มีการอัปเดตความปลอดภัยสำคัญพร้อมใช้งาน!", "home.show_announcements": "แสดงประกาศ", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index 9de043bb20..c623caa3fb 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -358,7 +358,7 @@ "keyboard_shortcuts.my_profile": "mở hồ sơ của bạn", "keyboard_shortcuts.notifications": "mở thông báo", "keyboard_shortcuts.open_media": "mở ảnh hoặc video", - "keyboard_shortcuts.pinned": "mở những tút đã ghim", + "keyboard_shortcuts.pinned": "Open pinned posts list", "keyboard_shortcuts.profile": "mở trang của người đăng tút", "keyboard_shortcuts.reply": "trả lời", "keyboard_shortcuts.requests": "mở danh sách yêu cầu theo dõi", diff --git a/app/javascript/mastodon/reducers/accounts.ts b/app/javascript/mastodon/reducers/accounts.ts index e6f07340c0..5a9cc7220c 100644 --- a/app/javascript/mastodon/reducers/accounts.ts +++ b/app/javascript/mastodon/reducers/accounts.ts @@ -59,25 +59,19 @@ export const accountsReducer: Reducer = ( return normalizeAccounts(state, action.payload.accounts); else if (followAccountSuccess.match(action)) { return state - .update( - action.payload.relationship.id, - (account) => account?.update('followers_count', (n) => n + 1), + .update(action.payload.relationship.id, (account) => + account?.update('followers_count', (n) => n + 1), ) - .update( - getCurrentUser(), - (account) => account?.update('following_count', (n) => n + 1), + .update(getCurrentUser(), (account) => + account?.update('following_count', (n) => n + 1), ); } else if (unfollowAccountSuccess.match(action)) return state - .update( - action.payload.relationship.id, - (account) => - account?.update('followers_count', (n) => Math.max(0, n - 1)), + .update(action.payload.relationship.id, (account) => + account?.update('followers_count', (n) => Math.max(0, n - 1)), ) - .update( - getCurrentUser(), - (account) => - account?.update('following_count', (n) => Math.max(0, n - 1)), + .update(getCurrentUser(), (account) => + account?.update('following_count', (n) => Math.max(0, n - 1)), ); else return state; }; diff --git a/app/javascript/mastodon/store/typed_functions.ts b/app/javascript/mastodon/store/typed_functions.ts index 46a10b8b47..4859b82651 100644 --- a/app/javascript/mastodon/store/typed_functions.ts +++ b/app/javascript/mastodon/store/typed_functions.ts @@ -1,12 +1,11 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; -import type { TypedUseSelectorHook } from 'react-redux'; // eslint-disable-next-line @typescript-eslint/no-restricted-imports import { useDispatch, useSelector } from 'react-redux'; import type { AppDispatch, RootState } from './store'; -export const useAppDispatch: () => AppDispatch = useDispatch; -export const useAppSelector: TypedUseSelectorHook = useSelector; +export const useAppDispatch = useDispatch.withTypes(); +export const useAppSelector = useSelector.withTypes(); export const createAppAsyncThunk = createAsyncThunk.withTypes<{ state: RootState; diff --git a/app/javascript/material-icons/400-24px/account_circle-fill.svg b/app/javascript/material-icons/400-24px/account_circle-fill.svg new file mode 100644 index 0000000000..1bf9d57a31 --- /dev/null +++ b/app/javascript/material-icons/400-24px/account_circle-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/account_circle.svg b/app/javascript/material-icons/400-24px/account_circle.svg new file mode 100644 index 0000000000..ce59194be0 --- /dev/null +++ b/app/javascript/material-icons/400-24px/account_circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/add-fill.svg b/app/javascript/material-icons/400-24px/add-fill.svg new file mode 100644 index 0000000000..f8bc9309ce --- /dev/null +++ b/app/javascript/material-icons/400-24px/add-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/add.svg b/app/javascript/material-icons/400-24px/add.svg new file mode 100644 index 0000000000..f8bc9309ce --- /dev/null +++ b/app/javascript/material-icons/400-24px/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/add_photo_alternate-fill.svg b/app/javascript/material-icons/400-24px/add_photo_alternate-fill.svg new file mode 100644 index 0000000000..deb3f8e0d9 --- /dev/null +++ b/app/javascript/material-icons/400-24px/add_photo_alternate-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/add_photo_alternate.svg b/app/javascript/material-icons/400-24px/add_photo_alternate.svg new file mode 100644 index 0000000000..0ae8ad841c --- /dev/null +++ b/app/javascript/material-icons/400-24px/add_photo_alternate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/add_reaction-fill.svg b/app/javascript/material-icons/400-24px/add_reaction-fill.svg new file mode 100644 index 0000000000..3ea1c30a52 --- /dev/null +++ b/app/javascript/material-icons/400-24px/add_reaction-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/add_reaction.svg b/app/javascript/material-icons/400-24px/add_reaction.svg new file mode 100644 index 0000000000..77aace24b0 --- /dev/null +++ b/app/javascript/material-icons/400-24px/add_reaction.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/alternate_email-fill.svg b/app/javascript/material-icons/400-24px/alternate_email-fill.svg new file mode 100644 index 0000000000..7648cf9755 --- /dev/null +++ b/app/javascript/material-icons/400-24px/alternate_email-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/alternate_email.svg b/app/javascript/material-icons/400-24px/alternate_email.svg new file mode 100644 index 0000000000..7648cf9755 --- /dev/null +++ b/app/javascript/material-icons/400-24px/alternate_email.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/arrow_back-fill.svg b/app/javascript/material-icons/400-24px/arrow_back-fill.svg new file mode 100644 index 0000000000..cba0c8b2a8 --- /dev/null +++ b/app/javascript/material-icons/400-24px/arrow_back-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/arrow_back.svg b/app/javascript/material-icons/400-24px/arrow_back.svg new file mode 100644 index 0000000000..cba0c8b2a8 --- /dev/null +++ b/app/javascript/material-icons/400-24px/arrow_back.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/arrow_drop_down-fill.svg b/app/javascript/material-icons/400-24px/arrow_drop_down-fill.svg new file mode 100644 index 0000000000..48c72546df --- /dev/null +++ b/app/javascript/material-icons/400-24px/arrow_drop_down-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/arrow_drop_down.svg b/app/javascript/material-icons/400-24px/arrow_drop_down.svg new file mode 100644 index 0000000000..48c72546df --- /dev/null +++ b/app/javascript/material-icons/400-24px/arrow_drop_down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/arrow_right_alt-fill.svg b/app/javascript/material-icons/400-24px/arrow_right_alt-fill.svg new file mode 100644 index 0000000000..4bf73bb6da --- /dev/null +++ b/app/javascript/material-icons/400-24px/arrow_right_alt-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/arrow_right_alt.svg b/app/javascript/material-icons/400-24px/arrow_right_alt.svg new file mode 100644 index 0000000000..4bf73bb6da --- /dev/null +++ b/app/javascript/material-icons/400-24px/arrow_right_alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/attach_file-fill.svg b/app/javascript/material-icons/400-24px/attach_file-fill.svg new file mode 100644 index 0000000000..e719e8fd06 --- /dev/null +++ b/app/javascript/material-icons/400-24px/attach_file-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/attach_file.svg b/app/javascript/material-icons/400-24px/attach_file.svg new file mode 100644 index 0000000000..e719e8fd06 --- /dev/null +++ b/app/javascript/material-icons/400-24px/attach_file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/block-fill.svg b/app/javascript/material-icons/400-24px/block-fill.svg new file mode 100644 index 0000000000..20e9889ae8 --- /dev/null +++ b/app/javascript/material-icons/400-24px/block-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/block.svg b/app/javascript/material-icons/400-24px/block.svg new file mode 100644 index 0000000000..20e9889ae8 --- /dev/null +++ b/app/javascript/material-icons/400-24px/block.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/bookmark-fill.svg b/app/javascript/material-icons/400-24px/bookmark-fill.svg new file mode 100644 index 0000000000..3a7b4d2e8b --- /dev/null +++ b/app/javascript/material-icons/400-24px/bookmark-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/bookmark.svg b/app/javascript/material-icons/400-24px/bookmark.svg new file mode 100644 index 0000000000..a8226a6d87 --- /dev/null +++ b/app/javascript/material-icons/400-24px/bookmark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/bookmarks-fill.svg b/app/javascript/material-icons/400-24px/bookmarks-fill.svg new file mode 100644 index 0000000000..f5231f925a --- /dev/null +++ b/app/javascript/material-icons/400-24px/bookmarks-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/bookmarks.svg b/app/javascript/material-icons/400-24px/bookmarks.svg new file mode 100644 index 0000000000..67dffd6857 --- /dev/null +++ b/app/javascript/material-icons/400-24px/bookmarks.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/brush-fill.svg b/app/javascript/material-icons/400-24px/brush-fill.svg new file mode 100644 index 0000000000..f92d77ab32 --- /dev/null +++ b/app/javascript/material-icons/400-24px/brush-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/brush.svg b/app/javascript/material-icons/400-24px/brush.svg new file mode 100644 index 0000000000..d583fce54d --- /dev/null +++ b/app/javascript/material-icons/400-24px/brush.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/campaign-fill.svg b/app/javascript/material-icons/400-24px/campaign-fill.svg new file mode 100644 index 0000000000..3df7275bf6 --- /dev/null +++ b/app/javascript/material-icons/400-24px/campaign-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/campaign.svg b/app/javascript/material-icons/400-24px/campaign.svg new file mode 100644 index 0000000000..a6d893fed4 --- /dev/null +++ b/app/javascript/material-icons/400-24px/campaign.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cancel-fill.svg b/app/javascript/material-icons/400-24px/cancel-fill.svg new file mode 100644 index 0000000000..f7d476f253 --- /dev/null +++ b/app/javascript/material-icons/400-24px/cancel-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cancel.svg b/app/javascript/material-icons/400-24px/cancel.svg new file mode 100644 index 0000000000..8504fbfdad --- /dev/null +++ b/app/javascript/material-icons/400-24px/cancel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cancel_presentation-fill.svg b/app/javascript/material-icons/400-24px/cancel_presentation-fill.svg new file mode 100644 index 0000000000..8e8e6a1ee6 --- /dev/null +++ b/app/javascript/material-icons/400-24px/cancel_presentation-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cancel_presentation.svg b/app/javascript/material-icons/400-24px/cancel_presentation.svg new file mode 100644 index 0000000000..c0da419cd0 --- /dev/null +++ b/app/javascript/material-icons/400-24px/cancel_presentation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/chat-fill.svg b/app/javascript/material-icons/400-24px/chat-fill.svg new file mode 100644 index 0000000000..3a74e02f16 --- /dev/null +++ b/app/javascript/material-icons/400-24px/chat-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/chat.svg b/app/javascript/material-icons/400-24px/chat.svg new file mode 100644 index 0000000000..4d910a87f1 --- /dev/null +++ b/app/javascript/material-icons/400-24px/chat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/check-fill.svg b/app/javascript/material-icons/400-24px/check-fill.svg new file mode 100644 index 0000000000..1655d12bf3 --- /dev/null +++ b/app/javascript/material-icons/400-24px/check-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/check.svg b/app/javascript/material-icons/400-24px/check.svg new file mode 100644 index 0000000000..1655d12bf3 --- /dev/null +++ b/app/javascript/material-icons/400-24px/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/check_box_outline_blank-fill.svg b/app/javascript/material-icons/400-24px/check_box_outline_blank-fill.svg new file mode 100644 index 0000000000..3f7df315a5 --- /dev/null +++ b/app/javascript/material-icons/400-24px/check_box_outline_blank-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/check_box_outline_blank.svg b/app/javascript/material-icons/400-24px/check_box_outline_blank.svg new file mode 100644 index 0000000000..3f7df315a5 --- /dev/null +++ b/app/javascript/material-icons/400-24px/check_box_outline_blank.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/chevron_left-fill.svg b/app/javascript/material-icons/400-24px/chevron_left-fill.svg new file mode 100644 index 0000000000..53783746ae --- /dev/null +++ b/app/javascript/material-icons/400-24px/chevron_left-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/chevron_left.svg b/app/javascript/material-icons/400-24px/chevron_left.svg new file mode 100644 index 0000000000..53783746ae --- /dev/null +++ b/app/javascript/material-icons/400-24px/chevron_left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/chevron_right-fill.svg b/app/javascript/material-icons/400-24px/chevron_right-fill.svg new file mode 100644 index 0000000000..4100467365 --- /dev/null +++ b/app/javascript/material-icons/400-24px/chevron_right-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/chevron_right.svg b/app/javascript/material-icons/400-24px/chevron_right.svg new file mode 100644 index 0000000000..4100467365 --- /dev/null +++ b/app/javascript/material-icons/400-24px/chevron_right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/close-fill.svg b/app/javascript/material-icons/400-24px/close-fill.svg new file mode 100644 index 0000000000..5a60c58e77 --- /dev/null +++ b/app/javascript/material-icons/400-24px/close-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/close.svg b/app/javascript/material-icons/400-24px/close.svg new file mode 100644 index 0000000000..5a60c58e77 --- /dev/null +++ b/app/javascript/material-icons/400-24px/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/code-fill.svg b/app/javascript/material-icons/400-24px/code-fill.svg new file mode 100644 index 0000000000..8ef5c55cd4 --- /dev/null +++ b/app/javascript/material-icons/400-24px/code-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/code.svg b/app/javascript/material-icons/400-24px/code.svg new file mode 100644 index 0000000000..8ef5c55cd4 --- /dev/null +++ b/app/javascript/material-icons/400-24px/code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/content_copy-fill.svg b/app/javascript/material-icons/400-24px/content_copy-fill.svg new file mode 100644 index 0000000000..dabf094503 --- /dev/null +++ b/app/javascript/material-icons/400-24px/content_copy-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/content_copy.svg b/app/javascript/material-icons/400-24px/content_copy.svg new file mode 100644 index 0000000000..d875c84491 --- /dev/null +++ b/app/javascript/material-icons/400-24px/content_copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/delete-fill.svg b/app/javascript/material-icons/400-24px/delete-fill.svg new file mode 100644 index 0000000000..59d1abb8bc --- /dev/null +++ b/app/javascript/material-icons/400-24px/delete-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/delete.svg b/app/javascript/material-icons/400-24px/delete.svg new file mode 100644 index 0000000000..560d174b9b --- /dev/null +++ b/app/javascript/material-icons/400-24px/delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/delete_forever-fill.svg b/app/javascript/material-icons/400-24px/delete_forever-fill.svg new file mode 100644 index 0000000000..40fe4497f5 --- /dev/null +++ b/app/javascript/material-icons/400-24px/delete_forever-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/delete_forever.svg b/app/javascript/material-icons/400-24px/delete_forever.svg new file mode 100644 index 0000000000..763f517d1d --- /dev/null +++ b/app/javascript/material-icons/400-24px/delete_forever.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/description-fill.svg b/app/javascript/material-icons/400-24px/description-fill.svg new file mode 100644 index 0000000000..07998b29d6 --- /dev/null +++ b/app/javascript/material-icons/400-24px/description-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/description.svg b/app/javascript/material-icons/400-24px/description.svg new file mode 100644 index 0000000000..309a4f5b38 --- /dev/null +++ b/app/javascript/material-icons/400-24px/description.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/done-fill.svg b/app/javascript/material-icons/400-24px/done-fill.svg new file mode 100644 index 0000000000..1655d12bf3 --- /dev/null +++ b/app/javascript/material-icons/400-24px/done-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/done.svg b/app/javascript/material-icons/400-24px/done.svg new file mode 100644 index 0000000000..1655d12bf3 --- /dev/null +++ b/app/javascript/material-icons/400-24px/done.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/done_all-fill.svg b/app/javascript/material-icons/400-24px/done_all-fill.svg new file mode 100644 index 0000000000..8f05228c40 --- /dev/null +++ b/app/javascript/material-icons/400-24px/done_all-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/done_all.svg b/app/javascript/material-icons/400-24px/done_all.svg new file mode 100644 index 0000000000..8f05228c40 --- /dev/null +++ b/app/javascript/material-icons/400-24px/done_all.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/download-fill.svg b/app/javascript/material-icons/400-24px/download-fill.svg new file mode 100644 index 0000000000..6a171ea822 --- /dev/null +++ b/app/javascript/material-icons/400-24px/download-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/download.svg b/app/javascript/material-icons/400-24px/download.svg new file mode 100644 index 0000000000..6a171ea822 --- /dev/null +++ b/app/javascript/material-icons/400-24px/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/edit-fill.svg b/app/javascript/material-icons/400-24px/edit-fill.svg new file mode 100644 index 0000000000..278e79978e --- /dev/null +++ b/app/javascript/material-icons/400-24px/edit-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/edit.svg b/app/javascript/material-icons/400-24px/edit.svg new file mode 100644 index 0000000000..cb81b11302 --- /dev/null +++ b/app/javascript/material-icons/400-24px/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/edit_note-fill.svg b/app/javascript/material-icons/400-24px/edit_note-fill.svg new file mode 100644 index 0000000000..b18db1df8e --- /dev/null +++ b/app/javascript/material-icons/400-24px/edit_note-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/edit_note.svg b/app/javascript/material-icons/400-24px/edit_note.svg new file mode 100644 index 0000000000..cf7e98405a --- /dev/null +++ b/app/javascript/material-icons/400-24px/edit_note.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/expand_less-fill.svg b/app/javascript/material-icons/400-24px/expand_less-fill.svg new file mode 100644 index 0000000000..453729655d --- /dev/null +++ b/app/javascript/material-icons/400-24px/expand_less-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/expand_less.svg b/app/javascript/material-icons/400-24px/expand_less.svg new file mode 100644 index 0000000000..453729655d --- /dev/null +++ b/app/javascript/material-icons/400-24px/expand_less.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/expand_more-fill.svg b/app/javascript/material-icons/400-24px/expand_more-fill.svg new file mode 100644 index 0000000000..0c8f273596 --- /dev/null +++ b/app/javascript/material-icons/400-24px/expand_more-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/expand_more.svg b/app/javascript/material-icons/400-24px/expand_more.svg new file mode 100644 index 0000000000..0c8f273596 --- /dev/null +++ b/app/javascript/material-icons/400-24px/expand_more.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/find_in_page-fill.svg b/app/javascript/material-icons/400-24px/find_in_page-fill.svg new file mode 100644 index 0000000000..146f838a27 --- /dev/null +++ b/app/javascript/material-icons/400-24px/find_in_page-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/find_in_page.svg b/app/javascript/material-icons/400-24px/find_in_page.svg new file mode 100644 index 0000000000..f21c2786ca --- /dev/null +++ b/app/javascript/material-icons/400-24px/find_in_page.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/flag-fill.svg b/app/javascript/material-icons/400-24px/flag-fill.svg new file mode 100644 index 0000000000..e44a94d90b --- /dev/null +++ b/app/javascript/material-icons/400-24px/flag-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/flag.svg b/app/javascript/material-icons/400-24px/flag.svg new file mode 100644 index 0000000000..cb4c810e08 --- /dev/null +++ b/app/javascript/material-icons/400-24px/flag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/forum-fill.svg b/app/javascript/material-icons/400-24px/forum-fill.svg new file mode 100644 index 0000000000..2459058aa3 --- /dev/null +++ b/app/javascript/material-icons/400-24px/forum-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/forum.svg b/app/javascript/material-icons/400-24px/forum.svg new file mode 100644 index 0000000000..6f5d8d7a4d --- /dev/null +++ b/app/javascript/material-icons/400-24px/forum.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/fullscreen-fill.svg b/app/javascript/material-icons/400-24px/fullscreen-fill.svg new file mode 100644 index 0000000000..940c878a7d --- /dev/null +++ b/app/javascript/material-icons/400-24px/fullscreen-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/fullscreen.svg b/app/javascript/material-icons/400-24px/fullscreen.svg new file mode 100644 index 0000000000..940c878a7d --- /dev/null +++ b/app/javascript/material-icons/400-24px/fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/fullscreen_exit-fill.svg b/app/javascript/material-icons/400-24px/fullscreen_exit-fill.svg new file mode 100644 index 0000000000..d9d45a6c6a --- /dev/null +++ b/app/javascript/material-icons/400-24px/fullscreen_exit-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/fullscreen_exit.svg b/app/javascript/material-icons/400-24px/fullscreen_exit.svg new file mode 100644 index 0000000000..d9d45a6c6a --- /dev/null +++ b/app/javascript/material-icons/400-24px/fullscreen_exit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/group-fill.svg b/app/javascript/material-icons/400-24px/group-fill.svg new file mode 100644 index 0000000000..c0d6cef5c5 --- /dev/null +++ b/app/javascript/material-icons/400-24px/group-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/group.svg b/app/javascript/material-icons/400-24px/group.svg new file mode 100644 index 0000000000..dbc2c937e4 --- /dev/null +++ b/app/javascript/material-icons/400-24px/group.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/home-fill.svg b/app/javascript/material-icons/400-24px/home-fill.svg new file mode 100644 index 0000000000..e254416380 --- /dev/null +++ b/app/javascript/material-icons/400-24px/home-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/home.svg b/app/javascript/material-icons/400-24px/home.svg new file mode 100644 index 0000000000..d700ddea7b --- /dev/null +++ b/app/javascript/material-icons/400-24px/home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/image-fill.svg b/app/javascript/material-icons/400-24px/image-fill.svg new file mode 100644 index 0000000000..ba28ad3534 --- /dev/null +++ b/app/javascript/material-icons/400-24px/image-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/image.svg b/app/javascript/material-icons/400-24px/image.svg new file mode 100644 index 0000000000..0e7c11d402 --- /dev/null +++ b/app/javascript/material-icons/400-24px/image.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/info-fill.svg b/app/javascript/material-icons/400-24px/info-fill.svg new file mode 100644 index 0000000000..0232e17ad0 --- /dev/null +++ b/app/javascript/material-icons/400-24px/info-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/info.svg b/app/javascript/material-icons/400-24px/info.svg new file mode 100644 index 0000000000..05606f4e59 --- /dev/null +++ b/app/javascript/material-icons/400-24px/info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/insert_chart-fill.svg b/app/javascript/material-icons/400-24px/insert_chart-fill.svg new file mode 100644 index 0000000000..12d137ca89 --- /dev/null +++ b/app/javascript/material-icons/400-24px/insert_chart-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/insert_chart.svg b/app/javascript/material-icons/400-24px/insert_chart.svg new file mode 100644 index 0000000000..4f2a10be59 --- /dev/null +++ b/app/javascript/material-icons/400-24px/insert_chart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/link-fill.svg b/app/javascript/material-icons/400-24px/link-fill.svg new file mode 100644 index 0000000000..319a0681c4 --- /dev/null +++ b/app/javascript/material-icons/400-24px/link-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/link.svg b/app/javascript/material-icons/400-24px/link.svg new file mode 100644 index 0000000000..319a0681c4 --- /dev/null +++ b/app/javascript/material-icons/400-24px/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/list_alt-fill.svg b/app/javascript/material-icons/400-24px/list_alt-fill.svg new file mode 100644 index 0000000000..6aa8b50823 --- /dev/null +++ b/app/javascript/material-icons/400-24px/list_alt-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/list_alt.svg b/app/javascript/material-icons/400-24px/list_alt.svg new file mode 100644 index 0000000000..cca8ab1955 --- /dev/null +++ b/app/javascript/material-icons/400-24px/list_alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/lock-fill.svg b/app/javascript/material-icons/400-24px/lock-fill.svg new file mode 100644 index 0000000000..0815d78418 --- /dev/null +++ b/app/javascript/material-icons/400-24px/lock-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/lock.svg b/app/javascript/material-icons/400-24px/lock.svg new file mode 100644 index 0000000000..20b9e3984e --- /dev/null +++ b/app/javascript/material-icons/400-24px/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/lock_open-fill.svg b/app/javascript/material-icons/400-24px/lock_open-fill.svg new file mode 100644 index 0000000000..60309dce5e --- /dev/null +++ b/app/javascript/material-icons/400-24px/lock_open-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/lock_open.svg b/app/javascript/material-icons/400-24px/lock_open.svg new file mode 100644 index 0000000000..824c70b7c4 --- /dev/null +++ b/app/javascript/material-icons/400-24px/lock_open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/logout-fill.svg b/app/javascript/material-icons/400-24px/logout-fill.svg new file mode 100644 index 0000000000..4881453501 --- /dev/null +++ b/app/javascript/material-icons/400-24px/logout-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/logout.svg b/app/javascript/material-icons/400-24px/logout.svg new file mode 100644 index 0000000000..4881453501 --- /dev/null +++ b/app/javascript/material-icons/400-24px/logout.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/mail-fill.svg b/app/javascript/material-icons/400-24px/mail-fill.svg new file mode 100644 index 0000000000..5e7e4a2fb2 --- /dev/null +++ b/app/javascript/material-icons/400-24px/mail-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/mail.svg b/app/javascript/material-icons/400-24px/mail.svg new file mode 100644 index 0000000000..15e1d12d4e --- /dev/null +++ b/app/javascript/material-icons/400-24px/mail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/manufacturing-fill.svg b/app/javascript/material-icons/400-24px/manufacturing-fill.svg new file mode 100644 index 0000000000..f19180759c --- /dev/null +++ b/app/javascript/material-icons/400-24px/manufacturing-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/manufacturing.svg b/app/javascript/material-icons/400-24px/manufacturing.svg new file mode 100644 index 0000000000..f19180759c --- /dev/null +++ b/app/javascript/material-icons/400-24px/manufacturing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/markdown-fill.svg b/app/javascript/material-icons/400-24px/markdown-fill.svg new file mode 100644 index 0000000000..18a0670518 --- /dev/null +++ b/app/javascript/material-icons/400-24px/markdown-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/markdown.svg b/app/javascript/material-icons/400-24px/markdown.svg new file mode 100644 index 0000000000..3396c2f99a --- /dev/null +++ b/app/javascript/material-icons/400-24px/markdown.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/menu-fill.svg b/app/javascript/material-icons/400-24px/menu-fill.svg new file mode 100644 index 0000000000..2f427e91c8 --- /dev/null +++ b/app/javascript/material-icons/400-24px/menu-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/menu.svg b/app/javascript/material-icons/400-24px/menu.svg new file mode 100644 index 0000000000..2f427e91c8 --- /dev/null +++ b/app/javascript/material-icons/400-24px/menu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/more_horiz-fill.svg b/app/javascript/material-icons/400-24px/more_horiz-fill.svg new file mode 100644 index 0000000000..e777154892 --- /dev/null +++ b/app/javascript/material-icons/400-24px/more_horiz-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/more_horiz.svg b/app/javascript/material-icons/400-24px/more_horiz.svg new file mode 100644 index 0000000000..e777154892 --- /dev/null +++ b/app/javascript/material-icons/400-24px/more_horiz.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/movie-fill.svg b/app/javascript/material-icons/400-24px/movie-fill.svg new file mode 100644 index 0000000000..d295408958 --- /dev/null +++ b/app/javascript/material-icons/400-24px/movie-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/movie.svg b/app/javascript/material-icons/400-24px/movie.svg new file mode 100644 index 0000000000..e98fa48473 --- /dev/null +++ b/app/javascript/material-icons/400-24px/movie.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/music_note-fill.svg b/app/javascript/material-icons/400-24px/music_note-fill.svg new file mode 100644 index 0000000000..b10ad1921a --- /dev/null +++ b/app/javascript/material-icons/400-24px/music_note-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/music_note.svg b/app/javascript/material-icons/400-24px/music_note.svg new file mode 100644 index 0000000000..b10ad1921a --- /dev/null +++ b/app/javascript/material-icons/400-24px/music_note.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/notifications-fill.svg b/app/javascript/material-icons/400-24px/notifications-fill.svg new file mode 100644 index 0000000000..0730efefca --- /dev/null +++ b/app/javascript/material-icons/400-24px/notifications-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/notifications.svg b/app/javascript/material-icons/400-24px/notifications.svg new file mode 100644 index 0000000000..dbfe0e0409 --- /dev/null +++ b/app/javascript/material-icons/400-24px/notifications.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/notifications_active-fill.svg b/app/javascript/material-icons/400-24px/notifications_active-fill.svg new file mode 100644 index 0000000000..856a0ed8a5 --- /dev/null +++ b/app/javascript/material-icons/400-24px/notifications_active-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/notifications_active.svg b/app/javascript/material-icons/400-24px/notifications_active.svg new file mode 100644 index 0000000000..1389a10e0a --- /dev/null +++ b/app/javascript/material-icons/400-24px/notifications_active.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/open_in_new-fill.svg b/app/javascript/material-icons/400-24px/open_in_new-fill.svg new file mode 100644 index 0000000000..42895ffd13 --- /dev/null +++ b/app/javascript/material-icons/400-24px/open_in_new-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/open_in_new.svg b/app/javascript/material-icons/400-24px/open_in_new.svg new file mode 100644 index 0000000000..42895ffd13 --- /dev/null +++ b/app/javascript/material-icons/400-24px/open_in_new.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/pause-fill.svg b/app/javascript/material-icons/400-24px/pause-fill.svg new file mode 100644 index 0000000000..fc9a8074de --- /dev/null +++ b/app/javascript/material-icons/400-24px/pause-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/pause.svg b/app/javascript/material-icons/400-24px/pause.svg new file mode 100644 index 0000000000..95bc792fc3 --- /dev/null +++ b/app/javascript/material-icons/400-24px/pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/person-fill.svg b/app/javascript/material-icons/400-24px/person-fill.svg new file mode 100644 index 0000000000..73ef1efc10 --- /dev/null +++ b/app/javascript/material-icons/400-24px/person-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/person.svg b/app/javascript/material-icons/400-24px/person.svg new file mode 100644 index 0000000000..a3f6b246c8 --- /dev/null +++ b/app/javascript/material-icons/400-24px/person.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/person_add-fill.svg b/app/javascript/material-icons/400-24px/person_add-fill.svg new file mode 100644 index 0000000000..3fa7f65288 --- /dev/null +++ b/app/javascript/material-icons/400-24px/person_add-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/person_add.svg b/app/javascript/material-icons/400-24px/person_add.svg new file mode 100644 index 0000000000..39b592bf04 --- /dev/null +++ b/app/javascript/material-icons/400-24px/person_add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/person_check-fill.svg b/app/javascript/material-icons/400-24px/person_check-fill.svg new file mode 100644 index 0000000000..21d91f1933 --- /dev/null +++ b/app/javascript/material-icons/400-24px/person_check-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/person_check.svg b/app/javascript/material-icons/400-24px/person_check.svg new file mode 100644 index 0000000000..fbe013ac7b --- /dev/null +++ b/app/javascript/material-icons/400-24px/person_check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/play_arrow-fill.svg b/app/javascript/material-icons/400-24px/play_arrow-fill.svg new file mode 100644 index 0000000000..6465b90222 --- /dev/null +++ b/app/javascript/material-icons/400-24px/play_arrow-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/play_arrow.svg b/app/javascript/material-icons/400-24px/play_arrow.svg new file mode 100644 index 0000000000..52f0fcc9c4 --- /dev/null +++ b/app/javascript/material-icons/400-24px/play_arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/public-fill.svg b/app/javascript/material-icons/400-24px/public-fill.svg new file mode 100644 index 0000000000..1e9e79de4d --- /dev/null +++ b/app/javascript/material-icons/400-24px/public-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/public.svg b/app/javascript/material-icons/400-24px/public.svg new file mode 100644 index 0000000000..1e9e79de4d --- /dev/null +++ b/app/javascript/material-icons/400-24px/public.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/push_pin-fill.svg b/app/javascript/material-icons/400-24px/push_pin-fill.svg new file mode 100644 index 0000000000..6095ba77ee --- /dev/null +++ b/app/javascript/material-icons/400-24px/push_pin-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/push_pin.svg b/app/javascript/material-icons/400-24px/push_pin.svg new file mode 100644 index 0000000000..e1abd900a7 --- /dev/null +++ b/app/javascript/material-icons/400-24px/push_pin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/rectangle-fill.svg b/app/javascript/material-icons/400-24px/rectangle-fill.svg new file mode 100644 index 0000000000..64b038f268 --- /dev/null +++ b/app/javascript/material-icons/400-24px/rectangle-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/rectangle.svg b/app/javascript/material-icons/400-24px/rectangle.svg new file mode 100644 index 0000000000..ada92f2cf5 --- /dev/null +++ b/app/javascript/material-icons/400-24px/rectangle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/refresh-fill.svg b/app/javascript/material-icons/400-24px/refresh-fill.svg new file mode 100644 index 0000000000..a7a6bc801b --- /dev/null +++ b/app/javascript/material-icons/400-24px/refresh-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/refresh.svg b/app/javascript/material-icons/400-24px/refresh.svg new file mode 100644 index 0000000000..a7a6bc801b --- /dev/null +++ b/app/javascript/material-icons/400-24px/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/repeat-fill.svg b/app/javascript/material-icons/400-24px/repeat-fill.svg new file mode 100644 index 0000000000..c1b09d8026 --- /dev/null +++ b/app/javascript/material-icons/400-24px/repeat-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/repeat.svg b/app/javascript/material-icons/400-24px/repeat.svg new file mode 100644 index 0000000000..c1b09d8026 --- /dev/null +++ b/app/javascript/material-icons/400-24px/repeat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/reply-fill.svg b/app/javascript/material-icons/400-24px/reply-fill.svg new file mode 100644 index 0000000000..eb661f2823 --- /dev/null +++ b/app/javascript/material-icons/400-24px/reply-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/reply.svg b/app/javascript/material-icons/400-24px/reply.svg new file mode 100644 index 0000000000..eb661f2823 --- /dev/null +++ b/app/javascript/material-icons/400-24px/reply.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/reply_all-fill.svg b/app/javascript/material-icons/400-24px/reply_all-fill.svg new file mode 100644 index 0000000000..74c9573eaf --- /dev/null +++ b/app/javascript/material-icons/400-24px/reply_all-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/reply_all.svg b/app/javascript/material-icons/400-24px/reply_all.svg new file mode 100644 index 0000000000..74c9573eaf --- /dev/null +++ b/app/javascript/material-icons/400-24px/reply_all.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/search-fill.svg b/app/javascript/material-icons/400-24px/search-fill.svg new file mode 100644 index 0000000000..ef0d0521eb --- /dev/null +++ b/app/javascript/material-icons/400-24px/search-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/search.svg b/app/javascript/material-icons/400-24px/search.svg new file mode 100644 index 0000000000..ef0d0521eb --- /dev/null +++ b/app/javascript/material-icons/400-24px/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/settings-fill.svg b/app/javascript/material-icons/400-24px/settings-fill.svg new file mode 100644 index 0000000000..f133479502 --- /dev/null +++ b/app/javascript/material-icons/400-24px/settings-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/settings.svg b/app/javascript/material-icons/400-24px/settings.svg new file mode 100644 index 0000000000..817c782f05 --- /dev/null +++ b/app/javascript/material-icons/400-24px/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/share-fill.svg b/app/javascript/material-icons/400-24px/share-fill.svg new file mode 100644 index 0000000000..5a6b0d0a8d --- /dev/null +++ b/app/javascript/material-icons/400-24px/share-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/share.svg b/app/javascript/material-icons/400-24px/share.svg new file mode 100644 index 0000000000..6876cd42da --- /dev/null +++ b/app/javascript/material-icons/400-24px/share.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/smart_toy-fill.svg b/app/javascript/material-icons/400-24px/smart_toy-fill.svg new file mode 100644 index 0000000000..df417f5ff7 --- /dev/null +++ b/app/javascript/material-icons/400-24px/smart_toy-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/smart_toy.svg b/app/javascript/material-icons/400-24px/smart_toy.svg new file mode 100644 index 0000000000..b84efc73b1 --- /dev/null +++ b/app/javascript/material-icons/400-24px/smart_toy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/star-fill.svg b/app/javascript/material-icons/400-24px/star-fill.svg new file mode 100644 index 0000000000..cb2231e634 --- /dev/null +++ b/app/javascript/material-icons/400-24px/star-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/star.svg b/app/javascript/material-icons/400-24px/star.svg new file mode 100644 index 0000000000..1736e085d0 --- /dev/null +++ b/app/javascript/material-icons/400-24px/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/tag-fill.svg b/app/javascript/material-icons/400-24px/tag-fill.svg new file mode 100644 index 0000000000..ce76d537b3 --- /dev/null +++ b/app/javascript/material-icons/400-24px/tag-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/tag.svg b/app/javascript/material-icons/400-24px/tag.svg new file mode 100644 index 0000000000..ce76d537b3 --- /dev/null +++ b/app/javascript/material-icons/400-24px/tag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/trip-fill.svg b/app/javascript/material-icons/400-24px/trip-fill.svg new file mode 100644 index 0000000000..97c8c46dad --- /dev/null +++ b/app/javascript/material-icons/400-24px/trip-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/trip.svg b/app/javascript/material-icons/400-24px/trip.svg new file mode 100644 index 0000000000..f158a738c6 --- /dev/null +++ b/app/javascript/material-icons/400-24px/trip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/tune-fill.svg b/app/javascript/material-icons/400-24px/tune-fill.svg new file mode 100644 index 0000000000..887f8bd498 --- /dev/null +++ b/app/javascript/material-icons/400-24px/tune-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/tune.svg b/app/javascript/material-icons/400-24px/tune.svg new file mode 100644 index 0000000000..887f8bd498 --- /dev/null +++ b/app/javascript/material-icons/400-24px/tune.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/upload_file-fill.svg b/app/javascript/material-icons/400-24px/upload_file-fill.svg new file mode 100644 index 0000000000..639d77af36 --- /dev/null +++ b/app/javascript/material-icons/400-24px/upload_file-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/upload_file.svg b/app/javascript/material-icons/400-24px/upload_file.svg new file mode 100644 index 0000000000..40ce5b65e5 --- /dev/null +++ b/app/javascript/material-icons/400-24px/upload_file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/visibility-fill.svg b/app/javascript/material-icons/400-24px/visibility-fill.svg new file mode 100644 index 0000000000..44b5f4c606 --- /dev/null +++ b/app/javascript/material-icons/400-24px/visibility-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/visibility.svg b/app/javascript/material-icons/400-24px/visibility.svg new file mode 100644 index 0000000000..8fe45d09af --- /dev/null +++ b/app/javascript/material-icons/400-24px/visibility.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/visibility_off-fill.svg b/app/javascript/material-icons/400-24px/visibility_off-fill.svg new file mode 100644 index 0000000000..e21fbd88df --- /dev/null +++ b/app/javascript/material-icons/400-24px/visibility_off-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/visibility_off.svg b/app/javascript/material-icons/400-24px/visibility_off.svg new file mode 100644 index 0000000000..d98cf8d942 --- /dev/null +++ b/app/javascript/material-icons/400-24px/visibility_off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/volume_off-fill.svg b/app/javascript/material-icons/400-24px/volume_off-fill.svg new file mode 100644 index 0000000000..b3d12d4d98 --- /dev/null +++ b/app/javascript/material-icons/400-24px/volume_off-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/volume_off.svg b/app/javascript/material-icons/400-24px/volume_off.svg new file mode 100644 index 0000000000..a0acf63747 --- /dev/null +++ b/app/javascript/material-icons/400-24px/volume_off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/volume_up-fill.svg b/app/javascript/material-icons/400-24px/volume_up-fill.svg new file mode 100644 index 0000000000..dd5771215e --- /dev/null +++ b/app/javascript/material-icons/400-24px/volume_up-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/volume_up.svg b/app/javascript/material-icons/400-24px/volume_up.svg new file mode 100644 index 0000000000..fd9006a6d2 --- /dev/null +++ b/app/javascript/material-icons/400-24px/volume_up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/LICENSE b/app/javascript/material-icons/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/app/javascript/material-icons/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/app/javascript/material-icons/README.md b/app/javascript/material-icons/README.md new file mode 100644 index 0000000000..1479cb2255 --- /dev/null +++ b/app/javascript/material-icons/README.md @@ -0,0 +1 @@ +Files in this directory are Material Symbols icons fetched using the `icons:download` task. diff --git a/app/javascript/styles/fonts/inter.scss b/app/javascript/styles/fonts/inter.scss new file mode 100644 index 0000000000..bb4899b701 --- /dev/null +++ b/app/javascript/styles/fonts/inter.scss @@ -0,0 +1,8 @@ +@font-face { + font-family: Inter; + src: url('../fonts/inter/inter-variable-font-slnt-wght.woff2') + format('woff2-variations'); + font-weight: 100 900; + font-style: normal; + mso-generic-font-family: swiss; /* stylelint-disable-line property-no-unknown -- Proprietary property for Outlook on Windows. */ +} diff --git a/public/inert.css b/app/javascript/styles/inert.scss similarity index 78% rename from public/inert.css rename to app/javascript/styles/inert.scss index 54e10616d2..a60045d7be 100644 --- a/public/inert.css +++ b/app/javascript/styles/inert.scss @@ -1,3 +1,5 @@ +/* This is needed for the wicg-inert polyfill */ + [inert] { pointer-events: none; cursor: default; diff --git a/app/javascript/styles/mailer.scss b/app/javascript/styles/mailer.scss index 92d00cae8b..a2cbb494b4 100644 --- a/app/javascript/styles/mailer.scss +++ b/app/javascript/styles/mailer.scss @@ -1,574 +1,620 @@ -@import 'mastodon/variables'; -@import 'fonts/roboto'; +@import 'fonts/inter'; -table, -td, -div { - box-sizing: border-box; -} - -html, body { - width: 100% !important; - min-width: 100%; + accent-color: #6364ff; + word-break: break-word; margin: 0; + background-color: #f3f2f5; padding: 0; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} - -.email-body { - td, - div, - a, - span { - line-height: inherit; - } -} - -a { - &, - &:visited, - span { - text-decoration: none; - color: $ui-highlight-color; - } - - #outlook & { - padding: 0; - } -} - -img { - outline: none; - border: 0; - text-decoration: none; - -ms-interpolation-mode: bicubic; - clear: both; - line-height: 100%; -} - -table { - border-spacing: 0; - mso-table-lspace: 0; - mso-table-rspace: 0; -} - -td { - vertical-align: top; -} - -.auto-dir { - p { - unicode-bidi: plaintext; - } - - a { - unicode-bidi: isolate; - } -} - -.email-table, -.content-section, -.column, -.column-cell { - width: 100%; - min-width: 100%; -} - -.email-body { - font-size: 0 !important; - line-height: 100%; - text-align: center; - padding-left: 16px; - padding-right: 16px; -} - -.email-start { - padding-top: 32px; -} - -.email-end { - padding-bottom: 32px; -} - -.email-body, -html, -body { - background-color: lighten($ui-base-color, 4%); -} - -.email-container, -.email-row, -.col-0, -.col-1, -.col-2, -.col-3, -.col-4, -.col-5, -.col-6 { - font-size: 0; - display: inline-block; - width: 100%; - min-width: 100%; - min-width: 0 !important; - vertical-align: top; -} - -.content-cell { - width: 100%; - min-width: 100%; - min-width: 0 !important; -} - -.column-cell { - padding-top: 16px; - padding-bottom: 16px; - vertical-align: top; - - &.button-cell { - padding-top: 0; - } -} - -.email-container { - max-width: 632px; - margin: 0 auto; - text-align: center; -} - -.email-row { - display: block; - max-width: 600px !important; - margin: 0 auto; - text-align: center; - clear: both; -} - -.col-0 { - max-width: 50px; -} - -.col-1 { - max-width: 100px; -} - -.col-2 { - max-width: 200px; -} - -.col-3 { - max-width: 300px; -} - -.col-4 { - max-width: 400px; -} - -.col-5 { - max-width: 500px; -} - -.col-6 { - max-width: 600px; -} - -.column-cell, -.column-cell td, -p { - font-family: Helvetica, Arial, sans-serif; - - @media only screen { - font-family: $font-sans-serif, sans-serif !important; - } -} - -.email-body .column-cell, -.column-cell, -p { - font-size: 15px; - line-height: 23px; - color: $ui-primary-color; - mso-line-height-rule: exactly; - text-rendering: optimizelegibility; -} - -p { - display: block; - margin-top: 0; - margin-bottom: 16px; - - &.small { - font-size: 13px; - } - - &.lead { - font-size: 19px; - line-height: 27px; - } + -webkit-text-size-adjust: none; + text-size-adjust: none; } +p, h1, h2, h3, h4, h5, h6 { - color: $ui-secondary-color; - margin-left: 0; - margin-right: 0; - margin-top: 20px; - margin-bottom: 8px; + margin: 0; + background-color: transparent; padding: 0; - font-weight: 500; + border: none; + font-family: Inter, 'Lucida Grande', sans-serif; } -h1 { - font-size: 26px; - line-height: 36px; +img { + max-width: 100%; + height: auto; + border: none; + text-indent: 0; + vertical-align: middle; + color: inherit; + font-family: inherit; } -h2 { - font-size: 23px; - line-height: 30px; +table { + border: none; } -h3 { - font-size: 19px; - line-height: 25px; +table + p { + margin-top: 16px; } -h5 { - font-size: 16px; - line-height: 21px; - font-weight: 700; - color: lighten($ui-base-color, 34%); +.email { + min-width: 280px; + font-family: Inter, 'Lucida Grande', sans-serif; + word-break: break-word; + color: #17063b; + background-color: #f3f2f5; } -.input-cell { - h5 { - margin-top: 4px; - } -} - -.input { - td { - background: darken($ui-base-color, 8%); - border-radius: 4px; - padding: 16px; - line-height: 20px; - mso-line-height-rule: exactly; - text-align: center; - font-weight: 500; - font-size: 17px; - } -} - -.content-cell, -.blank-cell { +.email-container { + max-width: 740px; + margin: 0 auto; width: 100%; - font-size: 0; - text-align: center; - vertical-align: top; - padding-left: 16px; - padding-right: 16px; } -.content-cell { - background-color: darken($ui-base-color, 4%); - - &.darker { - background-color: darken($ui-base-color, 8%); - } +// Outer email card +.email-card-table { + border-collapse: collapse; + width: 100%; } -.hero { - background-color: $ui-base-color; - padding-top: 20px; +.email-card-td { + overflow: hidden; + box-shadow: 0 4px 16px 0 rgba(23, 6, 59, 4%); + background-color: #fff; } -.hero-with-button { - padding-bottom: 16px; - - h1 { - margin-bottom: 4px; - } - - p.lead { - margin-bottom: 32px; - } +// Inner email card +.email-inner-card-table { + border-collapse: separate; + width: 100%; + border-radius: 12px; } -.header { - border-radius: 5px 5px 0 0; - background-color: darken($ui-base-color, 8%); - - .column-cell { - text-align: center; - padding-top: 20px; - padding-bottom: 8px; - } +.email-inner-card-td-without-padding, +.email-inner-card-td { + border-radius: 12px; + overflow: hidden; + box-shadow: 0 4px 16px 0 rgba(23, 6, 59, 8%); + background-color: #fff; + border: 1px solid #dfdee3; } -.content-start { - padding-top: 32px; +.email-inner-card-td { + padding: 24px; } -.content-end { - border-radius: 0 0 5px 5px; - padding-top: 16px; +// Account +.email-account-banner-table { + background-color: #f3f2f5; + border-top-left-radius: 12px; + border-top-right-radius: 12px; } -.footer { - .column-cell, - p { - color: lighten($ui-base-color, 34%); - } +.email-account-banner-td { + border-top-left-radius: 12px; + border-top-right-radius: 12px; + height: 140px; + vertical-align: bottom; + background-position: center !important; + background-size: cover !important; +} - p { - margin-bottom: 0; - font-size: 13px; +.email-account-banner-inner-td { + padding: 24px 24px 0; + mso-padding-alt: 24px; +} - &.small { - margin-bottom: 0; - } - } +.email-account-banner-overlap-div { + max-height: 42px; +} - a { - color: lighten($ui-base-color, 34%); - text-decoration: underline; - } +.email-account-banner-icon-table { + width: auto; + margin: 0; + overflow: hidden; + border-radius: 8px; + border-collapse: separate; + background-color: #fff; + border: 2px solid #fff; img { - opacity: 0.3; - } -} - -.logo { - position: relative; - left: -4px; -} - -.button { - display: table; - margin-left: auto; - margin-right: auto; - - td { - line-height: 20px; - mso-line-height-rule: exactly; - border-radius: 4px; - text-align: center; - font-weight: 500; - font-size: 17px; - padding: 0 !important; - - a, - a span { - color: $primary-text-color; - display: block !important; - text-align: center !important; - vertical-align: top !important; - line-height: inherit !important; - } - - a { - padding: 10px 22px !important; - line-height: 26px !important; - font-weight: 500 !important; - } - } - - &.button-small { - td { - border-radius: 4px; - font-size: 14px; - padding: 8px 16px; - - a { - padding: 5px 16px !important; - line-height: 26px !important; - } - } - } -} - -.button-default { - background-color: darken($ui-base-color, 8%); -} - -.button-primary { - background-color: darken($ui-highlight-color, 3%); -} - -.text-center { - text-align: center; -} - -.text-right { - text-align: right; -} - -.padded { - padding-left: 16px; - padding-right: 16px; -} - -.padded-bottom { - padding-bottom: 32px; -} - -.margin-bottom { - margin-bottom: 20px; -} - -.hero-icon { - width: 64px; - - td { - text-align: center; - vertical-align: middle; - line-height: 100%; - mso-line-height-rule: exactly; - padding: 16px; - border-radius: 80px; - background: $success-green; - } - - &.warning-icon td { - background: $gold-star; - } - - &.alert-icon td { - background: $error-red; - } - - img { - max-width: 32px; - width: 32px; - height: 32px; display: block; - line-height: 100%; + max-width: 100%; + border: none; + border-radius: 6px; } } -.hr { - width: 100%; +.email-account-body-td { + padding: 56px 24px 24px; + mso-padding-alt: 24px; +} +.email-account-name { + font-size: 16px; + font-weight: 600; + line-height: 24px; + color: #17063b; +} + +.email-account-handle { + font-size: 14px; + line-height: 20px; + color: #746a89; +} + +.email-account-stats-table { td { - font-size: 0; - line-height: 1px; - mso-line-height-rule: exactly; - min-height: 1px; - overflow: hidden; - height: 2px; - background-color: transparent !important; - border-top: 1px solid lighten($ui-base-color, 8%); + padding-right: 16px; + font-size: 14px; + line-height: 20px; + color: #746a89; + } + + b { + font-weight: 600; + color: #17063b; + } + + span { + white-space: nowrap; } } -.status { - padding-bottom: 32px; - - &--highlighted { - border: 1px solid lighten($ui-base-color, 8%); - border-radius: 4px; - padding-bottom: 16px; - margin-bottom: 16px; - } - - .status-header { - td { - font-size: 14px; - padding-bottom: 15px; - } - - bdi { - color: $white; - font-size: 16px; - display: block; - font-weight: 500; - } - - td:first-child { - padding-right: 10px; - } - - img { - width: 48px; - height: 48px; - border-radius: 4px; - } - } +// Utility classes +.email-w-full { + width: 100%; +} +.email-prose { p { - font-size: 19px; - margin-bottom: 20px; + color: #17063b; + font-size: 14px; + line-height: 20px; - &.status-footer { - color: lighten($ui-base-color, 26%); - font-size: 14px; - margin-bottom: 0; + &:not(:last-child) { + margin-bottom: 16px; + } - a { - color: lighten($ui-base-color, 26%); + a:not([class]) { + color: #6364ff; + text-decoration: none; + + &:hover { + color: #563acc !important; } } } } -.border-top { - border-top: 1px solid lighten($ui-base-color, 8%); +.email-padding-24 { + padding: 24px; } -ul { - padding-left: 15px; - margin-top: 0; - margin-bottom: 0; +.email-padding-top-24 { + padding-top: 24px; +} + +.email-padding-top-16 { padding-top: 16px; - - li { - margin-bottom: 16px; - color: lighten($ui-base-color, 26%); - - span { - color: $ui-primary-color; - } - } } -ul.rules-list { +.email-padding-top-0 { padding-top: 0; } -@media only screen and (device-width >= 768px) and (device-width <= 1024px) and (orientation: landscape) { - body { - min-height: 1024px !important; +.email-border-top { + border-top: 1px solid #dfdee3; +} + +.email-border-bottom { + border-bottom: 1px solid #dfdee3; +} + +// Header +.email-header-td { + padding: 16px 32px; + background-color: #1b001f; + background-image: url('../images/mailer-new/common/header-bg-start.png'); + background-position: left top; + background-repeat: repeat; +} + +.email-header-logo-table { + width: auto; + margin: 0; +} + +.email-header-logo-td { + padding: 16px 0; + font-size: 0; + + img { + color: #fff; + font-size: 16px; + font-weight: bold; + max-height: 40px; } } -@media (width <= 697px) { - .email-container, - .col-1, - .col-2, - .col-3, - .col-4, - .col-5, - .col-6 { - width: 100% !important; - max-width: none !important; - } +.email-header-logo-a { + display: inline-block; - .email-start { - padding-top: 16px !important; - } - - .email-end { - padding-bottom: 16px !important; - } - - .padded { - padding-left: 0 !important; - padding-right: 0 !important; + img { + display: inline-block; + color: #fff; + } +} + +.email-header-logo-div { + max-height: 0; +} + +.email-header-logo-p { + word-break: break-all; + padding-left: 40px; + padding-top: 26px; + font-size: 11px; + line-height: 13px; + color: #8d808f; + text-align: left; +} + +.email-header-logo-span { + display: block; + text-align: right; +} + +.email-header-heading-td { + padding: 16px 0; +} + +.email-header-heading-img-td { + width: 56px; + text-align: left; + vertical-align: top; + + img { + width: 56px; + height: 56px; + border-radius: 12px; + } +} + +.email-header-heading-txt-td { + vertical-align: middle; + padding-left: 16px; + padding-right: 16px; + + h1 { + margin-bottom: 5px; + color: #fff; + font-size: 24px; + line-height: 28px; + font-weight: 600; + } + + p { + color: #a399a5; + font-size: 18px; + line-height: 21.6px; + font-weight: 500; + } + + &:only-child { + padding-left: 0; + padding-right: 0; + } +} + +// To make the design work with images off +// we create an empty div that overlaps with +// the rest of the content with a dark background. +.email-header-after-div { + max-height: 0; +} + +.email-header-after-inside-div { + height: 30px; + background-color: #1b001f; +} + +// Body content +.email-body-td { + background-image: url('../images/mailer-new/common/header-bg-end.png'); + background-position: left top; + background-repeat: no-repeat; +} + +.email-body-padding-td { + padding: 0 32px 32px; + mso-padding-alt: 32px; +} + +.email-body-padding-td { + & > p { + font-size: 14px; + line-height: 20px; + color: #17063b; + + a { + color: #6364ff; + text-decoration: none; + + &:hover { + color: #563acc !important; + } + } + } +} + +// Footer +.email-footer-td { + padding: 28px 32px 32px; + text-align: center; +} + +.email-footer-logo-a { + display: inline-block; +} + +.email-footer-p { + color: #9b94ab; + text-align: center; + font-size: 12px; + line-height: 20px; + + a { + color: #9b94ab; + text-decoration: underline; + } + + &:first-child { + margin-bottom: 12px; + } +} + +// Button +.email-btn-table { + margin: 0; + max-width: 100%; + border-collapse: separate; + border-radius: 8px; + background-color: #6364ff; +} + +.email-btn-td { + height: 40px; + text-align: center; + mso-padding-alt: 0 35px; +} + +.email-btn-a { + display: block; + border-radius: 8px; + padding-left: 35px; + padding-right: 35px; + padding-top: 10px; + padding-bottom: 10px; + text-align: center; + font-family: Inter, 'Lucida Grande', sans-serif; + font-size: 14px; + font-weight: 600; + line-height: 20px; + color: #fff; + text-decoration: none; + transition: background-color 0.3s ease-in-out; +} + +// Status +.email-status-header-img { + vertical-align: top; + width: 48px; + + img { + width: 48px; + height: 48px; + border-radius: 8px; + overflow: hidden; + } +} + +.email-status-header-text { + padding-left: 16px; + padding-right: 16px; + vertical-align: middle; +} + +.email-status-header-name { + font-size: 16px; + font-weight: 600; + line-height: 24px; + color: #17063b; +} + +.email-status-header-handle { + font-size: 14px; + line-height: 20px; + color: #746a89; +} + +.email-status-content { + padding-top: 24px; +} + +.email-status-spoiler { + color: #746a89; + font-style: italic; + margin-bottom: 8px; +} + +.email-status-prose { + p { + font-size: 14px; + line-height: 20px; + color: #17063b; + } + + a { + color: #6364ff; + text-decoration: none; + + &:hover { + color: #563acc !important; + } + } +} + +.email-status-media { + margin-top: 16px; + font-size: 14px; + line-height: 20px; + color: #17063b; + + img { + border-radius: 8px; + } + + a { + color: #6364ff; + text-decoration: none; + + &:hover { + color: #563acc !important; + } + } +} + +.email-status-footer { + margin-top: 16px; + font-size: 12px; + line-height: 16px; + color: #746a89; + + a { + color: #746a89; + } + + a:hover { + color: #746a89 !important; + text-decoration: underline !important; + } +} + +// Purple frame for emphasis +.email-frame-table { + background-color: #efefff; + border-radius: 8px; +} + +.email-frame-td { + padding: 16px; +} + +.email-frame-wrapper-td { + padding-bottom: 16px; +} + +.email-frame-td > p { + text-align: center; + font-size: 16px; + line-height: 24px; +} + +// Checklist item +.email-checklist-wrapper-td { + padding: 4px 0; +} + +.email-checklist-table { + border-radius: 12px; + border-width: 1px; + border-style: solid; + border-color: #efefff; + background-color: #fff; +} + +.email-checklist-td { + padding: 16px; +} + +.email-checklist-icons-td { + width: 84px; + vertical-align: top; +} + +.email-checklist-icons-checkbox-td { + width: 20px; + vertical-align: middle; + + img { + max-width: 100%; + width: 20px; + } +} + +.email-checklist-icons-step-td { + width: 64px; + text-align: center; + vertical-align: middle; + + img { + max-width: 100%; + width: 40px; + } +} + +.email-checklist-text-td { + h3 { + margin: 0 0 4px; + color: #17063b; + font-size: 14px; + font-weight: 600; + line-height: 16.8px; + } + + p { + margin: 0 0 2px; + color: #746a89; + font-size: 14px; + line-height: 16.8px; + } + + .email-btn-table { + width: 100px; + } + + .email-btn-td { + mso-padding-alt: 10px; + } + + .email-btn-a { + padding-left: 10px; + padding-right: 10px; + } +} + +// Responsive +/* stylelint-disable-next-line media-feature-range-notation -- Basic media queries have better support across email clients. */ +@media only screen and (min-width: 740px) { + .email-desktop-p-8 { + padding: 32px !important; + } + + .email-desktop-rounded-16px { + border-radius: 16px !important; + } + + .email-header-td { + border-radius: 16px 16px 0 0 !important; + } + + .email-desktop-flex { + display: flex; } } diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 486a8b61ba..b441be5f43 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -187,8 +187,8 @@ .icon { flex: 0 0 auto; - width: 20px; - height: 20px; + width: 24px; + height: 24px; aspect-ratio: 1; path { @@ -200,7 +200,7 @@ display: inline-flex; color: $action-button-color; border: 0; - padding: 2px; + padding: 0; border-radius: 4px; background: transparent; cursor: pointer; @@ -1417,8 +1417,7 @@ body > [data-popper-placement] { .icon { width: 15px; height: 15px; - position: relative; - top: 0.145em; + vertical-align: middle; } } @@ -2341,7 +2340,7 @@ $ui-header-height: 55px; .drawer__tab { display: flex; flex: 1 1 auto; - padding: 15px 5px 13px; + padding: 13px 3px 11px; color: $darker-text-color; text-decoration: none; text-align: center; @@ -3224,7 +3223,7 @@ $ui-header-height: 55px; align-items: center; gap: 5px; font-size: 16px; - padding: 15px; + padding: 13px; text-decoration: none; overflow: hidden; white-space: nowrap; @@ -3823,7 +3822,7 @@ a.status-card { gap: 5px; margin: 0; border: 0; - padding: 15px; + padding: 13px; padding-inline-end: 0; color: inherit; background: transparent; @@ -5567,6 +5566,10 @@ a.status-card { padding-inline-end: 10px; } + .icon { + vertical-align: middle; + } + .button { flex: 0 0 auto; } @@ -6117,6 +6120,7 @@ a.status-card { gap: 2px; } +.media-gallery__alt__label, .media-gallery__gifv__label { display: flex; align-items: center; @@ -6193,6 +6197,7 @@ a.status-card { .icon { color: $dark-text-color; + vertical-align: middle; } } } @@ -7438,6 +7443,13 @@ noscript { span { user-select: all; } + + .icon-lock { + height: 16px; + width: 16px; + position: relative; + top: 3px; + } } } } diff --git a/app/javascript/types/image.d.ts b/app/javascript/types/image.d.ts index 07d1929555..8a08eca9f6 100644 --- a/app/javascript/types/image.d.ts +++ b/app/javascript/types/image.d.ts @@ -20,16 +20,20 @@ declare module '*.png' { } declare module '*.svg' { + const path: string; + export default path; +} + +declare module '*.svg?react' { import type React from 'react'; interface SVGPropsWithTitle extends React.SVGProps { title?: string; } - export const ReactComponent: React.FC; + const ReactComponent: React.FC; - const path: string; - export default path; + export default ReactComponent; } declare module '*.webp' { diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 8eff9fdf40..eb332a44cd 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -283,6 +283,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity RedownloadMediaWorker.perform_in(rand(30..600).seconds, media_attachment.id) rescue Seahorse::Client::NetworkingError => e Rails.logger.warn "Error storing media attachment: #{e}" + RedownloadMediaWorker.perform_async(media_attachment.id) end end diff --git a/app/lib/admin/system_check/media_privacy_check.rb b/app/lib/admin/system_check/media_privacy_check.rb index 1df05b120e..2ddc8e8b07 100644 --- a/app/lib/admin/system_check/media_privacy_check.rb +++ b/app/lib/admin/system_check/media_privacy_check.rb @@ -78,7 +78,7 @@ class Admin::SystemCheck::MediaPrivacyCheck < Admin::SystemCheck::BaseCheck @media_attachment ||= begin attachment = Account.representative.media_attachments.first if attachment.present? - attachment.touch # rubocop:disable Rails/SkipsModelValidations + attachment.touch attachment else create_test_attachment! diff --git a/app/lib/annual_report.rb b/app/lib/annual_report.rb new file mode 100644 index 0000000000..cf4297f2a4 --- /dev/null +++ b/app/lib/annual_report.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +class AnnualReport + include DatabaseHelper + + SOURCES = [ + AnnualReport::Archetype, + AnnualReport::TypeDistribution, + AnnualReport::TopStatuses, + AnnualReport::MostUsedApps, + AnnualReport::CommonlyInteractedWithAccounts, + AnnualReport::TimeSeries, + AnnualReport::TopHashtags, + AnnualReport::MostRebloggedAccounts, + AnnualReport::Percentiles, + ].freeze + + SCHEMA = 1 + + def initialize(account, year) + @account = account + @year = year + end + + def generate + return if GeneratedAnnualReport.exists?(account: @account, year: @year) + + GeneratedAnnualReport.create( + account: @account, + year: @year, + schema_version: SCHEMA, + data: data + ) + end + + private + + def data + with_read_replica do + SOURCES.each_with_object({}) { |klass, hsh| hsh.merge!(klass.new(@account, @year).generate) } + end + end +end diff --git a/app/lib/annual_report/archetype.rb b/app/lib/annual_report/archetype.rb new file mode 100644 index 0000000000..ea9ef366df --- /dev/null +++ b/app/lib/annual_report/archetype.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +class AnnualReport::Archetype < AnnualReport::Source + # Average number of posts (including replies and reblogs) made by + # each active user in a single year (2023) + AVERAGE_PER_YEAR = 113 + + def generate + { + archetype: archetype, + } + end + + private + + def archetype + if (standalone_count + replies_count + reblogs_count) < AVERAGE_PER_YEAR + :lurker + elsif reblogs_count > (standalone_count * 2) + :booster + elsif polls_count > (standalone_count * 0.1) # standalone_count includes posts with polls + :pollster + elsif replies_count > (standalone_count * 2) + :replier + else + :oracle + end + end + + def polls_count + @polls_count ||= base_scope.where.not(poll_id: nil).count + end + + def reblogs_count + @reblogs_count ||= base_scope.where.not(reblog_of_id: nil).count + end + + def replies_count + @replies_count ||= base_scope.where.not(in_reply_to_id: nil).where.not(in_reply_to_account_id: @account.id).count + end + + def standalone_count + @standalone_count ||= base_scope.without_replies.without_reblogs.count + end + + def base_scope + @account.statuses.where(id: year_as_snowflake_range) + end +end diff --git a/app/lib/annual_report/commonly_interacted_with_accounts.rb b/app/lib/annual_report/commonly_interacted_with_accounts.rb new file mode 100644 index 0000000000..af5e854c22 --- /dev/null +++ b/app/lib/annual_report/commonly_interacted_with_accounts.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class AnnualReport::CommonlyInteractedWithAccounts < AnnualReport::Source + SET_SIZE = 40 + + def generate + { + commonly_interacted_with_accounts: commonly_interacted_with_accounts.map do |(account_id, count)| + { + account_id: account_id, + count: count, + } + end, + } + end + + private + + def commonly_interacted_with_accounts + @account.statuses.reorder(nil).where(id: year_as_snowflake_range).where.not(in_reply_to_account_id: @account.id).group(:in_reply_to_account_id).having('count(*) > 1').order(total: :desc).limit(SET_SIZE).pluck(Arel.sql('in_reply_to_account_id, count(*) AS total')) + end +end diff --git a/app/lib/annual_report/most_reblogged_accounts.rb b/app/lib/annual_report/most_reblogged_accounts.rb new file mode 100644 index 0000000000..e3e8a7c90b --- /dev/null +++ b/app/lib/annual_report/most_reblogged_accounts.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class AnnualReport::MostRebloggedAccounts < AnnualReport::Source + SET_SIZE = 10 + + def generate + { + most_reblogged_accounts: most_reblogged_accounts.map do |(account_id, count)| + { + account_id: account_id, + count: count, + } + end, + } + end + + private + + def most_reblogged_accounts + @account.statuses.reorder(nil).where(id: year_as_snowflake_range).where.not(reblog_of_id: nil).joins(reblog: :account).group('accounts.id').having('count(*) > 1').order(total: :desc).limit(SET_SIZE).pluck(Arel.sql('accounts.id, count(*) as total')) + end +end diff --git a/app/lib/annual_report/most_used_apps.rb b/app/lib/annual_report/most_used_apps.rb new file mode 100644 index 0000000000..85ff1ff86e --- /dev/null +++ b/app/lib/annual_report/most_used_apps.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class AnnualReport::MostUsedApps < AnnualReport::Source + SET_SIZE = 10 + + def generate + { + most_used_apps: most_used_apps.map do |(name, count)| + { + name: name, + count: count, + } + end, + } + end + + private + + def most_used_apps + @account.statuses.reorder(nil).where(id: year_as_snowflake_range).joins(:application).group('oauth_applications.name').order(total: :desc).limit(SET_SIZE).pluck(Arel.sql('oauth_applications.name, count(*) as total')) + end +end diff --git a/app/lib/annual_report/percentiles.rb b/app/lib/annual_report/percentiles.rb new file mode 100644 index 0000000000..9fe4698ee5 --- /dev/null +++ b/app/lib/annual_report/percentiles.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +class AnnualReport::Percentiles < AnnualReport::Source + def generate + { + percentiles: { + followers: (total_with_fewer_followers / (total_with_any_followers + 1.0)) * 100, + statuses: (total_with_fewer_statuses / (total_with_any_statuses + 1.0)) * 100, + }, + } + end + + private + + def followers_gained + @followers_gained ||= @account.passive_relationships.where("date_part('year', follows.created_at) = ?", @year).count + end + + def statuses_created + @statuses_created ||= @account.statuses.where(id: year_as_snowflake_range).count + end + + def total_with_fewer_followers + @total_with_fewer_followers ||= Follow.find_by_sql([<<~SQL.squish, { year: @year, comparison: followers_gained }]).first.total + WITH tmp0 AS ( + SELECT follows.target_account_id + FROM follows + INNER JOIN accounts ON accounts.id = follows.target_account_id + WHERE date_part('year', follows.created_at) = :year + AND accounts.domain IS NULL + GROUP BY follows.target_account_id + HAVING COUNT(*) < :comparison + ) + SELECT count(*) AS total + FROM tmp0 + SQL + end + + def total_with_fewer_statuses + @total_with_fewer_statuses ||= Status.find_by_sql([<<~SQL.squish, { comparison: statuses_created, min_id: year_as_snowflake_range.first, max_id: year_as_snowflake_range.last }]).first.total + WITH tmp0 AS ( + SELECT statuses.account_id + FROM statuses + INNER JOIN accounts ON accounts.id = statuses.account_id + WHERE statuses.id BETWEEN :min_id AND :max_id + AND accounts.domain IS NULL + GROUP BY statuses.account_id + HAVING count(*) < :comparison + ) + SELECT count(*) AS total + FROM tmp0 + SQL + end + + def total_with_any_followers + @total_with_any_followers ||= Follow.where("date_part('year', follows.created_at) = ?", @year).joins(:target_account).merge(Account.local).count('distinct follows.target_account_id') + end + + def total_with_any_statuses + @total_with_any_statuses ||= Status.where(id: year_as_snowflake_range).joins(:account).merge(Account.local).count('distinct statuses.account_id') + end +end diff --git a/app/lib/annual_report/source.rb b/app/lib/annual_report/source.rb new file mode 100644 index 0000000000..1ccb622676 --- /dev/null +++ b/app/lib/annual_report/source.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class AnnualReport::Source + attr_reader :account, :year + + def initialize(account, year) + @account = account + @year = year + end + + protected + + def year_as_snowflake_range + (Mastodon::Snowflake.id_at(DateTime.new(year, 1, 1))..Mastodon::Snowflake.id_at(DateTime.new(year, 12, 31))) + end +end diff --git a/app/lib/annual_report/time_series.rb b/app/lib/annual_report/time_series.rb new file mode 100644 index 0000000000..a144bac0d1 --- /dev/null +++ b/app/lib/annual_report/time_series.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class AnnualReport::TimeSeries < AnnualReport::Source + def generate + { + time_series: (1..12).map do |month| + { + month: month, + statuses: statuses_per_month[month] || 0, + following: following_per_month[month] || 0, + followers: followers_per_month[month] || 0, + } + end, + } + end + + private + + def statuses_per_month + @statuses_per_month ||= @account.statuses.reorder(nil).where(id: year_as_snowflake_range).group(:period).pluck(Arel.sql("date_part('month', created_at)::int AS period, count(*)")).to_h + end + + def following_per_month + @following_per_month ||= @account.active_relationships.where("date_part('year', created_at) = ?", @year).group(:period).pluck(Arel.sql("date_part('month', created_at)::int AS period, count(*)")).to_h + end + + def followers_per_month + @followers_per_month ||= @account.passive_relationships.where("date_part('year', created_at) = ?", @year).group(:period).pluck(Arel.sql("date_part('month', created_at)::int AS period, count(*)")).to_h + end +end diff --git a/app/lib/annual_report/top_hashtags.rb b/app/lib/annual_report/top_hashtags.rb new file mode 100644 index 0000000000..488dacb1b4 --- /dev/null +++ b/app/lib/annual_report/top_hashtags.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class AnnualReport::TopHashtags < AnnualReport::Source + SET_SIZE = 40 + + def generate + { + top_hashtags: top_hashtags.map do |(name, count)| + { + name: name, + count: count, + } + end, + } + end + + private + + def top_hashtags + Tag.joins(:statuses).where(statuses: { id: @account.statuses.where(id: year_as_snowflake_range).reorder(nil).select(:id) }).group(:id).having('count(*) > 1').order(total: :desc).limit(SET_SIZE).pluck(Arel.sql('COALESCE(tags.display_name, tags.name), count(*) AS total')) + end +end diff --git a/app/lib/annual_report/top_statuses.rb b/app/lib/annual_report/top_statuses.rb new file mode 100644 index 0000000000..112e5591ce --- /dev/null +++ b/app/lib/annual_report/top_statuses.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class AnnualReport::TopStatuses < AnnualReport::Source + def generate + top_reblogs = base_scope.order(reblogs_count: :desc).first&.id + top_favourites = base_scope.where.not(id: top_reblogs).order(favourites_count: :desc).first&.id + top_replies = base_scope.where.not(id: [top_reblogs, top_favourites]).order(replies_count: :desc).first&.id + + { + top_statuses: { + by_reblogs: top_reblogs, + by_favourites: top_favourites, + by_replies: top_replies, + }, + } + end + + def base_scope + @account.statuses.with_public_visibility.joins(:status_stat).where(id: year_as_snowflake_range).reorder(nil) + end +end diff --git a/app/lib/annual_report/type_distribution.rb b/app/lib/annual_report/type_distribution.rb new file mode 100644 index 0000000000..fc12a6f1f4 --- /dev/null +++ b/app/lib/annual_report/type_distribution.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class AnnualReport::TypeDistribution < AnnualReport::Source + def generate + { + type_distribution: { + total: base_scope.count, + reblogs: base_scope.where.not(reblog_of_id: nil).count, + replies: base_scope.where.not(in_reply_to_id: nil).where.not(in_reply_to_account_id: @account.id).count, + standalone: base_scope.without_replies.without_reblogs.count, + }, + } + end + + private + + def base_scope + @account.statuses.where(id: year_as_snowflake_range) + end +end diff --git a/app/lib/attachment_batch.rb b/app/lib/attachment_batch.rb index b28f5c3d7f..32ccb0b13c 100644 --- a/app/lib/attachment_batch.rb +++ b/app/lib/attachment_batch.rb @@ -37,7 +37,7 @@ class AttachmentBatch def clear remove_files - batch.update_all(nullified_attributes) # rubocop:disable Rails/SkipsModelValidations + batch.update_all(nullified_attributes) end private diff --git a/app/lib/status_cache_hydrator.rb b/app/lib/status_cache_hydrator.rb index 45b50cb379..34f6199ec0 100644 --- a/app/lib/status_cache_hydrator.rb +++ b/app/lib/status_cache_hydrator.rb @@ -26,11 +26,11 @@ class StatusCacheHydrator def hydrate_non_reblog_payload(empty_payload, account_id) empty_payload.tap do |payload| - payload[:favourited] = Favourite.where(account_id: account_id, status_id: @status.id).exists? - payload[:reblogged] = Status.where(account_id: account_id, reblog_of_id: @status.id).exists? - payload[:muted] = ConversationMute.where(account_id: account_id, conversation_id: @status.conversation_id).exists? - payload[:bookmarked] = Bookmark.where(account_id: account_id, status_id: @status.id).exists? - payload[:pinned] = StatusPin.where(account_id: account_id, status_id: @status.id).exists? if @status.account_id == account_id + payload[:favourited] = Favourite.exists?(account_id: account_id, status_id: @status.id) + payload[:reblogged] = Status.exists?(account_id: account_id, reblog_of_id: @status.id) + payload[:muted] = ConversationMute.exists?(account_id: account_id, conversation_id: @status.conversation_id) + payload[:bookmarked] = Bookmark.exists?(account_id: account_id, status_id: @status.id) + payload[:pinned] = StatusPin.exists?(account_id: account_id, status_id: @status.id) if @status.account_id == account_id payload[:filtered] = mapped_applied_custom_filter(account_id, @status) if payload[:poll] @@ -51,11 +51,11 @@ class StatusCacheHydrator # used to create the status, we need to hydrate it here too payload[:reblog][:application] = payload_reblog_application if payload[:reblog][:application].nil? && @status.reblog.account_id == account_id - payload[:reblog][:favourited] = Favourite.where(account_id: account_id, status_id: @status.reblog_of_id).exists? - payload[:reblog][:reblogged] = Status.where(account_id: account_id, reblog_of_id: @status.reblog_of_id).exists? - payload[:reblog][:muted] = ConversationMute.where(account_id: account_id, conversation_id: @status.reblog.conversation_id).exists? - payload[:reblog][:bookmarked] = Bookmark.where(account_id: account_id, status_id: @status.reblog_of_id).exists? - payload[:reblog][:pinned] = StatusPin.where(account_id: account_id, status_id: @status.reblog_of_id).exists? if @status.reblog.account_id == account_id + payload[:reblog][:favourited] = Favourite.exists?(account_id: account_id, status_id: @status.reblog_of_id) + payload[:reblog][:reblogged] = Status.exists?(account_id: account_id, reblog_of_id: @status.reblog_of_id) + payload[:reblog][:muted] = ConversationMute.exists?(account_id: account_id, conversation_id: @status.reblog.conversation_id) + payload[:reblog][:bookmarked] = Bookmark.exists?(account_id: account_id, status_id: @status.reblog_of_id) + payload[:reblog][:pinned] = StatusPin.exists?(account_id: account_id, status_id: @status.reblog_of_id) if @status.reblog.account_id == account_id payload[:reblog][:filtered] = payload[:filtered] if payload[:reblog][:poll] diff --git a/app/lib/status_reach_finder.rb b/app/lib/status_reach_finder.rb index 36fb0e80fb..17e42e3ec3 100644 --- a/app/lib/status_reach_finder.rb +++ b/app/lib/status_reach_finder.rb @@ -16,28 +16,28 @@ class StatusReachFinder private def reached_account_inboxes + Account.where(id: reached_account_ids).inboxes + end + + def reached_account_ids # When the status is a reblog, there are no interactions with it # directly, we assume all interactions are with the original one if @status.reblog? - [] + [reblog_of_account_id] else - Account.where(id: reached_account_ids).inboxes - end - end - - def reached_account_ids - [ - replied_to_account_id, - reblog_of_account_id, - mentioned_account_ids, - reblogs_account_ids, - favourites_account_ids, - replies_account_ids, - ].tap do |arr| - arr.flatten! - arr.compact! - arr.uniq! + [ + replied_to_account_id, + reblog_of_account_id, + mentioned_account_ids, + reblogs_account_ids, + favourites_account_ids, + replies_account_ids, + ].tap do |arr| + arr.flatten! + arr.compact! + arr.uniq! + end end end diff --git a/app/lib/vacuum/media_attachments_vacuum.rb b/app/lib/vacuum/media_attachments_vacuum.rb index ab7ea4092f..e558195290 100644 --- a/app/lib/vacuum/media_attachments_vacuum.rb +++ b/app/lib/vacuum/media_attachments_vacuum.rb @@ -27,11 +27,17 @@ class Vacuum::MediaAttachmentsVacuum end def media_attachments_past_retention_period - MediaAttachment.remote.cached.where(MediaAttachment.arel_table[:created_at].lt(@retention_period.ago)).where(MediaAttachment.arel_table[:updated_at].lt(@retention_period.ago)) + MediaAttachment + .remote + .cached + .created_before(@retention_period.ago) + .updated_before(@retention_period.ago) end def orphaned_media_attachments - MediaAttachment.unattached.where(MediaAttachment.arel_table[:created_at].lt(TTL.ago)) + MediaAttachment + .unattached + .created_before(TTL.ago) end def retention_period? diff --git a/app/mailers/notification_mailer.rb b/app/mailers/notification_mailer.rb index 737ce9d418..f011b266f7 100644 --- a/app/mailers/notification_mailer.rb +++ b/app/mailers/notification_mailer.rb @@ -12,6 +12,8 @@ class NotificationMailer < ApplicationMailer default to: -> { email_address_with_name(@user.email, @me.username) } + layout 'mailer' + def mention return unless @user.functional? && @status.present? diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 432b851b5e..3b1a085cb8 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -191,6 +191,18 @@ class UserMailer < Devise::Mailer end end + def failed_2fa(user, remote_ip, user_agent, timestamp) + @resource = user + @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 + end + end + private def default_devise_subject diff --git a/app/models/account.rb b/app/models/account.rb index 0e38e07be8..55eee725d2 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -127,13 +127,13 @@ class Account < ApplicationRecord scope :bots, -> { where(actor_type: %w(Application Service)) } scope :groups, -> { where(actor_type: 'Group') } scope :alphabetic, -> { order(domain: :asc, username: :asc) } + scope :matches_uri_prefix, ->(value) { where(arel_table[:uri].matches("#{sanitize_sql_like(value)}/%", false, true)).or(where(uri: value)) } scope :matches_username, ->(value) { where('lower((username)::text) LIKE lower(?)', "#{value}%") } scope :matches_display_name, ->(value) { where(arel_table[:display_name].matches("#{value}%")) } - scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } scope :without_unapproved, -> { left_outer_joins(:user).merge(User.approved.confirmed).or(remote) } + scope :auditable, -> { where(id: Admin::ActionLog.select(:account_id).distinct) } scope :searchable, -> { without_unapproved.without_suspended.where(moved_to_account_id: nil) } scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).joins(:account_stat) } - scope :followable_by, ->(account) { joins(arel_table.join(Follow.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(Follow.arel_table[:target_account_id]).and(Follow.arel_table[:account_id].eq(account.id))).join_sources).where(Follow.arel_table[:id].eq(nil)).joins(arel_table.join(FollowRequest.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(FollowRequest.arel_table[:target_account_id]).and(FollowRequest.arel_table[:account_id].eq(account.id))).join_sources).where(FollowRequest.arel_table[:id].eq(nil)) } scope :by_recent_status, -> { includes(:account_stat).merge(AccountStat.order('last_status_at DESC NULLS LAST')).references(:account_stat) } scope :by_recent_activity, -> { left_joins(:user, :account_stat).order(coalesced_activity_timestamps.desc).order(id: :desc) } scope :popular, -> { order('account_stats.followers_count desc') } diff --git a/app/models/account_suggestions.rb b/app/models/account_suggestions.rb index d62176c7ca..25c8b04d50 100644 --- a/app/models/account_suggestions.rb +++ b/app/models/account_suggestions.rb @@ -29,7 +29,7 @@ class AccountSuggestions # a complicated query on this end. account_ids = account_ids_with_sources[offset, limit] - accounts_map = Account.where(id: account_ids.map(&:first)).includes(:account_stat).index_by(&:id) + accounts_map = Account.where(id: account_ids.map(&:first)).includes(:account_stat, :user).index_by(&:id) account_ids.filter_map do |(account_id, source)| next unless accounts_map.key?(account_id) diff --git a/app/models/account_suggestions/source.rb b/app/models/account_suggestions/source.rb index ee93a1342f..d83f5e3773 100644 --- a/app/models/account_suggestions/source.rb +++ b/app/models/account_suggestions/source.rb @@ -8,11 +8,31 @@ class AccountSuggestions::Source protected def base_account_scope(account) - Account.searchable - .followable_by(account) - .not_excluded_by_account(account) - .not_domain_blocked_by_account(account) - .where.not(id: account.id) - .joins("LEFT OUTER JOIN follow_recommendation_mutes ON follow_recommendation_mutes.target_account_id = accounts.id AND follow_recommendation_mutes.account_id = #{account.id}").where(follow_recommendation_mutes: { target_account_id: nil }) + Account + .searchable + .where.not(follows_sql, id: account.id) + .where.not(follow_requests_sql, id: account.id) + .not_excluded_by_account(account) + .not_domain_blocked_by_account(account) + .where.not(id: account.id) + .where.not(follow_recommendation_mutes_sql, id: account.id) + end + + def follows_sql + <<~SQL.squish + EXISTS (SELECT 1 FROM follows WHERE follows.target_account_id = accounts.id AND follows.account_id = :id) + SQL + end + + def follow_requests_sql + <<~SQL.squish + EXISTS (SELECT 1 FROM follow_requests WHERE follow_requests.target_account_id = accounts.id AND follow_requests.account_id = :id) + SQL + end + + def follow_recommendation_mutes_sql + <<~SQL.squish + EXISTS (SELECT 1 FROM follow_recommendation_mutes WHERE follow_recommendation_mutes.target_account_id = accounts.id AND follow_recommendation_mutes.account_id = :id) + SQL end end diff --git a/app/models/account_summary.rb b/app/models/account_summary.rb index 0d8835b83c..2a21d09a8b 100644 --- a/app/models/account_summary.rb +++ b/app/models/account_summary.rb @@ -12,9 +12,11 @@ class AccountSummary < ApplicationRecord self.primary_key = :account_id + has_many :follow_recommendation_suppressions, primary_key: :account_id, foreign_key: :account_id, inverse_of: false + scope :safe, -> { where(sensitive: false) } scope :localized, ->(locale) { where(language: locale) } - scope :filtered, -> { joins(arel_table.join(FollowRecommendationSuppression.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:account_id].eq(FollowRecommendationSuppression.arel_table[:account_id])).join_sources).where(FollowRecommendationSuppression.arel_table[:id].eq(nil)) } + scope :filtered, -> { where.missing(:follow_recommendation_suppressions) } def self.refresh Scenic.database.refresh_materialized_view(table_name, concurrently: false, cascade: false) diff --git a/app/models/admin/action_log_filter.rb b/app/models/admin/action_log_filter.rb index d413cb386d..f581af74e8 100644 --- a/app/models/admin/action_log_filter.rb +++ b/app/models/admin/action_log_filter.rb @@ -72,7 +72,7 @@ class Admin::ActionLogFilter end def results - scope = latest_action_logs.includes(:target) + scope = latest_action_logs.includes(:target, :account) params.each do |key, value| next if key.to_s == 'page' diff --git a/app/models/announcement.rb b/app/models/announcement.rb index 86f7037a56..e630570020 100644 --- a/app/models/announcement.rb +++ b/app/models/announcement.rb @@ -75,22 +75,41 @@ class Announcement < ApplicationRecord end def reactions(account = nil) - records = begin - scope = announcement_reactions.group(:announcement_id, :name, :custom_emoji_id).order(Arel.sql('MIN(created_at) ASC')) - - if account.nil? - scope.select('name, custom_emoji_id, count(*) as count, false as me') - else - scope.select("name, custom_emoji_id, count(*) as count, exists(select 1 from announcement_reactions r where r.account_id = #{account.id} and r.announcement_id = announcement_reactions.announcement_id and r.name = announcement_reactions.name) as me") + grouped_ordered_announcement_reactions.select( + [:name, :custom_emoji_id, 'COUNT(*) as count'].tap do |values| + values << value_for_reaction_me_column(account) end - end.to_a - - ActiveRecord::Associations::Preloader.new(records: records, associations: :custom_emoji).call - records + ).to_a.tap do |records| + ActiveRecord::Associations::Preloader.new(records: records, associations: :custom_emoji).call + end end private + def grouped_ordered_announcement_reactions + announcement_reactions + .group(:announcement_id, :name, :custom_emoji_id) + .order( + Arel.sql('MIN(created_at)').asc + ) + end + + def value_for_reaction_me_column(account) + if account.nil? + 'FALSE AS me' + else + <<~SQL.squish + EXISTS( + SELECT 1 + FROM announcement_reactions inner_reactions + WHERE inner_reactions.account_id = #{account.id} + AND inner_reactions.announcement_id = announcement_reactions.announcement_id + AND inner_reactions.name = announcement_reactions.name + ) AS me + SQL + end + end + def set_published return unless scheduled_at.blank? || scheduled_at.past? diff --git a/app/models/appeal.rb b/app/models/appeal.rb index f1290ad01a..395056b76f 100644 --- a/app/models/appeal.rb +++ b/app/models/appeal.rb @@ -20,8 +20,11 @@ class Appeal < ApplicationRecord belongs_to :account belongs_to :strike, class_name: 'AccountWarning', foreign_key: 'account_warning_id', inverse_of: :appeal - belongs_to :approved_by_account, class_name: 'Account', optional: true - belongs_to :rejected_by_account, class_name: 'Account', optional: true + + with_options class_name: 'Account', optional: true do + belongs_to :approved_by_account + belongs_to :rejected_by_account + end validates :text, presence: true, length: { maximum: 2_000 } validates :account_warning_id, uniqueness: true diff --git a/app/models/bulk_import.rb b/app/models/bulk_import.rb index 810e471849..406fb2aba2 100644 --- a/app/models/bulk_import.rb +++ b/app/models/bulk_import.rb @@ -44,8 +44,8 @@ class BulkImport < ApplicationRecord def self.progress!(bulk_import_id, imported: false) # Use `increment_counter` so that the incrementation is done atomically in the database - BulkImport.increment_counter(:processed_items, bulk_import_id) # rubocop:disable Rails/SkipsModelValidations - BulkImport.increment_counter(:imported_items, bulk_import_id) if imported # rubocop:disable Rails/SkipsModelValidations + BulkImport.increment_counter(:processed_items, bulk_import_id) + BulkImport.increment_counter(:imported_items, bulk_import_id) if imported # Since the incrementation has been done atomically, concurrent access to `bulk_import` is now bening bulk_import = BulkImport.find(bulk_import_id) diff --git a/app/models/concerns/account/interactions.rb b/app/models/concerns/account/interactions.rb index a7ff55e5c2..710cff49ef 100644 --- a/app/models/concerns/account/interactions.rb +++ b/app/models/concerns/account/interactions.rb @@ -183,7 +183,7 @@ module Account::Interactions end def following?(other_account) - active_relationships.where(target_account: other_account).exists? + active_relationships.exists?(target_account: other_account) end def following_anyone? @@ -199,35 +199,39 @@ module Account::Interactions end def blocking?(other_account) - block_relationships.where(target_account: other_account).exists? + block_relationships.exists?(target_account: other_account) end def domain_blocking?(other_domain) - domain_blocks.where(domain: other_domain).exists? + domain_blocks.exists?(domain: other_domain) end def muting?(other_account) - mute_relationships.where(target_account: other_account).exists? + mute_relationships.exists?(target_account: other_account) end def muting_conversation?(conversation) - conversation_mutes.where(conversation: conversation).exists? + conversation_mutes.exists?(conversation: conversation) end def muting_notifications?(other_account) - mute_relationships.where(target_account: other_account, hide_notifications: true).exists? + mute_relationships.exists?(target_account: other_account, hide_notifications: true) end def muting_reblogs?(other_account) - active_relationships.where(target_account: other_account, show_reblogs: false).exists? + active_relationships.exists?(target_account: other_account, show_reblogs: false) end def requested?(other_account) - follow_requests.where(target_account: other_account).exists? + follow_requests.exists?(target_account: other_account) end def favourited?(status) - status.proper.favourites.where(account: self).exists? + status.proper.favourites.exists?(account: self) + end + + def reacted?(status, name, custom_emoji = nil) + status.proper.status_reactions.where(account: self, name: name, custom_emoji: custom_emoji).exists? end def reacted?(status, name, custom_emoji = nil) @@ -235,19 +239,19 @@ module Account::Interactions end def bookmarked?(status) - status.proper.bookmarks.where(account: self).exists? + status.proper.bookmarks.exists?(account: self) end def reblogged?(status) - status.proper.reblogs.where(account: self).exists? + status.proper.reblogs.exists?(account: self) end def pinned?(status) - status_pins.where(status: status).exists? + status_pins.exists?(status: status) end def endorsed?(account) - account_pins.where(target_account: account).exists? + account_pins.exists?(target_account: account) end def status_matches_filters(status) diff --git a/app/models/concerns/user/omniauthable.rb b/app/models/concerns/user/omniauthable.rb index 6d1d1b8cc3..113bfda230 100644 --- a/app/models/concerns/user/omniauthable.rb +++ b/app/models/concerns/user/omniauthable.rb @@ -61,7 +61,7 @@ module User::Omniauthable user.account.avatar_remote_url = nil end - user.confirm! if email_is_verified + user.mark_email_as_confirmed! if email_is_verified user.save! user end diff --git a/app/models/domain_allow.rb b/app/models/domain_allow.rb index ce9597b4d1..47ada7ac23 100644 --- a/app/models/domain_allow.rb +++ b/app/models/domain_allow.rb @@ -17,8 +17,6 @@ class DomainAllow < ApplicationRecord validates :domain, presence: true, uniqueness: true, domain: true - scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } - def to_log_human_identifier domain end diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb index 8da099256a..a05db099a8 100644 --- a/app/models/domain_block.rb +++ b/app/models/domain_block.rb @@ -28,7 +28,6 @@ class DomainBlock < ApplicationRecord has_many :accounts, foreign_key: :domain, primary_key: :domain, inverse_of: false, dependent: nil delegate :count, to: :accounts, prefix: true - scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } scope :with_user_facing_limitations, -> { where(severity: [:silence, :suspend]) } scope :with_limitations, -> { where(severity: [:silence, :suspend]).or(where(reject_media: true)) } scope :by_severity, -> { in_order_of(:severity, %w(noop silence suspend)).order(:domain) } diff --git a/app/models/email_domain_block.rb b/app/models/email_domain_block.rb index f1b14c8b08..40be59420a 100644 --- a/app/models/email_domain_block.rb +++ b/app/models/email_domain_block.rb @@ -21,8 +21,10 @@ class EmailDomainBlock < ApplicationRecord include DomainNormalizable include Paginable - belongs_to :parent, class_name: 'EmailDomainBlock', optional: true - has_many :children, class_name: 'EmailDomainBlock', foreign_key: :parent_id, inverse_of: :parent, dependent: :destroy + with_options class_name: 'EmailDomainBlock' do + belongs_to :parent, optional: true + has_many :children, foreign_key: :parent_id, inverse_of: :parent, dependent: :destroy + end validates :domain, presence: true, uniqueness: true, domain: true diff --git a/app/models/featured_tag.rb b/app/models/featured_tag.rb index 7c36aa8b0b..ea8aa4787c 100644 --- a/app/models/featured_tag.rb +++ b/app/models/featured_tag.rb @@ -45,7 +45,7 @@ class FeaturedTag < ApplicationRecord end def decrement(deleted_status_id) - update(statuses_count: [0, statuses_count - 1].max, last_status_at: account.statuses.where(visibility: %i(public unlisted)).tagged_with(tag).where.not(id: deleted_status_id).select(:created_at).first&.created_at) + update(statuses_count: [0, statuses_count - 1].max, last_status_at: visible_tagged_account_statuses.where.not(id: deleted_status_id).select(:created_at).first&.created_at) end private @@ -55,8 +55,8 @@ class FeaturedTag < ApplicationRecord end def reset_data - self.statuses_count = account.statuses.where(visibility: %i(public unlisted)).tagged_with(tag).count - self.last_status_at = account.statuses.where(visibility: %i(public unlisted)).tagged_with(tag).select(:created_at).first&.created_at + self.statuses_count = visible_tagged_account_statuses.count + self.last_status_at = visible_tagged_account_statuses.select(:created_at).first&.created_at end def validate_featured_tags_limit @@ -66,6 +66,14 @@ class FeaturedTag < ApplicationRecord end def validate_tag_uniqueness - errors.add(:name, :taken) if FeaturedTag.by_name(name).where(account_id: account_id).exists? + errors.add(:name, :taken) if tag_already_featured_for_account? + end + + def tag_already_featured_for_account? + FeaturedTag.by_name(name).exists?(account_id: account_id) + end + + def visible_tagged_account_statuses + account.statuses.where(visibility: %i(public unlisted)).tagged_with(tag) end end diff --git a/app/models/follow_request.rb b/app/models/follow_request.rb index 3c5e8f96f0..c13cc718d8 100644 --- a/app/models/follow_request.rb +++ b/app/models/follow_request.rb @@ -33,7 +33,7 @@ class FollowRequest < ApplicationRecord def authorize! follow = account.follow!(target_account, reblogs: show_reblogs, notify: notify, languages: languages, uri: uri, bypass_limit: true) - ListAccount.where(follow_request: self).update_all(follow_request_id: nil, follow_id: follow.id) # rubocop:disable Rails/SkipsModelValidations + ListAccount.where(follow_request: self).update_all(follow_request_id: nil, follow_id: follow.id) MergeWorker.perform_async(target_account.id, account.id) if account.local? destroy! end diff --git a/app/models/form/import.rb b/app/models/form/import.rb index 712acf3706..fc83d9c58c 100644 --- a/app/models/form/import.rb +++ b/app/models/form/import.rb @@ -69,7 +69,7 @@ class Form::Import ApplicationRecord.transaction do now = Time.now.utc @bulk_import = current_account.bulk_imports.create(type: type, overwrite: overwrite || false, state: :unconfirmed, original_filename: data.original_filename, likely_mismatched: likely_mismatched?) - nb_items = BulkImportRow.insert_all(parsed_rows.map { |row| { bulk_import_id: bulk_import.id, data: row, created_at: now, updated_at: now } }).length # rubocop:disable Rails/SkipsModelValidations + nb_items = BulkImportRow.insert_all(parsed_rows.map { |row| { bulk_import_id: bulk_import.id, data: row, created_at: now, updated_at: now } }).length @bulk_import.update(total_items: nb_items) end end diff --git a/app/models/generated_annual_report.rb b/app/models/generated_annual_report.rb new file mode 100644 index 0000000000..43c97d7108 --- /dev/null +++ b/app/models/generated_annual_report.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: generated_annual_reports +# +# id :bigint(8) not null, primary key +# account_id :bigint(8) not null +# year :integer not null +# data :jsonb not null +# schema_version :integer not null +# viewed_at :datetime +# created_at :datetime not null +# updated_at :datetime not null +# + +class GeneratedAnnualReport < ApplicationRecord + belongs_to :account + + scope :pending, -> { where(viewed_at: nil) } + + def viewed? + viewed_at.present? + end + + def view! + update!(viewed_at: Time.now.utc) + end + + def account_ids + data['most_reblogged_accounts'].pluck('account_id') + data['commonly_interacted_with_accounts'].pluck('account_id') + end + + def status_ids + data['top_statuses'].values + end +end diff --git a/app/models/instance.rb b/app/models/instance.rb index 17ee0cbb1e..8f8d87c62a 100644 --- a/app/models/instance.rb +++ b/app/models/instance.rb @@ -23,6 +23,7 @@ class Instance < ApplicationRecord scope :searchable, -> { where.not(domain: DomainBlock.select(:domain)) } scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } + scope :domain_starts_with, ->(value) { where(arel_table[:domain].matches("#{sanitize_sql_like(value)}%", false, true)) } scope :by_domain_and_subdomains, ->(domain) { where("reverse('.' || domain) LIKE reverse(?)", "%.#{domain}") } def self.refresh diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 5af4ec46ed..90eda3dc8d 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -204,12 +204,14 @@ class MediaAttachment < ApplicationRecord validates :file, presence: true, if: :local? validates :thumbnail, absence: true, if: -> { local? && !audio_or_video? } - scope :attached, -> { where.not(status_id: nil).or(where.not(scheduled_status_id: nil)) } - scope :cached, -> { remote.where.not(file_file_name: nil) } - scope :local, -> { where(remote_url: '') } - scope :ordered, -> { order(id: :asc) } - scope :remote, -> { where.not(remote_url: '') } + scope :attached, -> { where.not(status_id: nil).or(where.not(scheduled_status_id: nil)) } + scope :cached, -> { remote.where.not(file_file_name: nil) } + scope :created_before, ->(value) { where(arel_table[:created_at].lt(value)) } + scope :local, -> { where(remote_url: '') } + scope :ordered, -> { order(id: :asc) } + scope :remote, -> { where.not(remote_url: '') } scope :unattached, -> { where(status_id: nil, scheduled_status_id: nil) } + scope :updated_before, ->(value) { where(arel_table[:updated_at].lt(value)) } attr_accessor :skip_download diff --git a/app/models/poll.rb b/app/models/poll.rb index 72f04f00a7..cc4184f80a 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -27,8 +27,11 @@ class Poll < ApplicationRecord belongs_to :status has_many :votes, class_name: 'PollVote', inverse_of: :poll, dependent: :delete_all - has_many :voters, -> { group('accounts.id') }, through: :votes, class_name: 'Account', source: :account - has_many :local_voters, -> { group('accounts.id').merge(Account.local) }, through: :votes, class_name: 'Account', source: :account + + with_options class_name: 'Account', source: :account, through: :votes do + has_many :voters, -> { group('accounts.id') } + has_many :local_voters, -> { group('accounts.id').merge(Account.local) } + end has_many :notifications, as: :activity, dependent: :destroy @@ -54,7 +57,7 @@ class Poll < ApplicationRecord end def voted?(account) - account.id == account_id || votes.where(account: account).exists? + account.id == account_id || votes.exists?(account: account) end def own_votes(account) diff --git a/app/models/privacy_policy.rb b/app/models/privacy_policy.rb index 36cbf18822..c0d6e1b76d 100644 --- a/app/models/privacy_policy.rb +++ b/app/models/privacy_policy.rb @@ -1,66 +1,7 @@ # frozen_string_literal: true class PrivacyPolicy < ActiveModelSerializers::Model - DEFAULT_PRIVACY_POLICY = <<~TXT - This privacy policy describes how %{domain} ("%{domain}", "we", "us") collects, protects and uses the personally identifiable information you may provide through the %{domain} website or its API. The policy also describes the choices available to you regarding our use of your personal information and how you can access and update this information. This policy does not apply to the practices of companies that %{domain} does not own or control, or to individuals that %{domain} does not employ or manage. - - # What information do we collect? - - - **Basic account information**: If you register on this server, you may be asked to enter a username, an e-mail address and a password. You may also enter additional profile information such as a display name and biography, and upload a profile picture and header image. The username, display name, biography, profile picture and header image are always listed publicly. - - **Posts, following and other public information**: The list of people you follow is listed publicly, the same is true for your followers. When you submit a message, the date and time is stored as well as the application you submitted the message from. Messages may contain media attachments, such as pictures and videos. Public and unlisted posts are available publicly. When you feature a post on your profile, that is also publicly available information. Your posts are delivered to your followers, in some cases it means they are delivered to different servers and copies are stored there. When you delete posts, this is likewise delivered to your followers. The action of reblogging or favouriting another post is always public. - - **Direct and followers-only posts**: All posts are stored and processed on the server. Followers-only posts are delivered to your followers and users who are mentioned in them, and direct posts are delivered only to users mentioned in them. In some cases it means they are delivered to different servers and copies are stored there. We make a good faith effort to limit the access to those posts only to authorized persons, but other servers may fail to do so. Therefore it's important to review servers your followers belong to. You may toggle an option to approve and reject new followers manually in the settings. **Please keep in mind that the operators of the server and any receiving server may view such messages**, and that recipients may screenshot, copy or otherwise re-share them. **Do not share any sensitive information over Mastodon.** - - **IPs and other metadata**: When you log in, we record the IP address you log in from, as well as the name of your browser application. All the logged in sessions are available for your review and revocation in the settings. The latest IP address used is stored for up to 12 months. We also may retain server logs which include the IP address of every request to our server. - - # What do we use your information for? - - Any of the information we collect from you may be used in the following ways: - - - To provide the core functionality of Mastodon. You can only interact with other people's content and post your own content when you are logged in. For example, you may follow other people to view their combined posts in your own personalized home timeline. - - To aid moderation of the community, for example comparing your IP address with other known ones to determine ban evasion or other violations. - - The email address you provide may be used to send you information, notifications about other people interacting with your content or sending you messages, and to respond to inquiries, and/or other requests or questions. - - # How do we protect your information? - - We implement a variety of security measures to maintain the safety of your personal information when you enter, submit, or access your personal information. Among other things, your browser session, as well as the traffic between your applications and the API, are secured with SSL, and your password is hashed using a strong one-way algorithm. You may enable two-factor authentication to further secure access to your account. - - # What is our data retention policy? - - We will make a good faith effort to: - - - Retain server logs containing the IP address of all requests to this server, in so far as such logs are kept, no more than 90 days. - - Retain the IP addresses associated with registered users no more than 12 months. - - You can request and download an archive of your content, including your posts, media attachments, profile picture, and header image. - - You may irreversibly delete your account at any time. - - # Do we use cookies? - - Yes. Cookies are small files that a site or its service provider transfers to your computer's hard drive through your Web browser (if you allow). These cookies enable the site to recognize your browser and, if you have a registered account, associate it with your registered account. - - We use cookies to understand and save your preferences for future visits. - - # Do we disclose any information to outside parties? - - We do not sell, trade, or otherwise transfer to outside parties your personally identifiable information. This does not include trusted third parties who assist us in operating our site, conducting our business, or servicing you, so long as those parties agree to keep this information confidential. We may also release your information when we believe release is appropriate to comply with the law, enforce our site policies, or protect ours or others rights, property, or safety. - - Your public content may be downloaded by other servers in the network. Your public and followers-only posts are delivered to the servers where your followers reside, and direct messages are delivered to the servers of the recipients, in so far as those followers or recipients reside on a different server than this. - - When you authorize an application to use your account, depending on the scope of permissions you approve, it may access your public profile information, your following list, your followers, your lists, all your posts, and your favourites. Applications can never access your e-mail address or password. - - # Site usage by children - - If this server is in the EU or the EEA: Our site, products and services are all directed to people who are at least 16 years old. If you are under the age of 16, per the requirements of the GDPR (General Data Protection Regulation) do not use this site. - - If this server is in the USA: Our site, products and services are all directed to people who are at least 13 years old. If you are under the age of 13, per the requirements of COPPA (Children's Online Privacy Protection Act) do not use this site. - - Law requirements can be different if this server is in another jurisdiction. - - ___ - - This document is CC-BY-SA. Originally adapted from the [Discourse privacy policy](https://github.com/discourse/discourse). - TXT - + DEFAULT_PRIVACY_POLICY = Rails.root.join('config', 'templates', 'privacy-policy.md').read DEFAULT_UPDATED_AT = DateTime.new(2022, 10, 7).freeze attributes :updated_at, :text diff --git a/app/models/report.rb b/app/models/report.rb index c565362cc6..38da26d7b7 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -29,16 +29,19 @@ class Report < ApplicationRecord rate_limit by: :account, family: :reports belongs_to :account - belongs_to :target_account, class_name: 'Account' - belongs_to :action_taken_by_account, class_name: 'Account', optional: true - belongs_to :assigned_account, class_name: 'Account', optional: true + + with_options class_name: 'Account' do + belongs_to :target_account + belongs_to :action_taken_by_account, optional: true + belongs_to :assigned_account, optional: true + end has_many :notes, class_name: 'ReportNote', inverse_of: :report, dependent: :destroy has_many :notifications, as: :activity, dependent: :destroy scope :unresolved, -> { where(action_taken_at: nil) } scope :resolved, -> { where.not(action_taken_at: nil) } - scope :with_accounts, -> { includes([:account, :target_account, :action_taken_by_account, :assigned_account].index_with({ user: [:invite_request, :invite] })) } + scope :with_accounts, -> { includes([:account, :target_account, :action_taken_by_account, :assigned_account].index_with([:account_stat, { user: [:invite_request, :invite, :ips] }])) } # A report is considered local if the reporter is local delegate :local?, to: :account diff --git a/app/models/session_activation.rb b/app/models/session_activation.rb index 7f5f0d9a9a..c67180d3ba 100644 --- a/app/models/session_activation.rb +++ b/app/models/session_activation.rb @@ -41,7 +41,7 @@ class SessionActivation < ApplicationRecord class << self def active?(id) - id && where(session_id: id).exists? + id && exists?(session_id: id) end def activate(**options) diff --git a/app/models/status.rb b/app/models/status.rb index 95dc602fc5..33998a2b87 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -61,8 +61,10 @@ class Status < ApplicationRecord belongs_to :conversation, optional: true belongs_to :preloadable_poll, class_name: 'Poll', foreign_key: 'poll_id', optional: true, inverse_of: false - belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :replies, optional: true - belongs_to :reblog, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblogs, optional: true + with_options class_name: 'Status', optional: true do + belongs_to :thread, foreign_key: 'in_reply_to_id', inverse_of: :replies + belongs_to :reblog, foreign_key: 'reblog_of_id', inverse_of: :reblogs + end has_many :favourites, inverse_of: :status, dependent: :destroy has_many :bookmarks, inverse_of: :status, dependent: :destroy @@ -269,7 +271,7 @@ class Status < ApplicationRecord end def reported? - @reported ||= Report.where(target_account: account).unresolved.where('? = ANY(status_ids)', id).exists? + @reported ||= Report.where(target_account: account).unresolved.exists?(['? = ANY(status_ids)', id]) end def emojis @@ -282,20 +284,13 @@ class Status < ApplicationRecord end def reactions(account = nil) - records = begin - scope = status_reactions.group(:status_id, :name, :custom_emoji_id).order(Arel.sql('MIN(created_at) ASC')) - - if account.nil? - scope.select('name, custom_emoji_id, count(*) as count, false as me') - else - scope.select(<<~SQL.squish) - name, custom_emoji_id, count(*) as count, exists(select 1 from status_reactions r where r.account_id = #{account.id} and r.status_id = status_reactions.status_id and r.name = status_reactions.name and (r.custom_emoji_id = status_reactions.custom_emoji_id or r.custom_emoji_id is null and status_reactions.custom_emoji_id is null)) as me - SQL + grouped_ordered_status_reactions.select( + [:name, :custom_emoji_id, 'COUNT(*) as count'].tap do |values| + values << value_for_reaction_me_column(account) end + ).to_a.tap do |records| + ActiveRecord::Associations::Preloader.new(records: records, associations: :custom_emoji).call end - - ActiveRecord::Associations::Preloader.new(records: records, associations: :custom_emoji) - records end def ordered_media_attachments @@ -485,6 +480,35 @@ class Status < ApplicationRecord private + def grouped_ordered_status_reactions + status_reactions + .group(:status_id, :name, :custom_emoji_id) + .order( + Arel.sql('MIN(created_at)').asc + ) + end + + def value_for_reaction_me_column(account) + if account.nil? + 'FALSE AS me' + else + <<~SQL.squish + EXISTS( + SELECT 1 + FROM status_reactions inner_reactions + WHERE inner_reactions.account_id = #{account.id} + AND inner_reactions.status_id = status_reactions.status_id + AND inner_reactions.name = status_reactions.name + AND ( + inner_reactions.custom_emoji_id = status_reactions.custom_emoji_id + OR inner_reactions.custom_emoji_id IS NULL + AND status_reactions.custom_emoji_id IS NULL + ) + ) AS me + SQL + end + end + def update_status_stat!(attrs) return if marked_for_destruction? || destroyed? diff --git a/app/models/tag.rb b/app/models/tag.rb index 46e55d74f9..f2168ae904 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -39,6 +39,8 @@ class Tag < ApplicationRecord HASHTAG_NAME_RE = /\A(#{HASHTAG_NAME_PAT})\z/i HASHTAG_INVALID_CHARS_RE = /[^[:alnum:]\u0E47-\u0E4E#{HASHTAG_SEPARATORS}]/ + RECENT_STATUS_LIMIT = 1000 + validates :name, presence: true, format: { with: HASHTAG_NAME_RE } validates :display_name, format: { with: HASHTAG_NAME_RE } validate :validate_name_change, if: -> { !new_record? && name_changed? } @@ -53,7 +55,7 @@ class Tag < ApplicationRecord scope :not_trendable, -> { where(trendable: false) } scope :recently_used, lambda { |account| joins(:statuses) - .where(statuses: { id: account.statuses.select(:id).limit(1000) }) + .where(statuses: { id: account.statuses.select(:id).limit(RECENT_STATUS_LIMIT) }) .group(:id).order(Arel.sql('count(*) desc')) } scope :matches_name, ->(term) { where(arel_table[:name].lower.matches(arel_table.lower("#{sanitize_sql_like(Tag.normalize(term))}%"), nil, true)) } # Search with case-sensitive to use B-tree index diff --git a/app/models/user.rb b/app/models/user.rb index 56e575ca42..cc56c2f54e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -149,6 +149,10 @@ class User < ApplicationRecord end end + def self.skip_mx_check? + Rails.env.local? + end + def role if role_id.nil? UserRole.everyone @@ -186,37 +190,16 @@ class User < ApplicationRecord end def confirm - new_user = !confirmed? - self.approved = true if open_registrations? && !sign_up_from_ip_requires_approval? - - super - - if new_user - # Avoid extremely unlikely race condition when approving and confirming - # the user at the same time - reload unless approved? - - if approved? - prepare_new_user! - else - notify_staff_about_pending_account! - end + wrap_email_confirmation do + super end end - def confirm! - new_user = !confirmed? - self.approved = true if open_registrations? - - skip_confirmation! - save! - - if new_user - # Avoid extremely unlikely race condition when approving and confirming - # the user at the same time - reload unless approved? - - prepare_new_user! if approved? + # Mark current email as confirmed, bypassing Devise + def mark_email_as_confirmed! + wrap_email_confirmation do + skip_confirmation! + save! end end @@ -426,14 +409,53 @@ class User < ApplicationRecord end end + def grant_approval_on_confirmation? + # Re-check approval on confirmation if the server has switched to open registrations + open_registrations? && !sign_up_from_ip_requires_approval? && !sign_up_email_requires_approval? + end + + def wrap_email_confirmation + new_user = !confirmed? + self.approved = true if grant_approval_on_confirmation? + + yield + + if new_user + # Avoid extremely unlikely race condition when approving and confirming + # the user at the same time + reload unless approved? + + if approved? + prepare_new_user! + else + notify_staff_about_pending_account! + end + end + end + def sign_up_from_ip_requires_approval? - !sign_up_ip.nil? && IpBlock.where(severity: :sign_up_requires_approval).where('ip >>= ?', sign_up_ip.to_s).exists? + sign_up_ip.present? && IpBlock.sign_up_requires_approval.exists?(['ip >>= ?', sign_up_ip.to_s]) end def sign_up_email_requires_approval? - return false unless email.present? || unconfirmed_email.present? + return false if email.blank? - EmailDomainBlock.requires_approval?(email.presence || unconfirmed_email, attempt_ip: sign_up_ip) + _, domain = email.split('@', 2) + return false if domain.blank? + + records = [] + + # Doing this conditionally is not very satisfying, but this is consistent + # with the MX records validations we do and keeps the specs tractable. + unless self.class.skip_mx_check? + Resolv::DNS.open do |dns| + dns.timeouts = 5 + + records = dns.getresources(domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s }.compact_blank + end + end + + EmailDomainBlock.requires_approval?(records + [domain], attempt_ip: sign_up_ip) end def open_registrations? @@ -484,7 +506,7 @@ class User < ApplicationRecord end def validate_email_dns? - email_changed? && !external? && !Rails.env.local? + email_changed? && !external? && !self.class.skip_mx_check? end def validate_role_elevation diff --git a/app/presenters/annual_reports_presenter.rb b/app/presenters/annual_reports_presenter.rb new file mode 100644 index 0000000000..001e1d37b0 --- /dev/null +++ b/app/presenters/annual_reports_presenter.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class AnnualReportsPresenter + alias read_attribute_for_serialization send + + attr_reader :annual_reports + + def initialize(annual_reports) + @annual_reports = annual_reports + end + + def accounts + @accounts ||= Account.where(id: @annual_reports.flat_map(&:account_ids)).includes(:account_stat, :moved_to_account, user: :role) + end + + def statuses + @statuses ||= Status.where(id: @annual_reports.flat_map(&:status_ids)).with_includes + end + + def self.model_name + @model_name ||= ActiveModel::Name.new(self) + end +end diff --git a/app/serializers/manifest_serializer.rb b/app/serializers/manifest_serializer.rb index 501bb788e7..1c1f7d0ad5 100644 --- a/app/serializers/manifest_serializer.rb +++ b/app/serializers/manifest_serializer.rb @@ -39,7 +39,7 @@ class ManifestSerializer < ActiveModel::Serializer def icons ICON_SIZES.map do |size| { - src: full_pack_url("media/icons/android-chrome-#{size}x#{size}.png"), + src: frontend_asset_url("icons/android-chrome-#{size}x#{size}.png"), sizes: "#{size}x#{size}", type: 'image/png', purpose: 'any maskable', diff --git a/app/serializers/rest/annual_report_serializer.rb b/app/serializers/rest/annual_report_serializer.rb new file mode 100644 index 0000000000..1fb5ddb5c1 --- /dev/null +++ b/app/serializers/rest/annual_report_serializer.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class REST::AnnualReportSerializer < ActiveModel::Serializer + attributes :year, :data, :schema_version +end diff --git a/app/serializers/rest/annual_reports_serializer.rb b/app/serializers/rest/annual_reports_serializer.rb new file mode 100644 index 0000000000..ea9572be1b --- /dev/null +++ b/app/serializers/rest/annual_reports_serializer.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class REST::AnnualReportsSerializer < ActiveModel::Serializer + has_many :annual_reports, serializer: REST::AnnualReportSerializer + has_many :accounts, serializer: REST::AccountSerializer + has_many :statuses, serializer: REST::StatusSerializer +end diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb index 3978f7024d..2db5b9eafd 100644 --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@ -28,7 +28,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer } else { - url: full_pack_url('media/images/preview.png'), + url: frontend_asset_url('images/preview.png'), } end end diff --git a/app/serializers/rest/tag_serializer.rb b/app/serializers/rest/tag_serializer.rb index 7801e77d1f..017b572718 100644 --- a/app/serializers/rest/tag_serializer.rb +++ b/app/serializers/rest/tag_serializer.rb @@ -19,7 +19,7 @@ class REST::TagSerializer < ActiveModel::Serializer if instance_options && instance_options[:relationships] instance_options[:relationships].following_map[object.id] || false else - TagFollow.where(tag_id: object.id, account_id: current_user.account_id).exists? + TagFollow.exists?(tag_id: object.id, account_id: current_user.account_id) end end diff --git a/app/serializers/rest/v1/instance_serializer.rb b/app/serializers/rest/v1/instance_serializer.rb index 4b3e2b86d9..3e958ad13d 100644 --- a/app/serializers/rest/v1/instance_serializer.rb +++ b/app/serializers/rest/v1/instance_serializer.rb @@ -33,7 +33,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer end def thumbnail - instance_presenter.thumbnail ? full_asset_url(instance_presenter.thumbnail.file.url(:'@1x')) : full_pack_url('media/images/preview.png') + instance_presenter.thumbnail ? full_asset_url(instance_presenter.thumbnail.file.url(:'@1x')) : frontend_asset_url('images/preview.png') end def max_toot_chars diff --git a/app/services/activitypub/fetch_featured_collection_service.rb b/app/services/activitypub/fetch_featured_collection_service.rb index d2bae08a0e..89c3a1b6c0 100644 --- a/app/services/activitypub/fetch_featured_collection_service.rb +++ b/app/services/activitypub/fetch_featured_collection_service.rb @@ -23,9 +23,9 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService case collection['type'] when 'Collection', 'CollectionPage' - collection['items'] + as_array(collection['items']) when 'OrderedCollection', 'OrderedCollectionPage' - collection['orderedItems'] + as_array(collection['orderedItems']) end end diff --git a/app/services/activitypub/fetch_remote_status_service.rb b/app/services/activitypub/fetch_remote_status_service.rb index a491b32b26..e3a9b60b56 100644 --- a/app/services/activitypub/fetch_remote_status_service.rb +++ b/app/services/activitypub/fetch_remote_status_service.rb @@ -44,7 +44,7 @@ class ActivityPub::FetchRemoteStatusService < BaseService # If we fetched a status that already exists, then we need to treat the # activity as an update rather than create - activity_json['type'] = 'Update' if equals_or_includes_any?(activity_json['type'], %w(Create)) && Status.where(uri: object_uri, account_id: actor.id).exists? + activity_json['type'] = 'Update' if equals_or_includes_any?(activity_json['type'], %w(Create)) && Status.exists?(uri: object_uri, account_id: actor.id) with_redis do |redis| discoveries = redis.incr("status_discovery_per_request:#{@request_id}") diff --git a/app/services/activitypub/fetch_replies_service.rb b/app/services/activitypub/fetch_replies_service.rb index b5c7759ec5..e2ecdef165 100644 --- a/app/services/activitypub/fetch_replies_service.rb +++ b/app/services/activitypub/fetch_replies_service.rb @@ -26,9 +26,9 @@ class ActivityPub::FetchRepliesService < BaseService case collection['type'] when 'Collection', 'CollectionPage' - collection['items'] + as_array(collection['items']) when 'OrderedCollection', 'OrderedCollectionPage' - collection['orderedItems'] + as_array(collection['orderedItems']) end end @@ -37,7 +37,20 @@ class ActivityPub::FetchRepliesService < BaseService return unless @allow_synchronous_requests return if non_matching_uri_hosts?(@account.uri, collection_or_uri) - fetch_resource_without_id_validation(collection_or_uri, nil, true) + # NOTE: For backward compatibility reasons, Mastodon signs outgoing + # queries incorrectly by default. + # + # While this is relevant for all URLs with query strings, this is + # the only code path where this happens in practice. + # + # Therefore, retry with correct signatures if this fails. + begin + fetch_resource_without_id_validation(collection_or_uri, nil, true) + rescue Mastodon::UnexpectedResponseError => e + raise unless e.response && e.response.code == 401 && Addressable::URI.parse(collection_or_uri).query.present? + + fetch_resource_without_id_validation(collection_or_uri, nil, true, request_options: { with_query_string: true }) + end end def filtered_replies diff --git a/app/services/activitypub/synchronize_followers_service.rb b/app/services/activitypub/synchronize_followers_service.rb index 7ccc917309..f51d671a00 100644 --- a/app/services/activitypub/synchronize_followers_service.rb +++ b/app/services/activitypub/synchronize_followers_service.rb @@ -59,9 +59,9 @@ class ActivityPub::SynchronizeFollowersService < BaseService case collection['type'] when 'Collection', 'CollectionPage' - collection['items'] + as_array(collection['items']) when 'OrderedCollection', 'OrderedCollectionPage' - collection['orderedItems'] + as_array(collection['orderedItems']) end end diff --git a/app/services/keys/query_service.rb b/app/services/keys/query_service.rb index 14c9d9205b..33e13293f3 100644 --- a/app/services/keys/query_service.rb +++ b/app/services/keys/query_service.rb @@ -69,7 +69,7 @@ class Keys::QueryService < BaseService return if json['items'].blank? - @devices = json['items'].map do |device| + @devices = as_array(json['items']).map do |device| Device.new(device_id: device['id'], name: device['name'], identity_key: device.dig('identityKey', 'publicKeyBase64'), fingerprint_key: device.dig('fingerprintKey', 'publicKeyBase64'), claim_url: device['claim']) end rescue HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error => e diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb index 18e1748cea..9c3d410182 100644 --- a/app/services/reblog_service.rb +++ b/app/services/reblog_service.rb @@ -43,11 +43,7 @@ class ReblogService < BaseService def create_notification(reblog) reblogged_status = reblog.reblog - if reblogged_status.account.local? - LocalNotificationWorker.perform_async(reblogged_status.account_id, reblog.id, reblog.class.name, 'reblog') - elsif reblogged_status.account.activitypub? && !reblogged_status.account.following?(reblog.account) - ActivityPub::DeliveryWorker.perform_async(build_json(reblog), reblog.account_id, reblogged_status.account.inbox_url) - end + LocalNotificationWorker.perform_async(reblogged_status.account_id, reblog.id, reblog.class.name, 'reblog') if reblogged_status.account.local? end def increment_statistics diff --git a/app/services/vote_service.rb b/app/services/vote_service.rb index 3e92a1690a..878350388b 100644 --- a/app/services/vote_service.rb +++ b/app/services/vote_service.rb @@ -19,7 +19,7 @@ class VoteService < BaseService already_voted = true with_redis_lock("vote:#{@poll.id}:#{@account.id}") do - already_voted = @poll.votes.where(account: @account).exists? + already_voted = @poll.votes.exists?(account: @account) ApplicationRecord.transaction do @choices.each do |choice| diff --git a/app/validators/reaction_validator.rb b/app/validators/reaction_validator.rb index 4ed3376e8b..89d83de5a2 100644 --- a/app/validators/reaction_validator.rb +++ b/app/validators/reaction_validator.rb @@ -19,7 +19,7 @@ class ReactionValidator < ActiveModel::Validator end def new_reaction?(reaction) - !reaction.announcement.announcement_reactions.where(name: reaction.name).exists? + !reaction.announcement.announcement_reactions.exists?(name: reaction.name) end def limit_reached?(reaction) diff --git a/app/validators/vote_validator.rb b/app/validators/vote_validator.rb index fa2bd223dc..e725b4c0b8 100644 --- a/app/validators/vote_validator.rb +++ b/app/validators/vote_validator.rb @@ -35,7 +35,7 @@ class VoteValidator < ActiveModel::Validator if vote.persisted? account_votes_on_same_poll(vote).where(choice: vote.choice).where.not(poll_votes: { id: vote }).exists? else - account_votes_on_same_poll(vote).where(choice: vote.choice).exists? + account_votes_on_same_poll(vote).exists?(choice: vote.choice) end end diff --git a/app/views/application/mailer/_account.html.haml b/app/views/application/mailer/_account.html.haml new file mode 100644 index 0000000000..b0ef4f1e02 --- /dev/null +++ b/app/views/application/mailer/_account.html.haml @@ -0,0 +1,30 @@ +%table.email-w-full.email-account-banner-table{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td.email-account-banner-td{ height: 140, background: full_asset_url(account.header.url) } + %table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td.email-account-banner-inner-td + .email-account-banner-overlap-div + %table.email-account-banner-icon-table{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td + %img{ src: full_asset_url(account.avatar.url), width: 80, height: 80, alt: '' } +%table.email-w-full.email-account-body-table{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td.email-account-body-td + %p.email-account-name= display_name(account) + %p.email-account-handle= acct(account) + %table{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td.email-padding-top-16 + %table.email-w-full.email-account-stats-table{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td + %b= account_formatted_stat(account.statuses_count) + %span= t('accounts.posts', count: account.statuses_count) + %td + %b= account_formatted_stat(account.following_count) + %span= t('accounts.following') + %td + %b= hide_followers_count?(account) ? '-' : account_formatted_stat(account.followers_count) + %span= t('accounts.followers', count: account.followers_count) diff --git a/app/views/application/mailer/_button.html.haml b/app/views/application/mailer/_button.html.haml new file mode 100644 index 0000000000..61430732eb --- /dev/null +++ b/app/views/application/mailer/_button.html.haml @@ -0,0 +1,4 @@ +%table.email-btn-table{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td.email-btn-td + = link_to "#{text} ➜", url, class: 'email-btn-a email-btn-hover' diff --git a/app/views/application/mailer/_checklist.html.haml b/app/views/application/mailer/_checklist.html.haml new file mode 100644 index 0000000000..83072bd36b --- /dev/null +++ b/app/views/application/mailer/_checklist.html.haml @@ -0,0 +1,29 @@ +%table.email-w-full.email-checklist-wrapper-table{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td.email-checklist-wrapper-td + %table.email-w-full.email-checklist-table{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td.email-checklist-td + %table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td.email-checklist-icons-td + %table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td.email-checklist-icons-checkbox-td + - if defined?(checked) && checked + = image_tag frontend_asset_url('images/mailer-new/welcome/checkbox-on.png'), alt: '', width: 20, height: 20 + - else + = image_tag frontend_asset_url('images/mailer-new/welcome/checkbox-off.png'), alt: '', width: 20, height: 20 + %td.email-checklist-icons-step-td + - if defined?(step_image_url) + = image_tag step_image_url, alt: '', width: 40, height: 40 + %td.email-checklist-text-td + .email-desktop-flex + %div + - if defined?(title) + %h3= title + - if defined?(text) + %p= text + %div + - if defined?(button_text) && defined?(button_url) && defined?(checked) && !checked + = render 'application/mailer/button', text: button_text, url: button_url diff --git a/app/views/application/mailer/_frame.html.haml b/app/views/application/mailer/_frame.html.haml new file mode 100644 index 0000000000..74403e7678 --- /dev/null +++ b/app/views/application/mailer/_frame.html.haml @@ -0,0 +1,4 @@ +%table.email-w-full.email-frame-table{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td.email-frame-td + %p= text diff --git a/app/views/application/mailer/_heading.html.haml b/app/views/application/mailer/_heading.html.haml new file mode 100644 index 0000000000..9fc5dc7471 --- /dev/null +++ b/app/views/application/mailer/_heading.html.haml @@ -0,0 +1,13 @@ +%table.email-w-full.email-header-heading-table{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + %td.email-header-heading-td + %table.email-w-full{ cellspacing: 0, cellpadding: 0, border: 0, role: 'presentation' } + %tr + - if defined?(heading_image_url) + %td.email-header-heading-img-td + = image_tag heading_image_url, alt: '', width: 56, height: 56 + %td.email-header-heading-txt-td + - if defined?(heading_title) + %h1= heading_title + - if defined?(heading_subtitle) + %p= heading_subtitle diff --git a/app/views/custom_css/show.css.erb b/app/views/custom_css/show.css.erb index 9cd38fb371..78da809ed6 100644 --- a/app/views/custom_css/show.css.erb +++ b/app/views/custom_css/show.css.erb @@ -1,8 +1,8 @@ -<%- if Setting.custom_css.present? %> -<%= raw Setting.custom_css %> +<%- if custom_css_styles.present? %> +<%= raw custom_css_styles %> <%- end %> -<%- UserRole.where(highlighted: true).select { |role| role.color.present? }.each do |role| %> +<%- @user_roles.each do |role| %> .user-role-<%= role.id %> { --user-role-accent: <%= role.color %>; } diff --git a/app/views/disputes/strikes/show.html.haml b/app/views/disputes/strikes/show.html.haml index 62695b155e..5f72138821 100644 --- a/app/views/disputes/strikes/show.html.haml +++ b/app/views/disputes/strikes/show.html.haml @@ -21,7 +21,7 @@ .report-header .report-header__card - = render 'card', strike: @strike + = render 'disputes/strikes/card', strike: @strike .report-header__details .report-header__details__item diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 78fe6db11a..213b988ec2 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -14,12 +14,12 @@ %link{ rel: 'icon', href: '/favicon.ico', type: 'image/x-icon' }/ - %w(16 32 48).each do |size| - %link{ rel: 'icon', sizes: "#{size}x#{size}", href: asset_pack_path("media/icons/favicon-#{size}x#{size}.png"), type: 'image/png' }/ + %link{ rel: 'icon', sizes: "#{size}x#{size}", href: frontend_asset_path("icons/favicon-#{size}x#{size}.png"), type: 'image/png' }/ - %w(57 60 72 76 114 120 144 152 167 180 1024).each do |size| - %link{ rel: 'apple-touch-icon', sizes: "#{size}x#{size}", href: asset_pack_path("media/icons/apple-touch-icon-#{size}x#{size}.png") }/ + %link{ rel: 'apple-touch-icon', sizes: "#{size}x#{size}", href: frontend_asset_path("icons/apple-touch-icon-#{size}x#{size}.png") }/ - %link{ rel: 'mask-icon', href: asset_pack_path('media/images/logo-symbol-icon.svg'), color: '#6364FF' }/ + %link{ rel: 'mask-icon', href: frontend_asset_path('images/logo-symbol-icon.svg'), color: '#6364FF' }/ %link{ rel: 'manifest', href: manifest_path(format: :json) }/ %meta{ name: 'theme-color', content: '#191b22' }/ %meta{ name: 'apple-mobile-web-app-capable', content: 'yes' }/ @@ -27,6 +27,10 @@ %title= html_title = javascript_pack_tag 'common', crossorigin: 'anonymous' + + -# Needed for the wicg-inert polyfill. It needs to be on it's own