mirror of
https://git.kescher.at/CatCatNya/catstodon.git
synced 2024-11-28 03:41:37 +01:00
Merge pull request #2251 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes
This commit is contained in:
commit
f3c2035fce
314 changed files with 5436 additions and 5002 deletions
|
@ -69,7 +69,7 @@ services:
|
||||||
hard: -1
|
hard: -1
|
||||||
|
|
||||||
libretranslate:
|
libretranslate:
|
||||||
image: libretranslate/libretranslate:v1.3.10
|
image: libretranslate/libretranslate:v1.3.11
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- lt-data:/home/libretranslate/.local
|
- lt-data:/home/libretranslate/.local
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# This configuration was generated by
|
# This configuration was generated by
|
||||||
# `rubocop --auto-gen-config --auto-gen-only-exclude --no-exclude-limit --no-offense-counts --no-auto-gen-timestamp`
|
# `rubocop --auto-gen-config --auto-gen-only-exclude --no-exclude-limit --no-offense-counts --no-auto-gen-timestamp`
|
||||||
# using RuboCop version 1.50.2.
|
# using RuboCop version 1.52.1.
|
||||||
# The point is for the user to remove these configuration records
|
# The point is for the user to remove these configuration records
|
||||||
# one by one as the offenses are removed from the code base.
|
# one by one as the offenses are removed from the code base.
|
||||||
# Note that changes in the inspected code, or installation of new
|
# Note that changes in the inspected code, or installation of new
|
||||||
|
@ -48,18 +48,14 @@ Layout/SpaceInLambdaLiteral:
|
||||||
- 'config/environments/production.rb'
|
- 'config/environments/production.rb'
|
||||||
- 'config/initializers/content_security_policy.rb'
|
- 'config/initializers/content_security_policy.rb'
|
||||||
|
|
||||||
|
# This cop supports safe autocorrection (--autocorrect).
|
||||||
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
||||||
Lint/AmbiguousBlockAssociation:
|
Lint/AmbiguousBlockAssociation:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'spec/controllers/admin/account_moderation_notes_controller_spec.rb'
|
|
||||||
- 'spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb'
|
- 'spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb'
|
||||||
- 'spec/controllers/settings/two_factor_authentication/otp_authentication_controller_spec.rb'
|
- 'spec/controllers/settings/two_factor_authentication/otp_authentication_controller_spec.rb'
|
||||||
- 'spec/controllers/settings/two_factor_authentication/webauthn_credentials_controller_spec.rb'
|
|
||||||
- 'spec/services/activitypub/process_status_update_service_spec.rb'
|
- 'spec/services/activitypub/process_status_update_service_spec.rb'
|
||||||
- 'spec/services/post_status_service_spec.rb'
|
- 'spec/services/post_status_service_spec.rb'
|
||||||
- 'spec/services/suspend_account_service_spec.rb'
|
|
||||||
- 'spec/services/unsuspend_account_service_spec.rb'
|
|
||||||
- 'spec/workers/scheduler/accounts_statuses_cleanup_scheduler_spec.rb'
|
|
||||||
|
|
||||||
# Configuration parameters: AllowComments, AllowEmptyLambdas.
|
# Configuration parameters: AllowComments, AllowEmptyLambdas.
|
||||||
Lint/EmptyBlock:
|
Lint/EmptyBlock:
|
||||||
|
@ -124,6 +120,7 @@ Lint/UnusedBlockArgument:
|
||||||
- 'config/initializers/paperclip.rb'
|
- 'config/initializers/paperclip.rb'
|
||||||
- 'config/initializers/simple_form.rb'
|
- 'config/initializers/simple_form.rb'
|
||||||
|
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
Lint/UselessAssignment:
|
Lint/UselessAssignment:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/services/activitypub/process_status_update_service.rb'
|
- 'app/services/activitypub/process_status_update_service.rb'
|
||||||
|
@ -145,6 +142,7 @@ Lint/UselessAssignment:
|
||||||
- 'spec/services/resolve_url_service_spec.rb'
|
- 'spec/services/resolve_url_service_spec.rb'
|
||||||
- 'spec/views/statuses/show.html.haml_spec.rb'
|
- 'spec/views/statuses/show.html.haml_spec.rb'
|
||||||
|
|
||||||
|
# This cop supports safe autocorrection (--autocorrect).
|
||||||
# Configuration parameters: CheckForMethodsWithNoSideEffects.
|
# Configuration parameters: CheckForMethodsWithNoSideEffects.
|
||||||
Lint/Void:
|
Lint/Void:
|
||||||
Exclude:
|
Exclude:
|
||||||
|
@ -167,7 +165,7 @@ Metrics/CyclomaticComplexity:
|
||||||
|
|
||||||
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
||||||
Metrics/PerceivedComplexity:
|
Metrics/PerceivedComplexity:
|
||||||
Max: 28
|
Max: 27
|
||||||
|
|
||||||
Naming/AccessorMethodName:
|
Naming/AccessorMethodName:
|
||||||
Exclude:
|
Exclude:
|
||||||
|
@ -180,6 +178,7 @@ Naming/FileName:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'config/locales/sr-Latn.rb'
|
- 'config/locales/sr-Latn.rb'
|
||||||
|
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
# Configuration parameters: EnforcedStyleForLeadingUnderscores.
|
# Configuration parameters: EnforcedStyleForLeadingUnderscores.
|
||||||
# SupportedStylesForLeadingUnderscores: disallowed, required, optional
|
# SupportedStylesForLeadingUnderscores: disallowed, required, optional
|
||||||
Naming/MemoizedInstanceVariableName:
|
Naming/MemoizedInstanceVariableName:
|
||||||
|
@ -202,14 +201,9 @@ Naming/VariableNumber:
|
||||||
- 'db/migrate/20190820003045_update_statuses_index.rb'
|
- 'db/migrate/20190820003045_update_statuses_index.rb'
|
||||||
- 'db/migrate/20190823221802_add_local_index_to_statuses.rb'
|
- 'db/migrate/20190823221802_add_local_index_to_statuses.rb'
|
||||||
- 'db/migrate/20200119112504_add_public_index_to_statuses.rb'
|
- 'db/migrate/20200119112504_add_public_index_to_statuses.rb'
|
||||||
- 'spec/controllers/activitypub/followers_synchronizations_controller_spec.rb'
|
|
||||||
- 'spec/lib/feed_manager_spec.rb'
|
|
||||||
- 'spec/models/account_spec.rb'
|
- 'spec/models/account_spec.rb'
|
||||||
- 'spec/models/concerns/account_interactions_spec.rb'
|
|
||||||
- 'spec/models/custom_emoji_filter_spec.rb'
|
|
||||||
- 'spec/models/domain_block_spec.rb'
|
- 'spec/models/domain_block_spec.rb'
|
||||||
- 'spec/models/user_spec.rb'
|
- 'spec/models/user_spec.rb'
|
||||||
- 'spec/services/activitypub/fetch_featured_collection_service_spec.rb'
|
|
||||||
|
|
||||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
Performance/UnfreezeString:
|
Performance/UnfreezeString:
|
||||||
|
@ -322,8 +316,6 @@ RSpec/LetSetup:
|
||||||
- 'spec/controllers/admin/statuses_controller_spec.rb'
|
- 'spec/controllers/admin/statuses_controller_spec.rb'
|
||||||
- 'spec/controllers/api/v1/accounts/statuses_controller_spec.rb'
|
- 'spec/controllers/api/v1/accounts/statuses_controller_spec.rb'
|
||||||
- 'spec/controllers/api/v1/admin/accounts_controller_spec.rb'
|
- 'spec/controllers/api/v1/admin/accounts_controller_spec.rb'
|
||||||
- 'spec/controllers/api/v1/admin/domain_allows_controller_spec.rb'
|
|
||||||
- 'spec/controllers/api/v1/admin/domain_blocks_controller_spec.rb'
|
|
||||||
- 'spec/controllers/api/v1/filters_controller_spec.rb'
|
- 'spec/controllers/api/v1/filters_controller_spec.rb'
|
||||||
- 'spec/controllers/api/v1/followed_tags_controller_spec.rb'
|
- 'spec/controllers/api/v1/followed_tags_controller_spec.rb'
|
||||||
- 'spec/controllers/api/v1/tags_controller_spec.rb'
|
- 'spec/controllers/api/v1/tags_controller_spec.rb'
|
||||||
|
@ -363,7 +355,6 @@ RSpec/LetSetup:
|
||||||
- 'spec/services/suspend_account_service_spec.rb'
|
- 'spec/services/suspend_account_service_spec.rb'
|
||||||
- 'spec/services/unallow_domain_service_spec.rb'
|
- 'spec/services/unallow_domain_service_spec.rb'
|
||||||
- 'spec/services/unsuspend_account_service_spec.rb'
|
- 'spec/services/unsuspend_account_service_spec.rb'
|
||||||
- 'spec/workers/scheduler/accounts_statuses_cleanup_scheduler_spec.rb'
|
|
||||||
- 'spec/workers/scheduler/user_cleanup_scheduler_spec.rb'
|
- 'spec/workers/scheduler/user_cleanup_scheduler_spec.rb'
|
||||||
|
|
||||||
RSpec/MessageChain:
|
RSpec/MessageChain:
|
||||||
|
@ -396,7 +387,7 @@ RSpec/MessageSpies:
|
||||||
- 'spec/validators/status_length_validator_spec.rb'
|
- 'spec/validators/status_length_validator_spec.rb'
|
||||||
|
|
||||||
RSpec/MultipleExpectations:
|
RSpec/MultipleExpectations:
|
||||||
Max: 19
|
Max: 8
|
||||||
|
|
||||||
# Configuration parameters: AllowSubject.
|
# Configuration parameters: AllowSubject.
|
||||||
RSpec/MultipleMemoizedHelpers:
|
RSpec/MultipleMemoizedHelpers:
|
||||||
|
@ -424,7 +415,6 @@ RSpec/StubbedMock:
|
||||||
RSpec/SubjectDeclaration:
|
RSpec/SubjectDeclaration:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'spec/controllers/admin/domain_blocks_controller_spec.rb'
|
- 'spec/controllers/admin/domain_blocks_controller_spec.rb'
|
||||||
- 'spec/controllers/api/v1/admin/domain_blocks_controller_spec.rb'
|
|
||||||
- 'spec/models/account_migration_spec.rb'
|
- 'spec/models/account_migration_spec.rb'
|
||||||
- 'spec/models/account_spec.rb'
|
- 'spec/models/account_spec.rb'
|
||||||
- 'spec/models/relationship_filter_spec.rb'
|
- 'spec/models/relationship_filter_spec.rb'
|
||||||
|
@ -599,7 +589,6 @@ Rails/NegateInclude:
|
||||||
- 'app/models/concerns/attachmentable.rb'
|
- 'app/models/concerns/attachmentable.rb'
|
||||||
- 'app/models/concerns/remotable.rb'
|
- 'app/models/concerns/remotable.rb'
|
||||||
- 'app/models/custom_filter.rb'
|
- 'app/models/custom_filter.rb'
|
||||||
- 'app/models/webhook.rb'
|
|
||||||
- 'app/services/activitypub/process_status_update_service.rb'
|
- 'app/services/activitypub/process_status_update_service.rb'
|
||||||
- 'app/services/fetch_link_card_service.rb'
|
- 'app/services/fetch_link_card_service.rb'
|
||||||
- 'app/services/search_service.rb'
|
- 'app/services/search_service.rb'
|
||||||
|
@ -770,11 +759,9 @@ Rails/WhereExists:
|
||||||
- 'app/workers/move_worker.rb'
|
- 'app/workers/move_worker.rb'
|
||||||
- 'db/migrate/20190529143559_preserve_old_layout_for_existing_users.rb'
|
- 'db/migrate/20190529143559_preserve_old_layout_for_existing_users.rb'
|
||||||
- 'lib/tasks/tests.rake'
|
- 'lib/tasks/tests.rake'
|
||||||
- 'spec/controllers/api/v1/accounts/notes_controller_spec.rb'
|
|
||||||
- 'spec/controllers/api/v1/tags_controller_spec.rb'
|
- 'spec/controllers/api/v1/tags_controller_spec.rb'
|
||||||
- 'spec/models/account_spec.rb'
|
- 'spec/models/account_spec.rb'
|
||||||
- 'spec/services/activitypub/process_collection_service_spec.rb'
|
- 'spec/services/activitypub/process_collection_service_spec.rb'
|
||||||
- 'spec/services/post_status_service_spec.rb'
|
|
||||||
- 'spec/services/purge_domain_service_spec.rb'
|
- 'spec/services/purge_domain_service_spec.rb'
|
||||||
- 'spec/services/unallow_domain_service_spec.rb'
|
- 'spec/services/unallow_domain_service_spec.rb'
|
||||||
|
|
||||||
|
@ -796,6 +783,7 @@ Style/ClassVars:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'config/initializers/devise.rb'
|
- 'config/initializers/devise.rb'
|
||||||
|
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
Style/CombinableLoops:
|
Style/CombinableLoops:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/models/form/custom_emoji_batch.rb'
|
- 'app/models/form/custom_emoji_batch.rb'
|
||||||
|
|
62
Gemfile.lock
62
Gemfile.lock
|
@ -97,26 +97,26 @@ GEM
|
||||||
attr_required (1.0.1)
|
attr_required (1.0.1)
|
||||||
awrence (1.2.1)
|
awrence (1.2.1)
|
||||||
aws-eventstream (1.2.0)
|
aws-eventstream (1.2.0)
|
||||||
aws-partitions (1.772.0)
|
aws-partitions (1.780.0)
|
||||||
aws-sdk-core (3.174.0)
|
aws-sdk-core (3.175.0)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
aws-partitions (~> 1, >= 1.651.0)
|
aws-partitions (~> 1, >= 1.651.0)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
jmespath (~> 1, >= 1.6.1)
|
jmespath (~> 1, >= 1.6.1)
|
||||||
aws-sdk-kms (1.65.0)
|
aws-sdk-kms (1.67.0)
|
||||||
aws-sdk-core (~> 3, >= 3.174.0)
|
aws-sdk-core (~> 3, >= 3.174.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sdk-s3 (1.123.0)
|
aws-sdk-s3 (1.125.0)
|
||||||
aws-sdk-core (~> 3, >= 3.174.0)
|
aws-sdk-core (~> 3, >= 3.174.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.4)
|
aws-sigv4 (~> 1.4)
|
||||||
aws-sigv4 (1.5.2)
|
aws-sigv4 (1.5.2)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
bcrypt (3.1.18)
|
bcrypt (3.1.18)
|
||||||
better_errors (2.9.1)
|
better_errors (2.10.1)
|
||||||
coderay (>= 1.0.0)
|
|
||||||
erubi (>= 1.0.0)
|
erubi (>= 1.0.0)
|
||||||
rack (>= 0.9.0)
|
rack (>= 0.9.0)
|
||||||
|
rouge (>= 1.0.0)
|
||||||
better_html (2.0.1)
|
better_html (2.0.1)
|
||||||
actionview (>= 6.0)
|
actionview (>= 6.0)
|
||||||
activesupport (>= 6.0)
|
activesupport (>= 6.0)
|
||||||
|
@ -154,7 +154,7 @@ GEM
|
||||||
sshkit (~> 1.3)
|
sshkit (~> 1.3)
|
||||||
capistrano-yarn (2.0.2)
|
capistrano-yarn (2.0.2)
|
||||||
capistrano (~> 3.0)
|
capistrano (~> 3.0)
|
||||||
capybara (3.39.1)
|
capybara (3.39.2)
|
||||||
addressable
|
addressable
|
||||||
matrix
|
matrix
|
||||||
mini_mime (>= 0.1.3)
|
mini_mime (>= 0.1.3)
|
||||||
|
@ -174,7 +174,6 @@ GEM
|
||||||
chunky_png (1.4.0)
|
chunky_png (1.4.0)
|
||||||
climate_control (0.2.0)
|
climate_control (0.2.0)
|
||||||
cocoon (1.2.15)
|
cocoon (1.2.15)
|
||||||
coderay (1.1.3)
|
|
||||||
color_diff (0.1)
|
color_diff (0.1)
|
||||||
concurrent-ruby (1.2.2)
|
concurrent-ruby (1.2.2)
|
||||||
connection_pool (2.4.1)
|
connection_pool (2.4.1)
|
||||||
|
@ -229,7 +228,7 @@ GEM
|
||||||
erubi (1.12.0)
|
erubi (1.12.0)
|
||||||
et-orbi (1.2.7)
|
et-orbi (1.2.7)
|
||||||
tzinfo
|
tzinfo
|
||||||
excon (0.99.0)
|
excon (0.100.0)
|
||||||
fabrication (2.30.0)
|
fabrication (2.30.0)
|
||||||
faker (3.2.0)
|
faker (3.2.0)
|
||||||
i18n (>= 1.8.11, < 2)
|
i18n (>= 1.8.11, < 2)
|
||||||
|
@ -319,7 +318,7 @@ GEM
|
||||||
httplog (1.6.2)
|
httplog (1.6.2)
|
||||||
rack (>= 2.0)
|
rack (>= 2.0)
|
||||||
rainbow (>= 2.0.0)
|
rainbow (>= 2.0.0)
|
||||||
i18n (1.13.0)
|
i18n (1.14.1)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
i18n-tasks (1.0.12)
|
i18n-tasks (1.0.12)
|
||||||
activesupport (>= 4.0.2)
|
activesupport (>= 4.0.2)
|
||||||
|
@ -355,7 +354,7 @@ GEM
|
||||||
json-schema (4.0.0)
|
json-schema (4.0.0)
|
||||||
addressable (>= 2.8)
|
addressable (>= 2.8)
|
||||||
jsonapi-renderer (0.2.2)
|
jsonapi-renderer (0.2.2)
|
||||||
jwt (2.7.0)
|
jwt (2.7.1)
|
||||||
kaminari (1.2.2)
|
kaminari (1.2.2)
|
||||||
activesupport (>= 4.1.0)
|
activesupport (>= 4.1.0)
|
||||||
kaminari-actionview (= 1.2.2)
|
kaminari-actionview (= 1.2.2)
|
||||||
|
@ -414,12 +413,12 @@ GEM
|
||||||
mini_mime (1.1.2)
|
mini_mime (1.1.2)
|
||||||
mini_portile2 (2.8.2)
|
mini_portile2 (2.8.2)
|
||||||
minitest (5.18.0)
|
minitest (5.18.0)
|
||||||
msgpack (1.7.0)
|
msgpack (1.7.1)
|
||||||
multi_json (1.15.0)
|
multi_json (1.15.0)
|
||||||
multipart-post (2.3.0)
|
multipart-post (2.3.0)
|
||||||
net-http (0.3.2)
|
net-http (0.3.2)
|
||||||
uri
|
uri
|
||||||
net-imap (0.3.4)
|
net-imap (0.3.6)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-ldap (0.18.0)
|
net-ldap (0.18.0)
|
||||||
|
@ -436,7 +435,7 @@ GEM
|
||||||
nokogiri (1.15.2)
|
nokogiri (1.15.2)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
oj (3.14.3)
|
oj (3.15.0)
|
||||||
omniauth (1.9.2)
|
omniauth (1.9.2)
|
||||||
hashie (>= 3.4.6)
|
hashie (>= 3.4.6)
|
||||||
rack (>= 1.6.2, < 3)
|
rack (>= 1.6.2, < 3)
|
||||||
|
@ -470,8 +469,9 @@ GEM
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
ox (2.14.16)
|
ox (2.14.16)
|
||||||
parallel (1.23.0)
|
parallel (1.23.0)
|
||||||
parser (3.2.2.1)
|
parser (3.2.2.3)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
|
racc
|
||||||
parslet (2.0.0)
|
parslet (2.0.0)
|
||||||
pastel (0.8.0)
|
pastel (0.8.0)
|
||||||
tty-color (~> 0.5)
|
tty-color (~> 0.5)
|
||||||
|
@ -495,7 +495,7 @@ GEM
|
||||||
pundit (2.3.0)
|
pundit (2.3.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
raabro (1.4.0)
|
raabro (1.4.0)
|
||||||
racc (1.6.2)
|
racc (1.7.1)
|
||||||
rack (2.2.7)
|
rack (2.2.7)
|
||||||
rack-attack (6.6.1)
|
rack-attack (6.6.1)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
|
@ -547,17 +547,17 @@ GEM
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
rake (13.0.6)
|
rake (13.0.6)
|
||||||
rdf (3.2.10)
|
rdf (3.2.11)
|
||||||
link_header (~> 0.0, >= 0.0.8)
|
link_header (~> 0.0, >= 0.0.8)
|
||||||
rdf-normalize (0.5.1)
|
rdf-normalize (0.6.0)
|
||||||
rdf (~> 3.2)
|
rdf (~> 3.2)
|
||||||
redcarpet (3.6.0)
|
redcarpet (3.6.0)
|
||||||
redis (4.8.1)
|
redis (4.8.1)
|
||||||
redis-namespace (1.10.0)
|
redis-namespace (1.11.0)
|
||||||
redis (>= 4)
|
redis (>= 4)
|
||||||
redlock (1.3.2)
|
redlock (1.3.2)
|
||||||
redis (>= 3.0.0, < 6.0)
|
redis (>= 3.0.0, < 6.0)
|
||||||
regexp_parser (2.8.0)
|
regexp_parser (2.8.1)
|
||||||
request_store (1.5.1)
|
request_store (1.5.1)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
responders (3.1.0)
|
responders (3.1.0)
|
||||||
|
@ -565,6 +565,7 @@ GEM
|
||||||
railties (>= 5.2)
|
railties (>= 5.2)
|
||||||
rexml (3.2.5)
|
rexml (3.2.5)
|
||||||
rotp (6.2.2)
|
rotp (6.2.2)
|
||||||
|
rouge (4.1.2)
|
||||||
rpam2 (4.0.2)
|
rpam2 (4.0.2)
|
||||||
rqrcode (2.2.0)
|
rqrcode (2.2.0)
|
||||||
chunky_png (~> 1.0)
|
chunky_png (~> 1.0)
|
||||||
|
@ -591,20 +592,22 @@ GEM
|
||||||
sidekiq (>= 2.4.0)
|
sidekiq (>= 2.4.0)
|
||||||
rspec-support (3.12.0)
|
rspec-support (3.12.0)
|
||||||
rspec_chunked (0.6)
|
rspec_chunked (0.6)
|
||||||
rubocop (1.51.0)
|
rubocop (1.52.1)
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 3.2.0.0)
|
parser (>= 3.2.2.3)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
regexp_parser (>= 1.8, < 3.0)
|
regexp_parser (>= 1.8, < 3.0)
|
||||||
rexml (>= 3.2.5, < 4.0)
|
rexml (>= 3.2.5, < 4.0)
|
||||||
rubocop-ast (>= 1.28.0, < 2.0)
|
rubocop-ast (>= 1.28.0, < 2.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 2.4.0, < 3.0)
|
unicode-display_width (>= 2.4.0, < 3.0)
|
||||||
rubocop-ast (1.28.1)
|
rubocop-ast (1.29.0)
|
||||||
parser (>= 3.2.1.0)
|
parser (>= 3.2.1.0)
|
||||||
rubocop-capybara (2.18.0)
|
rubocop-capybara (2.18.0)
|
||||||
rubocop (~> 1.41)
|
rubocop (~> 1.41)
|
||||||
|
rubocop-factory_bot (2.23.1)
|
||||||
|
rubocop (~> 1.33)
|
||||||
rubocop-performance (1.18.0)
|
rubocop-performance (1.18.0)
|
||||||
rubocop (>= 1.7.0, < 2.0)
|
rubocop (>= 1.7.0, < 2.0)
|
||||||
rubocop-ast (>= 0.4.0)
|
rubocop-ast (>= 0.4.0)
|
||||||
|
@ -612,16 +615,17 @@ GEM
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.33.0, < 2.0)
|
rubocop (>= 1.33.0, < 2.0)
|
||||||
rubocop-rspec (2.19.0)
|
rubocop-rspec (2.22.0)
|
||||||
rubocop (~> 1.33)
|
rubocop (~> 1.33)
|
||||||
rubocop-capybara (~> 2.17)
|
rubocop-capybara (~> 2.17)
|
||||||
|
rubocop-factory_bot (~> 2.22)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
ruby-saml (1.13.0)
|
ruby-saml (1.15.0)
|
||||||
nokogiri (>= 1.10.5)
|
nokogiri (>= 1.13.10)
|
||||||
rexml
|
rexml
|
||||||
ruby2_keywords (0.0.5)
|
ruby2_keywords (0.0.5)
|
||||||
rubyzip (2.3.2)
|
rubyzip (2.3.2)
|
||||||
rufus-scheduler (3.8.2)
|
rufus-scheduler (3.9.1)
|
||||||
fugit (~> 1.1, >= 1.1.6)
|
fugit (~> 1.1, >= 1.1.6)
|
||||||
safety_net_attestation (0.4.0)
|
safety_net_attestation (0.4.0)
|
||||||
jwt (~> 2.0)
|
jwt (~> 2.0)
|
||||||
|
@ -680,13 +684,13 @@ GEM
|
||||||
attr_required (>= 0.0.5)
|
attr_required (>= 0.0.5)
|
||||||
httpclient (>= 2.4)
|
httpclient (>= 2.4)
|
||||||
sysexits (1.2.0)
|
sysexits (1.2.0)
|
||||||
temple (0.10.0)
|
temple (0.10.2)
|
||||||
terminal-table (3.0.2)
|
terminal-table (3.0.2)
|
||||||
unicode-display_width (>= 1.1.1, < 3)
|
unicode-display_width (>= 1.1.1, < 3)
|
||||||
terrapin (0.6.0)
|
terrapin (0.6.0)
|
||||||
climate_control (>= 0.0.3, < 1.0)
|
climate_control (>= 0.0.3, < 1.0)
|
||||||
thor (1.2.2)
|
thor (1.2.2)
|
||||||
tilt (2.1.0)
|
tilt (2.2.0)
|
||||||
timeout (0.3.2)
|
timeout (0.3.2)
|
||||||
tpm-key_attestation (0.12.0)
|
tpm-key_attestation (0.12.0)
|
||||||
bindata (~> 2.4)
|
bindata (~> 2.4)
|
||||||
|
|
|
@ -45,7 +45,7 @@ class Api::V1::ConversationsController < Api::BaseController
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
.to_a_paginated_by_id(limit_param(LIMIT), **params_slice(:max_id, :since_id, :min_id))
|
.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_pagination_headers
|
def insert_pagination_headers
|
||||||
|
|
|
@ -88,8 +88,10 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
|
||||||
def after_confirmation_path_for(_resource_name, user)
|
def after_confirmation_path_for(_resource_name, user)
|
||||||
if user.created_by_application && truthy_param?(:redirect_to_app)
|
if user.created_by_application && truthy_param?(:redirect_to_app)
|
||||||
user.created_by_application.confirmation_redirect_uri
|
user.created_by_application.confirmation_redirect_uri
|
||||||
|
elsif user_signed_in?
|
||||||
|
web_url('start')
|
||||||
else
|
else
|
||||||
super
|
new_user_session_path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
module CaptchaConcern
|
module CaptchaConcern
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
include Hcaptcha::Adapters::ViewMethods
|
include Hcaptcha::Adapters::ViewMethods
|
||||||
|
|
||||||
included do
|
included do
|
||||||
|
@ -35,18 +36,22 @@ module CaptchaConcern
|
||||||
flash.delete(:hcaptcha_error)
|
flash.delete(:hcaptcha_error)
|
||||||
yield message
|
yield message
|
||||||
end
|
end
|
||||||
|
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def extend_csp_for_captcha!
|
def extend_csp_for_captcha!
|
||||||
policy = request.content_security_policy
|
policy = request.content_security_policy
|
||||||
|
|
||||||
return unless captcha_required? && policy.present?
|
return unless captcha_required? && policy.present?
|
||||||
|
|
||||||
%w(script_src frame_src style_src connect_src).each do |directive|
|
%w(script_src frame_src style_src connect_src).each do |directive|
|
||||||
values = policy.send(directive)
|
values = policy.send(directive)
|
||||||
|
|
||||||
values << 'https://hcaptcha.com' unless values.include?('https://hcaptcha.com') || values.include?('https:')
|
values << 'https://hcaptcha.com' unless values.include?('https://hcaptcha.com') || values.include?('https:')
|
||||||
values << 'https://*.hcaptcha.com' unless values.include?('https://*.hcaptcha.com') || values.include?('https:')
|
values << 'https://*.hcaptcha.com' unless values.include?('https://*.hcaptcha.com') || values.include?('https:')
|
||||||
|
|
||||||
policy.send(directive, *values)
|
policy.send(directive, *values)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
41
app/controllers/mail_subscriptions_controller.rb
Normal file
41
app/controllers/mail_subscriptions_controller.rb
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class MailSubscriptionsController < ApplicationController
|
||||||
|
layout 'auth'
|
||||||
|
|
||||||
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
|
before_action :set_body_classes
|
||||||
|
before_action :set_user
|
||||||
|
before_action :set_type
|
||||||
|
|
||||||
|
def show; end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@user.settings[email_type_from_param] = false
|
||||||
|
@user.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_user
|
||||||
|
@user = GlobalID::Locator.locate_signed(params[:token], for: 'unsubscribe')
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_body_classes
|
||||||
|
@body_classes = 'lighter'
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_type
|
||||||
|
@type = email_type_from_param
|
||||||
|
end
|
||||||
|
|
||||||
|
def email_type_from_param
|
||||||
|
case params[:type]
|
||||||
|
when 'follow', 'reblog', 'favourite', 'mention', 'follow_request'
|
||||||
|
"notification_emails.#{params[:type]}"
|
||||||
|
else
|
||||||
|
raise ArgumentError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
15
app/controllers/settings/verifications_controller.rb
Normal file
15
app/controllers/settings/verifications_controller.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Settings::VerificationsController < Settings::BaseController
|
||||||
|
before_action :set_account
|
||||||
|
|
||||||
|
def show
|
||||||
|
@verified_links = @account.fields.select(&:verified?)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_account
|
||||||
|
@account = current_account
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,27 @@
|
||||||
|
interface Props {
|
||||||
|
size: number;
|
||||||
|
strokeWidth: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CircularProgress: React.FC<Props> = ({ size, strokeWidth }) => {
|
||||||
|
const viewBox = `0 0 ${size} ${size}`;
|
||||||
|
const radius = (size - strokeWidth) / 2;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
viewBox={viewBox}
|
||||||
|
className='circular-progress'
|
||||||
|
role='progressbar'
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
fill='none'
|
||||||
|
cx={size / 2}
|
||||||
|
cy={size / 2}
|
||||||
|
r={radius}
|
||||||
|
strokeWidth={`${strokeWidth}px`}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
|
@ -8,8 +8,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||||
import Overlay from 'react-overlays/Overlay';
|
import Overlay from 'react-overlays/Overlay';
|
||||||
|
|
||||||
import { CircularProgress } from 'flavours/glitch/components/loading_indicator';
|
import { CircularProgress } from "./circular_progress";
|
||||||
|
|
||||||
import { IconButton } from './icon_button';
|
import { IconButton } from './icon_button';
|
||||||
|
|
||||||
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
|
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { PureComponent } from 'react';
|
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
|
|
||||||
export default class LoadPending extends PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
onClick: PropTypes.func,
|
|
||||||
count: PropTypes.number,
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { count } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button className='load-more load-gap' onClick={this.props.onClick}>
|
|
||||||
<FormattedMessage id='load_pending' defaultMessage='{count, plural, one {# new item} other {# new items}}' values={{ count }} />
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
18
app/javascript/flavours/glitch/components/load_pending.tsx
Normal file
18
app/javascript/flavours/glitch/components/load_pending.tsx
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onClick: (event: React.MouseEvent) => void;
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LoadPending: React.FC<Props> = ({ onClick, count }) => {
|
||||||
|
return (
|
||||||
|
<button className='load-more load-gap' onClick={onClick}>
|
||||||
|
<FormattedMessage
|
||||||
|
id='load_pending'
|
||||||
|
defaultMessage='{count, plural, one {# new item} other {# new items}}'
|
||||||
|
values={{ count }}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,31 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
export const CircularProgress = ({ size, strokeWidth }) => {
|
|
||||||
const viewBox = `0 0 ${size} ${size}`;
|
|
||||||
const radius = (size - strokeWidth) / 2;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<svg width={size} heigh={size} viewBox={viewBox} className='circular-progress' role='progressbar'>
|
|
||||||
<circle
|
|
||||||
fill='none'
|
|
||||||
cx={size / 2}
|
|
||||||
cy={size / 2}
|
|
||||||
r={radius}
|
|
||||||
strokeWidth={`${strokeWidth}px`}
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CircularProgress.propTypes = {
|
|
||||||
size: PropTypes.number.isRequired,
|
|
||||||
strokeWidth: PropTypes.number.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
const LoadingIndicator = () => (
|
|
||||||
<div className='loading-indicator'>
|
|
||||||
<CircularProgress size={50} strokeWidth={6} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default LoadingIndicator;
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { CircularProgress } from './circular_progress';
|
||||||
|
|
||||||
|
export const LoadingIndicator: React.FC = () => (
|
||||||
|
<div className='loading-indicator'>
|
||||||
|
<CircularProgress size={50} strokeWidth={6} />
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -16,8 +16,8 @@ import IntersectionObserverWrapper from 'flavours/glitch/features/ui/util/inters
|
||||||
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../features/ui/util/fullscreen';
|
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../features/ui/util/fullscreen';
|
||||||
|
|
||||||
import { LoadMore } from './load_more';
|
import { LoadMore } from './load_more';
|
||||||
import LoadPending from './load_pending';
|
import { LoadPending } from './load_pending';
|
||||||
import LoadingIndicator from './loading_indicator';
|
import { LoadingIndicator } from './loading_indicator';
|
||||||
|
|
||||||
const MOUSE_IDLE_DELAY = 300;
|
const MOUSE_IDLE_DELAY = 300;
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,7 @@ class Header extends ImmutablePureComponent {
|
||||||
let badge;
|
let badge;
|
||||||
|
|
||||||
if (account.get('bot')) {
|
if (account.get('bot')) {
|
||||||
badge = (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Bot' /></div>);
|
badge = (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Automated' /></div>);
|
||||||
} else if (account.get('group')) {
|
} else if (account.get('group')) {
|
||||||
badge = (<div className='account-role group'><FormattedMessage id='account.badges.group' defaultMessage='Group' /></div>);
|
badge = (<div className='account-role group'><FormattedMessage id='account.badges.group' defaultMessage='Group' /></div>);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { lookupAccount, fetchAccount } from 'flavours/glitch/actions/accounts';
|
||||||
import { openModal } from 'flavours/glitch/actions/modal';
|
import { openModal } from 'flavours/glitch/actions/modal';
|
||||||
import { expandAccountMediaTimeline } from 'flavours/glitch/actions/timelines';
|
import { expandAccountMediaTimeline } from 'flavours/glitch/actions/timelines';
|
||||||
import { LoadMore } from 'flavours/glitch/components/load_more';
|
import { LoadMore } from 'flavours/glitch/components/load_more';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
|
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
|
||||||
import ProfileColumnHeader from 'flavours/glitch/features/account/components/profile_column_header';
|
import ProfileColumnHeader from 'flavours/glitch/features/account/components/profile_column_header';
|
||||||
import HeaderContainer from 'flavours/glitch/features/account_timeline/containers/header_container';
|
import HeaderContainer from 'flavours/glitch/features/account_timeline/containers/header_container';
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { getAccountHidden } from 'flavours/glitch/selectors';
|
||||||
|
|
||||||
import { fetchFeaturedTags } from '../../actions/featured_tags';
|
import { fetchFeaturedTags } from '../../actions/featured_tags';
|
||||||
import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines';
|
import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||||
import StatusList from '../../components/status_list';
|
import StatusList from '../../components/status_list';
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { debounce } from 'lodash';
|
||||||
|
|
||||||
import { fetchBlocks, expandBlocks } from 'flavours/glitch/actions/blocks';
|
import { fetchBlocks, expandBlocks } from 'flavours/glitch/actions/blocks';
|
||||||
import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim';
|
import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||||
import Column from 'flavours/glitch/features/ui/components/column';
|
import Column from 'flavours/glitch/features/ui/components/column';
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ export default class Upload extends ImmutablePureComponent {
|
||||||
const y = ((focusY / -2) + .5) * 100;
|
const y = ((focusY / -2) + .5) * 100;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='compose-form__upload' tabIndex={0} role='button'>
|
<div className='compose-form__upload'>
|
||||||
<Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>
|
<Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>
|
||||||
{({ scale }) => (
|
{({ scale }) => (
|
||||||
<div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
|
<div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { fetchDirectory, expandDirectory } from 'flavours/glitch/actions/directo
|
||||||
import Column from 'flavours/glitch/components/column';
|
import Column from 'flavours/glitch/components/column';
|
||||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||||
import { LoadMore } from 'flavours/glitch/components/load_more';
|
import { LoadMore } from 'flavours/glitch/components/load_more';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import { RadioButton } from 'flavours/glitch/components/radio_button';
|
import { RadioButton } from 'flavours/glitch/components/radio_button';
|
||||||
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
|
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
||||||
|
|
||||||
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
|
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
|
||||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||||
import DomainContainer from '../../containers/domain_container';
|
import DomainContainer from '../../containers/domain_container';
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
|
|
||||||
|
|
51
app/javascript/flavours/glitch/features/emoji/emoji_compressed.d.ts
vendored
Normal file
51
app/javascript/flavours/glitch/features/emoji/emoji_compressed.d.ts
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import type { BaseEmoji, EmojiData, NimbleEmojiIndex } from 'emoji-mart';
|
||||||
|
import type { Category, Data, Emoji } from 'emoji-mart/dist-es/utils/data';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The 'search' property, although not defined in the [`Emoji`]{@link node_modules/@types/emoji-mart/dist-es/utils/data.d.ts#Emoji} type,
|
||||||
|
* is used in the application.
|
||||||
|
* This could be due to an oversight by the library maintainer.
|
||||||
|
* The `search` property is defined and used [here]{@link node_modules/emoji-mart/dist/utils/data.js#uncompress}.
|
||||||
|
*/
|
||||||
|
export type Search = string;
|
||||||
|
/*
|
||||||
|
* The 'skins' property does not exist in the application data.
|
||||||
|
* This could be a potential area of refactoring or error handling.
|
||||||
|
* The non-existence of 'skins' property is evident at [this location]{@link app/javascript/flavours/glitch/features/emoji/emoji_compressed.js:121}.
|
||||||
|
*/
|
||||||
|
export type Skins = null;
|
||||||
|
|
||||||
|
export type FilenameData = string[] | string[][];
|
||||||
|
export type ShortCodesToEmojiDataKey =
|
||||||
|
| EmojiData['id']
|
||||||
|
| BaseEmoji['native']
|
||||||
|
| keyof NimbleEmojiIndex['emojis'];
|
||||||
|
|
||||||
|
export type SearchData = [
|
||||||
|
BaseEmoji['native'],
|
||||||
|
Emoji['short_names'],
|
||||||
|
Search,
|
||||||
|
Emoji['unified']
|
||||||
|
];
|
||||||
|
|
||||||
|
export interface ShortCodesToEmojiData {
|
||||||
|
[key: ShortCodesToEmojiDataKey]: [FilenameData, SearchData];
|
||||||
|
}
|
||||||
|
export type EmojisWithoutShortCodes = FilenameData[];
|
||||||
|
|
||||||
|
export type EmojiCompressed = [
|
||||||
|
ShortCodesToEmojiData,
|
||||||
|
Skins,
|
||||||
|
Category[],
|
||||||
|
Data['aliases'],
|
||||||
|
EmojisWithoutShortCodes
|
||||||
|
];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* `emoji_compressed.js` uses `babel-plugin-preval`, which makes it difficult to convert to TypeScript.
|
||||||
|
* As a temporary solution, we are allowing a default export here to apply the TypeScript type `EmojiCompressed` to the JS file export.
|
||||||
|
* - {@link app/javascript/flavours/glitch/features/emoji/emoji_compressed.js}
|
||||||
|
*/
|
||||||
|
declare const emojiCompressed: EmojiCompressed;
|
||||||
|
|
||||||
|
export default emojiCompressed; // eslint-disable-line import/no-default-export
|
|
@ -118,6 +118,16 @@ Object.keys(emojiIndex.emojis).forEach(key => {
|
||||||
// inconsistent behavior in dev mode
|
// inconsistent behavior in dev mode
|
||||||
module.exports = JSON.parse(JSON.stringify([
|
module.exports = JSON.parse(JSON.stringify([
|
||||||
shortCodesToEmojiData,
|
shortCodesToEmojiData,
|
||||||
|
/*
|
||||||
|
* The property `skins` is not found in the current context.
|
||||||
|
* This could potentially lead to issues when interacting with modules or data structures
|
||||||
|
* that expect the presence of `skins` property.
|
||||||
|
* Currently, no definitions or references to `skins` property can be found in:
|
||||||
|
* - {@link node_modules/emoji-mart/dist/utils/data.js}
|
||||||
|
* - {@link node_modules/emoji-mart/data/all.json}
|
||||||
|
* - {@link app/javascript/flavours/glitch/features/emoji/emoji_compressed.d.ts#Skins}
|
||||||
|
* Future refactorings or updates should consider adding definitions or handling for `skins` property.
|
||||||
|
*/
|
||||||
emojiMartData.skins,
|
emojiMartData.skins,
|
||||||
emojiMartData.categories,
|
emojiMartData.categories,
|
||||||
emojiMartData.aliases,
|
emojiMartData.aliases,
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
// The output of this module is designed to mimic emoji-mart's
|
|
||||||
// "data" object, such that we can use it for a light version of emoji-mart's
|
|
||||||
// emojiIndex.search functionality.
|
|
||||||
import emojiCompressed from './emoji_compressed';
|
|
||||||
import { unicodeToUnifiedName } from './unicode_to_unified_name';
|
|
||||||
|
|
||||||
const [ shortCodesToEmojiData, skins, categories, short_names ] = emojiCompressed;
|
|
||||||
|
|
||||||
const emojis = {};
|
|
||||||
|
|
||||||
// decompress
|
|
||||||
Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
|
|
||||||
let [
|
|
||||||
filenameData, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
||||||
searchData,
|
|
||||||
] = shortCodesToEmojiData[shortCode];
|
|
||||||
let [
|
|
||||||
native,
|
|
||||||
short_names,
|
|
||||||
search,
|
|
||||||
unified,
|
|
||||||
] = searchData;
|
|
||||||
|
|
||||||
if (!unified) {
|
|
||||||
// unified name can be derived from unicodeToUnifiedName
|
|
||||||
unified = unicodeToUnifiedName(native);
|
|
||||||
}
|
|
||||||
|
|
||||||
short_names = [shortCode].concat(short_names);
|
|
||||||
emojis[shortCode] = {
|
|
||||||
native,
|
|
||||||
search,
|
|
||||||
short_names,
|
|
||||||
unified,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export {
|
|
||||||
emojis,
|
|
||||||
skins,
|
|
||||||
categories,
|
|
||||||
short_names,
|
|
||||||
};
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
// The output of this module is designed to mimic emoji-mart's
|
||||||
|
// "data" object, such that we can use it for a light version of emoji-mart's
|
||||||
|
// emojiIndex.search functionality.
|
||||||
|
import type { BaseEmoji } from 'emoji-mart';
|
||||||
|
import type { Emoji } from 'emoji-mart/dist-es/utils/data';
|
||||||
|
|
||||||
|
import type { Search, ShortCodesToEmojiData } from './emoji_compressed';
|
||||||
|
import emojiCompressed from './emoji_compressed';
|
||||||
|
import { unicodeToUnifiedName } from './unicode_to_unified_name';
|
||||||
|
|
||||||
|
type Emojis = {
|
||||||
|
[key in keyof ShortCodesToEmojiData]: {
|
||||||
|
native: BaseEmoji['native'];
|
||||||
|
search: Search;
|
||||||
|
short_names: Emoji['short_names'];
|
||||||
|
unified: Emoji['unified'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const [
|
||||||
|
shortCodesToEmojiData,
|
||||||
|
skins,
|
||||||
|
categories,
|
||||||
|
short_names,
|
||||||
|
_emojisWithoutShortCodes,
|
||||||
|
] = emojiCompressed;
|
||||||
|
|
||||||
|
const emojis: Emojis = {};
|
||||||
|
|
||||||
|
// decompress
|
||||||
|
Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
|
||||||
|
const [_filenameData, searchData] = shortCodesToEmojiData[shortCode];
|
||||||
|
const native = searchData[0];
|
||||||
|
let short_names = searchData[1];
|
||||||
|
const search = searchData[2];
|
||||||
|
let unified = searchData[3];
|
||||||
|
|
||||||
|
if (!unified) {
|
||||||
|
// unified name can be derived from unicodeToUnifiedName
|
||||||
|
unified = unicodeToUnifiedName(native);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (short_names) short_names = [shortCode].concat(short_names);
|
||||||
|
emojis[shortCode] = {
|
||||||
|
native,
|
||||||
|
search,
|
||||||
|
short_names,
|
||||||
|
unified,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export { emojis, skins, categories, short_names };
|
|
@ -8,7 +8,7 @@ import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { fetchTrendingLinks } from 'flavours/glitch/actions/trends';
|
import { fetchTrendingLinks } from 'flavours/glitch/actions/trends';
|
||||||
import DismissableBanner from 'flavours/glitch/components/dismissable_banner';
|
import DismissableBanner from 'flavours/glitch/components/dismissable_banner';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
|
|
||||||
import Story from './components/story';
|
import Story from './components/story';
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { connect } from 'react-redux';
|
||||||
import { expandSearch } from 'flavours/glitch/actions/search';
|
import { expandSearch } from 'flavours/glitch/actions/search';
|
||||||
import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag';
|
import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag';
|
||||||
import { LoadMore } from 'flavours/glitch/components/load_more';
|
import { LoadMore } from 'flavours/glitch/components/load_more';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import Account from 'flavours/glitch/containers/account_container';
|
import Account from 'flavours/glitch/containers/account_container';
|
||||||
import Status from 'flavours/glitch/containers/status_container';
|
import Status from 'flavours/glitch/containers/status_container';
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { fetchSuggestions, dismissSuggestion } from 'flavours/glitch/actions/suggestions';
|
import { fetchSuggestions, dismissSuggestion } from 'flavours/glitch/actions/suggestions';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import AccountCard from 'flavours/glitch/features/directory/components/account_card';
|
import AccountCard from 'flavours/glitch/features/directory/components/account_card';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { connect } from 'react-redux';
|
||||||
import { fetchTrendingHashtags } from 'flavours/glitch/actions/trends';
|
import { fetchTrendingHashtags } from 'flavours/glitch/actions/trends';
|
||||||
import DismissableBanner from 'flavours/glitch/components/dismissable_banner';
|
import DismissableBanner from 'flavours/glitch/components/dismissable_banner';
|
||||||
import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag';
|
import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { connect } from 'react-redux';
|
||||||
import { fetchFavourites } from 'flavours/glitch/actions/interactions';
|
import { fetchFavourites } from 'flavours/glitch/actions/interactions';
|
||||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||||
import { Icon } from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
||||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||||
import Column from 'flavours/glitch/features/ui/components/column';
|
import Column from 'flavours/glitch/features/ui/components/column';
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
fetchFollowers,
|
fetchFollowers,
|
||||||
expandFollowers,
|
expandFollowers,
|
||||||
} from 'flavours/glitch/actions/accounts';
|
} from 'flavours/glitch/actions/accounts';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
||||||
import { TimelineHint } from 'flavours/glitch/components/timeline_hint';
|
import { TimelineHint } from 'flavours/glitch/components/timeline_hint';
|
||||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
fetchFollowing,
|
fetchFollowing,
|
||||||
expandFollowing,
|
expandFollowing,
|
||||||
} from 'flavours/glitch/actions/accounts';
|
} from 'flavours/glitch/actions/accounts';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
||||||
import { TimelineHint } from 'flavours/glitch/components/timeline_hint';
|
import { TimelineHint } from 'flavours/glitch/components/timeline_hint';
|
||||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { expandListTimeline } from 'flavours/glitch/actions/timelines';
|
||||||
import Column from 'flavours/glitch/components/column';
|
import Column from 'flavours/glitch/components/column';
|
||||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||||
import { Icon } from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import { RadioButton } from 'flavours/glitch/components/radio_button';
|
import { RadioButton } from 'flavours/glitch/components/radio_button';
|
||||||
import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error';
|
import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error';
|
||||||
import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
|
import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { createSelector } from 'reselect';
|
||||||
|
|
||||||
import { fetchLists } from 'flavours/glitch/actions/lists';
|
import { fetchLists } from 'flavours/glitch/actions/lists';
|
||||||
import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim';
|
import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
||||||
import Column from 'flavours/glitch/features/ui/components/column';
|
import Column from 'flavours/glitch/features/ui/components/column';
|
||||||
import ColumnLink from 'flavours/glitch/features/ui/components/column_link';
|
import ColumnLink from 'flavours/glitch/features/ui/components/column_link';
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { debounce } from 'lodash';
|
||||||
|
|
||||||
import { fetchMutes, expandMutes } from 'flavours/glitch/actions/mutes';
|
import { fetchMutes, expandMutes } from 'flavours/glitch/actions/mutes';
|
||||||
import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim';
|
import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
||||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||||
import Column from 'flavours/glitch/features/ui/components/column';
|
import Column from 'flavours/glitch/features/ui/components/column';
|
||||||
|
|
|
@ -8,10 +8,12 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import AvatarOverlay from 'flavours/glitch/components/avatar_overlay';
|
import AvatarOverlay from 'flavours/glitch/components/avatar_overlay';
|
||||||
import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp';
|
import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp';
|
||||||
|
|
||||||
|
// This needs to be kept in sync with app/models/report.rb
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
openReport: { id: 'report_notification.open', defaultMessage: 'Open report' },
|
openReport: { id: 'report_notification.open', defaultMessage: 'Open report' },
|
||||||
other: { id: 'report_notification.categories.other', defaultMessage: 'Other' },
|
other: { id: 'report_notification.categories.other', defaultMessage: 'Other' },
|
||||||
spam: { id: 'report_notification.categories.spam', defaultMessage: 'Spam' },
|
spam: { id: 'report_notification.categories.spam', defaultMessage: 'Spam' },
|
||||||
|
legal: { id: 'report_notification.categories.legal', defaultMessage: 'Legal' },
|
||||||
violation: { id: 'report_notification.categories.violation', defaultMessage: 'Rule violation' },
|
violation: { id: 'report_notification.categories.violation', defaultMessage: 'Rule violation' },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { connect } from 'react-redux';
|
||||||
import { fetchReblogs } from 'flavours/glitch/actions/interactions';
|
import { fetchReblogs } from 'flavours/glitch/actions/interactions';
|
||||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||||
import { Icon } from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
||||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||||
import Column from 'flavours/glitch/features/ui/components/column';
|
import Column from 'flavours/glitch/features/ui/components/column';
|
||||||
|
|
|
@ -8,7 +8,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import Button from 'flavours/glitch/components/button';
|
import Button from 'flavours/glitch/components/button';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import StatusCheckBox from 'flavours/glitch/features/report/containers/status_check_box_container';
|
import StatusCheckBox from 'flavours/glitch/features/report/containers/status_check_box_container';
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ import {
|
||||||
undoStatusTranslation,
|
undoStatusTranslation,
|
||||||
} from 'flavours/glitch/actions/statuses';
|
} from 'flavours/glitch/actions/statuses';
|
||||||
import { Icon } from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import { textForScreenReader, defaultMediaVisibility } from 'flavours/glitch/components/status';
|
import { textForScreenReader, defaultMediaVisibility } from 'flavours/glitch/components/status';
|
||||||
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
|
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
|
||||||
import StatusContainer from 'flavours/glitch/containers/status_container';
|
import StatusContainer from 'flavours/glitch/containers/status_container';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
|
|
||||||
// Keep the markup in sync with <BundleModalError />
|
// Keep the markup in sync with <BundleModalError />
|
||||||
// (make sure they have the same dimensions)
|
// (make sure they have the same dimensions)
|
||||||
|
|
|
@ -1050,7 +1050,9 @@ code {
|
||||||
}
|
}
|
||||||
|
|
||||||
.simple_form .h-captcha {
|
.simple_form .h-captcha {
|
||||||
text-align: center;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.permissions-list {
|
.permissions-list {
|
||||||
|
|
27
app/javascript/mastodon/components/circular_progress.tsx
Normal file
27
app/javascript/mastodon/components/circular_progress.tsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
interface Props {
|
||||||
|
size: number;
|
||||||
|
strokeWidth: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CircularProgress: React.FC<Props> = ({ size, strokeWidth }) => {
|
||||||
|
const viewBox = `0 0 ${size} ${size}`;
|
||||||
|
const radius = (size - strokeWidth) / 2;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
viewBox={viewBox}
|
||||||
|
className='circular-progress'
|
||||||
|
role='progressbar'
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
fill='none'
|
||||||
|
cx={size / 2}
|
||||||
|
cy={size / 2}
|
||||||
|
r={radius}
|
||||||
|
strokeWidth={`${strokeWidth}px`}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
|
@ -8,8 +8,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||||
import Overlay from 'react-overlays/Overlay';
|
import Overlay from 'react-overlays/Overlay';
|
||||||
|
|
||||||
import { CircularProgress } from 'mastodon/components/loading_indicator';
|
import { CircularProgress } from "./circular_progress";
|
||||||
|
|
||||||
import { IconButton } from './icon_button';
|
import { IconButton } from './icon_button';
|
||||||
|
|
||||||
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
|
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { PureComponent } from 'react';
|
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
|
|
||||||
export default class LoadPending extends PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
onClick: PropTypes.func,
|
|
||||||
count: PropTypes.number,
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { count } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button className='load-more load-gap' onClick={this.props.onClick}>
|
|
||||||
<FormattedMessage id='load_pending' defaultMessage='{count, plural, one {# new item} other {# new items}}' values={{ count }} />
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
18
app/javascript/mastodon/components/load_pending.tsx
Normal file
18
app/javascript/mastodon/components/load_pending.tsx
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onClick: (event: React.MouseEvent) => void;
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LoadPending: React.FC<Props> = ({ onClick, count }) => {
|
||||||
|
return (
|
||||||
|
<button className='load-more load-gap' onClick={onClick}>
|
||||||
|
<FormattedMessage
|
||||||
|
id='load_pending'
|
||||||
|
defaultMessage='{count, plural, one {# new item} other {# new items}}'
|
||||||
|
values={{ count }}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,31 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
export const CircularProgress = ({ size, strokeWidth }) => {
|
|
||||||
const viewBox = `0 0 ${size} ${size}`;
|
|
||||||
const radius = (size - strokeWidth) / 2;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<svg width={size} height={size} viewBox={viewBox} className='circular-progress' role='progressbar'>
|
|
||||||
<circle
|
|
||||||
fill='none'
|
|
||||||
cx={size / 2}
|
|
||||||
cy={size / 2}
|
|
||||||
r={radius}
|
|
||||||
strokeWidth={`${strokeWidth}px`}
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CircularProgress.propTypes = {
|
|
||||||
size: PropTypes.number.isRequired,
|
|
||||||
strokeWidth: PropTypes.number.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
const LoadingIndicator = () => (
|
|
||||||
<div className='loading-indicator'>
|
|
||||||
<CircularProgress size={50} strokeWidth={6} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default LoadingIndicator;
|
|
7
app/javascript/mastodon/components/loading_indicator.tsx
Normal file
7
app/javascript/mastodon/components/loading_indicator.tsx
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { CircularProgress } from './circular_progress';
|
||||||
|
|
||||||
|
export const LoadingIndicator: React.FC = () => (
|
||||||
|
<div className='loading-indicator'>
|
||||||
|
<CircularProgress size={50} strokeWidth={6} />
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -16,8 +16,8 @@ import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from
|
||||||
import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper';
|
import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper';
|
||||||
|
|
||||||
import { LoadMore } from './load_more';
|
import { LoadMore } from './load_more';
|
||||||
import LoadPending from './load_pending';
|
import { LoadPending } from './load_pending';
|
||||||
import LoadingIndicator from './loading_indicator';
|
import { LoadingIndicator } from './loading_indicator';
|
||||||
|
|
||||||
const MOUSE_IDLE_DELAY = 300;
|
const MOUSE_IDLE_DELAY = 300;
|
||||||
|
|
||||||
|
|
|
@ -374,7 +374,7 @@ class Header extends ImmutablePureComponent {
|
||||||
let badge;
|
let badge;
|
||||||
|
|
||||||
if (account.get('bot')) {
|
if (account.get('bot')) {
|
||||||
badge = (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Bot' /></div>);
|
badge = (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Automated' /></div>);
|
||||||
} else if (account.get('group')) {
|
} else if (account.get('group')) {
|
||||||
badge = (<div className='account-role group'><FormattedMessage id='account.badges.group' defaultMessage='Group' /></div>);
|
badge = (<div className='account-role group'><FormattedMessage id='account.badges.group' defaultMessage='Group' /></div>);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { lookupAccount, fetchAccount } from 'mastodon/actions/accounts';
|
||||||
import { openModal } from 'mastodon/actions/modal';
|
import { openModal } from 'mastodon/actions/modal';
|
||||||
import ColumnBackButton from 'mastodon/components/column_back_button';
|
import ColumnBackButton from 'mastodon/components/column_back_button';
|
||||||
import { LoadMore } from 'mastodon/components/load_more';
|
import { LoadMore } from 'mastodon/components/load_more';
|
||||||
import LoadingIndicator from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import ScrollContainer from 'mastodon/containers/scroll_container';
|
import ScrollContainer from 'mastodon/containers/scroll_container';
|
||||||
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
||||||
import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
|
import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { lookupAccount, fetchAccount } from '../../actions/accounts';
|
||||||
import { fetchFeaturedTags } from '../../actions/featured_tags';
|
import { fetchFeaturedTags } from '../../actions/featured_tags';
|
||||||
import { expandAccountFeaturedTimeline, expandAccountTimeline, connectTimeline, disconnectTimeline } from '../../actions/timelines';
|
import { expandAccountFeaturedTimeline, expandAccountTimeline, connectTimeline, disconnectTimeline } from '../../actions/timelines';
|
||||||
import ColumnBackButton from '../../components/column_back_button';
|
import ColumnBackButton from '../../components/column_back_button';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||||
import StatusList from '../../components/status_list';
|
import StatusList from '../../components/status_list';
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { debounce } from 'lodash';
|
||||||
|
|
||||||
import { fetchBlocks, expandBlocks } from '../../actions/blocks';
|
import { fetchBlocks, expandBlocks } from '../../actions/blocks';
|
||||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||||
import ScrollableList from '../../components/scrollable_list';
|
import ScrollableList from '../../components/scrollable_list';
|
||||||
import AccountContainer from '../../containers/account_container';
|
import AccountContainer from '../../containers/account_container';
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
|
|
|
@ -46,7 +46,7 @@ export default class Upload extends ImmutablePureComponent {
|
||||||
const y = ((focusY / -2) + .5) * 100;
|
const y = ((focusY / -2) + .5) * 100;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='compose-form__upload' tabIndex={0} role='button'>
|
<div className='compose-form__upload'>
|
||||||
<Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>
|
<Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>
|
||||||
{({ scale }) => (
|
{({ scale }) => (
|
||||||
<div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
|
<div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { fetchDirectory, expandDirectory } from 'mastodon/actions/directory';
|
||||||
import Column from 'mastodon/components/column';
|
import Column from 'mastodon/components/column';
|
||||||
import ColumnHeader from 'mastodon/components/column_header';
|
import ColumnHeader from 'mastodon/components/column_header';
|
||||||
import { LoadMore } from 'mastodon/components/load_more';
|
import { LoadMore } from 'mastodon/components/load_more';
|
||||||
import LoadingIndicator from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import { RadioButton } from 'mastodon/components/radio_button';
|
import { RadioButton } from 'mastodon/components/radio_button';
|
||||||
import ScrollContainer from 'mastodon/containers/scroll_container';
|
import ScrollContainer from 'mastodon/containers/scroll_container';
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { debounce } from 'lodash';
|
||||||
|
|
||||||
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
|
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
|
||||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||||
import ScrollableList from '../../components/scrollable_list';
|
import ScrollableList from '../../components/scrollable_list';
|
||||||
import DomainContainer from '../../containers/domain_container';
|
import DomainContainer from '../../containers/domain_container';
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
|
|
51
app/javascript/mastodon/features/emoji/emoji_compressed.d.ts
vendored
Normal file
51
app/javascript/mastodon/features/emoji/emoji_compressed.d.ts
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import type { BaseEmoji, EmojiData, NimbleEmojiIndex } from 'emoji-mart';
|
||||||
|
import type { Category, Data, Emoji } from 'emoji-mart/dist-es/utils/data';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The 'search' property, although not defined in the [`Emoji`]{@link node_modules/@types/emoji-mart/dist-es/utils/data.d.ts#Emoji} type,
|
||||||
|
* is used in the application.
|
||||||
|
* This could be due to an oversight by the library maintainer.
|
||||||
|
* The `search` property is defined and used [here]{@link node_modules/emoji-mart/dist/utils/data.js#uncompress}.
|
||||||
|
*/
|
||||||
|
export type Search = string;
|
||||||
|
/*
|
||||||
|
* The 'skins' property does not exist in the application data.
|
||||||
|
* This could be a potential area of refactoring or error handling.
|
||||||
|
* The non-existence of 'skins' property is evident at [this location]{@link app/javascript/mastodon/features/emoji/emoji_compressed.js:121}.
|
||||||
|
*/
|
||||||
|
export type Skins = null;
|
||||||
|
|
||||||
|
export type FilenameData = string[] | string[][];
|
||||||
|
export type ShortCodesToEmojiDataKey =
|
||||||
|
| EmojiData['id']
|
||||||
|
| BaseEmoji['native']
|
||||||
|
| keyof NimbleEmojiIndex['emojis'];
|
||||||
|
|
||||||
|
export type SearchData = [
|
||||||
|
BaseEmoji['native'],
|
||||||
|
Emoji['short_names'],
|
||||||
|
Search,
|
||||||
|
Emoji['unified']
|
||||||
|
];
|
||||||
|
|
||||||
|
export interface ShortCodesToEmojiData {
|
||||||
|
[key: ShortCodesToEmojiDataKey]: [FilenameData, SearchData];
|
||||||
|
}
|
||||||
|
export type EmojisWithoutShortCodes = FilenameData[];
|
||||||
|
|
||||||
|
export type EmojiCompressed = [
|
||||||
|
ShortCodesToEmojiData,
|
||||||
|
Skins,
|
||||||
|
Category[],
|
||||||
|
Data['aliases'],
|
||||||
|
EmojisWithoutShortCodes
|
||||||
|
];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* `emoji_compressed.js` uses `babel-plugin-preval`, which makes it difficult to convert to TypeScript.
|
||||||
|
* As a temporary solution, we are allowing a default export here to apply the TypeScript type `EmojiCompressed` to the JS file export.
|
||||||
|
* - {@link app/javascript/mastodon/features/emoji/emoji_compressed.js}
|
||||||
|
*/
|
||||||
|
declare const emojiCompressed: EmojiCompressed;
|
||||||
|
|
||||||
|
export default emojiCompressed; // eslint-disable-line import/no-default-export
|
|
@ -118,6 +118,16 @@ Object.keys(emojiIndex.emojis).forEach(key => {
|
||||||
// inconsistent behavior in dev mode
|
// inconsistent behavior in dev mode
|
||||||
module.exports = JSON.parse(JSON.stringify([
|
module.exports = JSON.parse(JSON.stringify([
|
||||||
shortCodesToEmojiData,
|
shortCodesToEmojiData,
|
||||||
|
/*
|
||||||
|
* The property `skins` is not found in the current context.
|
||||||
|
* This could potentially lead to issues when interacting with modules or data structures
|
||||||
|
* that expect the presence of `skins` property.
|
||||||
|
* Currently, no definitions or references to `skins` property can be found in:
|
||||||
|
* - {@link node_modules/emoji-mart/dist/utils/data.js}
|
||||||
|
* - {@link node_modules/emoji-mart/data/all.json}
|
||||||
|
* - {@link app/javascript/mastodon/features/emoji/emoji_compressed.d.ts#Skins}
|
||||||
|
* Future refactorings or updates should consider adding definitions or handling for `skins` property.
|
||||||
|
*/
|
||||||
emojiMartData.skins,
|
emojiMartData.skins,
|
||||||
emojiMartData.categories,
|
emojiMartData.categories,
|
||||||
emojiMartData.aliases,
|
emojiMartData.aliases,
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
// The output of this module is designed to mimic emoji-mart's
|
|
||||||
// "data" object, such that we can use it for a light version of emoji-mart's
|
|
||||||
// emojiIndex.search functionality.
|
|
||||||
import emojiCompressed from './emoji_compressed';
|
|
||||||
import { unicodeToUnifiedName } from './unicode_to_unified_name';
|
|
||||||
|
|
||||||
const [ shortCodesToEmojiData, skins, categories, short_names ] = emojiCompressed;
|
|
||||||
|
|
||||||
const emojis = {};
|
|
||||||
|
|
||||||
// decompress
|
|
||||||
Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
|
|
||||||
let [
|
|
||||||
filenameData, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
||||||
searchData,
|
|
||||||
] = shortCodesToEmojiData[shortCode];
|
|
||||||
let [
|
|
||||||
native,
|
|
||||||
short_names,
|
|
||||||
search,
|
|
||||||
unified,
|
|
||||||
] = searchData;
|
|
||||||
|
|
||||||
if (!unified) {
|
|
||||||
// unified name can be derived from unicodeToUnifiedName
|
|
||||||
unified = unicodeToUnifiedName(native);
|
|
||||||
}
|
|
||||||
|
|
||||||
short_names = [shortCode].concat(short_names);
|
|
||||||
emojis[shortCode] = {
|
|
||||||
native,
|
|
||||||
search,
|
|
||||||
short_names,
|
|
||||||
unified,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export {
|
|
||||||
emojis,
|
|
||||||
skins,
|
|
||||||
categories,
|
|
||||||
short_names,
|
|
||||||
};
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
// The output of this module is designed to mimic emoji-mart's
|
||||||
|
// "data" object, such that we can use it for a light version of emoji-mart's
|
||||||
|
// emojiIndex.search functionality.
|
||||||
|
import type { BaseEmoji } from 'emoji-mart';
|
||||||
|
import type { Emoji } from 'emoji-mart/dist-es/utils/data';
|
||||||
|
|
||||||
|
import type { Search, ShortCodesToEmojiData } from './emoji_compressed';
|
||||||
|
import emojiCompressed from './emoji_compressed';
|
||||||
|
import { unicodeToUnifiedName } from './unicode_to_unified_name';
|
||||||
|
|
||||||
|
type Emojis = {
|
||||||
|
[key in keyof ShortCodesToEmojiData]: {
|
||||||
|
native: BaseEmoji['native'];
|
||||||
|
search: Search;
|
||||||
|
short_names: Emoji['short_names'];
|
||||||
|
unified: Emoji['unified'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const [
|
||||||
|
shortCodesToEmojiData,
|
||||||
|
skins,
|
||||||
|
categories,
|
||||||
|
short_names,
|
||||||
|
_emojisWithoutShortCodes,
|
||||||
|
] = emojiCompressed;
|
||||||
|
|
||||||
|
const emojis: Emojis = {};
|
||||||
|
|
||||||
|
// decompress
|
||||||
|
Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
|
||||||
|
const [_filenameData, searchData] = shortCodesToEmojiData[shortCode];
|
||||||
|
const native = searchData[0];
|
||||||
|
let short_names = searchData[1];
|
||||||
|
const search = searchData[2];
|
||||||
|
let unified = searchData[3];
|
||||||
|
|
||||||
|
if (!unified) {
|
||||||
|
// unified name can be derived from unicodeToUnifiedName
|
||||||
|
unified = unicodeToUnifiedName(native);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (short_names) short_names = [shortCode].concat(short_names);
|
||||||
|
emojis[shortCode] = {
|
||||||
|
native,
|
||||||
|
search,
|
||||||
|
short_names,
|
||||||
|
unified,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export { emojis, skins, categories, short_names };
|
|
@ -8,7 +8,7 @@ import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { fetchTrendingLinks } from 'mastodon/actions/trends';
|
import { fetchTrendingLinks } from 'mastodon/actions/trends';
|
||||||
import DismissableBanner from 'mastodon/components/dismissable_banner';
|
import DismissableBanner from 'mastodon/components/dismissable_banner';
|
||||||
import LoadingIndicator from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
|
|
||||||
import Story from './components/story';
|
import Story from './components/story';
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { connect } from 'react-redux';
|
||||||
import { expandSearch } from 'mastodon/actions/search';
|
import { expandSearch } from 'mastodon/actions/search';
|
||||||
import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag';
|
import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag';
|
||||||
import { LoadMore } from 'mastodon/components/load_more';
|
import { LoadMore } from 'mastodon/components/load_more';
|
||||||
import LoadingIndicator from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import Account from 'mastodon/containers/account_container';
|
import Account from 'mastodon/containers/account_container';
|
||||||
import Status from 'mastodon/containers/status_container';
|
import Status from 'mastodon/containers/status_container';
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { fetchSuggestions } from 'mastodon/actions/suggestions';
|
import { fetchSuggestions } from 'mastodon/actions/suggestions';
|
||||||
import LoadingIndicator from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import AccountCard from 'mastodon/features/directory/components/account_card';
|
import AccountCard from 'mastodon/features/directory/components/account_card';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { connect } from 'react-redux';
|
||||||
import { fetchTrendingHashtags } from 'mastodon/actions/trends';
|
import { fetchTrendingHashtags } from 'mastodon/actions/trends';
|
||||||
import DismissableBanner from 'mastodon/components/dismissable_banner';
|
import DismissableBanner from 'mastodon/components/dismissable_banner';
|
||||||
import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag';
|
import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag';
|
||||||
import LoadingIndicator from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
hashtags: state.getIn(['trends', 'tags', 'items']),
|
hashtags: state.getIn(['trends', 'tags', 'items']),
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { connect } from 'react-redux';
|
||||||
import { fetchFavourites } from 'mastodon/actions/interactions';
|
import { fetchFavourites } from 'mastodon/actions/interactions';
|
||||||
import ColumnHeader from 'mastodon/components/column_header';
|
import ColumnHeader from 'mastodon/components/column_header';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import LoadingIndicator from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||||
import AccountContainer from 'mastodon/containers/account_container';
|
import AccountContainer from 'mastodon/containers/account_container';
|
||||||
import Column from 'mastodon/features/ui/components/column';
|
import Column from 'mastodon/features/ui/components/column';
|
||||||
|
|
|
@ -20,7 +20,7 @@ import {
|
||||||
expandFollowers,
|
expandFollowers,
|
||||||
} from '../../actions/accounts';
|
} from '../../actions/accounts';
|
||||||
import ColumnBackButton from '../../components/column_back_button';
|
import ColumnBackButton from '../../components/column_back_button';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||||
import ScrollableList from '../../components/scrollable_list';
|
import ScrollableList from '../../components/scrollable_list';
|
||||||
import AccountContainer from '../../containers/account_container';
|
import AccountContainer from '../../containers/account_container';
|
||||||
import LimitedAccountHint from '../account_timeline/components/limited_account_hint';
|
import LimitedAccountHint from '../account_timeline/components/limited_account_hint';
|
||||||
|
|
|
@ -20,7 +20,7 @@ import {
|
||||||
expandFollowing,
|
expandFollowing,
|
||||||
} from '../../actions/accounts';
|
} from '../../actions/accounts';
|
||||||
import ColumnBackButton from '../../components/column_back_button';
|
import ColumnBackButton from '../../components/column_back_button';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||||
import ScrollableList from '../../components/scrollable_list';
|
import ScrollableList from '../../components/scrollable_list';
|
||||||
import AccountContainer from '../../containers/account_container';
|
import AccountContainer from '../../containers/account_container';
|
||||||
import LimitedAccountHint from '../account_timeline/components/limited_account_hint';
|
import LimitedAccountHint from '../account_timeline/components/limited_account_hint';
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { expandListTimeline } from 'mastodon/actions/timelines';
|
||||||
import Column from 'mastodon/components/column';
|
import Column from 'mastodon/components/column';
|
||||||
import ColumnHeader from 'mastodon/components/column_header';
|
import ColumnHeader from 'mastodon/components/column_header';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import LoadingIndicator from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import { RadioButton } from 'mastodon/components/radio_button';
|
import { RadioButton } from 'mastodon/components/radio_button';
|
||||||
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
||||||
import StatusListContainer from 'mastodon/features/ui/containers/status_list_container';
|
import StatusListContainer from 'mastodon/features/ui/containers/status_list_container';
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { createSelector } from 'reselect';
|
||||||
import { fetchLists } from 'mastodon/actions/lists';
|
import { fetchLists } from 'mastodon/actions/lists';
|
||||||
import Column from 'mastodon/components/column';
|
import Column from 'mastodon/components/column';
|
||||||
import ColumnHeader from 'mastodon/components/column_header';
|
import ColumnHeader from 'mastodon/components/column_header';
|
||||||
import LoadingIndicator from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||||
import ColumnLink from 'mastodon/features/ui/components/column_link';
|
import ColumnLink from 'mastodon/features/ui/components/column_link';
|
||||||
import ColumnSubheading from 'mastodon/features/ui/components/column_subheading';
|
import ColumnSubheading from 'mastodon/features/ui/components/column_subheading';
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { debounce } from 'lodash';
|
||||||
|
|
||||||
import { fetchMutes, expandMutes } from '../../actions/mutes';
|
import { fetchMutes, expandMutes } from '../../actions/mutes';
|
||||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||||
import ScrollableList from '../../components/scrollable_list';
|
import ScrollableList from '../../components/scrollable_list';
|
||||||
import AccountContainer from '../../containers/account_container';
|
import AccountContainer from '../../containers/account_container';
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
|
|
|
@ -8,10 +8,12 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { AvatarOverlay } from 'mastodon/components/avatar_overlay';
|
import { AvatarOverlay } from 'mastodon/components/avatar_overlay';
|
||||||
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
||||||
|
|
||||||
|
// This needs to be kept in sync with app/models/report.rb
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
openReport: { id: 'report_notification.open', defaultMessage: 'Open report' },
|
openReport: { id: 'report_notification.open', defaultMessage: 'Open report' },
|
||||||
other: { id: 'report_notification.categories.other', defaultMessage: 'Other' },
|
other: { id: 'report_notification.categories.other', defaultMessage: 'Other' },
|
||||||
spam: { id: 'report_notification.categories.spam', defaultMessage: 'Spam' },
|
spam: { id: 'report_notification.categories.spam', defaultMessage: 'Spam' },
|
||||||
|
legal: { id: 'report_notification.categories.legal', defaultMessage: 'Legal' },
|
||||||
violation: { id: 'report_notification.categories.violation', defaultMessage: 'Rule violation' },
|
violation: { id: 'report_notification.categories.violation', defaultMessage: 'Rule violation' },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { Icon } from 'mastodon/components/icon';
|
||||||
|
|
||||||
import { fetchReblogs } from '../../actions/interactions';
|
import { fetchReblogs } from '../../actions/interactions';
|
||||||
import ColumnHeader from '../../components/column_header';
|
import ColumnHeader from '../../components/column_header';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||||
import ScrollableList from '../../components/scrollable_list';
|
import ScrollableList from '../../components/scrollable_list';
|
||||||
import AccountContainer from '../../containers/account_container';
|
import AccountContainer from '../../containers/account_container';
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
|
|
|
@ -8,7 +8,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import Button from 'mastodon/components/button';
|
import Button from 'mastodon/components/button';
|
||||||
import LoadingIndicator from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import StatusCheckBox from 'mastodon/features/report/containers/status_check_box_container';
|
import StatusCheckBox from 'mastodon/features/report/containers/status_check_box_container';
|
||||||
|
|
||||||
const mapStateToProps = (state, { accountId }) => ({
|
const mapStateToProps = (state, { accountId }) => ({
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { createSelector } from 'reselect';
|
||||||
import { HotKeys } from 'react-hotkeys';
|
import { HotKeys } from 'react-hotkeys';
|
||||||
|
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import LoadingIndicator from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import ScrollContainer from 'mastodon/containers/scroll_container';
|
import ScrollContainer from 'mastodon/containers/scroll_container';
|
||||||
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import LoadingIndicator from '../../../components/loading_indicator';
|
import { LoadingIndicator } from '../../../components/loading_indicator';
|
||||||
|
|
||||||
// Keep the markup in sync with <BundleModalError />
|
// Keep the markup in sync with <BundleModalError />
|
||||||
// (make sure they have the same dimensions)
|
// (make sure they have the same dimensions)
|
||||||
|
|
|
@ -393,11 +393,6 @@ class UI extends PureComponent {
|
||||||
navigator.serviceWorker.addEventListener('message', this.handleServiceWorkerPostMessage);
|
navigator.serviceWorker.addEventListener('message', this.handleServiceWorkerPostMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// On first launch, redirect to the follow recommendations page
|
|
||||||
if (signedIn && this.props.firstLaunch) {
|
|
||||||
this.context.router.history.replace('/start');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signedIn) {
|
if (signedIn) {
|
||||||
this.props.dispatch(fetchMarkers());
|
this.props.dispatch(fetchMarkers());
|
||||||
this.props.dispatch(expandHomeTimeline());
|
this.props.dispatch(expandHomeTimeline());
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"about.rules": "Server rules",
|
"about.rules": "Server rules",
|
||||||
"account.account_note_header": "Note",
|
"account.account_note_header": "Note",
|
||||||
"account.add_or_remove_from_list": "Add or Remove from lists",
|
"account.add_or_remove_from_list": "Add or Remove from lists",
|
||||||
"account.badges.bot": "Bot",
|
"account.badges.bot": "Automated",
|
||||||
"account.badges.group": "Group",
|
"account.badges.group": "Group",
|
||||||
"account.block": "Block @{name}",
|
"account.block": "Block @{name}",
|
||||||
"account.block_domain": "Block domain {domain}",
|
"account.block_domain": "Block domain {domain}",
|
||||||
|
@ -553,6 +553,7 @@
|
||||||
"report.unfollow": "Unfollow @{name}",
|
"report.unfollow": "Unfollow @{name}",
|
||||||
"report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.",
|
"report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.",
|
||||||
"report_notification.attached_statuses": "{count, plural, one {{count} post} other {{count} posts}} attached",
|
"report_notification.attached_statuses": "{count, plural, one {{count} post} other {{count} posts}} attached",
|
||||||
|
"report_notification.categories.legal": "Legal",
|
||||||
"report_notification.categories.other": "Other",
|
"report_notification.categories.other": "Other",
|
||||||
"report_notification.categories.spam": "Spam",
|
"report_notification.categories.spam": "Spam",
|
||||||
"report_notification.categories.violation": "Rule violation",
|
"report_notification.categories.violation": "Rule violation",
|
||||||
|
|
|
@ -1048,7 +1048,9 @@ code {
|
||||||
}
|
}
|
||||||
|
|
||||||
.simple_form .h-captcha {
|
.simple_form .h-captcha {
|
||||||
text-align: center;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.permissions-list {
|
.permissions-list {
|
||||||
|
|
|
@ -8,61 +8,71 @@ class NotificationMailer < ApplicationMailer
|
||||||
|
|
||||||
def mention(recipient, notification)
|
def mention(recipient, notification)
|
||||||
@me = recipient
|
@me = recipient
|
||||||
|
@user = recipient.user
|
||||||
|
@type = 'mention'
|
||||||
@status = notification.target_status
|
@status = notification.target_status
|
||||||
|
|
||||||
return unless @me.user.functional? && @status.present?
|
return unless @user.functional? && @status.present?
|
||||||
|
|
||||||
locale_for_account(@me) do
|
locale_for_account(@me) do
|
||||||
thread_by_conversation(@status.conversation)
|
thread_by_conversation(@status.conversation)
|
||||||
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct)
|
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def follow(recipient, notification)
|
def follow(recipient, notification)
|
||||||
@me = recipient
|
@me = recipient
|
||||||
|
@user = recipient.user
|
||||||
|
@type = 'follow'
|
||||||
@account = notification.from_account
|
@account = notification.from_account
|
||||||
|
|
||||||
return unless @me.user.functional?
|
return unless @user.functional?
|
||||||
|
|
||||||
locale_for_account(@me) do
|
locale_for_account(@me) do
|
||||||
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.follow.subject', name: @account.acct)
|
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.follow.subject', name: @account.acct)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def favourite(recipient, notification)
|
def favourite(recipient, notification)
|
||||||
@me = recipient
|
@me = recipient
|
||||||
|
@user = recipient.user
|
||||||
|
@type = 'favourite'
|
||||||
@account = notification.from_account
|
@account = notification.from_account
|
||||||
@status = notification.target_status
|
@status = notification.target_status
|
||||||
|
|
||||||
return unless @me.user.functional? && @status.present?
|
return unless @user.functional? && @status.present?
|
||||||
|
|
||||||
locale_for_account(@me) do
|
locale_for_account(@me) do
|
||||||
thread_by_conversation(@status.conversation)
|
thread_by_conversation(@status.conversation)
|
||||||
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct)
|
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def reblog(recipient, notification)
|
def reblog(recipient, notification)
|
||||||
@me = recipient
|
@me = recipient
|
||||||
|
@user = recipient.user
|
||||||
|
@type = 'reblog'
|
||||||
@account = notification.from_account
|
@account = notification.from_account
|
||||||
@status = notification.target_status
|
@status = notification.target_status
|
||||||
|
|
||||||
return unless @me.user.functional? && @status.present?
|
return unless @user.functional? && @status.present?
|
||||||
|
|
||||||
locale_for_account(@me) do
|
locale_for_account(@me) do
|
||||||
thread_by_conversation(@status.conversation)
|
thread_by_conversation(@status.conversation)
|
||||||
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct)
|
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def follow_request(recipient, notification)
|
def follow_request(recipient, notification)
|
||||||
@me = recipient
|
@me = recipient
|
||||||
|
@user = recipient.user
|
||||||
|
@type = 'follow_request'
|
||||||
@account = notification.from_account
|
@account = notification.from_account
|
||||||
|
|
||||||
return unless @me.user.functional?
|
return unless @user.functional?
|
||||||
|
|
||||||
locale_for_account(@me) do
|
locale_for_account(@me) do
|
||||||
mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct)
|
mail to: email_address_with_name(@user.email, @me.username), subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -43,22 +43,21 @@ class AccountConversation < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def to_a_paginated_by_id(limit, min_id: nil, max_id: nil, since_id: nil, preload_participants: true)
|
def to_a_paginated_by_id(limit, options = {})
|
||||||
array = begin
|
array = begin
|
||||||
if min_id
|
if options[:min_id]
|
||||||
paginate_by_min_id(limit, min_id, max_id).reverse
|
paginate_by_min_id(limit, options[:min_id], options[:max_id]).reverse
|
||||||
else
|
else
|
||||||
paginate_by_max_id(limit, max_id, since_id).to_a
|
paginate_by_max_id(limit, options[:max_id], options[:since_id]).to_a
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if preload_participants
|
# Preload participants
|
||||||
participant_ids = array.flat_map(&:participant_account_ids)
|
participant_ids = array.flat_map(&:participant_account_ids)
|
||||||
accounts_by_id = Account.where(id: participant_ids).index_by(&:id)
|
accounts_by_id = Account.where(id: participant_ids).index_by(&:id)
|
||||||
|
|
||||||
array.each do |conversation|
|
array.each do |conversation|
|
||||||
conversation.participant_accounts = conversation.participant_account_ids.filter_map { |id| accounts_by_id[id] }
|
conversation.participant_accounts = conversation.participant_account_ids.filter_map { |id| accounts_by_id[id] }
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
array
|
array
|
||||||
|
|
|
@ -26,6 +26,7 @@ class Admin::AccountAction
|
||||||
alias include_statuses? include_statuses
|
alias include_statuses? include_statuses
|
||||||
|
|
||||||
validates :type, :target_account, :current_account, presence: true
|
validates :type, :target_account, :current_account, presence: true
|
||||||
|
validates :type, inclusion: { in: TYPES }
|
||||||
|
|
||||||
def initialize(attributes = {})
|
def initialize(attributes = {})
|
||||||
@send_email_notification = true
|
@send_email_notification = true
|
||||||
|
@ -71,6 +72,10 @@ class Admin::AccountAction
|
||||||
TYPES - %w(none disable)
|
TYPES - %w(none disable)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def i18n_scope
|
||||||
|
:activerecord
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -48,6 +48,7 @@ class Report < ApplicationRecord
|
||||||
|
|
||||||
validate :validate_rule_ids
|
validate :validate_rule_ids
|
||||||
|
|
||||||
|
# entries here needs to be kept in sync with app/javascript/mastodon/features/notifications/components/report.jsx
|
||||||
enum category: {
|
enum category: {
|
||||||
other: 0,
|
other: 0,
|
||||||
spam: 1_000,
|
spam: 1_000,
|
||||||
|
|
|
@ -7,10 +7,12 @@
|
||||||
= hidden_field_tag :confirmation_token, params[:confirmation_token]
|
= hidden_field_tag :confirmation_token, params[:confirmation_token]
|
||||||
= hidden_field_tag :redirect_to_app, params[:redirect_to_app]
|
= hidden_field_tag :redirect_to_app, params[:redirect_to_app]
|
||||||
|
|
||||||
|
%h1.title= t('auth.captcha_confirmation.title')
|
||||||
%p.lead= t('auth.captcha_confirmation.hint_html')
|
%p.lead= t('auth.captcha_confirmation.hint_html')
|
||||||
|
|
||||||
.field-group
|
= render_captcha
|
||||||
= render_captcha
|
|
||||||
|
%p.lead= t('auth.captcha_confirmation.help_html', email: mail_to(Setting.site_contact_email, nil))
|
||||||
|
|
||||||
.actions
|
.actions
|
||||||
%button.button= t('challenge.confirm')
|
= button_tag t('challenge.confirm'), class: 'button', type: :submit
|
||||||
|
|
|
@ -44,7 +44,11 @@
|
||||||
%tbody
|
%tbody
|
||||||
%td.column-cell
|
%td.column-cell
|
||||||
%p= t 'about.hosted_on', domain: site_hostname
|
%p= t 'about.hosted_on', domain: site_hostname
|
||||||
%p= link_to t('application_mailer.notification_preferences'), settings_preferences_notifications_url
|
%p
|
||||||
|
= link_to t('application_mailer.notification_preferences'), settings_preferences_notifications_url
|
||||||
|
- if defined?(@type)
|
||||||
|
·
|
||||||
|
= link_to t('application_mailer.unsubscribe'), unsubscribe_url(token: @user.to_sgid(for: 'unsubscribe').to_s, type: @type)
|
||||||
%td.column-cell.text-right
|
%td.column-cell.text-right
|
||||||
= link_to root_url do
|
= link_to root_url do
|
||||||
= image_tag full_pack_url('media/images/mailer/logo.png'), alt: 'Mastodon', height: 24
|
= image_tag full_pack_url('media/images/mailer/logo.png'), alt: 'Mastodon', height: 24
|
||||||
|
|
9
app/views/mail_subscriptions/create.html.haml
Normal file
9
app/views/mail_subscriptions/create.html.haml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
- content_for :page_title do
|
||||||
|
= t('mail_subscriptions.unsubscribe.title')
|
||||||
|
|
||||||
|
.simple_form
|
||||||
|
%h1.title= t('mail_subscriptions.unsubscribe.complete')
|
||||||
|
%p.lead
|
||||||
|
= t('mail_subscriptions.unsubscribe.success_html', domain: content_tag(:strong, site_hostname), type: content_tag(:strong, I18n.t(@type, scope: 'mail_subscriptions.unsubscribe.emails')), email: content_tag(:strong, @user.email))
|
||||||
|
%p.lead
|
||||||
|
= t('mail_subscriptions.unsubscribe.resubscribe_html', settings_path: settings_preferences_notifications_path)
|
12
app/views/mail_subscriptions/show.html.haml
Normal file
12
app/views/mail_subscriptions/show.html.haml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
- content_for :page_title do
|
||||||
|
= t('mail_subscriptions.unsubscribe.title')
|
||||||
|
|
||||||
|
.simple_form
|
||||||
|
%h1.title= t('mail_subscriptions.unsubscribe.title')
|
||||||
|
%p.lead
|
||||||
|
= t('mail_subscriptions.unsubscribe.confirmation_html', domain: content_tag(:strong, site_hostname), type: content_tag(:strong, I18n.t(@type, scope: 'mail_subscriptions.unsubscribe.emails')), email: content_tag(:strong, @user.email), settings_path: settings_preferences_notifications_path)
|
||||||
|
|
||||||
|
= form_tag unsubscribe_path, method: :post do
|
||||||
|
= hidden_field_tag :token, params[:token]
|
||||||
|
= hidden_field_tag :type, params[:type]
|
||||||
|
= button_tag t('mail_subscriptions.unsubscribe.action'), type: :submit
|
|
@ -1,13 +1,15 @@
|
||||||
- content_for :page_title do
|
- content_for :page_title do
|
||||||
= t('settings.featured_tags')
|
= t('settings.featured_tags')
|
||||||
|
|
||||||
%p= t('featured_tags.hint_html')
|
- content_for :heading do
|
||||||
|
%h2= t('settings.profile')
|
||||||
%hr.spacer/
|
= render partial: 'settings/shared/profile_navigation'
|
||||||
|
|
||||||
= simple_form_for @featured_tag, url: settings_featured_tags_path do |f|
|
= simple_form_for @featured_tag, url: settings_featured_tags_path do |f|
|
||||||
= render 'shared/error_messages', object: @featured_tag
|
= render 'shared/error_messages', object: @featured_tag
|
||||||
|
|
||||||
|
%p.lead= t('featured_tags.hint_html')
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :name, wrapper: :with_block_label, hint: safe_join([t('simple_form.hints.featured_tag.name'), safe_join(@recently_used_tags.map { |tag| link_to("##{tag.display_name}", settings_featured_tags_path(featured_tag: { name: tag.name }), method: :post) }, ', ')], ' ')
|
= f.input :name, wrapper: :with_block_label, hint: safe_join([t('simple_form.hints.featured_tag.name'), safe_join(@recently_used_tags.map { |tag| link_to("##{tag.display_name}", settings_featured_tags_path(featured_tag: { name: tag.name }), method: :post) }, ', ')], ' ')
|
||||||
|
|
||||||
|
|
|
@ -1,76 +1,76 @@
|
||||||
- content_for :page_title do
|
- content_for :page_title do
|
||||||
= t('settings.edit_profile')
|
= t('settings.edit_profile')
|
||||||
|
|
||||||
- content_for :heading_actions do
|
- content_for :heading do
|
||||||
= button_tag t('generic.save_changes'), class: 'button', form: 'edit_profile'
|
%h2= t('settings.profile')
|
||||||
|
= render partial: 'settings/shared/profile_navigation'
|
||||||
|
|
||||||
= simple_form_for @account, url: settings_profile_path, html: { method: :put, id: 'edit_profile' } do |f|
|
= simple_form_for @account, url: settings_profile_path, html: { method: :put, id: 'edit_profile' } do |f|
|
||||||
= render 'shared/error_messages', object: @account
|
= render 'shared/error_messages', object: @account
|
||||||
|
|
||||||
.fields-row
|
%p.lead= t('edit_profile.hint_html')
|
||||||
.fields-row__column.fields-group.fields-row__column-6
|
|
||||||
= f.input :display_name, wrapper: :with_label, input_html: { maxlength: Account::MAX_DISPLAY_NAME_LENGTH, data: { default: @account.username } }, hint: false
|
%h4= t('edit_profile.basic_information')
|
||||||
= f.input :note, wrapper: :with_label, input_html: { maxlength: Account::MAX_NOTE_LENGTH }, hint: false
|
|
||||||
|
|
||||||
.fields-row
|
.fields-row
|
||||||
.fields-row__column.fields-row__column-6
|
.fields-row__column.fields-row__column-6
|
||||||
= render 'application/card', account: @account
|
.fields-group
|
||||||
|
= f.input :display_name, wrapper: :with_block_label, input_html: { maxlength: Account::MAX_DISPLAY_NAME_LENGTH, data: { default: @account.username } }
|
||||||
|
|
||||||
.fields-row__column.fields-group.fields-row__column-6
|
.fields-group
|
||||||
= f.input :header, wrapper: :with_label, input_html: { accept: AccountHeader::IMAGE_MIME_TYPES.join(',') }, hint: picture_hint(t('simple_form.hints.defaults.header', dimensions: '1500x500', size: number_to_human_size(AccountHeader::LIMIT)), @account.header)
|
= f.input :note, wrapper: :with_block_label, input_html: { maxlength: Account::MAX_NOTE_LENGTH }
|
||||||
|
|
||||||
= f.input :avatar, wrapper: :with_label, input_html: { accept: AccountAvatar::IMAGE_MIME_TYPES.join(',') }, hint: picture_hint(t('simple_form.hints.defaults.avatar', dimensions: '400x400', size: number_to_human_size(AccountAvatar::LIMIT)), @account.avatar)
|
|
||||||
|
|
||||||
%hr.spacer/
|
|
||||||
|
|
||||||
.fields-group
|
|
||||||
= f.input :locked, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.locked')
|
|
||||||
|
|
||||||
.fields-group
|
|
||||||
= f.input :bot, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.bot')
|
|
||||||
|
|
||||||
.fields-group
|
|
||||||
= f.input :discoverable, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.discoverable'), recommended: true
|
|
||||||
|
|
||||||
.fields-group
|
|
||||||
= f.input :hide_collections, as: :boolean, wrapper: :with_label, label: t('simple_form.labels.defaults.setting_hide_network'), hint: t('simple_form.hints.defaults.setting_hide_network')
|
|
||||||
|
|
||||||
%hr.spacer/
|
|
||||||
|
|
||||||
.fields-row
|
|
||||||
.fields-row__column.fields-group.fields-row__column-6
|
.fields-row__column.fields-group.fields-row__column-6
|
||||||
.input.with_block_label
|
.input.with_block_label
|
||||||
%label= t('simple_form.labels.defaults.fields')
|
%label= t('simple_form.labels.defaults.fields')
|
||||||
%span.hint= t('simple_form.hints.defaults.fields', count: Account::DEFAULT_FIELDS_SIZE)
|
%span.hint= t('simple_form.hints.account.fields')
|
||||||
|
|
||||||
= f.simple_fields_for :fields do |fields_f|
|
= f.simple_fields_for :fields do |fields_f|
|
||||||
.row
|
.row
|
||||||
= fields_f.input :name, placeholder: t('simple_form.labels.account.fields.name'), input_html: { maxlength: 255 }
|
= fields_f.input :name, placeholder: t('simple_form.labels.account.fields.name'), input_html: { maxlength: 255 }
|
||||||
= fields_f.input :value, placeholder: t('simple_form.labels.account.fields.value'), input_html: { maxlength: 255 }
|
= fields_f.input :value, placeholder: t('simple_form.labels.account.fields.value'), input_html: { maxlength: 255 }
|
||||||
|
|
||||||
.fields-row__column.fields-group.fields-row__column-6
|
.fields-row
|
||||||
%h6= t('verification.verification')
|
.fields-row__column.fields-row__column-6
|
||||||
%p.hint= t('verification.explanation_html')
|
.fields-group
|
||||||
|
= f.input :avatar, wrapper: :with_block_label, input_html: { accept: AccountAvatar::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.avatar', dimensions: '400x400', size: number_to_human_size(AccountAvatar::LIMIT))
|
||||||
|
|
||||||
.input-copy
|
- if @account.avatar.present?
|
||||||
.input-copy__wrapper
|
.fields-row__column.fields-row__column-6
|
||||||
%input{ type: :text, maxlength: '999', spellcheck: 'false', readonly: 'true', value: link_to('Mastodon', ActivityPub::TagManager.instance.url_for(@account), rel: 'me').to_str }
|
.fields-group
|
||||||
%button{ type: :button }= t('generic.copy')
|
= image_tag @account.avatar.url, class: 'fields-group__thumbnail', width: 90, height: 90
|
||||||
|
= link_to settings_profile_picture_path('avatar'), data: { method: :delete }, class: 'link-button link-button--destructive' do
|
||||||
|
= fa_icon 'trash fw'
|
||||||
|
= t('generic.delete')
|
||||||
|
|
||||||
|
.fields-row
|
||||||
|
.fields-row__column.fields-row__column-6
|
||||||
|
.fields-group
|
||||||
|
= f.input :header, wrapper: :with_block_label, input_html: { accept: AccountHeader::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.header', dimensions: '1500x500', size: number_to_human_size(AccountHeader::LIMIT))
|
||||||
|
|
||||||
|
- if @account.header.present?
|
||||||
|
.fields-row__column.fields-row__column-6
|
||||||
|
.fields-group
|
||||||
|
= image_tag @account.header.url, class: 'fields-group__thumbnail'
|
||||||
|
= link_to settings_profile_picture_path('header'), data: { method: :delete }, class: 'link-button link-button--destructive' do
|
||||||
|
= fa_icon 'trash fw'
|
||||||
|
= t('generic.delete')
|
||||||
|
|
||||||
|
%h4= t('edit_profile.safety_and_privacy')
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= f.input :discoverable, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.discoverable'), recommended: true
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= f.input :locked, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.locked')
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= f.input :hide_collections, as: :boolean, wrapper: :with_label, label: t('simple_form.labels.defaults.setting_hide_network'), hint: t('simple_form.hints.defaults.setting_hide_network')
|
||||||
|
|
||||||
|
%h4= t('edit_profile.other')
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= f.input :bot, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.bot')
|
||||||
|
|
||||||
.actions
|
.actions
|
||||||
= f.button :button, t('generic.save_changes'), type: :submit
|
= f.button :button, t('generic.save_changes'), type: :submit
|
||||||
|
|
||||||
%hr/
|
|
||||||
|
|
||||||
%h6= t('auth.migrate_account')
|
|
||||||
%p.muted-hint= t('auth.migrate_account_html', path: settings_migration_path)
|
|
||||||
|
|
||||||
%hr.spacer/
|
|
||||||
|
|
||||||
%h6= t 'migrations.incoming_migrations'
|
|
||||||
%p.muted-hint= t('migrations.incoming_migrations_html', path: settings_aliases_path)
|
|
||||||
|
|
||||||
%hr.spacer/
|
|
||||||
|
|
||||||
%h6= t('auth.delete_account')
|
|
||||||
%p.muted-hint= t('auth.delete_account_html', path: settings_delete_path)
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
%ul.no-list
|
|
||||||
- if controller_name != 'profiles'
|
|
||||||
%li= link_to t('settings.edit_profile'), settings_profile_path
|
|
||||||
- if controller_name != 'preferences'
|
|
||||||
%li= link_to t('settings.preferences'), settings_preferences_path
|
|
||||||
- if controller_name != 'registrations'
|
|
||||||
%li= link_to t('auth.change_password'), edit_user_registration_path
|
|
||||||
- if controller_name != 'two_factor_authentications'
|
|
||||||
%li= link_to t('settings.two_factor_authentication'), settings_two_factor_authentication_path
|
|
||||||
%li= link_to t('settings.back'), root_path
|
|
6
app/views/settings/shared/_profile_navigation.html.haml
Normal file
6
app/views/settings/shared/_profile_navigation.html.haml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
.content__heading__tabs
|
||||||
|
= render_navigation renderer: :links do |primary|
|
||||||
|
:ruby
|
||||||
|
primary.item :profile, safe_join([fa_icon('user fw'), t('settings.edit_profile')]), settings_profile_path
|
||||||
|
primary.item :verification, safe_join([fa_icon('check fw'), t('verification.verification')]), settings_verification_path
|
||||||
|
primary.item :featured_tags, safe_join([fa_icon('hashtag fw'), t('settings.featured_tags')]), settings_featured_tags_path
|
30
app/views/settings/verifications/show.html.haml
Normal file
30
app/views/settings/verifications/show.html.haml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
- content_for :page_title do
|
||||||
|
= t('verification.verification')
|
||||||
|
|
||||||
|
- content_for :heading do
|
||||||
|
%h2= t('settings.profile')
|
||||||
|
= render partial: 'settings/shared/profile_navigation'
|
||||||
|
|
||||||
|
.simple_form
|
||||||
|
%p.lead= t('verification.hint_html')
|
||||||
|
|
||||||
|
%h4= t('verification.here_is_how')
|
||||||
|
|
||||||
|
%p.lead= t('verification.instructions_html')
|
||||||
|
|
||||||
|
.input-copy.lead
|
||||||
|
.input-copy__wrapper
|
||||||
|
%input{ type: :text, maxlength: '999', spellcheck: 'false', readonly: 'true', value: link_to('Mastodon', ActivityPub::TagManager.instance.url_for(@account), rel: 'me').to_str }
|
||||||
|
%button{ type: :button }= t('generic.copy')
|
||||||
|
|
||||||
|
%p.lead= t('verification.extra_instructions_html')
|
||||||
|
|
||||||
|
- if @verified_links.any?
|
||||||
|
%h4= t('verification.verified_links')
|
||||||
|
|
||||||
|
%ul.lead
|
||||||
|
- @verified_links.each do |field|
|
||||||
|
%li
|
||||||
|
%span.verified-badge
|
||||||
|
= fa_icon 'check', class: 'verified-badge__mark'
|
||||||
|
%span= field.value
|
|
@ -12,6 +12,9 @@ module.exports = (api) => {
|
||||||
debug: false,
|
debug: false,
|
||||||
include: [
|
include: [
|
||||||
'transform-numeric-separator',
|
'transform-numeric-separator',
|
||||||
|
'transform-optional-chaining',
|
||||||
|
'transform-nullish-coalescing-operator',
|
||||||
|
'transform-class-properties',
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,8 +27,6 @@ module.exports = (api) => {
|
||||||
plugins: [
|
plugins: [
|
||||||
['formatjs'],
|
['formatjs'],
|
||||||
'preval',
|
'preval',
|
||||||
'@babel/plugin-transform-optional-chaining',
|
|
||||||
'@babel/plugin-transform-nullish-coalescing-operator',
|
|
||||||
],
|
],
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -74,6 +74,7 @@ ignore_unused:
|
||||||
- 'notification_mailer.*'
|
- 'notification_mailer.*'
|
||||||
- 'imports.overwrite_preambles.{following,blocking,muting,domain_blocking,bookmarks}_html'
|
- 'imports.overwrite_preambles.{following,blocking,muting,domain_blocking,bookmarks}_html'
|
||||||
- 'imports.preambles.{following,blocking,muting,domain_blocking,bookmarks}_html'
|
- 'imports.preambles.{following,blocking,muting,domain_blocking,bookmarks}_html'
|
||||||
|
- 'mail_subscriptions.unsubscribe.emails.*'
|
||||||
|
|
||||||
ignore_inconsistent_interpolations:
|
ignore_inconsistent_interpolations:
|
||||||
- '*.one'
|
- '*.one'
|
||||||
|
|
|
@ -4,7 +4,6 @@ en:
|
||||||
glitch_only: glitch-soc
|
glitch_only: glitch-soc
|
||||||
hints:
|
hints:
|
||||||
defaults:
|
defaults:
|
||||||
fields: You can have up to %{count} items displayed as a table on your profile
|
|
||||||
setting_default_content_type_html: When writing toots, assume they are written in raw HTML, unless specified otherwise
|
setting_default_content_type_html: When writing toots, assume they are written in raw HTML, unless specified otherwise
|
||||||
setting_default_content_type_markdown: When writing toots, assume they are using Markdown for rich text formatting, unless specified otherwise
|
setting_default_content_type_markdown: When writing toots, assume they are using Markdown for rich text formatting, unless specified otherwise
|
||||||
setting_default_content_type_plain: When writing toots, assume they are plain text with no special formatting, unless specified otherwise (default Mastodon behavior)
|
setting_default_content_type_plain: When writing toots, assume they are plain text with no special formatting, unless specified otherwise (default Mastodon behavior)
|
||||||
|
|
|
@ -940,7 +940,6 @@ an:
|
||||||
your_token: Lo tuyo token d'acceso
|
your_token: Lo tuyo token d'acceso
|
||||||
auth:
|
auth:
|
||||||
apply_for_account: Solicitar una cuenta
|
apply_for_account: Solicitar una cuenta
|
||||||
change_password: Clau
|
|
||||||
delete_account: Borrar cuenta
|
delete_account: Borrar cuenta
|
||||||
delete_account_html: Si deseya eliminar la suya cuenta, puede <a href="%{path}">proceder aquí</a>. Será pediu d'una confirmación.
|
delete_account_html: Si deseya eliminar la suya cuenta, puede <a href="%{path}">proceder aquí</a>. Será pediu d'una confirmación.
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -990,7 +990,6 @@ ar:
|
||||||
your_token: رمز نفاذك
|
your_token: رمز نفاذك
|
||||||
auth:
|
auth:
|
||||||
apply_for_account: اطلُب حسابًا
|
apply_for_account: اطلُب حسابًا
|
||||||
change_password: الكلمة السرية
|
|
||||||
confirmations:
|
confirmations:
|
||||||
wrong_email_hint: إذا كان عنوان البريد الإلكتروني هذا غير صحيح، يمكنك تغييره في إعدادات الحساب.
|
wrong_email_hint: إذا كان عنوان البريد الإلكتروني هذا غير صحيح، يمكنك تغييره في إعدادات الحساب.
|
||||||
delete_account: حذف الحساب
|
delete_account: حذف الحساب
|
||||||
|
|
|
@ -449,7 +449,6 @@ ast:
|
||||||
warning: Ten munchu curiáu con estos datos, ¡enxamás nun los compartas con naide!
|
warning: Ten munchu curiáu con estos datos, ¡enxamás nun los compartas con naide!
|
||||||
your_token: El pase d'accesu
|
your_token: El pase d'accesu
|
||||||
auth:
|
auth:
|
||||||
change_password: Contraseña
|
|
||||||
confirmations:
|
confirmations:
|
||||||
wrong_email_hint: Si la direición de corréu electrónicu nun ye correuta, pues camudala na configuración de la cuenta.
|
wrong_email_hint: Si la direición de corréu electrónicu nun ye correuta, pues camudala na configuración de la cuenta.
|
||||||
delete_account: Desaniciu de la cuenta
|
delete_account: Desaniciu de la cuenta
|
||||||
|
|
|
@ -1015,7 +1015,6 @@ be:
|
||||||
your_token: Ваш токен доступу
|
your_token: Ваш токен доступу
|
||||||
auth:
|
auth:
|
||||||
apply_for_account: Пакінуць заяўку
|
apply_for_account: Пакінуць заяўку
|
||||||
change_password: Пароль
|
|
||||||
confirmations:
|
confirmations:
|
||||||
wrong_email_hint: Калі гэты адрас электроннай пошты памылковы, вы можаце змяніць яго ў наладах уліковага запісу.
|
wrong_email_hint: Калі гэты адрас электроннай пошты памылковы, вы можаце змяніць яго ў наладах уліковага запісу.
|
||||||
delete_account: Выдаліць уліковы запіс
|
delete_account: Выдаліць уліковы запіс
|
||||||
|
@ -1768,7 +1767,6 @@ be:
|
||||||
seamless_external_login: Вы ўвайшлі праз знешні сэрвіс, таму налады пароля і эл. пошты недаступныя.
|
seamless_external_login: Вы ўвайшлі праз знешні сэрвіс, таму налады пароля і эл. пошты недаступныя.
|
||||||
signed_in_as: 'Увайшлі як:'
|
signed_in_as: 'Увайшлі як:'
|
||||||
verification:
|
verification:
|
||||||
explanation_html: 'Вы можаце <strong>пацвердзіць сябе як уладальніка спасылак у метададзеных вашага профілю</strong>. Для гэтага спасылка на вэб-сайт павінна ўтрымліваць спасылку на ваш профіль Mastodon. Пасля дадавання спасылка, вам спатрэбіцца вярнуцца і перазахаваць свой профіль, каб усё адбыдося. Зваротная спасылка <strong>павінна</strong> мець атрыбут <code>rel="me"</code>. Тэкставы змест спасылкі не мае значэння. Вось прыклад:'
|
|
||||||
verification: Верыфікацыя
|
verification: Верыфікацыя
|
||||||
webauthn_credentials:
|
webauthn_credentials:
|
||||||
add: Дадаць новы ключ бяспекі
|
add: Дадаць новы ключ бяспекі
|
||||||
|
|
|
@ -979,7 +979,6 @@ bg:
|
||||||
your_token: Вашият код за достъп
|
your_token: Вашият код за достъп
|
||||||
auth:
|
auth:
|
||||||
apply_for_account: Заявка за акаунт
|
apply_for_account: Заявка за акаунт
|
||||||
change_password: Парола
|
|
||||||
confirmations:
|
confirmations:
|
||||||
wrong_email_hint: Ако този адрес на е-поща не е правилен, то може да го промените в настройки на акаунта.
|
wrong_email_hint: Ако този адрес на е-поща не е правилен, то може да го промените в настройки на акаунта.
|
||||||
delete_account: Изтриване на акаунта
|
delete_account: Изтриване на акаунта
|
||||||
|
@ -1704,7 +1703,6 @@ bg:
|
||||||
seamless_external_login: Влезли сте чрез външна услуга, така че настройките за парола и имейл не са налични.
|
seamless_external_login: Влезли сте чрез външна услуга, така че настройките за парола и имейл не са налични.
|
||||||
signed_in_as: 'Влезли като:'
|
signed_in_as: 'Влезли като:'
|
||||||
verification:
|
verification:
|
||||||
explanation_html: 'Може да <strong>потвърдите себе си като собственик на връзките в метаданните на профила си</strong>. За целта свързаният уебсайт трябва да съдържа обратна връзка към профилa ви в Mastodon. След добавянето на връзката, може да се наложи да се върнете тук и да запазите пак профила си, за да влезе в сила потвърждаването. Връзката обратно <strong>трябва</strong> да има атрибут <code>rel="me"</code>. Текстовото съдържание на връзката няма значение. Ето пример:'
|
|
||||||
verification: Проверка
|
verification: Проверка
|
||||||
webauthn_credentials:
|
webauthn_credentials:
|
||||||
add: Добавяне на нов ключ за сигурност
|
add: Добавяне на нов ключ за сигурност
|
||||||
|
|
|
@ -288,7 +288,6 @@ br:
|
||||||
view: 'Sellet :'
|
view: 'Sellet :'
|
||||||
view_status: Gwelet ar c'hannad
|
view_status: Gwelet ar c'hannad
|
||||||
auth:
|
auth:
|
||||||
change_password: Ger-tremen
|
|
||||||
delete_account: Dilemel ar gont
|
delete_account: Dilemel ar gont
|
||||||
login: Mont tre
|
login: Mont tre
|
||||||
logout: Digennaskañ
|
logout: Digennaskañ
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue